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
end
def create
@snippet = @project.snippets.build(snippet_params)
@snippet.author = current_user
if @snippet.save
redirect_to namespace_project_snippet_path(@project.namespace, @project,
@snippet)
else
respond_with(@snippet)
end
@snippet = CreateSnippetService.new(@project, current_user,
snippet_params).execute
respond_with(@snippet,
location: namespace_project_snippet_path(@project.namespace,
@project, @snippet))
end
def edit
end
def update
if @snippet.update_attributes(snippet_params)
redirect_to namespace_project_snippet_path(@project.namespace, @project, @snippet)
else
respond_with(@snippet)
end
UpdateSnippetService.new(project, current_user, @snippet,
snippet_params).execute
respond_with(@snippet,
location: namespace_project_snippet_path(@project.namespace,
@project, @snippet))
end
def show
......
......@@ -42,25 +42,19 @@ class SnippetsController < ApplicationController
end
def create
@snippet = PersonalSnippet.new(snippet_params)
@snippet.author = current_user
@snippet = CreateSnippetService.new(nil, current_user,
snippet_params).execute
if @snippet.save
redirect_to snippet_path(@snippet)
else
respond_with @snippet
end
respond_with @snippet.becomes(Snippet)
end
def edit
end
def update
if @snippet.update_attributes(snippet_params)
redirect_to snippet_path(@snippet)
else
respond_with @snippet
end
UpdateSnippetService.new(nil, current_user, @snippet,
snippet_params).execute
respond_with @snippet.becomes(Snippet)
end
def show
......
......@@ -45,7 +45,8 @@ module GitlabRoutingHelper
namespace_project_merge_request_url(entity.project.namespace, entity.project, entity, *args)
end
def snippet_url(entity, *args)
def project_snippet_url(entity, *args)
namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args)
end
end
......@@ -31,6 +31,21 @@ class BaseService
SystemHooksService.new
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
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
class CreateService < Projects::BaseService
class CreateService < BaseService
def initialize(user, params)
@current_user, @params = user, params.dup
end
......
module Projects
class UpdateService < Projects::BaseService
class UpdateService < BaseService
def execute
# check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level]
......
class UpdateSnippetService < BaseService
attr_accessor :snippet
def initialize(project = nil, user, snippet, params = {})
def initialize(project, user, snippet, params)
super(project, user, params)
@snippet = snippet
end
......@@ -9,10 +9,10 @@ class UpdateSnippetService < BaseService
def execute
# check that user is allowed to set specified 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) &&
Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
deny_visibility_level(snippet, new_visibility_level)
deny_visibility_level(snippet, new_visibility)
return snippet
end
end
......
......@@ -42,18 +42,19 @@ module API
# title (required) - The title of a snippet
# file_name (required) - The name of a snippet file
# code (required) - The content of a snippet
# visibility_level (required) - The snippet's visibility
# Example Request:
# POST /projects/:id/snippets
post ":id/snippets" do
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?
@snippet = user_project.snippets.new attrs
@snippet.author = current_user
@snippet = CreateSnippetservice.new(user_project, current_user,
attrs).execute
if @snippet.save
if @snippet.saved?
present @snippet, with: Entities::ProjectSnippet
else
render_validation_error!(@snippet)
......@@ -68,19 +69,22 @@ module API
# title (optional) - The title of a snippet
# file_name (optional) - The name of a snippet file
# code (optional) - The content of a snippet
# visibility_level (optional) - The snippet's visibility
# Example Request:
# PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id])
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?
if @snippet.update_attributes attrs
present @snippet, with: Entities::ProjectSnippet
else
UpdateSnippetService.new(user_project, current_user, @snippet,
attrs).execute
if @snippet.errors.any?
render_validation_error!(@snippet)
else
present @snippet, with: Entities::ProjectSnippet
end
end
......
......@@ -51,9 +51,9 @@ module Gitlab
anchor: "note_#{note.id}")
elsif note.for_project_snippet?
snippet = Snippet.find(note.noteable_id)
snippet_url(snippet,
host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
project_snippet_url(snippet,
host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
end
end
end
......
......@@ -425,7 +425,8 @@ describe API::API, api: true do
describe 'POST /projects/:id/snippets' do
it 'should create a new project snippet' do
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(json_response['title']).to eq('api test')
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