Skip to content
Snippets Groups Projects
Commit 928fc94c authored by Vinnie Okada's avatar Vinnie Okada
Browse files

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
No related branches found
No related tags found
1 merge request!8686add "Uplaod" and "Replace" functionality
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
@@ -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)
Loading
Loading
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
Loading
Loading
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]
Loading
Loading
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
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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)
Loading
Loading
@@ -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
 
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment