Commit b9d989dc056a2a2b9316ff9aa06b57c736426871
Exists in
master
and in
4 other branches
Merge branch 'Andrew8xx8-gist'
Showing
60 changed files
with
972 additions
and
210 deletions
Show diff stats
app/controllers/projects/application_controller.rb
1 | class Projects::ApplicationController < ApplicationController | 1 | class Projects::ApplicationController < ApplicationController |
2 | - | ||
3 | - before_filter :authorize_admin_team_member! | ||
4 | - | ||
5 | - protected | ||
6 | - | ||
7 | - def user_team | ||
8 | - @team ||= UserTeam.find_by_path(params[:id]) | ||
9 | - end | ||
10 | - | 2 | + before_filter :project |
3 | + before_filter :repository | ||
11 | end | 4 | end |
@@ -0,0 +1,91 @@ | @@ -0,0 +1,91 @@ | ||
1 | +class Projects::SnippetsController < Projects::ApplicationController | ||
2 | + before_filter :module_enabled | ||
3 | + before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw] | ||
4 | + | ||
5 | + # Allow read any snippet | ||
6 | + before_filter :authorize_read_project_snippet! | ||
7 | + | ||
8 | + # Allow write(create) snippet | ||
9 | + before_filter :authorize_write_project_snippet!, only: [:new, :create] | ||
10 | + | ||
11 | + # Allow modify snippet | ||
12 | + before_filter :authorize_modify_project_snippet!, only: [:edit, :update] | ||
13 | + | ||
14 | + # Allow destroy snippet | ||
15 | + before_filter :authorize_admin_project_snippet!, only: [:destroy] | ||
16 | + | ||
17 | + layout 'project_resource' | ||
18 | + | ||
19 | + respond_to :html | ||
20 | + | ||
21 | + def index | ||
22 | + @snippets = @project.snippets.fresh.non_expired | ||
23 | + end | ||
24 | + | ||
25 | + def new | ||
26 | + @snippet = @project.snippets.build | ||
27 | + end | ||
28 | + | ||
29 | + def create | ||
30 | + @snippet = @project.snippets.build(params[:project_snippet]) | ||
31 | + @snippet.author = current_user | ||
32 | + | ||
33 | + if @snippet.save | ||
34 | + redirect_to project_snippet_path(@project, @snippet) | ||
35 | + else | ||
36 | + respond_with(@snippet) | ||
37 | + end | ||
38 | + end | ||
39 | + | ||
40 | + def edit | ||
41 | + end | ||
42 | + | ||
43 | + def update | ||
44 | + if @snippet.update_attributes(params[:project_snippet]) | ||
45 | + redirect_to project_snippet_path(@project, @snippet) | ||
46 | + else | ||
47 | + respond_with(@snippet) | ||
48 | + end | ||
49 | + end | ||
50 | + | ||
51 | + def show | ||
52 | + @note = @project.notes.new(noteable: @snippet) | ||
53 | + @target_type = :snippet | ||
54 | + @target_id = @snippet.id | ||
55 | + end | ||
56 | + | ||
57 | + def destroy | ||
58 | + return access_denied! unless can?(current_user, :admin_project_snippet, @snippet) | ||
59 | + | ||
60 | + @snippet.destroy | ||
61 | + | ||
62 | + redirect_to project_snippets_path(@project) | ||
63 | + end | ||
64 | + | ||
65 | + def raw | ||
66 | + send_data( | ||
67 | + @snippet.content, | ||
68 | + type: "text/plain", | ||
69 | + disposition: 'inline', | ||
70 | + filename: @snippet.file_name | ||
71 | + ) | ||
72 | + end | ||
73 | + | ||
74 | + protected | ||
75 | + | ||
76 | + def snippet | ||
77 | + @snippet ||= @project.snippets.find(params[:id]) | ||
78 | + end | ||
79 | + | ||
80 | + def authorize_modify_project_snippet! | ||
81 | + return render_404 unless can?(current_user, :modify_project_snippet, @snippet) | ||
82 | + end | ||
83 | + | ||
84 | + def authorize_admin_project_snippet! | ||
85 | + return render_404 unless can?(current_user, :admin_project_snippet, @snippet) | ||
86 | + end | ||
87 | + | ||
88 | + def module_enabled | ||
89 | + return render_404 unless @project.snippets_enabled | ||
90 | + end | ||
91 | +end |
app/controllers/projects/teams_controller.rb
1 | class Projects::TeamsController < Projects::ApplicationController | 1 | class Projects::TeamsController < Projects::ApplicationController |
2 | 2 | ||
3 | + before_filter :authorize_admin_team_member! | ||
4 | + | ||
3 | def available | 5 | def available |
4 | @teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams | 6 | @teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams |
5 | @teams = @teams.without_project(project) | 7 | @teams = @teams.without_project(project) |
@@ -24,4 +26,9 @@ class Projects::TeamsController < Projects::ApplicationController | @@ -24,4 +26,9 @@ class Projects::TeamsController < Projects::ApplicationController | ||
24 | redirect_to project_team_index_path(project) | 26 | redirect_to project_team_index_path(project) |
25 | end | 27 | end |
26 | 28 | ||
29 | + protected | ||
30 | + | ||
31 | + def user_team | ||
32 | + @team ||= UserTeam.find_by_path(params[:id]) | ||
33 | + end | ||
27 | end | 34 | end |
app/controllers/snippets_controller.rb
1 | -class SnippetsController < ProjectResourceController | ||
2 | - before_filter :module_enabled | 1 | +class SnippetsController < ApplicationController |
3 | before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw] | 2 | before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw] |
4 | 3 | ||
5 | - # Allow read any snippet | ||
6 | - before_filter :authorize_read_snippet! | ||
7 | - | ||
8 | - # Allow write(create) snippet | ||
9 | - before_filter :authorize_write_snippet!, only: [:new, :create] | ||
10 | - | ||
11 | # Allow modify snippet | 4 | # Allow modify snippet |
12 | before_filter :authorize_modify_snippet!, only: [:edit, :update] | 5 | before_filter :authorize_modify_snippet!, only: [:edit, :update] |
13 | 6 | ||
@@ -17,22 +10,38 @@ class SnippetsController < ProjectResourceController | @@ -17,22 +10,38 @@ class SnippetsController < ProjectResourceController | ||
17 | respond_to :html | 10 | respond_to :html |
18 | 11 | ||
19 | def index | 12 | def index |
20 | - @snippets = @project.snippets.fresh.non_expired | 13 | + @snippets = Snippet.public.fresh.non_expired.page(params[:page]).per(20) |
14 | + end | ||
15 | + | ||
16 | + def user_index | ||
17 | + @user = User.find_by_username(params[:username]) | ||
18 | + | ||
19 | + @snippets = @current_user.snippets.fresh.non_expired | ||
20 | + | ||
21 | + @snippets = case params[:scope] | ||
22 | + when 'public' then | ||
23 | + @snippets.public | ||
24 | + when 'private' then | ||
25 | + @snippets.private | ||
26 | + else | ||
27 | + @snippets | ||
28 | + end | ||
29 | + | ||
30 | + @snippets = @snippets.page(params[:page]).per(20) | ||
21 | end | 31 | end |
22 | 32 | ||
23 | def new | 33 | def new |
24 | - @snippet = @project.snippets.new | 34 | + @snippet = PersonalSnippet.new |
25 | end | 35 | end |
26 | 36 | ||
27 | def create | 37 | def create |
28 | - @snippet = @project.snippets.new(params[:snippet]) | 38 | + @snippet = PersonalSnippet.new(params[:personal_snippet]) |
29 | @snippet.author = current_user | 39 | @snippet.author = current_user |
30 | - @snippet.save | ||
31 | 40 | ||
32 | - if @snippet.valid? | ||
33 | - redirect_to [@project, @snippet] | 41 | + if @snippet.save |
42 | + redirect_to snippet_path(@snippet) | ||
34 | else | 43 | else |
35 | - respond_with(@snippet) | 44 | + respond_with @snippet |
36 | end | 45 | end |
37 | end | 46 | end |
38 | 47 | ||
@@ -40,27 +49,22 @@ class SnippetsController < ProjectResourceController | @@ -40,27 +49,22 @@ class SnippetsController < ProjectResourceController | ||
40 | end | 49 | end |
41 | 50 | ||
42 | def update | 51 | def update |
43 | - @snippet.update_attributes(params[:snippet]) | ||
44 | - | ||
45 | - if @snippet.valid? | ||
46 | - redirect_to [@project, @snippet] | 52 | + if @snippet.update_attributes(params[:personal_snippet]) |
53 | + redirect_to snippet_path(@snippet) | ||
47 | else | 54 | else |
48 | - respond_with(@snippet) | 55 | + respond_with @snippet |
49 | end | 56 | end |
50 | end | 57 | end |
51 | 58 | ||
52 | def show | 59 | def show |
53 | - @note = @project.notes.new(noteable: @snippet) | ||
54 | - @target_type = :snippet | ||
55 | - @target_id = @snippet.id | ||
56 | end | 60 | end |
57 | 61 | ||
58 | def destroy | 62 | def destroy |
59 | - return access_denied! unless can?(current_user, :admin_snippet, @snippet) | 63 | + return access_denied! unless can?(current_user, :admin_personal_snippet, @snippet) |
60 | 64 | ||
61 | @snippet.destroy | 65 | @snippet.destroy |
62 | 66 | ||
63 | - redirect_to project_snippets_path(@project) | 67 | + redirect_to snippets_path |
64 | end | 68 | end |
65 | 69 | ||
66 | def raw | 70 | def raw |
@@ -75,18 +79,14 @@ class SnippetsController < ProjectResourceController | @@ -75,18 +79,14 @@ class SnippetsController < ProjectResourceController | ||
75 | protected | 79 | protected |
76 | 80 | ||
77 | def snippet | 81 | def snippet |
78 | - @snippet ||= @project.snippets.find(params[:id]) | 82 | + @snippet ||= PersonalSnippet.find(params[:id]) |
79 | end | 83 | end |
80 | 84 | ||
81 | def authorize_modify_snippet! | 85 | def authorize_modify_snippet! |
82 | - return render_404 unless can?(current_user, :modify_snippet, @snippet) | 86 | + return render_404 unless can?(current_user, :modify_personal_snippet, @snippet) |
83 | end | 87 | end |
84 | 88 | ||
85 | def authorize_admin_snippet! | 89 | def authorize_admin_snippet! |
86 | - return render_404 unless can?(current_user, :admin_snippet, @snippet) | ||
87 | - end | ||
88 | - | ||
89 | - def module_enabled | ||
90 | - return render_404 unless @project.snippets_enabled | 90 | + return render_404 unless can?(current_user, :admin_personal_snippet, @snippet) |
91 | end | 91 | end |
92 | end | 92 | end |
app/helpers/tab_helper.rb
@@ -73,7 +73,7 @@ module TabHelper | @@ -73,7 +73,7 @@ module TabHelper | ||
73 | end | 73 | end |
74 | 74 | ||
75 | def project_tab_class | 75 | def project_tab_class |
76 | - return "active" if current_page?(controller: "projects", action: :edit, id: @project) | 76 | + return "active" if current_page?(controller: "/projects", action: :edit, id: @project) |
77 | 77 | ||
78 | if ['services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name | 78 | if ['services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name |
79 | "active" | 79 | "active" |
app/models/ability.rb
@@ -7,7 +7,8 @@ class Ability | @@ -7,7 +7,8 @@ class Ability | ||
7 | when "Project" then project_abilities(user, subject) | 7 | when "Project" then project_abilities(user, subject) |
8 | when "Issue" then issue_abilities(user, subject) | 8 | when "Issue" then issue_abilities(user, subject) |
9 | when "Note" then note_abilities(user, subject) | 9 | when "Note" then note_abilities(user, subject) |
10 | - when "Snippet" then snippet_abilities(user, subject) | 10 | + when "ProjectSnippet" then project_snippet_abilities(user, subject) |
11 | + when "PersonalSnippet" then personal_snippet_abilities(user, subject) | ||
11 | when "MergeRequest" then merge_request_abilities(user, subject) | 12 | when "MergeRequest" then merge_request_abilities(user, subject) |
12 | when "Group", "Namespace" then group_abilities(user, subject) | 13 | when "Group", "Namespace" then group_abilities(user, subject) |
13 | when "UserTeam" then user_team_abilities(user, subject) | 14 | when "UserTeam" then user_team_abilities(user, subject) |
@@ -54,7 +55,7 @@ class Ability | @@ -54,7 +55,7 @@ class Ability | ||
54 | :read_wiki, | 55 | :read_wiki, |
55 | :read_issue, | 56 | :read_issue, |
56 | :read_milestone, | 57 | :read_milestone, |
57 | - :read_snippet, | 58 | + :read_project_snippet, |
58 | :read_team_member, | 59 | :read_team_member, |
59 | :read_merge_request, | 60 | :read_merge_request, |
60 | :read_note, | 61 | :read_note, |
@@ -67,8 +68,8 @@ class Ability | @@ -67,8 +68,8 @@ class Ability | ||
67 | def project_report_rules | 68 | def project_report_rules |
68 | project_guest_rules + [ | 69 | project_guest_rules + [ |
69 | :download_code, | 70 | :download_code, |
70 | - :write_snippet, | ||
71 | - :fork_project | 71 | + :fork_project, |
72 | + :write_project_snippet | ||
72 | ] | 73 | ] |
73 | end | 74 | end |
74 | 75 | ||
@@ -84,11 +85,11 @@ class Ability | @@ -84,11 +85,11 @@ class Ability | ||
84 | project_dev_rules + [ | 85 | project_dev_rules + [ |
85 | :push_code_to_protected_branches, | 86 | :push_code_to_protected_branches, |
86 | :modify_issue, | 87 | :modify_issue, |
87 | - :modify_snippet, | 88 | + :modify_project_snippet, |
88 | :modify_merge_request, | 89 | :modify_merge_request, |
89 | :admin_issue, | 90 | :admin_issue, |
90 | :admin_milestone, | 91 | :admin_milestone, |
91 | - :admin_snippet, | 92 | + :admin_project_snippet, |
92 | :admin_team_member, | 93 | :admin_team_member, |
93 | :admin_merge_request, | 94 | :admin_merge_request, |
94 | :admin_note, | 95 | :admin_note, |
@@ -135,8 +136,7 @@ class Ability | @@ -135,8 +136,7 @@ class Ability | ||
135 | rules.flatten | 136 | rules.flatten |
136 | end | 137 | end |
137 | 138 | ||
138 | - | ||
139 | - [:issue, :note, :snippet, :merge_request].each do |name| | 139 | + [:issue, :note, :project_snippet, :personal_snippet, :merge_request].each do |name| |
140 | define_method "#{name}_abilities" do |user, subject| | 140 | define_method "#{name}_abilities" do |user, subject| |
141 | if subject.author == user | 141 | if subject.author == user |
142 | [ | 142 | [ |
app/models/event.rb
@@ -241,6 +241,10 @@ class Event < ActiveRecord::Base | @@ -241,6 +241,10 @@ class Event < ActiveRecord::Base | ||
241 | target.noteable_type == "Commit" | 241 | target.noteable_type == "Commit" |
242 | end | 242 | end |
243 | 243 | ||
244 | + def note_project_snippet? | ||
245 | + target.noteable_type == "Snippet" | ||
246 | + end | ||
247 | + | ||
244 | def note_target | 248 | def note_target |
245 | target.noteable | 249 | target.noteable |
246 | end | 250 | end |
app/models/note.rb
@@ -159,4 +159,10 @@ class Note < ActiveRecord::Base | @@ -159,4 +159,10 @@ class Note < ActiveRecord::Base | ||
159 | "wall" | 159 | "wall" |
160 | end | 160 | end |
161 | end | 161 | end |
162 | + | ||
163 | + # FIXME: Hack for polymorphic associations with STI | ||
164 | + # For more information wisit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations | ||
165 | + def noteable_type=(sType) | ||
166 | + super(sType.to_s.classify.constantize.base_class.to_s) | ||
167 | + end | ||
162 | end | 168 | end |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +# == Schema Information | ||
2 | +# | ||
3 | +# Table name: snippets | ||
4 | +# | ||
5 | +# id :integer not null, primary key | ||
6 | +# title :string(255) | ||
7 | +# content :text | ||
8 | +# author_id :integer not null | ||
9 | +# project_id :integer not null | ||
10 | +# created_at :datetime not null | ||
11 | +# updated_at :datetime not null | ||
12 | +# file_name :string(255) | ||
13 | +# expires_at :datetime | ||
14 | +# type :string(255) | ||
15 | +# private :boolean | ||
16 | + | ||
17 | +class PersonalSnippet < Snippet | ||
18 | +end |
app/models/project.rb
@@ -57,7 +57,7 @@ class Project < ActiveRecord::Base | @@ -57,7 +57,7 @@ class Project < ActiveRecord::Base | ||
57 | has_many :milestones, dependent: :destroy | 57 | has_many :milestones, dependent: :destroy |
58 | has_many :users_projects, dependent: :destroy | 58 | has_many :users_projects, dependent: :destroy |
59 | has_many :notes, dependent: :destroy | 59 | has_many :notes, dependent: :destroy |
60 | - has_many :snippets, dependent: :destroy | 60 | + has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet" |
61 | has_many :hooks, dependent: :destroy, class_name: "ProjectHook" | 61 | has_many :hooks, dependent: :destroy, class_name: "ProjectHook" |
62 | has_many :protected_branches, dependent: :destroy | 62 | has_many :protected_branches, dependent: :destroy |
63 | has_many :user_team_project_relationships, dependent: :destroy | 63 | has_many :user_team_project_relationships, dependent: :destroy |
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +# == Schema Information | ||
2 | +# | ||
3 | +# Table name: snippets | ||
4 | +# | ||
5 | +# id :integer not null, primary key | ||
6 | +# title :string(255) | ||
7 | +# content :text | ||
8 | +# author_id :integer not null | ||
9 | +# project_id :integer not null | ||
10 | +# created_at :datetime not null | ||
11 | +# updated_at :datetime not null | ||
12 | +# file_name :string(255) | ||
13 | +# expires_at :datetime | ||
14 | +# type :string(255) | ||
15 | +# private :boolean | ||
16 | + | ||
17 | +class ProjectSnippet < Snippet | ||
18 | + belongs_to :project | ||
19 | + belongs_to :author, class_name: "User" | ||
20 | + | ||
21 | + validates :project, presence: true | ||
22 | + | ||
23 | + # Scopes | ||
24 | + scope :fresh, -> { order("created_at DESC") } | ||
25 | + scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) } | ||
26 | + scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) } | ||
27 | +end |
app/models/snippet.rb
@@ -11,29 +11,31 @@ | @@ -11,29 +11,31 @@ | ||
11 | # updated_at :datetime not null | 11 | # updated_at :datetime not null |
12 | # file_name :string(255) | 12 | # file_name :string(255) |
13 | # expires_at :datetime | 13 | # expires_at :datetime |
14 | -# | 14 | +# type :string(255) |
15 | +# private :boolean | ||
15 | 16 | ||
16 | class Snippet < ActiveRecord::Base | 17 | class Snippet < ActiveRecord::Base |
17 | include Linguist::BlobHelper | 18 | include Linguist::BlobHelper |
18 | 19 | ||
19 | - attr_accessible :title, :content, :file_name, :expires_at | 20 | + attr_accessible :title, :content, :file_name, :expires_at, :private |
20 | 21 | ||
21 | - belongs_to :project | ||
22 | belongs_to :author, class_name: "User" | 22 | belongs_to :author, class_name: "User" |
23 | + | ||
23 | has_many :notes, as: :noteable, dependent: :destroy | 24 | has_many :notes, as: :noteable, dependent: :destroy |
24 | 25 | ||
25 | delegate :name, :email, to: :author, prefix: true, allow_nil: true | 26 | delegate :name, :email, to: :author, prefix: true, allow_nil: true |
26 | 27 | ||
27 | validates :author, presence: true | 28 | validates :author, presence: true |
28 | - validates :project, presence: true | ||
29 | validates :title, presence: true, length: { within: 0..255 } | 29 | validates :title, presence: true, length: { within: 0..255 } |
30 | validates :file_name, presence: true, length: { within: 0..255 } | 30 | validates :file_name, presence: true, length: { within: 0..255 } |
31 | validates :content, presence: true | 31 | validates :content, presence: true |
32 | 32 | ||
33 | # Scopes | 33 | # Scopes |
34 | - scope :fresh, -> { order("created_at DESC") } | ||
35 | - scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) } | 34 | + scope :public, -> { where(private: false) } |
35 | + scope :private, -> { where(private: true) } | ||
36 | + scope :fresh, -> { order("created_at DESC") } | ||
36 | scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) } | 37 | scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) } |
38 | + scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) } | ||
37 | 39 | ||
38 | def self.content_types | 40 | def self.content_types |
39 | [ | 41 | [ |
app/models/user.rb
@@ -78,6 +78,7 @@ class User < ActiveRecord::Base | @@ -78,6 +78,7 @@ class User < ActiveRecord::Base | ||
78 | has_many :team_projects, through: :user_team_project_relationships | 78 | has_many :team_projects, through: :user_team_project_relationships |
79 | 79 | ||
80 | # Projects | 80 | # Projects |
81 | + has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet" | ||
81 | has_many :users_projects, dependent: :destroy | 82 | has_many :users_projects, dependent: :destroy |
82 | has_many :issues, dependent: :destroy, foreign_key: :author_id | 83 | has_many :issues, dependent: :destroy, foreign_key: :author_id |
83 | has_many :notes, dependent: :destroy, foreign_key: :author_id | 84 | has_many :notes, dependent: :destroy, foreign_key: :author_id |
app/views/events/event/_note.html.haml
@@ -5,6 +5,10 @@ | @@ -5,6 +5,10 @@ | ||
5 | - if event.note_commit? | 5 | - if event.note_commit? |
6 | = event.note_target_type | 6 | = event.note_target_type |
7 | = link_to event.note_short_commit_id, project_commit_path(event.project, event.note_commit_id), class: "commit_short_id" | 7 | = link_to event.note_short_commit_id, project_commit_path(event.project, event.note_commit_id), class: "commit_short_id" |
8 | + - if event.note_project_snippet? | ||
9 | + = link_to project_snippet_path(event.project, event.note_target) do | ||
10 | + %strong | ||
11 | + #{event.note_target_type} ##{truncate event.note_target_id} | ||
8 | - else | 12 | - else |
9 | = link_to [event.project, event.note_target] do | 13 | = link_to [event.project, event.note_target] do |
10 | %strong | 14 | %strong |
app/views/layouts/_head_panel.html.haml
@@ -18,6 +18,9 @@ | @@ -18,6 +18,9 @@ | ||
18 | %li | 18 | %li |
19 | = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do | 19 | = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do |
20 | %i.icon-globe | 20 | %i.icon-globe |
21 | + %li | ||
22 | + = link_to snippets_path, title: "Snippets area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do | ||
23 | + %i.icon-paste | ||
21 | - if current_user.is_admin? | 24 | - if current_user.is_admin? |
22 | %li | 25 | %li |
23 | = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do | 26 | = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do |
@@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
1 | +!!! 5 | ||
2 | +%html{ lang: "en"} | ||
3 | + = render "layouts/head", title: "Snipepts" | ||
4 | + %body{class: "#{app_theme} application"} | ||
5 | + = render "layouts/head_panel", title: "Snippets" | ||
6 | + = render "layouts/flash" | ||
7 | + %nav.main-nav | ||
8 | + .container | ||
9 | + %ul | ||
10 | + = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do | ||
11 | + = link_to root_path, title: "Back to dashboard" do | ||
12 | + %i.icon-home | ||
13 | + = nav_link(path: 'snippet#new') do | ||
14 | + = link_to new_snippet_path do | ||
15 | + New snippet | ||
16 | + = nav_link(path: 'snippets#user_index') do | ||
17 | + = link_to user_snippets_path(@current_user) do | ||
18 | + My snippets | ||
19 | + = nav_link(path: 'snippets#index') do | ||
20 | + = link_to snippets_path do | ||
21 | + Discover snippets | ||
22 | + .container | ||
23 | + .content= yield |
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +.file_holder | ||
2 | + .file_title | ||
3 | + %i.icon-file | ||
4 | + %strong= @snippet.file_name | ||
5 | + %span.options | ||
6 | + = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank" | ||
7 | + .file_content.code | ||
8 | + - unless @snippet.content.empty? | ||
9 | + %div{class: user_color_scheme_class} | ||
10 | + = raw @snippet.colorize(formatter: :gitlab) | ||
11 | + - else | ||
12 | + %p.nothing_here_message Empty file |
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +%h3.page_title | ||
2 | + = @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}" | ||
3 | +%hr | ||
4 | +.snippet-form-holder | ||
5 | + = form_for [@project, @snippet], as: :project_snippet, url: url do |f| | ||
6 | + -if @snippet.errors.any? | ||
7 | + .alert.alert-error | ||
8 | + %ul | ||
9 | + - @snippet.errors.full_messages.each do |msg| | ||
10 | + %li= msg | ||
11 | + | ||
12 | + .clearfix | ||
13 | + = f.label :title | ||
14 | + .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true | ||
15 | + .clearfix | ||
16 | + = f.label "Lifetime" | ||
17 | + .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'} | ||
18 | + .clearfix | ||
19 | + .file-editor | ||
20 | + = f.label :file_name, "File" | ||
21 | + .input | ||
22 | + .file_holder.snippet | ||
23 | + .file_title | ||
24 | + = f.text_field :file_name, placeholder: "example.rb", class: 'snippet-file-name', required: true | ||
25 | + .file_content.code | ||
26 | + %pre#editor= @snippet.content | ||
27 | + = f.hidden_field :content, class: 'snippet-file-content' | ||
28 | + | ||
29 | + .form-actions | ||
30 | + = f.submit 'Save', class: "btn-save btn" | ||
31 | + = link_to "Cancel", project_snippets_path(@project), class: " btn" | ||
32 | + - unless @snippet.new_record? | ||
33 | + .pull-right= link_to 'Destroy', project_snippet_path(@project, @snippet), confirm: 'Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" | ||
34 | + | ||
35 | + | ||
36 | +:javascript | ||
37 | + var editor = ace.edit("editor"); | ||
38 | + $(".snippet-form-holder form").submit(function(){ | ||
39 | + $(".snippet-file-content").val(editor.getValue()); | ||
40 | + }); | ||
41 | + |
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +%tr | ||
2 | + %td | ||
3 | + = image_tag gravatar_icon(snippet.author_email), class: "avatar s24" | ||
4 | + %a{href: project_snippet_path(snippet.project, snippet)} | ||
5 | + %strong= truncate(snippet.title, length: 60) | ||
6 | + %td | ||
7 | + = snippet.file_name | ||
8 | + %td | ||
9 | + %span.cgray | ||
10 | + - if snippet.expires_at | ||
11 | + = snippet.expires_at.to_date.to_s(:short) | ||
12 | + - else | ||
13 | + Never |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | += render "projects/snippets/form", url: project_snippet_path(@project, @snippet) |
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +%h3.page_title | ||
2 | + Snippets | ||
3 | + %small share code pastes with others out of git repository | ||
4 | + | ||
5 | + - if can? current_user, :write_project_snippet, @project | ||
6 | + = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do | ||
7 | + Add new snippet | ||
8 | +%br | ||
9 | +%table | ||
10 | + %thead | ||
11 | + %tr | ||
12 | + %th Title | ||
13 | + %th File Name | ||
14 | + %th Expires At | ||
15 | + = render partial: "projects/snippets/snippet", collection: @snippets | ||
16 | + - if @snippets.empty? | ||
17 | + %tr | ||
18 | + %td{colspan: 3} | ||
19 | + %h3.nothing_here_message Nothing here. |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | += render "projects/snippets/form", url: project_snippets_path(@project, @snippet) |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +%h3.page_title | ||
2 | + = @snippet.title | ||
3 | + %small= @snippet.file_name | ||
4 | + - if can?(current_user, :admin_project_snippet, @project) || @snippet.author == current_user | ||
5 | + = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right", title: 'Edit Snippet' | ||
6 | + | ||
7 | +%br | ||
8 | +%div= render 'projects/snippets/blob' | ||
9 | +%div#notes= render "notes/notes_with_form" |
app/views/snippets/_blob.html.haml
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | %i.icon-file | 3 | %i.icon-file |
4 | %strong= @snippet.file_name | 4 | %strong= @snippet.file_name |
5 | %span.options | 5 | %span.options |
6 | - = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank" | 6 | + = link_to "raw", raw_snippet_path(@snippet), class: "btn btn-tiny", target: "_blank" |
7 | .file_content.code | 7 | .file_content.code |
8 | - unless @snippet.content.empty? | 8 | - unless @snippet.content.empty? |
9 | %div{class: user_color_scheme_class} | 9 | %div{class: user_color_scheme_class} |
app/views/snippets/_form.html.haml
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | = @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}" | 2 | = @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}" |
3 | %hr | 3 | %hr |
4 | .snippet-form-holder | 4 | .snippet-form-holder |
5 | - = form_for [@project, @snippet] do |f| | 5 | + = form_for @snippet, as: :personal_snippet, url: url do |f| |
6 | -if @snippet.errors.any? | 6 | -if @snippet.errors.any? |
7 | .alert.alert-error | 7 | .alert.alert-error |
8 | %ul | 8 | %ul |
@@ -13,6 +13,9 @@ | @@ -13,6 +13,9 @@ | ||
13 | = f.label :title | 13 | = f.label :title |
14 | .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true | 14 | .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true |
15 | .clearfix | 15 | .clearfix |
16 | + = f.label "Private?" | ||
17 | + .input= f.check_box :private, {class: ''} | ||
18 | + .clearfix | ||
16 | = f.label "Lifetime" | 19 | = f.label "Lifetime" |
17 | .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'} | 20 | .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'} |
18 | .clearfix | 21 | .clearfix |
@@ -28,9 +31,9 @@ | @@ -28,9 +31,9 @@ | ||
28 | 31 | ||
29 | .form-actions | 32 | .form-actions |
30 | = f.submit 'Save', class: "btn-save btn" | 33 | = f.submit 'Save', class: "btn-save btn" |
31 | - = link_to "Cancel", project_snippets_path(@project), class: " btn" | 34 | + = link_to "Cancel", snippets_path(@project), class: " btn" |
32 | - unless @snippet.new_record? | 35 | - unless @snippet.new_record? |
33 | - .pull-right= link_to 'Destroy', [@project, @snippet], confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" | 36 | + .pull-right= link_to 'Destroy', snippet_path(@snippet), confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" |
34 | 37 | ||
35 | 38 | ||
36 | :javascript | 39 | :javascript |
app/views/snippets/_snippet.html.haml
1 | %tr | 1 | %tr |
2 | %td | 2 | %td |
3 | + - if snippet.private? | ||
4 | + %i.icon-lock | ||
5 | + - else | ||
6 | + %i.icon-globe | ||
3 | = image_tag gravatar_icon(snippet.author_email), class: "avatar s24" | 7 | = image_tag gravatar_icon(snippet.author_email), class: "avatar s24" |
4 | - %a{href: project_snippet_path(snippet.project, snippet)} | ||
5 | - %strong= truncate(snippet.title, length: 60) | 8 | + - if snippet.project_id? |
9 | + %a{href: project_snippet_path(snippet.project, snippet)} | ||
10 | + %strong= truncate(snippet.title, length: 60) | ||
11 | + - else | ||
12 | + %a{href: snippet_path(snippet)} | ||
13 | + %strong= truncate(snippet.title, length: 60) | ||
6 | %td | 14 | %td |
7 | = snippet.file_name | 15 | = snippet.file_name |
8 | %td | 16 | %td |
@@ -11,3 +19,6 @@ | @@ -11,3 +19,6 @@ | ||
11 | = snippet.expires_at.to_date.to_s(:short) | 19 | = snippet.expires_at.to_date.to_s(:short) |
12 | - else | 20 | - else |
13 | Never | 21 | Never |
22 | + %td | ||
23 | + - if snippet.project_id? | ||
24 | + = link_to snippet.project.name, project_path(snippet.project) |
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +%table | ||
2 | + %thead | ||
3 | + %tr | ||
4 | + %th Title | ||
5 | + %th File Name | ||
6 | + %th Expires At | ||
7 | + %th Project | ||
8 | + | ||
9 | + = render partial: 'snippet', collection: @snippets | ||
10 | + - if @snippets.empty? | ||
11 | + %tr | ||
12 | + %td{colspan: 4} | ||
13 | + %h3.nothing_here_message Nothing here. | ||
14 | + | ||
15 | += paginate @snippets |
app/views/snippets/edit.html.haml
app/views/snippets/index.html.haml
1 | %h3.page_title | 1 | %h3.page_title |
2 | - Snippets | 2 | + Public snippets |
3 | %small share code pastes with others out of git repository | 3 | %small share code pastes with others out of git repository |
4 | + = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do | ||
5 | + Add new snippet | ||
6 | + | ||
7 | +%hr | ||
8 | +.row | ||
9 | + .span12 | ||
10 | + = render 'snippets' | ||
4 | 11 | ||
5 | - - if can? current_user, :write_snippet, @project | ||
6 | - = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do | ||
7 | - Add new snippet | ||
8 | -%br | ||
9 | -%table | ||
10 | - %thead | ||
11 | - %tr | ||
12 | - %th Title | ||
13 | - %th File Name | ||
14 | - %th Expires At | ||
15 | - = render @snippets | ||
16 | - - if @snippets.empty? | ||
17 | - %tr | ||
18 | - %td{colspan: 3} | ||
19 | - %h3.nothing_here_message Nothing here. |
app/views/snippets/new.html.haml
app/views/snippets/show.html.haml
1 | %h3.page_title | 1 | %h3.page_title |
2 | + - if @snippet.private? | ||
3 | + %i.icon-lock | ||
4 | + - else | ||
5 | + %i.icon-globe | ||
6 | + | ||
2 | = @snippet.title | 7 | = @snippet.title |
3 | %small= @snippet.file_name | 8 | %small= @snippet.file_name |
4 | - - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user | ||
5 | - = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right", title: 'Edit Snippet' | 9 | + - if @snippet.author == current_user |
10 | + = link_to "Edit", edit_snippet_path(@snippet), class: "btn btn-small pull-right", title: 'Edit Snippet' | ||
6 | 11 | ||
7 | %br | 12 | %br |
8 | %div= render 'blob' | 13 | %div= render 'blob' |
9 | -%div#notes= render "notes/notes_with_form" |
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +%h3.page_title | ||
2 | + Snippets by | ||
3 | + = @user.name | ||
4 | + %small share code pastes with others out of git repository | ||
5 | + = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do | ||
6 | + Add new snippet | ||
7 | + | ||
8 | +%hr | ||
9 | +.row | ||
10 | + .span3 | ||
11 | + %ul.nav.nav-pills.nav-stacked | ||
12 | + = nav_tab :scope, nil do | ||
13 | + = link_to "All", user_snippets_path(@user) | ||
14 | + = nav_tab :scope, 'private' do | ||
15 | + = link_to "Private", user_snippets_path(@user, scope: 'private') | ||
16 | + = nav_tab :scope, 'public' do | ||
17 | + = link_to "Public", user_snippets_path(@user, scope: 'public') | ||
18 | + | ||
19 | + .span9 | ||
20 | + = render 'snippets' |
config/routes.rb
@@ -39,6 +39,16 @@ Gitlab::Application.routes.draw do | @@ -39,6 +39,16 @@ Gitlab::Application.routes.draw do | ||
39 | get 'help/workflow' => 'help#workflow' | 39 | get 'help/workflow' => 'help#workflow' |
40 | 40 | ||
41 | # | 41 | # |
42 | + # Global snippets | ||
43 | + # | ||
44 | + resources :snippets do | ||
45 | + member do | ||
46 | + get "raw" | ||
47 | + end | ||
48 | + end | ||
49 | + get "/s/:username" => "snippets#user_index", as: :user_snippets, constraints: { username: /.*/ } | ||
50 | + | ||
51 | + # | ||
42 | # Public namespace | 52 | # Public namespace |
43 | # | 53 | # |
44 | namespace :public do | 54 | namespace :public do |
@@ -182,6 +192,14 @@ Gitlab::Application.routes.draw do | @@ -182,6 +192,14 @@ Gitlab::Application.routes.draw do | ||
182 | resources :graph, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/} | 192 | resources :graph, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/} |
183 | match "/compare/:from...:to" => "compare#show", as: "compare", via: [:get, :post], constraints: {from: /.+/, to: /.+/} | 193 | match "/compare/:from...:to" => "compare#show", as: "compare", via: [:get, :post], constraints: {from: /.+/, to: /.+/} |
184 | 194 | ||
195 | + scope module: :projects do | ||
196 | + resources :snippets do | ||
197 | + member do | ||
198 | + get "raw" | ||
199 | + end | ||
200 | + end | ||
201 | + end | ||
202 | + | ||
185 | resources :wikis, only: [:show, :edit, :destroy, :create] do | 203 | resources :wikis, only: [:show, :edit, :destroy, :create] do |
186 | collection do | 204 | collection do |
187 | get :pages | 205 | get :pages |
@@ -255,19 +273,12 @@ Gitlab::Application.routes.draw do | @@ -255,19 +273,12 @@ Gitlab::Application.routes.draw do | ||
255 | end | 273 | end |
256 | end | 274 | end |
257 | 275 | ||
258 | - resources :snippets do | ||
259 | - member do | ||
260 | - get "raw" | ||
261 | - end | ||
262 | - end | ||
263 | - | ||
264 | resources :hooks, only: [:index, :create, :destroy] do | 276 | resources :hooks, only: [:index, :create, :destroy] do |
265 | member do | 277 | member do |
266 | get :test | 278 | get :test |
267 | end | 279 | end |
268 | end | 280 | end |
269 | 281 | ||
270 | - | ||
271 | resources :team, controller: 'team_members', only: [:index] | 282 | resources :team, controller: 'team_members', only: [:index] |
272 | resources :milestones, except: [:destroy] | 283 | resources :milestones, except: [:destroy] |
273 | 284 |
db/migrate/20130324172327_change_project_id_to_null_in_snipepts.rb
0 → 100644
db/migrate/20130324203535_add_type_value_for_snippets.rb
0 → 100644
db/schema.rb
@@ -203,12 +203,14 @@ ActiveRecord::Schema.define(:version => 20130522141856) do | @@ -203,12 +203,14 @@ ActiveRecord::Schema.define(:version => 20130522141856) do | ||
203 | create_table "snippets", :force => true do |t| | 203 | create_table "snippets", :force => true do |t| |
204 | t.string "title" | 204 | t.string "title" |
205 | t.text "content" | 205 | t.text "content" |
206 | - t.integer "author_id", :null => false | ||
207 | - t.integer "project_id", :null => false | ||
208 | - t.datetime "created_at", :null => false | ||
209 | - t.datetime "updated_at", :null => false | 206 | + t.integer "author_id", :null => false |
207 | + t.integer "project_id" | ||
208 | + t.datetime "created_at", :null => false | ||
209 | + t.datetime "updated_at", :null => false | ||
210 | t.string "file_name" | 210 | t.string "file_name" |
211 | t.datetime "expires_at" | 211 | t.datetime "expires_at" |
212 | + t.boolean "private", :default => true, :null => false | ||
213 | + t.string "type" | ||
212 | end | 214 | end |
213 | 215 | ||
214 | add_index "snippets", ["created_at"], :name => "index_snippets_on_created_at" | 216 | add_index "snippets", ["created_at"], :name => "index_snippets_on_created_at" |
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +Feature: Project Snippets | ||
2 | + Background: | ||
3 | + Given I sign in as a user | ||
4 | + And I own project "Shop" | ||
5 | + And project "Shop" have "Snippet one" snippet | ||
6 | + And project "Shop" have no "Snippet two" snippet | ||
7 | + And I visit project "Shop" snippets page | ||
8 | + | ||
9 | + Scenario: I should see snippets | ||
10 | + Given I visit project "Shop" snippets page | ||
11 | + Then I should see "Snippet one" in snippets | ||
12 | + And I should not see "Snippet two" in snippets | ||
13 | + | ||
14 | + Scenario: I create new project snippet | ||
15 | + Given I click link "New Snippet" | ||
16 | + And I submit new snippet "Snippet three" | ||
17 | + Then I should see snippet "Snippet three" | ||
18 | + | ||
19 | + @javascript | ||
20 | + Scenario: I comment on a snippet "Snippet one" | ||
21 | + Given I visit snippet page "Snippet one" | ||
22 | + And I leave a comment like "Good snippet!" | ||
23 | + Then I should see comment "Good snippet!" | ||
24 | + | ||
25 | + Scenario: I update "Snippet one" | ||
26 | + Given I visit snippet page "Snippet one" | ||
27 | + And I click link "Edit" | ||
28 | + And I submit new title "Snippet new title" | ||
29 | + Then I should see "Snippet new title" | ||
30 | + | ||
31 | + Scenario: I destroy "Snippet one" | ||
32 | + Given I visit snippet page "Snippet one" | ||
33 | + And I click link "Edit" | ||
34 | + And I click link "Destroy" | ||
35 | + Then I should not see "Snippet one" in snippets |
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | +Feature: Discover Snippets | ||
2 | + Background: | ||
3 | + Given I sign in as a user | ||
4 | + And I have public "Personal snippet one" snippet | ||
5 | + And I have private "Personal snippet private" snippet | ||
6 | + | ||
7 | + Scenario: I should see snippets | ||
8 | + Given I visit snippets page | ||
9 | + Then I should see "Personal snippet one" in snippets | ||
10 | + And I should not see "Personal snippet private" in snippets |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +Feature: Snippets Feature | ||
2 | + Background: | ||
3 | + Given I sign in as a user | ||
4 | + And I have public "Personal snippet one" snippet | ||
5 | + And I have private "Personal snippet private" snippet | ||
6 | + | ||
7 | + Scenario: I create new snippet | ||
8 | + Given I visit new snippet page | ||
9 | + And I submit new snippet "Personal snippet three" | ||
10 | + Then I should see snippet "Personal snippet three" | ||
11 | + | ||
12 | + Scenario: I update "Personal snippet one" | ||
13 | + Given I visit snippet page "Personal snippet one" | ||
14 | + And I click link "Edit" | ||
15 | + And I submit new title "Personal snippet new title" | ||
16 | + Then I should see "Personal snippet new title" | ||
17 | + | ||
18 | + Scenario: Set "Personal snippet one" public | ||
19 | + Given I visit snippet page "Personal snippet one" | ||
20 | + And I click link "Edit" | ||
21 | + And I uncheck "Private" checkbox | ||
22 | + Then I should see "Personal snippet one" public | ||
23 | + | ||
24 | + Scenario: I destroy "Personal snippet one" | ||
25 | + Given I visit snippet page "Personal snippet one" | ||
26 | + And I click link "Edit" | ||
27 | + And I click link "Destroy" | ||
28 | + Then I should not see "Personal snippet one" in snippets |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +Feature: User Snippets | ||
2 | + Background: | ||
3 | + Given I sign in as a user | ||
4 | + And I have public "Personal snippet one" snippet | ||
5 | + And I have private "Personal snippet private" snippet | ||
6 | + | ||
7 | + Scenario: I should see all my snippets | ||
8 | + Given I visit my snippets page | ||
9 | + Then I should see "Personal snippet one" in snippets | ||
10 | + And I should see "Personal snippet private" in snippets | ||
11 | + | ||
12 | + Scenario: I can see only my private snippets | ||
13 | + Given I visit my snippets page | ||
14 | + And I click "Private" filter | ||
15 | + Then I should not see "Personal snippet one" in snippets | ||
16 | + And I should see "Personal snippet private" in snippets | ||
17 | + | ||
18 | + Scenario: I can see only my public snippets | ||
19 | + Given I visit my snippets page | ||
20 | + And I click "Public" filter | ||
21 | + Then I should see "Personal snippet one" in snippets | ||
22 | + And I should not see "Personal snippet private" in snippets |
@@ -0,0 +1,100 @@ | @@ -0,0 +1,100 @@ | ||
1 | +class ProjectSnippets < Spinach::FeatureSteps | ||
2 | + include SharedAuthentication | ||
3 | + include SharedProject | ||
4 | + include SharedNote | ||
5 | + include SharedPaths | ||
6 | + | ||
7 | + And 'project "Shop" have "Snippet one" snippet' do | ||
8 | + create(:project_snippet, | ||
9 | + title: "Snippet one", | ||
10 | + content: "Test content", | ||
11 | + file_name: "snippet.rb", | ||
12 | + project: project, | ||
13 | + author: project.users.first) | ||
14 | + end | ||
15 | + | ||
16 | + And 'project "Shop" have no "Snippet two" snippet' do | ||
17 | + create(:snippet, | ||
18 | + title: "Snippet two", | ||
19 | + content: "Test content", | ||
20 | + file_name: "snippet.rb", | ||
21 | + author: project.users.first) | ||
22 | + end | ||
23 | + | ||
24 | + Given 'I click link "New Snippet"' do | ||
25 | + click_link "Add new snippet" | ||
26 | + end | ||
27 | + | ||
28 | + Given 'I click link "Snippet one"' do | ||
29 | + click_link "Snippet one" | ||
30 | + end | ||
31 | + | ||
32 | + Then 'I should see "Snippet one" in snippets' do | ||
33 | + page.should have_content "Snippet one" | ||
34 | + end | ||
35 | + | ||
36 | + And 'I should not see "Snippet two" in snippets' do | ||
37 | + page.should_not have_content "Snippet two" | ||
38 | + end | ||
39 | + | ||
40 | + And 'I should not see "Snippet one" in snippets' do | ||
41 | + page.should_not have_content "Snippet one" | ||
42 | + end | ||
43 | + | ||
44 | + And 'I click link "Edit"' do | ||
45 | + within ".page_title" do | ||
46 | + click_link "Edit" | ||
47 | + end | ||
48 | + end | ||
49 | + | ||
50 | + And 'I click link "Destroy"' do | ||
51 | + click_link "Destroy" | ||
52 | + end | ||
53 | + | ||
54 | + And 'I submit new snippet "Snippet three"' do | ||
55 | + fill_in "project_snippet_title", :with => "Snippet three" | ||
56 | + select "forever", :from => "project_snippet_expires_at" | ||
57 | + fill_in "project_snippet_file_name", :with => "my_snippet.rb" | ||
58 | + within('.file-editor') do | ||
59 | + find(:xpath, "//input[@id='project_snippet_content']").set 'Content of snippet three' | ||
60 | + end | ||
61 | + click_button "Save" | ||
62 | + end | ||
63 | + | ||
64 | + Then 'I should see snippet "Snippet three"' do | ||
65 | + page.should have_content "Snippet three" | ||
66 | + page.should have_content "Content of snippet three" | ||
67 | + end | ||
68 | + | ||
69 | + And 'I submit new title "Snippet new title"' do | ||
70 | + fill_in "project_snippet_title", :with => "Snippet new title" | ||
71 | + click_button "Save" | ||
72 | + end | ||
73 | + | ||
74 | + Then 'I should see "Snippet new title"' do | ||
75 | + page.should have_content "Snippet new title" | ||
76 | + end | ||
77 | + | ||
78 | + And 'I leave a comment like "Good snippet!"' do | ||
79 | + within('.js-main-target-form') do | ||
80 | + fill_in "note_note", with: "Good snippet!" | ||
81 | + click_button "Add Comment" | ||
82 | + end | ||
83 | + end | ||
84 | + | ||
85 | + Then 'I should see comment "Good snippet!"' do | ||
86 | + page.should have_content "Good snippet!" | ||
87 | + end | ||
88 | + | ||
89 | + And 'I visit snippet page "Snippet one"' do | ||
90 | + visit project_snippet_path(project, project_snippet) | ||
91 | + end | ||
92 | + | ||
93 | + def project | ||
94 | + @project ||= Project.find_by_name!("Shop") | ||
95 | + end | ||
96 | + | ||
97 | + def project_snippet | ||
98 | + @project_snippet ||= ProjectSnippet.find_by_title!("Snippet One") | ||
99 | + end | ||
100 | +end |
features/steps/shared/paths.rb
@@ -275,6 +275,22 @@ module SharedPaths | @@ -275,6 +275,22 @@ module SharedPaths | ||
275 | visit public_root_path | 275 | visit public_root_path |
276 | end | 276 | end |
277 | 277 | ||
278 | + # ---------------------------------------- | ||
279 | + # Snippets | ||
280 | + # ---------------------------------------- | ||
281 | + | ||
282 | + Given 'I visit project "Shop" snippets page' do | ||
283 | + visit project_snippets_path(project) | ||
284 | + end | ||
285 | + | ||
286 | + Given 'I visit snippets page' do | ||
287 | + visit snippets_path | ||
288 | + end | ||
289 | + | ||
290 | + Given 'I visit new snippet page' do | ||
291 | + visit new_snippet_path | ||
292 | + end | ||
293 | + | ||
278 | def root_ref | 294 | def root_ref |
279 | @project.repository.root_ref | 295 | @project.repository.root_ref |
280 | end | 296 | end |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +module SharedSnippet | ||
2 | + include Spinach::DSL | ||
3 | + | ||
4 | + And 'I have public "Personal snippet one" snippet' do | ||
5 | + create(:personal_snippet, | ||
6 | + title: "Personal snippet one", | ||
7 | + content: "Test content", | ||
8 | + file_name: "snippet.rb", | ||
9 | + private: false, | ||
10 | + author: current_user) | ||
11 | + end | ||
12 | + | ||
13 | + And 'I have private "Personal snippet private" snippet' do | ||
14 | + create(:personal_snippet, | ||
15 | + title: "Personal snippet private", | ||
16 | + content: "Provate content", | ||
17 | + file_name: "private_snippet.rb", | ||
18 | + private: true, | ||
19 | + author: current_user) | ||
20 | + end | ||
21 | +end |
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +class DiscoverSnippets < Spinach::FeatureSteps | ||
2 | + include SharedAuthentication | ||
3 | + include SharedPaths | ||
4 | + include SharedSnippet | ||
5 | + | ||
6 | + Then 'I should see "Personal snippet one" in snippets' do | ||
7 | + page.should have_content "Personal snippet one" | ||
8 | + end | ||
9 | + | ||
10 | + And 'I should not see "Personal snippet private" in snippets' do | ||
11 | + page.should_not have_content "Personal snippet private" | ||
12 | + end | ||
13 | + | ||
14 | + def snippet | ||
15 | + @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one") | ||
16 | + end | ||
17 | +end |
@@ -0,0 +1,65 @@ | @@ -0,0 +1,65 @@ | ||
1 | +class SnippetsFeature < Spinach::FeatureSteps | ||
2 | + include SharedAuthentication | ||
3 | + include SharedPaths | ||
4 | + include SharedProject | ||
5 | + include SharedSnippet | ||
6 | + | ||
7 | + Given 'I click link "Personal snippet one"' do | ||
8 | + click_link "Personal snippet one" | ||
9 | + end | ||
10 | + | ||
11 | + And 'I should not see "Personal snippet one" in snippets' do | ||
12 | + page.should_not have_content "Personal snippet one" | ||
13 | + end | ||
14 | + | ||
15 | + And 'I click link "Edit"' do | ||
16 | + within ".page_title" do | ||
17 | + click_link "Edit" | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
21 | + And 'I click link "Destroy"' do | ||
22 | + click_link "Destroy" | ||
23 | + end | ||
24 | + | ||
25 | + And 'I submit new snippet "Personal snippet three"' do | ||
26 | + fill_in "personal_snippet_title", :with => "Personal snippet three" | ||
27 | + select "forever", :from => "personal_snippet_expires_at" | ||
28 | + fill_in "personal_snippet_file_name", :with => "my_snippet.rb" | ||
29 | + within('.file-editor') do | ||
30 | + find(:xpath, "//input[@id='personal_snippet_content']").set 'Content of snippet three' | ||
31 | + end | ||
32 | + click_button "Save" | ||
33 | + end | ||
34 | + | ||
35 | + Then 'I should see snippet "Personal snippet three"' do | ||
36 | + page.should have_content "Personal snippet three" | ||
37 | + page.should have_content "Content of snippet three" | ||
38 | + end | ||
39 | + | ||
40 | + And 'I submit new title "Personal snippet new title"' do | ||
41 | + fill_in "personal_snippet_title", :with => "Personal snippet new title" | ||
42 | + click_button "Save" | ||
43 | + end | ||
44 | + | ||
45 | + Then 'I should see "Personal snippet new title"' do | ||
46 | + page.should have_content "Personal snippet new title" | ||
47 | + end | ||
48 | + | ||
49 | + And 'I uncheck "Private" checkbox' do | ||
50 | + find(:xpath, "//input[@id='personal_snippet_private']").set true | ||
51 | + click_button "Save" | ||
52 | + end | ||
53 | + | ||
54 | + Then 'I should see "Personal snippet one" public' do | ||
55 | + page.should have_no_xpath("//i[@class='public-snippet']") | ||
56 | + end | ||
57 | + | ||
58 | + And 'I visit snippet page "Personal snippet one"' do | ||
59 | + visit snippet_path(snippet) | ||
60 | + end | ||
61 | + | ||
62 | + def snippet | ||
63 | + @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one") | ||
64 | + end | ||
65 | +end |
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +class UserSnippets < Spinach::FeatureSteps | ||
2 | + include SharedAuthentication | ||
3 | + include SharedPaths | ||
4 | + include SharedSnippet | ||
5 | + | ||
6 | + Given 'I visit my snippets page' do | ||
7 | + visit user_snippets_path(current_user) | ||
8 | + end | ||
9 | + | ||
10 | + Then 'I should see "Personal snippet one" in snippets' do | ||
11 | + page.should have_content "Personal snippet one" | ||
12 | + end | ||
13 | + | ||
14 | + And 'I should see "Personal snippet private" in snippets' do | ||
15 | + page.should have_content "Personal snippet private" | ||
16 | + end | ||
17 | + | ||
18 | + Then 'I should not see "Personal snippet one" in snippets' do | ||
19 | + page.should_not have_content "Personal snippet one" | ||
20 | + end | ||
21 | + | ||
22 | + And 'I should not see "Personal snippet private" in snippets' do | ||
23 | + page.should_not have_content "Personal snippet private" | ||
24 | + end | ||
25 | + | ||
26 | + Given 'I click "Public" filter' do | ||
27 | + within('.nav-stacked') do | ||
28 | + click_link "Public" | ||
29 | + end | ||
30 | + end | ||
31 | + | ||
32 | + Given 'I click "Private" filter' do | ||
33 | + within('.nav-stacked') do | ||
34 | + click_link "Private" | ||
35 | + end | ||
36 | + end | ||
37 | + | ||
38 | + def snippet | ||
39 | + @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one") | ||
40 | + end | ||
41 | +end |
lib/api/projects.rb
@@ -328,7 +328,7 @@ module API | @@ -328,7 +328,7 @@ module API | ||
328 | # Example Request: | 328 | # Example Request: |
329 | # POST /projects/:id/snippets | 329 | # POST /projects/:id/snippets |
330 | post ":id/snippets" do | 330 | post ":id/snippets" do |
331 | - authorize! :write_snippet, user_project | 331 | + authorize! :write_project_snippet, user_project |
332 | required_attributes! [:title, :file_name, :code] | 332 | required_attributes! [:title, :file_name, :code] |
333 | 333 | ||
334 | attrs = attributes_for_keys [:title, :file_name] | 334 | attrs = attributes_for_keys [:title, :file_name] |
@@ -357,7 +357,7 @@ module API | @@ -357,7 +357,7 @@ module API | ||
357 | # PUT /projects/:id/snippets/:snippet_id | 357 | # PUT /projects/:id/snippets/:snippet_id |
358 | put ":id/snippets/:snippet_id" do | 358 | put ":id/snippets/:snippet_id" do |
359 | @snippet = user_project.snippets.find(params[:snippet_id]) | 359 | @snippet = user_project.snippets.find(params[:snippet_id]) |
360 | - authorize! :modify_snippet, @snippet | 360 | + authorize! :modify_project_snippet, @snippet |
361 | 361 | ||
362 | attrs = attributes_for_keys [:title, :file_name] | 362 | attrs = attributes_for_keys [:title, :file_name] |
363 | attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? | 363 | attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? |
@@ -380,7 +380,7 @@ module API | @@ -380,7 +380,7 @@ module API | ||
380 | delete ":id/snippets/:snippet_id" do | 380 | delete ":id/snippets/:snippet_id" do |
381 | begin | 381 | begin |
382 | @snippet = user_project.snippets.find(params[:snippet_id]) | 382 | @snippet = user_project.snippets.find(params[:snippet_id]) |
383 | - authorize! :modify_snippet, user_project | 383 | + authorize! :modify_project_snippet, @snippet |
384 | @snippet.destroy | 384 | @snippet.destroy |
385 | rescue | 385 | rescue |
386 | end | 386 | end |
spec/factories.rb
@@ -197,7 +197,7 @@ FactoryGirl.define do | @@ -197,7 +197,7 @@ FactoryGirl.define do | ||
197 | url | 197 | url |
198 | end | 198 | end |
199 | 199 | ||
200 | - factory :snippet do | 200 | + factory :project_snippet do |
201 | project | 201 | project |
202 | author | 202 | author |
203 | title | 203 | title |
@@ -205,6 +205,20 @@ FactoryGirl.define do | @@ -205,6 +205,20 @@ FactoryGirl.define do | ||
205 | file_name | 205 | file_name |
206 | end | 206 | end |
207 | 207 | ||
208 | + factory :personal_snippet do | ||
209 | + author | ||
210 | + title | ||
211 | + content | ||
212 | + file_name | ||
213 | + end | ||
214 | + | ||
215 | + factory :snippet do | ||
216 | + author | ||
217 | + title | ||
218 | + content | ||
219 | + file_name | ||
220 | + end | ||
221 | + | ||
208 | factory :protected_branch do | 222 | factory :protected_branch do |
209 | name | 223 | name |
210 | project | 224 | project |
spec/features/snippets_spec.rb
@@ -1,99 +0,0 @@ | @@ -1,99 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Snippets" do | ||
4 | - let(:project) { create(:project) } | ||
5 | - | ||
6 | - before do | ||
7 | - login_as :user | ||
8 | - project.team << [@user, :developer] | ||
9 | - end | ||
10 | - | ||
11 | - describe "GET /snippets" do | ||
12 | - before do | ||
13 | - @snippet = create(:snippet, | ||
14 | - author: @user, | ||
15 | - project: project) | ||
16 | - | ||
17 | - visit project_snippets_path(project) | ||
18 | - end | ||
19 | - | ||
20 | - subject { page } | ||
21 | - | ||
22 | - it { should have_content(@snippet.title[0..10]) } | ||
23 | - it { should have_content(@snippet.project.name) } | ||
24 | - | ||
25 | - describe "Destroy" do | ||
26 | - before do | ||
27 | - # admin access to remove snippet | ||
28 | - @user.users_projects.destroy_all | ||
29 | - project.team << [@user, :master] | ||
30 | - visit edit_project_snippet_path(project, @snippet) | ||
31 | - end | ||
32 | - | ||
33 | - it "should remove entry" do | ||
34 | - expect { | ||
35 | - click_link "destroy_snippet_#{@snippet.id}" | ||
36 | - }.to change { Snippet.count }.by(-1) | ||
37 | - end | ||
38 | - end | ||
39 | - end | ||
40 | - | ||
41 | - describe "New snippet" do | ||
42 | - before do | ||
43 | - visit project_snippets_path(project) | ||
44 | - click_link "New Snippet" | ||
45 | - end | ||
46 | - | ||
47 | - it "should open new snippet popup" do | ||
48 | - page.current_path.should == new_project_snippet_path(project) | ||
49 | - end | ||
50 | - | ||
51 | - describe "fill in", js: true do | ||
52 | - before do | ||
53 | - fill_in "snippet_title", with: "login function" | ||
54 | - fill_in "snippet_file_name", with: "test.rb" | ||
55 | - page.execute_script("editor.insert('def login; end');") | ||
56 | - end | ||
57 | - | ||
58 | - it { expect { click_button "Save" }.to change {Snippet.count}.by(1) } | ||
59 | - | ||
60 | - it "should add new snippet to table" do | ||
61 | - click_button "Save" | ||
62 | - page.current_path.should == project_snippet_path(project, Snippet.last) | ||
63 | - page.should have_content "login function" | ||
64 | - page.should have_content "test.rb" | ||
65 | - end | ||
66 | - end | ||
67 | - end | ||
68 | - | ||
69 | - describe "Edit snippet" do | ||
70 | - before do | ||
71 | - @snippet = create(:snippet, | ||
72 | - author: @user, | ||
73 | - project: project) | ||
74 | - visit project_snippet_path(project, @snippet) | ||
75 | - click_link "Edit Snippet" | ||
76 | - end | ||
77 | - | ||
78 | - it "should open edit page" do | ||
79 | - page.current_path.should == edit_project_snippet_path(project, @snippet) | ||
80 | - end | ||
81 | - | ||
82 | - describe "fill in" do | ||
83 | - before do | ||
84 | - fill_in "snippet_title", with: "login function" | ||
85 | - fill_in "snippet_file_name", with: "test.rb" | ||
86 | - end | ||
87 | - | ||
88 | - it { expect { click_button "Save" }.to_not change {Snippet.count} } | ||
89 | - | ||
90 | - it "should update snippet fields" do | ||
91 | - click_button "Save" | ||
92 | - | ||
93 | - page.current_path.should == project_snippet_path(project, @snippet) | ||
94 | - page.should have_content "login function" | ||
95 | - page.should have_content "test.rb" | ||
96 | - end | ||
97 | - end | ||
98 | - end | ||
99 | -end |
spec/helpers/gitlab_markdown_helper_spec.rb
@@ -10,7 +10,7 @@ describe GitlabMarkdownHelper do | @@ -10,7 +10,7 @@ describe GitlabMarkdownHelper do | ||
10 | let(:commit) { project.repository.commit } | 10 | let(:commit) { project.repository.commit } |
11 | let(:issue) { create(:issue, project: project) } | 11 | let(:issue) { create(:issue, project: project) } |
12 | let(:merge_request) { create(:merge_request, project: project) } | 12 | let(:merge_request) { create(:merge_request, project: project) } |
13 | - let(:snippet) { create(:snippet, project: project) } | 13 | + let(:snippet) { create(:project_snippet, project: project) } |
14 | let(:member) { project.users_projects.where(user_id: user).first } | 14 | let(:member) { project.users_projects.where(user_id: user).first } |
15 | 15 | ||
16 | before do | 16 | before do |
@@ -190,8 +190,43 @@ describe GitlabMarkdownHelper do | @@ -190,8 +190,43 @@ describe GitlabMarkdownHelper do | ||
190 | describe "referencing a snippet" do | 190 | describe "referencing a snippet" do |
191 | let(:object) { snippet } | 191 | let(:object) { snippet } |
192 | let(:reference) { "$#{snippet.id}" } | 192 | let(:reference) { "$#{snippet.id}" } |
193 | + let(:actual) { "Reference to #{reference}" } | ||
194 | + let(:expected) { project_snippet_path(project, object) } | ||
195 | + | ||
196 | + it "should link using a valid id" do | ||
197 | + gfm(actual).should match(expected) | ||
198 | + end | ||
199 | + | ||
200 | + it "should link with adjacent text" do | ||
201 | + # Wrap the reference in parenthesis | ||
202 | + gfm(actual.gsub(reference, "(#{reference})")).should match(expected) | ||
203 | + | ||
204 | + # Append some text to the end of the reference | ||
205 | + gfm(actual.gsub(reference, "#{reference}, right?")).should match(expected) | ||
206 | + end | ||
207 | + | ||
208 | + it "should keep whitespace intact" do | ||
209 | + actual = "Referenced #{reference} already." | ||
210 | + expected = /Referenced <a.+>[^\s]+<\/a> already/ | ||
211 | + gfm(actual).should match(expected) | ||
212 | + end | ||
213 | + | ||
214 | + it "should not link with an invalid id" do | ||
215 | + # Modify the reference string so it's still parsed, but is invalid | ||
216 | + reference.gsub!(/^(.)(\d+)$/, '\1' + ('\2' * 2)) | ||
217 | + gfm(actual).should == actual | ||
218 | + end | ||
219 | + | ||
220 | + it "should include a title attribute" do | ||
221 | + title = "Snippet: #{object.title}" | ||
222 | + gfm(actual).should match(/title="#{title}"/) | ||
223 | + end | ||
224 | + | ||
225 | + it "should include standard gfm classes" do | ||
226 | + css = object.class.to_s.underscore | ||
227 | + gfm(actual).should match(/class="\s?gfm gfm-snippet\s?"/) | ||
228 | + end | ||
193 | 229 | ||
194 | - include_examples 'referenced object' | ||
195 | end | 230 | end |
196 | 231 | ||
197 | describe "referencing multiple objects" do | 232 | describe "referencing multiple objects" do |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +# == Schema Information | ||
2 | +# | ||
3 | +# Table name: snippets | ||
4 | +# | ||
5 | +# id :integer not null, primary key | ||
6 | +# title :string(255) | ||
7 | +# content :text | ||
8 | +# author_id :integer not null | ||
9 | +# project_id :integer not null | ||
10 | +# created_at :datetime not null | ||
11 | +# updated_at :datetime not null | ||
12 | +# file_name :string(255) | ||
13 | +# expires_at :datetime | ||
14 | +# | ||
15 | + | ||
16 | +require 'spec_helper' | ||
17 | + | ||
18 | +describe ProjectSnippet do | ||
19 | + describe "Associations" do | ||
20 | + it { should belong_to(:project) } | ||
21 | + end | ||
22 | + | ||
23 | + describe "Mass assignment" do | ||
24 | + it { should_not allow_mass_assignment_of(:project_id) } | ||
25 | + end | ||
26 | + | ||
27 | + describe "Validation" do | ||
28 | + it { should validate_presence_of(:project) } | ||
29 | + end | ||
30 | +end |
spec/models/project_spec.rb
@@ -36,7 +36,7 @@ describe Project do | @@ -36,7 +36,7 @@ describe Project do | ||
36 | it { should have_many(:milestones).dependent(:destroy) } | 36 | it { should have_many(:milestones).dependent(:destroy) } |
37 | it { should have_many(:users_projects).dependent(:destroy) } | 37 | it { should have_many(:users_projects).dependent(:destroy) } |
38 | it { should have_many(:notes).dependent(:destroy) } | 38 | it { should have_many(:notes).dependent(:destroy) } |
39 | - it { should have_many(:snippets).dependent(:destroy) } | 39 | + it { should have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) } |
40 | it { should have_many(:deploy_keys_projects).dependent(:destroy) } | 40 | it { should have_many(:deploy_keys_projects).dependent(:destroy) } |
41 | it { should have_many(:deploy_keys) } | 41 | it { should have_many(:deploy_keys) } |
42 | it { should have_many(:hooks).dependent(:destroy) } | 42 | it { should have_many(:hooks).dependent(:destroy) } |
spec/models/snippet_spec.rb
@@ -17,19 +17,16 @@ require 'spec_helper' | @@ -17,19 +17,16 @@ require 'spec_helper' | ||
17 | 17 | ||
18 | describe Snippet do | 18 | describe Snippet do |
19 | describe "Associations" do | 19 | describe "Associations" do |
20 | - it { should belong_to(:project) } | ||
21 | it { should belong_to(:author).class_name('User') } | 20 | it { should belong_to(:author).class_name('User') } |
22 | it { should have_many(:notes).dependent(:destroy) } | 21 | it { should have_many(:notes).dependent(:destroy) } |
23 | end | 22 | end |
24 | 23 | ||
25 | describe "Mass assignment" do | 24 | describe "Mass assignment" do |
26 | it { should_not allow_mass_assignment_of(:author_id) } | 25 | it { should_not allow_mass_assignment_of(:author_id) } |
27 | - it { should_not allow_mass_assignment_of(:project_id) } | ||
28 | end | 26 | end |
29 | 27 | ||
30 | describe "Validation" do | 28 | describe "Validation" do |
31 | it { should validate_presence_of(:author) } | 29 | it { should validate_presence_of(:author) } |
32 | - it { should validate_presence_of(:project) } | ||
33 | 30 | ||
34 | it { should validate_presence_of(:title) } | 31 | it { should validate_presence_of(:title) } |
35 | it { should ensure_length_of(:title).is_within(0..255) } | 32 | it { should ensure_length_of(:title).is_within(0..255) } |
spec/models/user_spec.rb
@@ -41,6 +41,7 @@ require 'spec_helper' | @@ -41,6 +41,7 @@ require 'spec_helper' | ||
41 | describe User do | 41 | describe User do |
42 | describe "Associations" do | 42 | describe "Associations" do |
43 | it { should have_one(:namespace) } | 43 | it { should have_one(:namespace) } |
44 | + it { should have_many(:snippets).class_name('Snippet').dependent(:destroy) } | ||
44 | it { should have_many(:users_projects).dependent(:destroy) } | 45 | it { should have_many(:users_projects).dependent(:destroy) } |
45 | it { should have_many(:groups) } | 46 | it { should have_many(:groups) } |
46 | it { should have_many(:keys).dependent(:destroy) } | 47 | it { should have_many(:keys).dependent(:destroy) } |
spec/requests/api/notes_spec.rb
@@ -7,7 +7,7 @@ describe API::API do | @@ -7,7 +7,7 @@ describe API::API do | ||
7 | let!(:project) { create(:project, namespace: user.namespace ) } | 7 | let!(:project) { create(:project, namespace: user.namespace ) } |
8 | let!(:issue) { create(:issue, project: project, author: user) } | 8 | let!(:issue) { create(:issue, project: project, author: user) } |
9 | let!(:merge_request) { create(:merge_request, project: project, author: user) } | 9 | let!(:merge_request) { create(:merge_request, project: project, author: user) } |
10 | - let!(:snippet) { create(:snippet, project: project, author: user) } | 10 | + let!(:snippet) { create(:project_snippet, project: project, author: user) } |
11 | let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) } | 11 | let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) } |
12 | let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) } | 12 | let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) } |
13 | let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) } | 13 | let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) } |
spec/requests/api/projects_spec.rb
@@ -10,7 +10,7 @@ describe API::API do | @@ -10,7 +10,7 @@ describe API::API do | ||
10 | let(:admin) { create(:admin) } | 10 | let(:admin) { create(:admin) } |
11 | let!(:project) { create(:project_with_code, creator_id: user.id) } | 11 | let!(:project) { create(:project_with_code, creator_id: user.id) } |
12 | let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } | 12 | let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } |
13 | - let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } | 13 | + let!(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } |
14 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } | 14 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } |
15 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } | 15 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } |
16 | 16 |
spec/routing/project_routing_spec.rb
@@ -258,13 +258,37 @@ end | @@ -258,13 +258,37 @@ end | ||
258 | # project_snippet GET /:project_id/snippets/:id(.:format) snippets#show | 258 | # project_snippet GET /:project_id/snippets/:id(.:format) snippets#show |
259 | # PUT /:project_id/snippets/:id(.:format) snippets#update | 259 | # PUT /:project_id/snippets/:id(.:format) snippets#update |
260 | # DELETE /:project_id/snippets/:id(.:format) snippets#destroy | 260 | # DELETE /:project_id/snippets/:id(.:format) snippets#destroy |
261 | -describe SnippetsController, "routing" do | 261 | +describe Project::SnippetsController, "routing" do |
262 | it "to #raw" do | 262 | it "to #raw" do |
263 | - get("/gitlabhq/snippets/1/raw").should route_to('snippets#raw', project_id: 'gitlabhq', id: '1') | 263 | + get("/gitlabhq/snippets/1/raw").should route_to('projects/snippets#raw', project_id: 'gitlabhq', id: '1') |
264 | end | 264 | end |
265 | 265 | ||
266 | - it_behaves_like "RESTful project resources" do | ||
267 | - let(:controller) { 'snippets' } | 266 | + it "to #index" do |
267 | + get("/gitlabhq/snippets").should route_to("projects/snippets#index", project_id: 'gitlabhq') | ||
268 | + end | ||
269 | + | ||
270 | + it "to #create" do | ||
271 | + post("/gitlabhq/snippets").should route_to("projects/snippets#create", project_id: 'gitlabhq') | ||
272 | + end | ||
273 | + | ||
274 | + it "to #new" do | ||
275 | + get("/gitlabhq/snippets/new").should route_to("projects/snippets#new", project_id: 'gitlabhq') | ||
276 | + end | ||
277 | + | ||
278 | + it "to #edit" do | ||
279 | + get("/gitlabhq/snippets/1/edit").should route_to("projects/snippets#edit", project_id: 'gitlabhq', id: '1') | ||
280 | + end | ||
281 | + | ||
282 | + it "to #show" do | ||
283 | + get("/gitlabhq/snippets/1").should route_to("projects/snippets#show", project_id: 'gitlabhq', id: '1') | ||
284 | + end | ||
285 | + | ||
286 | + it "to #update" do | ||
287 | + put("/gitlabhq/snippets/1").should route_to("projects/snippets#update", project_id: 'gitlabhq', id: '1') | ||
288 | + end | ||
289 | + | ||
290 | + it "to #destroy" do | ||
291 | + delete("/gitlabhq/snippets/1").should route_to("projects/snippets#destroy", project_id: 'gitlabhq', id: '1') | ||
268 | end | 292 | end |
269 | end | 293 | end |
270 | 294 |
spec/routing/routing_spec.rb
@@ -19,6 +19,51 @@ describe "Mounted Apps", "routing" do | @@ -19,6 +19,51 @@ describe "Mounted Apps", "routing" do | ||
19 | end | 19 | end |
20 | end | 20 | end |
21 | 21 | ||
22 | +# snippets GET /snippets(.:format) snippets#index | ||
23 | +# POST /snippets(.:format) snippets#create | ||
24 | +# new_snippet GET /snippets/new(.:format) snippets#new | ||
25 | +# edit_snippet GET /snippets/:id/edit(.:format) snippets#edit | ||
26 | +# snippet GET /snippets/:id(.:format) snippets#show | ||
27 | +# PUT /snippets/:id(.:format) snippets#update | ||
28 | +# DELETE /snippets/:id(.:format) snippets#destroy | ||
29 | +describe SnippetsController, "routing" do | ||
30 | + it "to #user_index" do | ||
31 | + get("/s/User").should route_to('snippets#user_index', username: 'User') | ||
32 | + end | ||
33 | + | ||
34 | + it "to #raw" do | ||
35 | + get("/snippets/1/raw").should route_to('snippets#raw', id: '1') | ||
36 | + end | ||
37 | + | ||
38 | + it "to #index" do | ||
39 | + get("/snippets").should route_to('snippets#index') | ||
40 | + end | ||
41 | + | ||
42 | + it "to #create" do | ||
43 | + post("/snippets").should route_to('snippets#create') | ||
44 | + end | ||
45 | + | ||
46 | + it "to #new" do | ||
47 | + get("/snippets/new").should route_to('snippets#new') | ||
48 | + end | ||
49 | + | ||
50 | + it "to #edit" do | ||
51 | + get("/snippets/1/edit").should route_to('snippets#edit', id: '1') | ||
52 | + end | ||
53 | + | ||
54 | + it "to #show" do | ||
55 | + get("/snippets/1").should route_to('snippets#show', id: '1') | ||
56 | + end | ||
57 | + | ||
58 | + it "to #update" do | ||
59 | + put("/snippets/1").should route_to('snippets#update', id: '1') | ||
60 | + end | ||
61 | + | ||
62 | + it "to #destroy" do | ||
63 | + delete("/snippets/1").should route_to('snippets#destroy', id: '1') | ||
64 | + end | ||
65 | +end | ||
66 | + | ||
22 | # help GET /help(.:format) help#index | 67 | # help GET /help(.:format) help#index |
23 | # help_permissions GET /help/permissions(.:format) help#permissions | 68 | # help_permissions GET /help/permissions(.:format) help#permissions |
24 | # help_workflow GET /help/workflow(.:format) help#workflow | 69 | # help_workflow GET /help/workflow(.:format) help#workflow |