Commit 928fc94c authored by Vinnie Okada's avatar Vinnie Okada

Enforce restricted visibilities for snippets

Add new service classes to create and update project and personal
snippets.  These classes are responsible for enforcing restricted
visibility settings for non-admin users.
parent 285c5341
...@@ -28,26 +28,22 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -28,26 +28,22 @@ class Projects::SnippetsController < Projects::ApplicationController
end end
def create def create
@snippet = @project.snippets.build(snippet_params) @snippet = CreateSnippetService.new(@project, current_user,
@snippet.author = current_user snippet_params).execute
respond_with(@snippet,
if @snippet.save location: namespace_project_snippet_path(@project.namespace,
redirect_to namespace_project_snippet_path(@project.namespace, @project, @project, @snippet))
@snippet)
else
respond_with(@snippet)
end
end end
def edit def edit
end end
def update def update
if @snippet.update_attributes(snippet_params) UpdateSnippetService.new(project, current_user, @snippet,
redirect_to namespace_project_snippet_path(@project.namespace, @project, @snippet) snippet_params).execute
else respond_with(@snippet,
respond_with(@snippet) location: namespace_project_snippet_path(@project.namespace,
end @project, @snippet))
end end
def show def show
......
...@@ -42,25 +42,19 @@ class SnippetsController < ApplicationController ...@@ -42,25 +42,19 @@ class SnippetsController < ApplicationController
end end
def create def create
@snippet = PersonalSnippet.new(snippet_params) @snippet = CreateSnippetService.new(nil, current_user,
@snippet.author = current_user snippet_params).execute
if @snippet.save respond_with @snippet.becomes(Snippet)
redirect_to snippet_path(@snippet)
else
respond_with @snippet
end
end end
def edit def edit
end end
def update def update
if @snippet.update_attributes(snippet_params) UpdateSnippetService.new(nil, current_user, @snippet,
redirect_to snippet_path(@snippet) snippet_params).execute
else respond_with @snippet.becomes(Snippet)
respond_with @snippet
end
end end
def show def show
......
...@@ -45,7 +45,8 @@ module GitlabRoutingHelper ...@@ -45,7 +45,8 @@ module GitlabRoutingHelper
namespace_project_merge_request_url(entity.project.namespace, entity.project, entity, *args) namespace_project_merge_request_url(entity.project.namespace, entity.project, entity, *args)
end end
def snippet_url(entity, *args) def project_snippet_url(entity, *args)
namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args) namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args)
end end
end end
...@@ -31,6 +31,21 @@ class BaseService ...@@ -31,6 +31,21 @@ class BaseService
SystemHooksService.new SystemHooksService.new
end end
# Add an error to the specified model for restricted visibility levels
def deny_visibility_level(model, denied_visibility_level = nil)
denied_visibility_level ||= model.visibility_level
level_name = 'Unknown'
Gitlab::VisibilityLevel.options.each do |name, level|
level_name = name if level == denied_visibility_level
end
model.errors.add(
:visibility_level,
"#{level_name} visibility has been restricted by your GitLab administrator"
)
end
private private
def error(message, http_status = nil) def error(message, http_status = nil)
......
class CreateSnippetService < BaseService
def execute
if project.nil?
snippet = PersonalSnippet.new(params)
else
snippet = project.snippets.build(params)
end
unless Gitlab::VisibilityLevel.allowed_for?(current_user,
params[:visibility_level])
deny_visibility_level(snippet)
return snippet
end
snippet.author = current_user
snippet.save
snippet
end
end
module Projects
class BaseService < ::BaseService
# Add an error to the project for restricted visibility levels
def deny_visibility_level(project, denied_visibility_level = nil)
denied_visibility_level ||= project.visibility_level
level_name = 'Unknown'
Gitlab::VisibilityLevel.options.each do |name, level|
level_name = name if level == denied_visibility_level
end
project.errors.add(
:visibility_level,
"#{level_name} visibility has been restricted by your GitLab administrator"
)
end
end
end
module Projects module Projects
class CreateService < Projects::BaseService class CreateService < BaseService
def initialize(user, params) def initialize(user, params)
@current_user, @params = user, params.dup @current_user, @params = user, params.dup
end end
......
module Projects module Projects
class UpdateService < Projects::BaseService class UpdateService < BaseService
def execute def execute
# check that user is allowed to set specified visibility_level # check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level] new_visibility = params[:visibility_level]
......
class UpdateSnippetService < BaseService class UpdateSnippetService < BaseService
attr_accessor :snippet attr_accessor :snippet
def initialize(project = nil, user, snippet, params = {}) def initialize(project, user, snippet, params)
super(project, user, params) super(project, user, params)
@snippet = snippet @snippet = snippet
end end
...@@ -9,10 +9,10 @@ class UpdateSnippetService < BaseService ...@@ -9,10 +9,10 @@ class UpdateSnippetService < BaseService
def execute def execute
# check that user is allowed to set specified visibility_level # check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level] new_visibility = params[:visibility_level]
if new_visibility && new_visibility != snippet.visibility_level if new_visibility && new_visibility.to_i != snippet.visibility_level
unless can?(current_user, :change_visibility_level, snippet) && unless can?(current_user, :change_visibility_level, snippet) &&
Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility) Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
deny_visibility_level(snippet, new_visibility_level) deny_visibility_level(snippet, new_visibility)
return snippet return snippet
end end
end end
......
...@@ -42,18 +42,19 @@ module API ...@@ -42,18 +42,19 @@ module API
# title (required) - The title of a snippet # title (required) - The title of a snippet
# file_name (required) - The name of a snippet file # file_name (required) - The name of a snippet file
# code (required) - The content of a snippet # code (required) - The content of a snippet
# visibility_level (required) - The snippet's visibility
# Example Request: # Example Request:
# POST /projects/:id/snippets # POST /projects/:id/snippets
post ":id/snippets" do post ":id/snippets" do
authorize! :write_project_snippet, user_project authorize! :write_project_snippet, user_project
required_attributes! [:title, :file_name, :code] required_attributes! [:title, :file_name, :code, :visibility_level]
attrs = attributes_for_keys [:title, :file_name] attrs = attributes_for_keys [:title, :file_name, :visibility_level]
attrs[:content] = params[:code] if params[:code].present? attrs[:content] = params[:code] if params[:code].present?
@snippet = user_project.snippets.new attrs @snippet = CreateSnippetservice.new(user_project, current_user,
@snippet.author = current_user attrs).execute
if @snippet.save if @snippet.saved?
present @snippet, with: Entities::ProjectSnippet present @snippet, with: Entities::ProjectSnippet
else else
render_validation_error!(@snippet) render_validation_error!(@snippet)
...@@ -68,19 +69,22 @@ module API ...@@ -68,19 +69,22 @@ module API
# title (optional) - The title of a snippet # title (optional) - The title of a snippet
# file_name (optional) - The name of a snippet file # file_name (optional) - The name of a snippet file
# code (optional) - The content of a snippet # code (optional) - The content of a snippet
# visibility_level (optional) - The snippet's visibility
# Example Request: # Example Request:
# PUT /projects/:id/snippets/:snippet_id # PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do put ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id]) @snippet = user_project.snippets.find(params[:snippet_id])
authorize! :modify_project_snippet, @snippet authorize! :modify_project_snippet, @snippet
attrs = attributes_for_keys [:title, :file_name] attrs = attributes_for_keys [:title, :file_name, :visibility_level]
attrs[:content] = params[:code] if params[:code].present? attrs[:content] = params[:code] if params[:code].present?
if @snippet.update_attributes attrs UpdateSnippetService.new(user_project, current_user, @snippet,
present @snippet, with: Entities::ProjectSnippet attrs).execute
else if @snippet.errors.any?
render_validation_error!(@snippet) render_validation_error!(@snippet)
else
present @snippet, with: Entities::ProjectSnippet
end end
end end
......
...@@ -51,7 +51,7 @@ module Gitlab ...@@ -51,7 +51,7 @@ module Gitlab
anchor: "note_#{note.id}") anchor: "note_#{note.id}")
elsif note.for_project_snippet? elsif note.for_project_snippet?
snippet = Snippet.find(note.noteable_id) snippet = Snippet.find(note.noteable_id)
snippet_url(snippet, project_snippet_url(snippet,
host: Gitlab.config.gitlab['url'], host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}") anchor: "note_#{note.id}")
end end
......
...@@ -425,7 +425,8 @@ describe API::API, api: true do ...@@ -425,7 +425,8 @@ describe API::API, api: true do
describe 'POST /projects/:id/snippets' do describe 'POST /projects/:id/snippets' do
it 'should create a new project snippet' do it 'should create a new project snippet' do
post api("/projects/#{project.id}/snippets", user), post api("/projects/#{project.id}/snippets", user),
title: 'api test', file_name: 'sample.rb', code: 'test' title: 'api test', file_name: 'sample.rb', code: 'test',
visibility_level: '0'
expect(response.status).to eq(201) expect(response.status).to eq(201)
expect(json_response['title']).to eq('api test') expect(json_response['title']).to eq('api test')
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment