Commit bcc4e4dc7ed0740e92a61fc82c3c669f8f2d8d30
Exists in
master
and in
4 other branches
Merge branch 'gist' of https://github.com/Andrew8xx8/gitlabhq into Andrew8xx8-gist
Conflicts: Gemfile.lock app/models/ability.rb app/models/project.rb app/views/snippets/_form.html.haml db/schema.rb features/steps/shared/paths.rb spec/factories.rb spec/models/project_spec.rb
Showing
59 changed files
with
967 additions
and
209 deletions
Show diff stats
app/controllers/projects/application_controller.rb
| ... | ... | @@ -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 | 1 | class Projects::TeamsController < Projects::ApplicationController |
| 2 | 2 | |
| 3 | + before_filter :authorize_admin_team_member! | |
| 4 | + | |
| 3 | 5 | def available |
| 4 | 6 | @teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams |
| 5 | 7 | @teams = @teams.without_project(project) |
| ... | ... | @@ -24,4 +26,9 @@ class Projects::TeamsController < Projects::ApplicationController |
| 24 | 26 | redirect_to project_team_index_path(project) |
| 25 | 27 | end |
| 26 | 28 | |
| 29 | + protected | |
| 30 | + | |
| 31 | + def user_team | |
| 32 | + @team ||= UserTeam.find_by_path(params[:id]) | |
| 33 | + end | |
| 27 | 34 | end | ... | ... |
app/controllers/snippets_controller.rb
| 1 | -class SnippetsController < ProjectResourceController | |
| 2 | - before_filter :module_enabled | |
| 1 | +class SnippetsController < ApplicationController | |
| 3 | 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 | 4 | # Allow modify snippet |
| 12 | 5 | before_filter :authorize_modify_snippet!, only: [:edit, :update] |
| 13 | 6 | |
| ... | ... | @@ -17,22 +10,38 @@ class SnippetsController < ProjectResourceController |
| 17 | 10 | respond_to :html |
| 18 | 11 | |
| 19 | 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 | 31 | end |
| 22 | 32 | |
| 23 | 33 | def new |
| 24 | - @snippet = @project.snippets.new | |
| 34 | + @snippet = PersonalSnippet.new | |
| 25 | 35 | end |
| 26 | 36 | |
| 27 | 37 | def create |
| 28 | - @snippet = @project.snippets.new(params[:snippet]) | |
| 38 | + @snippet = PersonalSnippet.new(params[:personal_snippet]) | |
| 29 | 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 | 43 | else |
| 35 | - respond_with(@snippet) | |
| 44 | + respond_with @snippet | |
| 36 | 45 | end |
| 37 | 46 | end |
| 38 | 47 | |
| ... | ... | @@ -40,27 +49,22 @@ class SnippetsController < ProjectResourceController |
| 40 | 49 | end |
| 41 | 50 | |
| 42 | 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 | 54 | else |
| 48 | - respond_with(@snippet) | |
| 55 | + respond_with @snippet | |
| 49 | 56 | end |
| 50 | 57 | end |
| 51 | 58 | |
| 52 | 59 | def show |
| 53 | - @note = @project.notes.new(noteable: @snippet) | |
| 54 | - @target_type = :snippet | |
| 55 | - @target_id = @snippet.id | |
| 56 | 60 | end |
| 57 | 61 | |
| 58 | 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 | 65 | @snippet.destroy |
| 62 | 66 | |
| 63 | - redirect_to project_snippets_path(@project) | |
| 67 | + redirect_to snippets_path | |
| 64 | 68 | end |
| 65 | 69 | |
| 66 | 70 | def raw |
| ... | ... | @@ -75,18 +79,14 @@ class SnippetsController < ProjectResourceController |
| 75 | 79 | protected |
| 76 | 80 | |
| 77 | 81 | def snippet |
| 78 | - @snippet ||= @project.snippets.find(params[:id]) | |
| 82 | + @snippet ||= PersonalSnippet.find(params[:id]) | |
| 79 | 83 | end |
| 80 | 84 | |
| 81 | 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 | 87 | end |
| 84 | 88 | |
| 85 | 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 | 91 | end |
| 92 | 92 | end | ... | ... |
app/helpers/tab_helper.rb
| ... | ... | @@ -73,7 +73,7 @@ module TabHelper |
| 73 | 73 | end |
| 74 | 74 | |
| 75 | 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 | 78 | if ['services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name |
| 79 | 79 | "active" | ... | ... |
app/models/ability.rb
| ... | ... | @@ -7,7 +7,8 @@ class Ability |
| 7 | 7 | when "Project" then project_abilities(user, subject) |
| 8 | 8 | when "Issue" then issue_abilities(user, subject) |
| 9 | 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 | 12 | when "MergeRequest" then merge_request_abilities(user, subject) |
| 12 | 13 | when "Group", "Namespace" then group_abilities(user, subject) |
| 13 | 14 | when "UserTeam" then user_team_abilities(user, subject) |
| ... | ... | @@ -54,7 +55,7 @@ class Ability |
| 54 | 55 | :read_wiki, |
| 55 | 56 | :read_issue, |
| 56 | 57 | :read_milestone, |
| 57 | - :read_snippet, | |
| 58 | + :read_project_snippet, | |
| 58 | 59 | :read_team_member, |
| 59 | 60 | :read_merge_request, |
| 60 | 61 | :read_note, |
| ... | ... | @@ -67,8 +68,8 @@ class Ability |
| 67 | 68 | def project_report_rules |
| 68 | 69 | project_guest_rules + [ |
| 69 | 70 | :download_code, |
| 70 | - :write_snippet, | |
| 71 | 71 | :fork_project |
| 72 | + :write_project_snippet | |
| 72 | 73 | ] |
| 73 | 74 | end |
| 74 | 75 | |
| ... | ... | @@ -84,11 +85,11 @@ class Ability |
| 84 | 85 | project_dev_rules + [ |
| 85 | 86 | :push_code_to_protected_branches, |
| 86 | 87 | :modify_issue, |
| 87 | - :modify_snippet, | |
| 88 | + :modify_project_snippet, | |
| 88 | 89 | :modify_merge_request, |
| 89 | 90 | :admin_issue, |
| 90 | 91 | :admin_milestone, |
| 91 | - :admin_snippet, | |
| 92 | + :admin_project_snippet, | |
| 92 | 93 | :admin_team_member, |
| 93 | 94 | :admin_merge_request, |
| 94 | 95 | :admin_note, |
| ... | ... | @@ -135,8 +136,7 @@ class Ability |
| 135 | 136 | rules.flatten |
| 136 | 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 | 140 | define_method "#{name}_abilities" do |user, subject| |
| 141 | 141 | if subject.author == user |
| 142 | 142 | [ | ... | ... |
app/models/event.rb
app/models/note.rb
| ... | ... | @@ -159,4 +159,10 @@ class Note < ActiveRecord::Base |
| 159 | 159 | "wall" |
| 160 | 160 | end |
| 161 | 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 | 168 | end | ... | ... |
| ... | ... | @@ -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 | 57 | has_many :milestones, dependent: :destroy |
| 58 | 58 | has_many :users_projects, dependent: :destroy |
| 59 | 59 | has_many :notes, dependent: :destroy |
| 60 | - has_many :snippets, dependent: :destroy | |
| 60 | + has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet" | |
| 61 | 61 | has_many :hooks, dependent: :destroy, class_name: "ProjectHook" |
| 62 | 62 | has_many :protected_branches, dependent: :destroy |
| 63 | 63 | has_many :user_team_project_relationships, dependent: :destroy | ... | ... |
| ... | ... | @@ -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 | 11 | # updated_at :datetime not null |
| 12 | 12 | # file_name :string(255) |
| 13 | 13 | # expires_at :datetime |
| 14 | -# | |
| 14 | +# type :string(255) | |
| 15 | +# private :boolean | |
| 15 | 16 | |
| 16 | 17 | class Snippet < ActiveRecord::Base |
| 17 | 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 | 22 | belongs_to :author, class_name: "User" |
| 23 | + | |
| 23 | 24 | has_many :notes, as: :noteable, dependent: :destroy |
| 24 | 25 | |
| 25 | 26 | delegate :name, :email, to: :author, prefix: true, allow_nil: true |
| 26 | 27 | |
| 27 | 28 | validates :author, presence: true |
| 28 | - validates :project, presence: true | |
| 29 | 29 | validates :title, presence: true, length: { within: 0..255 } |
| 30 | 30 | validates :file_name, presence: true, length: { within: 0..255 } |
| 31 | 31 | validates :content, presence: true |
| 32 | 32 | |
| 33 | 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 | 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 | 40 | def self.content_types |
| 39 | 41 | [ | ... | ... |
app/models/user.rb
| ... | ... | @@ -78,6 +78,7 @@ class User < ActiveRecord::Base |
| 78 | 78 | has_many :team_projects, through: :user_team_project_relationships |
| 79 | 79 | |
| 80 | 80 | # Projects |
| 81 | + has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet" | |
| 81 | 82 | has_many :users_projects, dependent: :destroy |
| 82 | 83 | has_many :issues, dependent: :destroy, foreign_key: :author_id |
| 83 | 84 | has_many :notes, dependent: :destroy, foreign_key: :author_id | ... | ... |
app/views/events/event/_note.html.haml
| ... | ... | @@ -5,6 +5,10 @@ |
| 5 | 5 | - if event.note_commit? |
| 6 | 6 | = event.note_target_type |
| 7 | 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 | 12 | - else |
| 9 | 13 | = link_to [event.project, event.note_target] do |
| 10 | 14 | %strong | ... | ... |
| ... | ... | @@ -0,0 +1,22 @@ |
| 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 | + .container | |
| 8 | + %ul.main_menu | |
| 9 | + = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do | |
| 10 | + = link_to root_path, title: "Back to dashboard" do | |
| 11 | + %i.icon-arrow-left | |
| 12 | + = nav_link(path: 'snippet#new') do | |
| 13 | + = link_to new_snippet_path do | |
| 14 | + New snippet | |
| 15 | + = nav_link(path: 'snippets#user_index') do | |
| 16 | + = link_to user_snippets_path(@current_user) do | |
| 17 | + My snippets | |
| 18 | + = nav_link(path: 'snippets#index') do | |
| 19 | + = link_to snippets_path do | |
| 20 | + Discover snippets | |
| 21 | + | |
| 22 | + .content= yield | ... | ... |
| ... | ... | @@ -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 @@ |
| 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 @@ |
| 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 @@ |
| 1 | += render "projects/snippets/form", url: project_snippet_path(@project, @snippet) | ... | ... |
| ... | ... | @@ -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 @@ |
| 1 | += render "projects/snippets/form", url: project_snippets_path(@project, @snippet) | ... | ... |
| ... | ... | @@ -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 | 3 | %i.icon-file |
| 4 | 4 | %strong= @snippet.file_name |
| 5 | 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 | 7 | .file_content.code |
| 8 | 8 | - unless @snippet.content.empty? |
| 9 | 9 | %div{class: user_color_scheme_class} | ... | ... |
app/views/snippets/_form.html.haml
| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | = @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}" |
| 3 | 3 | %hr |
| 4 | 4 | .snippet-form-holder |
| 5 | - = form_for [@project, @snippet] do |f| | |
| 5 | + = form_for @snippet, as: :personal_snippet, url: url do |f| | |
| 6 | 6 | -if @snippet.errors.any? |
| 7 | 7 | .alert.alert-error |
| 8 | 8 | %ul |
| ... | ... | @@ -13,6 +13,9 @@ |
| 13 | 13 | = f.label :title |
| 14 | 14 | .input= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true |
| 15 | 15 | .clearfix |
| 16 | + = f.label "Private?" | |
| 17 | + .input= f.check_box :private, {class: ''} | |
| 18 | + .clearfix | |
| 16 | 19 | = f.label "Lifetime" |
| 17 | 20 | .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'} |
| 18 | 21 | .clearfix |
| ... | ... | @@ -28,9 +31,9 @@ |
| 28 | 31 | |
| 29 | 32 | .form-actions |
| 30 | 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 | 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 | 39 | :javascript | ... | ... |
app/views/snippets/_snippet.html.haml
| 1 | 1 | %tr |
| 2 | 2 | %td |
| 3 | + - if snippet.private? | |
| 4 | + %i.icon-lock | |
| 5 | + - else | |
| 6 | + %i.icon-globe | |
| 3 | 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 | 14 | %td |
| 7 | 15 | = snippet.file_name |
| 8 | 16 | %td |
| ... | ... | @@ -11,3 +19,6 @@ |
| 11 | 19 | = snippet.expires_at.to_date.to_s(:short) |
| 12 | 20 | - else |
| 13 | 21 | Never |
| 22 | + %td | |
| 23 | + - if snippet.project_id? | |
| 24 | + = link_to snippet.project.name, project_path(snippet.project) | ... | ... |
| ... | ... | @@ -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 | 1 | %h3.page_title |
| 2 | - Snippets | |
| 2 | + Public snippets | |
| 3 | 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 | 1 | %h3.page_title |
| 2 | + - if @snippet.private? | |
| 3 | + %i.icon-lock | |
| 4 | + - else | |
| 5 | + %i.icon-globe | |
| 6 | + | |
| 2 | 7 | = @snippet.title |
| 3 | 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 | 12 | %br |
| 8 | 13 | %div= render 'blob' |
| 9 | -%div#notes= render "notes/notes_with_form" | ... | ... |
| ... | ... | @@ -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 | 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 | 52 | # Public namespace |
| 43 | 53 | # |
| 44 | 54 | namespace :public do |
| ... | ... | @@ -182,6 +192,14 @@ Gitlab::Application.routes.draw do |
| 182 | 192 | resources :graph, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/} |
| 183 | 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 | 203 | resources :wikis, only: [:show, :edit, :destroy, :create] do |
| 186 | 204 | collection do |
| 187 | 205 | get :pages |
| ... | ... | @@ -255,19 +273,12 @@ Gitlab::Application.routes.draw do |
| 255 | 273 | end |
| 256 | 274 | end |
| 257 | 275 | |
| 258 | - resources :snippets do | |
| 259 | - member do | |
| 260 | - get "raw" | |
| 261 | - end | |
| 262 | - end | |
| 263 | - | |
| 264 | 276 | resources :hooks, only: [:index, :create, :destroy] do |
| 265 | 277 | member do |
| 266 | 278 | get :test |
| 267 | 279 | end |
| 268 | 280 | end |
| 269 | 281 | |
| 270 | - | |
| 271 | 282 | resources :team, controller: 'team_members', only: [:index] |
| 272 | 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 | 203 | create_table "snippets", :force => true do |t| |
| 204 | 204 | t.string "title" |
| 205 | 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 | 210 | t.string "file_name" |
| 211 | 211 | t.datetime "expires_at" |
| 212 | + t.boolean "private", :default => true, :null => false | |
| 213 | + t.string "type" | |
| 212 | 214 | end |
| 213 | 215 | |
| 214 | 216 | add_index "snippets", ["created_at"], :name => "index_snippets_on_created_at" | ... | ... |
| ... | ... | @@ -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 @@ |
| 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 @@ |
| 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 @@ |
| 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 @@ |
| 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 | 275 | visit public_root_path |
| 276 | 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 | 294 | def root_ref |
| 279 | 295 | @project.repository.root_ref |
| 280 | 296 | end | ... | ... |
| ... | ... | @@ -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 @@ |
| 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 @@ |
| 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 @@ |
| 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 | 328 | # Example Request: |
| 329 | 329 | # POST /projects/:id/snippets |
| 330 | 330 | post ":id/snippets" do |
| 331 | - authorize! :write_snippet, user_project | |
| 331 | + authorize! :write_project_snippet, user_project | |
| 332 | 332 | required_attributes! [:title, :file_name, :code] |
| 333 | 333 | |
| 334 | 334 | attrs = attributes_for_keys [:title, :file_name] |
| ... | ... | @@ -357,7 +357,7 @@ module API |
| 357 | 357 | # PUT /projects/:id/snippets/:snippet_id |
| 358 | 358 | put ":id/snippets/:snippet_id" do |
| 359 | 359 | @snippet = user_project.snippets.find(params[:snippet_id]) |
| 360 | - authorize! :modify_snippet, @snippet | |
| 360 | + authorize! :modify_project_snippet, @snippet | |
| 361 | 361 | |
| 362 | 362 | attrs = attributes_for_keys [:title, :file_name] |
| 363 | 363 | attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? |
| ... | ... | @@ -380,7 +380,7 @@ module API |
| 380 | 380 | delete ":id/snippets/:snippet_id" do |
| 381 | 381 | begin |
| 382 | 382 | @snippet = user_project.snippets.find(params[:snippet_id]) |
| 383 | - authorize! :modify_snippet, user_project | |
| 383 | + authorize! :modify_project_snippet, @snippet | |
| 384 | 384 | @snippet.destroy |
| 385 | 385 | rescue |
| 386 | 386 | end | ... | ... |
spec/factories.rb
| ... | ... | @@ -197,7 +197,7 @@ FactoryGirl.define do |
| 197 | 197 | url |
| 198 | 198 | end |
| 199 | 199 | |
| 200 | - factory :snippet do | |
| 200 | + factory :project_snippet do | |
| 201 | 201 | project |
| 202 | 202 | author |
| 203 | 203 | title |
| ... | ... | @@ -205,6 +205,20 @@ FactoryGirl.define do |
| 205 | 205 | file_name |
| 206 | 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 | 222 | factory :protected_branch do |
| 209 | 223 | name |
| 210 | 224 | project | ... | ... |
spec/features/snippets_spec.rb
| ... | ... | @@ -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 | 10 | let(:commit) { project.repository.commit } |
| 11 | 11 | let(:issue) { create(:issue, project: project) } |
| 12 | 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 | 14 | let(:member) { project.users_projects.where(user_id: user).first } |
| 15 | 15 | |
| 16 | 16 | before do |
| ... | ... | @@ -190,8 +190,43 @@ describe GitlabMarkdownHelper do |
| 190 | 190 | describe "referencing a snippet" do |
| 191 | 191 | let(:object) { snippet } |
| 192 | 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 | 230 | end |
| 196 | 231 | |
| 197 | 232 | describe "referencing multiple objects" do | ... | ... |
| ... | ... | @@ -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 | 36 | it { should have_many(:milestones).dependent(:destroy) } |
| 37 | 37 | it { should have_many(:users_projects).dependent(:destroy) } |
| 38 | 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 | 40 | it { should have_many(:deploy_keys_projects).dependent(:destroy) } |
| 41 | 41 | it { should have_many(:deploy_keys) } |
| 42 | 42 | it { should have_many(:hooks).dependent(:destroy) } | ... | ... |
spec/models/snippet_spec.rb
| ... | ... | @@ -17,19 +17,16 @@ require 'spec_helper' |
| 17 | 17 | |
| 18 | 18 | describe Snippet do |
| 19 | 19 | describe "Associations" do |
| 20 | - it { should belong_to(:project) } | |
| 21 | 20 | it { should belong_to(:author).class_name('User') } |
| 22 | 21 | it { should have_many(:notes).dependent(:destroy) } |
| 23 | 22 | end |
| 24 | 23 | |
| 25 | 24 | describe "Mass assignment" do |
| 26 | 25 | it { should_not allow_mass_assignment_of(:author_id) } |
| 27 | - it { should_not allow_mass_assignment_of(:project_id) } | |
| 28 | 26 | end |
| 29 | 27 | |
| 30 | 28 | describe "Validation" do |
| 31 | 29 | it { should validate_presence_of(:author) } |
| 32 | - it { should validate_presence_of(:project) } | |
| 33 | 30 | |
| 34 | 31 | it { should validate_presence_of(:title) } |
| 35 | 32 | it { should ensure_length_of(:title).is_within(0..255) } | ... | ... |
spec/models/user_spec.rb
| ... | ... | @@ -41,6 +41,7 @@ require 'spec_helper' |
| 41 | 41 | describe User do |
| 42 | 42 | describe "Associations" do |
| 43 | 43 | it { should have_one(:namespace) } |
| 44 | + it { should have_many(:snippets).class_name('Snippet').dependent(:destroy) } | |
| 44 | 45 | it { should have_many(:users_projects).dependent(:destroy) } |
| 45 | 46 | it { should have_many(:groups) } |
| 46 | 47 | it { should have_many(:keys).dependent(:destroy) } | ... | ... |
spec/requests/api/notes_spec.rb
| ... | ... | @@ -7,7 +7,7 @@ describe API::API do |
| 7 | 7 | let!(:project) { create(:project, namespace: user.namespace ) } |
| 8 | 8 | let!(:issue) { create(:issue, project: project, author: user) } |
| 9 | 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 | 11 | let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) } |
| 12 | 12 | let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) } |
| 13 | 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 | 10 | let(:admin) { create(:admin) } |
| 11 | 11 | let!(:project) { create(:project_with_code, creator_id: user.id) } |
| 12 | 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 | 14 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } |
| 15 | 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 | 258 | # project_snippet GET /:project_id/snippets/:id(.:format) snippets#show |
| 259 | 259 | # PUT /:project_id/snippets/:id(.:format) snippets#update |
| 260 | 260 | # DELETE /:project_id/snippets/:id(.:format) snippets#destroy |
| 261 | -describe SnippetsController, "routing" do | |
| 261 | +describe Project::SnippetsController, "routing" do | |
| 262 | 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 | 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 | 292 | end |
| 269 | 293 | end |
| 270 | 294 | ... | ... |
spec/routing/routing_spec.rb
| ... | ... | @@ -19,6 +19,51 @@ describe "Mounted Apps", "routing" do |
| 19 | 19 | end |
| 20 | 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 | 67 | # help GET /help(.:format) help#index |
| 23 | 68 | # help_permissions GET /help/permissions(.:format) help#permissions |
| 24 | 69 | # help_workflow GET /help/workflow(.:format) help#workflow | ... | ... |