Commit 1d2bdb4d5880bb1ad39b62c81ff2971aa0cb3798
1 parent
dba98240
Exists in
spb-stable
and in
3 other branches
Move all Context classes into Services
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Showing
36 changed files
with
499 additions
and
499 deletions
Show diff stats
app/contexts/base_context.rb
... | ... | @@ -1,19 +0,0 @@ |
1 | -class BaseContext | |
2 | - attr_accessor :project, :current_user, :params | |
3 | - | |
4 | - def initialize(project, user, params) | |
5 | - @project, @current_user, @params = project, user, params.dup | |
6 | - end | |
7 | - | |
8 | - def abilities | |
9 | - @abilities ||= begin | |
10 | - abilities = Six.new | |
11 | - abilities << Ability | |
12 | - abilities | |
13 | - end | |
14 | - end | |
15 | - | |
16 | - def can?(object, action, subject) | |
17 | - abilities.allowed?(object, action, subject) | |
18 | - end | |
19 | -end |
app/contexts/files/base_context.rb
... | ... | @@ -1,31 +0,0 @@ |
1 | -module Files | |
2 | - class BaseContext < ::BaseContext | |
3 | - attr_reader :ref, :path | |
4 | - | |
5 | - def initialize(project, user, params, ref, path = nil) | |
6 | - @project, @current_user, @params = project, user, params.dup | |
7 | - @ref = ref | |
8 | - @path = path | |
9 | - end | |
10 | - | |
11 | - private | |
12 | - | |
13 | - def error(message) | |
14 | - { | |
15 | - error: message, | |
16 | - status: :error | |
17 | - } | |
18 | - end | |
19 | - | |
20 | - def success | |
21 | - { | |
22 | - error: '', | |
23 | - status: :success | |
24 | - } | |
25 | - end | |
26 | - | |
27 | - def repository | |
28 | - project.repository | |
29 | - end | |
30 | - end | |
31 | -end |
app/contexts/files/create_context.rb
... | ... | @@ -1,46 +0,0 @@ |
1 | -require_relative "base_context" | |
2 | - | |
3 | -module Files | |
4 | - class CreateContext < BaseContext | |
5 | - def execute | |
6 | - allowed = if project.protected_branch?(ref) | |
7 | - can?(current_user, :push_code_to_protected_branches, project) | |
8 | - else | |
9 | - can?(current_user, :push_code, project) | |
10 | - end | |
11 | - | |
12 | - unless allowed | |
13 | - return error("You are not allowed to create file in this branch") | |
14 | - end | |
15 | - | |
16 | - unless repository.branch_names.include?(ref) | |
17 | - return error("You can only create files if you are on top of a branch") | |
18 | - end | |
19 | - | |
20 | - file_name = File.basename(path) | |
21 | - file_path = path | |
22 | - | |
23 | - unless file_name =~ Gitlab::Regex.path_regex | |
24 | - return error("Your changes could not be committed, because file name contains not allowed characters") | |
25 | - end | |
26 | - | |
27 | - blob = repository.blob_at(ref, file_path) | |
28 | - | |
29 | - if blob | |
30 | - return error("Your changes could not be committed, because file with such name exists") | |
31 | - end | |
32 | - | |
33 | - new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path) | |
34 | - created_successfully = new_file_action.commit!( | |
35 | - params[:content], | |
36 | - params[:commit_message] | |
37 | - ) | |
38 | - | |
39 | - if created_successfully | |
40 | - success | |
41 | - else | |
42 | - error("Your changes could not be committed, because the file has been changed") | |
43 | - end | |
44 | - end | |
45 | - end | |
46 | -end |
app/contexts/files/delete_context.rb
... | ... | @@ -1,40 +0,0 @@ |
1 | -require_relative "base_context" | |
2 | - | |
3 | -module Files | |
4 | - class DeleteContext < BaseContext | |
5 | - def execute | |
6 | - allowed = if project.protected_branch?(ref) | |
7 | - can?(current_user, :push_code_to_protected_branches, project) | |
8 | - else | |
9 | - can?(current_user, :push_code, project) | |
10 | - end | |
11 | - | |
12 | - unless allowed | |
13 | - return error("You are not allowed to push into this branch") | |
14 | - end | |
15 | - | |
16 | - unless repository.branch_names.include?(ref) | |
17 | - return error("You can only create files if you are on top of a branch") | |
18 | - end | |
19 | - | |
20 | - blob = repository.blob_at(ref, path) | |
21 | - | |
22 | - unless blob | |
23 | - return error("You can only edit text files") | |
24 | - end | |
25 | - | |
26 | - delete_file_action = Gitlab::Satellite::DeleteFileAction.new(current_user, project, ref, path) | |
27 | - | |
28 | - deleted_successfully = delete_file_action.commit!( | |
29 | - nil, | |
30 | - params[:commit_message] | |
31 | - ) | |
32 | - | |
33 | - if deleted_successfully | |
34 | - success | |
35 | - else | |
36 | - error("Your changes could not be committed, because the file has been changed") | |
37 | - end | |
38 | - end | |
39 | - end | |
40 | -end |
app/contexts/files/update_context.rb
... | ... | @@ -1,39 +0,0 @@ |
1 | -require_relative "base_context" | |
2 | - | |
3 | -module Files | |
4 | - class UpdateContext < BaseContext | |
5 | - def execute | |
6 | - allowed = if project.protected_branch?(ref) | |
7 | - can?(current_user, :push_code_to_protected_branches, project) | |
8 | - else | |
9 | - can?(current_user, :push_code, project) | |
10 | - end | |
11 | - | |
12 | - unless allowed | |
13 | - return error("You are not allowed to push into this branch") | |
14 | - end | |
15 | - | |
16 | - unless repository.branch_names.include?(ref) | |
17 | - return error("You can only create files if you are on top of a branch") | |
18 | - end | |
19 | - | |
20 | - blob = repository.blob_at(ref, path) | |
21 | - | |
22 | - unless blob | |
23 | - return error("You can only edit text files") | |
24 | - end | |
25 | - | |
26 | - new_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path) | |
27 | - created_successfully = new_file_action.commit!( | |
28 | - params[:content], | |
29 | - params[:commit_message] | |
30 | - ) | |
31 | - | |
32 | - if created_successfully | |
33 | - success | |
34 | - else | |
35 | - error("Your changes could not be committed, because the file has been changed") | |
36 | - end | |
37 | - end | |
38 | - end | |
39 | -end |
app/contexts/issues/bulk_update_context.rb
... | ... | @@ -1,39 +0,0 @@ |
1 | -module Issues | |
2 | - class BulkUpdateContext < BaseContext | |
3 | - def execute | |
4 | - update_data = params[:update] | |
5 | - | |
6 | - issues_ids = update_data[:issues_ids].split(",") | |
7 | - milestone_id = update_data[:milestone_id] | |
8 | - assignee_id = update_data[:assignee_id] | |
9 | - status = update_data[:status] | |
10 | - | |
11 | - new_state = nil | |
12 | - | |
13 | - if status.present? | |
14 | - if status == 'closed' | |
15 | - new_state = :close | |
16 | - else | |
17 | - new_state = :reopen | |
18 | - end | |
19 | - end | |
20 | - | |
21 | - opts = {} | |
22 | - opts[:milestone_id] = milestone_id if milestone_id.present? | |
23 | - opts[:assignee_id] = assignee_id if assignee_id.present? | |
24 | - | |
25 | - issues = Issue.where(id: issues_ids) | |
26 | - issues = issues.select { |issue| can?(current_user, :modify_issue, issue) } | |
27 | - | |
28 | - issues.each do |issue| | |
29 | - issue.update_attributes(opts) | |
30 | - issue.send new_state if new_state | |
31 | - end | |
32 | - | |
33 | - { | |
34 | - count: issues.count, | |
35 | - success: !issues.count.zero? | |
36 | - } | |
37 | - end | |
38 | - end | |
39 | -end |
app/contexts/notes/create_context.rb
app/contexts/notes/load_context.rb
... | ... | @@ -1,20 +0,0 @@ |
1 | -module Notes | |
2 | - class LoadContext < BaseContext | |
3 | - def execute | |
4 | - target_type = params[:target_type] | |
5 | - target_id = params[:target_id] | |
6 | - | |
7 | - | |
8 | - @notes = case target_type | |
9 | - when "commit" | |
10 | - project.notes.for_commit_id(target_id).not_inline.fresh | |
11 | - when "issue" | |
12 | - project.issues.find(target_id).notes.inc_author.fresh | |
13 | - when "merge_request" | |
14 | - project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh | |
15 | - when "snippet" | |
16 | - project.snippets.find(target_id).notes.fresh | |
17 | - end | |
18 | - end | |
19 | - end | |
20 | -end |
app/contexts/projects/create_context.rb
... | ... | @@ -1,80 +0,0 @@ |
1 | -module Projects | |
2 | - class CreateContext < BaseContext | |
3 | - def initialize(user, params) | |
4 | - @current_user, @params = user, params.dup | |
5 | - end | |
6 | - | |
7 | - def execute | |
8 | - # get namespace id | |
9 | - namespace_id = params.delete(:namespace_id) | |
10 | - | |
11 | - # check that user is allowed to set specified visibility_level | |
12 | - unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level]) | |
13 | - params.delete(:visibility_level) | |
14 | - end | |
15 | - | |
16 | - # Load default feature settings | |
17 | - default_features = Gitlab.config.gitlab.default_projects_features | |
18 | - | |
19 | - default_opts = { | |
20 | - issues_enabled: default_features.issues, | |
21 | - wiki_enabled: default_features.wiki, | |
22 | - wall_enabled: default_features.wall, | |
23 | - snippets_enabled: default_features.snippets, | |
24 | - merge_requests_enabled: default_features.merge_requests, | |
25 | - visibility_level: default_features.visibility_level | |
26 | - }.stringify_keys | |
27 | - | |
28 | - @project = Project.new(default_opts.merge(params)) | |
29 | - | |
30 | - # Parametrize path for project | |
31 | - # | |
32 | - # Ex. | |
33 | - # 'GitLab HQ'.parameterize => "gitlab-hq" | |
34 | - # | |
35 | - @project.path = @project.name.dup.parameterize unless @project.path.present? | |
36 | - | |
37 | - | |
38 | - if namespace_id | |
39 | - # Find matching namespace and check if it allowed | |
40 | - # for current user if namespace_id passed. | |
41 | - if allowed_namespace?(current_user, namespace_id) | |
42 | - @project.namespace_id = namespace_id | |
43 | - else | |
44 | - deny_namespace | |
45 | - return @project | |
46 | - end | |
47 | - else | |
48 | - # Set current user namespace if namespace_id is nil | |
49 | - @project.namespace_id = current_user.namespace_id | |
50 | - end | |
51 | - | |
52 | - @project.creator = current_user | |
53 | - | |
54 | - if @project.save | |
55 | - unless @project.group | |
56 | - @project.users_projects.create( | |
57 | - project_access: UsersProject::MASTER, | |
58 | - user: current_user | |
59 | - ) | |
60 | - end | |
61 | - end | |
62 | - | |
63 | - @project | |
64 | - rescue => ex | |
65 | - @project.errors.add(:base, "Can't save project. Please try again later") | |
66 | - @project | |
67 | - end | |
68 | - | |
69 | - protected | |
70 | - | |
71 | - def deny_namespace | |
72 | - @project.errors.add(:namespace, "is not valid") | |
73 | - end | |
74 | - | |
75 | - def allowed_namespace?(user, namespace_id) | |
76 | - namespace = Namespace.find_by_id(namespace_id) | |
77 | - current_user.can?(:manage_namespace, namespace) | |
78 | - end | |
79 | - end | |
80 | -end |
app/contexts/projects/fork_context.rb
... | ... | @@ -1,44 +0,0 @@ |
1 | -module Projects | |
2 | - class ForkContext < BaseContext | |
3 | - include Gitlab::ShellAdapter | |
4 | - | |
5 | - def initialize(project, user) | |
6 | - @from_project, @current_user = project, user | |
7 | - end | |
8 | - | |
9 | - def execute | |
10 | - project = @from_project.dup | |
11 | - project.name = @from_project.name | |
12 | - project.path = @from_project.path | |
13 | - project.namespace = current_user.namespace | |
14 | - project.creator = current_user | |
15 | - | |
16 | - # If the project cannot save, we do not want to trigger the project destroy | |
17 | - # as this can have the side effect of deleting a repo attached to an existing | |
18 | - # project with the same name and namespace | |
19 | - if project.valid? | |
20 | - begin | |
21 | - Project.transaction do | |
22 | - #First save the DB entries as they can be rolled back if the repo fork fails | |
23 | - project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id) | |
24 | - if project.save | |
25 | - project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) | |
26 | - end | |
27 | - #Now fork the repo | |
28 | - unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path) | |
29 | - raise "forking failed in gitlab-shell" | |
30 | - end | |
31 | - project.ensure_satellite_exists | |
32 | - end | |
33 | - rescue => ex | |
34 | - project.errors.add(:base, "Fork transaction failed.") | |
35 | - project.destroy | |
36 | - end | |
37 | - else | |
38 | - project.errors.add(:base, "Invalid fork destination") | |
39 | - end | |
40 | - project | |
41 | - | |
42 | - end | |
43 | - end | |
44 | -end |
app/contexts/projects/transfer_context.rb
... | ... | @@ -1,22 +0,0 @@ |
1 | -module Projects | |
2 | - class TransferContext < BaseContext | |
3 | - def execute(role = :default) | |
4 | - namespace_id = params[:project].delete(:namespace_id) | |
5 | - allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin | |
6 | - | |
7 | - if allowed_transfer && namespace_id.present? | |
8 | - if namespace_id.to_i != project.namespace_id | |
9 | - # Transfer to someone namespace | |
10 | - namespace = Namespace.find(namespace_id) | |
11 | - project.transfer(namespace) | |
12 | - end | |
13 | - end | |
14 | - | |
15 | - rescue ProjectTransferService::TransferError => ex | |
16 | - project.reload | |
17 | - project.errors.add(:namespace_id, ex.message) | |
18 | - false | |
19 | - end | |
20 | - end | |
21 | -end | |
22 | - |
app/contexts/projects/update_context.rb
... | ... | @@ -1,19 +0,0 @@ |
1 | -module Projects | |
2 | - class UpdateContext < BaseContext | |
3 | - def execute(role = :default) | |
4 | - params[:project].delete(:namespace_id) | |
5 | - # check that user is allowed to set specified visibility_level | |
6 | - unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:project][:visibility_level]) | |
7 | - params[:project].delete(:visibility_level) | |
8 | - end | |
9 | - | |
10 | - new_branch = params[:project].delete(:default_branch) | |
11 | - | |
12 | - if project.repository.exists? && new_branch && new_branch != project.default_branch | |
13 | - project.change_head(new_branch) | |
14 | - end | |
15 | - | |
16 | - project.update_attributes(params[:project], as: role) | |
17 | - end | |
18 | - end | |
19 | -end |
app/contexts/search/global_context.rb
... | ... | @@ -1,40 +0,0 @@ |
1 | -module Search | |
2 | - class GlobalContext | |
3 | - attr_accessor :current_user, :params | |
4 | - | |
5 | - def initialize(user, params) | |
6 | - @current_user, @params = user, params.dup | |
7 | - end | |
8 | - | |
9 | - def execute | |
10 | - query = params[:search] | |
11 | - query = Shellwords.shellescape(query) if query.present? | |
12 | - return result unless query.present? | |
13 | - | |
14 | - authorized_projects_ids = [] | |
15 | - authorized_projects_ids += current_user.authorized_projects.pluck(:id) if current_user | |
16 | - authorized_projects_ids += Project.public_or_internal_only(current_user).pluck(:id) | |
17 | - | |
18 | - group = Group.find_by_id(params[:group_id]) if params[:group_id].present? | |
19 | - projects = Project.where(id: authorized_projects_ids) | |
20 | - projects = projects.where(namespace_id: group.id) if group | |
21 | - projects = projects.search(query) | |
22 | - project_ids = projects.pluck(:id) | |
23 | - | |
24 | - result[:projects] = projects.limit(20) | |
25 | - result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20) | |
26 | - result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20) | |
27 | - result[:total_results] = %w(projects issues merge_requests).sum { |items| result[items.to_sym].size } | |
28 | - result | |
29 | - end | |
30 | - | |
31 | - def result | |
32 | - @result ||= { | |
33 | - projects: [], | |
34 | - merge_requests: [], | |
35 | - issues: [], | |
36 | - total_results: 0, | |
37 | - } | |
38 | - end | |
39 | - end | |
40 | -end |
app/contexts/search/project_context.rb
... | ... | @@ -1,37 +0,0 @@ |
1 | -module Search | |
2 | - class ProjectContext | |
3 | - attr_accessor :project, :current_user, :params | |
4 | - | |
5 | - def initialize(project, user, params) | |
6 | - @project, @current_user, @params = project, user, params.dup | |
7 | - end | |
8 | - | |
9 | - def execute | |
10 | - query = params[:search] | |
11 | - query = Shellwords.shellescape(query) if query.present? | |
12 | - return result unless query.present? | |
13 | - | |
14 | - if params[:search_code].present? | |
15 | - blobs = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo? | |
16 | - blobs = Kaminari.paginate_array(blobs).page(params[:page]).per(20) | |
17 | - result[:blobs] = blobs | |
18 | - result[:total_results] = blobs.total_count | |
19 | - else | |
20 | - result[:merge_requests] = project.merge_requests.search(query).order('updated_at DESC').limit(20) | |
21 | - result[:issues] = project.issues.search(query).order('updated_at DESC').limit(20) | |
22 | - result[:total_results] = %w(issues merge_requests).sum { |items| result[items.to_sym].size } | |
23 | - end | |
24 | - | |
25 | - result | |
26 | - end | |
27 | - | |
28 | - def result | |
29 | - @result ||= { | |
30 | - merge_requests: [], | |
31 | - issues: [], | |
32 | - blobs: [], | |
33 | - total_results: 0, | |
34 | - } | |
35 | - end | |
36 | - end | |
37 | -end |
app/controllers/admin/projects_controller.rb
... | ... | @@ -19,7 +19,7 @@ class Admin::ProjectsController < Admin::ApplicationController |
19 | 19 | end |
20 | 20 | |
21 | 21 | def transfer |
22 | - result = ::Projects::TransferContext.new(@project, current_user, project: params).execute(:admin) | |
22 | + result = ::Projects::TransferService.new(@project, current_user, project: params).execute(:admin) | |
23 | 23 | |
24 | 24 | if result |
25 | 25 | redirect_to [:admin, @project] | ... | ... |
app/controllers/projects/blob_controller.rb
... | ... | @@ -13,7 +13,7 @@ class Projects::BlobController < Projects::ApplicationController |
13 | 13 | end |
14 | 14 | |
15 | 15 | def destroy |
16 | - result = Files::DeleteContext.new(@project, current_user, params, @ref, @path).execute | |
16 | + result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute | |
17 | 17 | |
18 | 18 | if result[:status] == :success |
19 | 19 | flash[:notice] = "Your changes have been successfully committed" | ... | ... |
app/controllers/projects/edit_tree_controller.rb
... | ... | @@ -7,7 +7,7 @@ class Projects::EditTreeController < Projects::BaseTreeController |
7 | 7 | end |
8 | 8 | |
9 | 9 | def update |
10 | - result = Files::UpdateContext.new(@project, current_user, params, @ref, @path).execute | |
10 | + result = Files::UpdateService.new(@project, current_user, params, @ref, @path).execute | |
11 | 11 | |
12 | 12 | if result[:status] == :success |
13 | 13 | flash[:notice] = "Your changes have been successfully committed" | ... | ... |
app/controllers/projects/issues_controller.rb
... | ... | @@ -89,7 +89,7 @@ class Projects::IssuesController < Projects::ApplicationController |
89 | 89 | end |
90 | 90 | |
91 | 91 | def bulk_update |
92 | - result = Issues::BulkUpdateContext.new(project, current_user, params).execute | |
92 | + result = Issues::BulkUpdateService.new(project, current_user, params).execute | |
93 | 93 | redirect_to :back, notice: "#{result[:count]} issues updated" |
94 | 94 | end |
95 | 95 | ... | ... |
app/controllers/projects/new_tree_controller.rb
... | ... | @@ -6,7 +6,7 @@ class Projects::NewTreeController < Projects::BaseTreeController |
6 | 6 | |
7 | 7 | def update |
8 | 8 | file_path = File.join(@path, File.basename(params[:file_name])) |
9 | - result = Files::CreateContext.new(@project, current_user, params, @ref, file_path).execute | |
9 | + result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute | |
10 | 10 | |
11 | 11 | if result[:status] == :success |
12 | 12 | flash[:notice] = "Your changes have been successfully committed" | ... | ... |
app/controllers/projects/notes_controller.rb
... | ... | @@ -5,7 +5,7 @@ class Projects::NotesController < Projects::ApplicationController |
5 | 5 | before_filter :authorize_admin_note!, only: [:update, :destroy] |
6 | 6 | |
7 | 7 | def index |
8 | - @notes = Notes::LoadContext.new(project, current_user, params).execute | |
8 | + @notes = Notes::LoadService.new(project, current_user, params).execute | |
9 | 9 | |
10 | 10 | notes_json = { notes: [] } |
11 | 11 | |
... | ... | @@ -20,7 +20,7 @@ class Projects::NotesController < Projects::ApplicationController |
20 | 20 | end |
21 | 21 | |
22 | 22 | def create |
23 | - @note = Notes::CreateContext.new(project, current_user, params).execute | |
23 | + @note = Notes::CreateService.new(project, current_user, params).execute | |
24 | 24 | |
25 | 25 | respond_to do |format| |
26 | 26 | format.json { render_note_json(@note) } | ... | ... |
app/controllers/projects_controller.rb
... | ... | @@ -20,7 +20,7 @@ class ProjectsController < ApplicationController |
20 | 20 | end |
21 | 21 | |
22 | 22 | def create |
23 | - @project = ::Projects::CreateContext.new(current_user, params[:project]).execute | |
23 | + @project = ::Projects::CreateService.new(current_user, params[:project]).execute | |
24 | 24 | |
25 | 25 | respond_to do |format| |
26 | 26 | flash[:notice] = 'Project was successfully created.' if @project.saved? |
... | ... | @@ -36,7 +36,7 @@ class ProjectsController < ApplicationController |
36 | 36 | end |
37 | 37 | |
38 | 38 | def update |
39 | - status = ::Projects::UpdateContext.new(@project, current_user, params).execute | |
39 | + status = ::Projects::UpdateService.new(@project, current_user, params).execute | |
40 | 40 | |
41 | 41 | respond_to do |format| |
42 | 42 | if status |
... | ... | @@ -51,7 +51,7 @@ class ProjectsController < ApplicationController |
51 | 51 | end |
52 | 52 | |
53 | 53 | def transfer |
54 | - ::Projects::TransferContext.new(project, current_user, params).execute | |
54 | + ::Projects::TransferService.new(project, current_user, params).execute | |
55 | 55 | end |
56 | 56 | |
57 | 57 | def show |
... | ... | @@ -89,7 +89,7 @@ class ProjectsController < ApplicationController |
89 | 89 | end |
90 | 90 | |
91 | 91 | def fork |
92 | - @forked_project = ::Projects::ForkContext.new(project, current_user).execute | |
92 | + @forked_project = ::Projects::ForkService.new(project, current_user).execute | |
93 | 93 | |
94 | 94 | respond_to do |format| |
95 | 95 | format.html do | ... | ... |
app/controllers/search_controller.rb
... | ... | @@ -5,9 +5,9 @@ class SearchController < ApplicationController |
5 | 5 | |
6 | 6 | if @project |
7 | 7 | return access_denied! unless can?(current_user, :download_code, @project) |
8 | - @search_results = Search::ProjectContext.new(@project, current_user, params).execute | |
8 | + @search_results = Search::ProjectService.new(@project, current_user, params).execute | |
9 | 9 | else |
10 | - @search_results = Search::GlobalContext.new(current_user, params).execute | |
10 | + @search_results = Search::GlobalService.new(current_user, params).execute | |
11 | 11 | end |
12 | 12 | end |
13 | 13 | end | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +class BaseService | |
2 | + attr_accessor :project, :current_user, :params | |
3 | + | |
4 | + def initialize(project, user, params) | |
5 | + @project, @current_user, @params = project, user, params.dup | |
6 | + end | |
7 | + | |
8 | + def abilities | |
9 | + @abilities ||= begin | |
10 | + abilities = Six.new | |
11 | + abilities << Ability | |
12 | + abilities | |
13 | + end | |
14 | + end | |
15 | + | |
16 | + def can?(object, action, subject) | |
17 | + abilities.allowed?(object, action, subject) | |
18 | + end | |
19 | +end | ... | ... |
... | ... | @@ -0,0 +1,31 @@ |
1 | +module Files | |
2 | + class BaseService < ::BaseService | |
3 | + attr_reader :ref, :path | |
4 | + | |
5 | + def initialize(project, user, params, ref, path = nil) | |
6 | + @project, @current_user, @params = project, user, params.dup | |
7 | + @ref = ref | |
8 | + @path = path | |
9 | + end | |
10 | + | |
11 | + private | |
12 | + | |
13 | + def error(message) | |
14 | + { | |
15 | + error: message, | |
16 | + status: :error | |
17 | + } | |
18 | + end | |
19 | + | |
20 | + def success | |
21 | + { | |
22 | + error: '', | |
23 | + status: :success | |
24 | + } | |
25 | + end | |
26 | + | |
27 | + def repository | |
28 | + project.repository | |
29 | + end | |
30 | + end | |
31 | +end | ... | ... |
... | ... | @@ -0,0 +1,46 @@ |
1 | +require_relative "base_context" | |
2 | + | |
3 | +module Files | |
4 | + class CreateService < BaseService | |
5 | + def execute | |
6 | + allowed = if project.protected_branch?(ref) | |
7 | + can?(current_user, :push_code_to_protected_branches, project) | |
8 | + else | |
9 | + can?(current_user, :push_code, project) | |
10 | + end | |
11 | + | |
12 | + unless allowed | |
13 | + return error("You are not allowed to create file in this branch") | |
14 | + end | |
15 | + | |
16 | + unless repository.branch_names.include?(ref) | |
17 | + return error("You can only create files if you are on top of a branch") | |
18 | + end | |
19 | + | |
20 | + file_name = File.basename(path) | |
21 | + file_path = path | |
22 | + | |
23 | + unless file_name =~ Gitlab::Regex.path_regex | |
24 | + return error("Your changes could not be committed, because file name contains not allowed characters") | |
25 | + end | |
26 | + | |
27 | + blob = repository.blob_at(ref, file_path) | |
28 | + | |
29 | + if blob | |
30 | + return error("Your changes could not be committed, because file with such name exists") | |
31 | + end | |
32 | + | |
33 | + new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path) | |
34 | + created_successfully = new_file_action.commit!( | |
35 | + params[:content], | |
36 | + params[:commit_message] | |
37 | + ) | |
38 | + | |
39 | + if created_successfully | |
40 | + success | |
41 | + else | |
42 | + error("Your changes could not be committed, because the file has been changed") | |
43 | + end | |
44 | + end | |
45 | + end | |
46 | +end | ... | ... |
... | ... | @@ -0,0 +1,40 @@ |
1 | +require_relative "base_context" | |
2 | + | |
3 | +module Files | |
4 | + class DeleteService < BaseService | |
5 | + def execute | |
6 | + allowed = if project.protected_branch?(ref) | |
7 | + can?(current_user, :push_code_to_protected_branches, project) | |
8 | + else | |
9 | + can?(current_user, :push_code, project) | |
10 | + end | |
11 | + | |
12 | + unless allowed | |
13 | + return error("You are not allowed to push into this branch") | |
14 | + end | |
15 | + | |
16 | + unless repository.branch_names.include?(ref) | |
17 | + return error("You can only create files if you are on top of a branch") | |
18 | + end | |
19 | + | |
20 | + blob = repository.blob_at(ref, path) | |
21 | + | |
22 | + unless blob | |
23 | + return error("You can only edit text files") | |
24 | + end | |
25 | + | |
26 | + delete_file_action = Gitlab::Satellite::DeleteFileAction.new(current_user, project, ref, path) | |
27 | + | |
28 | + deleted_successfully = delete_file_action.commit!( | |
29 | + nil, | |
30 | + params[:commit_message] | |
31 | + ) | |
32 | + | |
33 | + if deleted_successfully | |
34 | + success | |
35 | + else | |
36 | + error("Your changes could not be committed, because the file has been changed") | |
37 | + end | |
38 | + end | |
39 | + end | |
40 | +end | ... | ... |
... | ... | @@ -0,0 +1,39 @@ |
1 | +require_relative "base_context" | |
2 | + | |
3 | +module Files | |
4 | + class UpdateService < BaseService | |
5 | + def execute | |
6 | + allowed = if project.protected_branch?(ref) | |
7 | + can?(current_user, :push_code_to_protected_branches, project) | |
8 | + else | |
9 | + can?(current_user, :push_code, project) | |
10 | + end | |
11 | + | |
12 | + unless allowed | |
13 | + return error("You are not allowed to push into this branch") | |
14 | + end | |
15 | + | |
16 | + unless repository.branch_names.include?(ref) | |
17 | + return error("You can only create files if you are on top of a branch") | |
18 | + end | |
19 | + | |
20 | + blob = repository.blob_at(ref, path) | |
21 | + | |
22 | + unless blob | |
23 | + return error("You can only edit text files") | |
24 | + end | |
25 | + | |
26 | + new_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path) | |
27 | + created_successfully = new_file_action.commit!( | |
28 | + params[:content], | |
29 | + params[:commit_message] | |
30 | + ) | |
31 | + | |
32 | + if created_successfully | |
33 | + success | |
34 | + else | |
35 | + error("Your changes could not be committed, because the file has been changed") | |
36 | + end | |
37 | + end | |
38 | + end | |
39 | +end | ... | ... |
... | ... | @@ -0,0 +1,39 @@ |
1 | +module Issues | |
2 | + class BulkUpdateService < BaseService | |
3 | + def execute | |
4 | + update_data = params[:update] | |
5 | + | |
6 | + issues_ids = update_data[:issues_ids].split(",") | |
7 | + milestone_id = update_data[:milestone_id] | |
8 | + assignee_id = update_data[:assignee_id] | |
9 | + status = update_data[:status] | |
10 | + | |
11 | + new_state = nil | |
12 | + | |
13 | + if status.present? | |
14 | + if status == 'closed' | |
15 | + new_state = :close | |
16 | + else | |
17 | + new_state = :reopen | |
18 | + end | |
19 | + end | |
20 | + | |
21 | + opts = {} | |
22 | + opts[:milestone_id] = milestone_id if milestone_id.present? | |
23 | + opts[:assignee_id] = assignee_id if assignee_id.present? | |
24 | + | |
25 | + issues = Issue.where(id: issues_ids) | |
26 | + issues = issues.select { |issue| can?(current_user, :modify_issue, issue) } | |
27 | + | |
28 | + issues.each do |issue| | |
29 | + issue.update_attributes(opts) | |
30 | + issue.send new_state if new_state | |
31 | + end | |
32 | + | |
33 | + { | |
34 | + count: issues.count, | |
35 | + success: !issues.count.zero? | |
36 | + } | |
37 | + end | |
38 | + end | |
39 | +end | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +module Notes | |
2 | + class LoadService < BaseService | |
3 | + def execute | |
4 | + target_type = params[:target_type] | |
5 | + target_id = params[:target_id] | |
6 | + | |
7 | + | |
8 | + @notes = case target_type | |
9 | + when "commit" | |
10 | + project.notes.for_commit_id(target_id).not_inline.fresh | |
11 | + when "issue" | |
12 | + project.issues.find(target_id).notes.inc_author.fresh | |
13 | + when "merge_request" | |
14 | + project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh | |
15 | + when "snippet" | |
16 | + project.snippets.find(target_id).notes.fresh | |
17 | + end | |
18 | + end | |
19 | + end | |
20 | +end | ... | ... |
... | ... | @@ -0,0 +1,80 @@ |
1 | +module Projects | |
2 | + class CreateService < BaseService | |
3 | + def initialize(user, params) | |
4 | + @current_user, @params = user, params.dup | |
5 | + end | |
6 | + | |
7 | + def execute | |
8 | + # get namespace id | |
9 | + namespace_id = params.delete(:namespace_id) | |
10 | + | |
11 | + # check that user is allowed to set specified visibility_level | |
12 | + unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level]) | |
13 | + params.delete(:visibility_level) | |
14 | + end | |
15 | + | |
16 | + # Load default feature settings | |
17 | + default_features = Gitlab.config.gitlab.default_projects_features | |
18 | + | |
19 | + default_opts = { | |
20 | + issues_enabled: default_features.issues, | |
21 | + wiki_enabled: default_features.wiki, | |
22 | + wall_enabled: default_features.wall, | |
23 | + snippets_enabled: default_features.snippets, | |
24 | + merge_requests_enabled: default_features.merge_requests, | |
25 | + visibility_level: default_features.visibility_level | |
26 | + }.stringify_keys | |
27 | + | |
28 | + @project = Project.new(default_opts.merge(params)) | |
29 | + | |
30 | + # Parametrize path for project | |
31 | + # | |
32 | + # Ex. | |
33 | + # 'GitLab HQ'.parameterize => "gitlab-hq" | |
34 | + # | |
35 | + @project.path = @project.name.dup.parameterize unless @project.path.present? | |
36 | + | |
37 | + | |
38 | + if namespace_id | |
39 | + # Find matching namespace and check if it allowed | |
40 | + # for current user if namespace_id passed. | |
41 | + if allowed_namespace?(current_user, namespace_id) | |
42 | + @project.namespace_id = namespace_id | |
43 | + else | |
44 | + deny_namespace | |
45 | + return @project | |
46 | + end | |
47 | + else | |
48 | + # Set current user namespace if namespace_id is nil | |
49 | + @project.namespace_id = current_user.namespace_id | |
50 | + end | |
51 | + | |
52 | + @project.creator = current_user | |
53 | + | |
54 | + if @project.save | |
55 | + unless @project.group | |
56 | + @project.users_projects.create( | |
57 | + project_access: UsersProject::MASTER, | |
58 | + user: current_user | |
59 | + ) | |
60 | + end | |
61 | + end | |
62 | + | |
63 | + @project | |
64 | + rescue => ex | |
65 | + @project.errors.add(:base, "Can't save project. Please try again later") | |
66 | + @project | |
67 | + end | |
68 | + | |
69 | + protected | |
70 | + | |
71 | + def deny_namespace | |
72 | + @project.errors.add(:namespace, "is not valid") | |
73 | + end | |
74 | + | |
75 | + def allowed_namespace?(user, namespace_id) | |
76 | + namespace = Namespace.find_by_id(namespace_id) | |
77 | + current_user.can?(:manage_namespace, namespace) | |
78 | + end | |
79 | + end | |
80 | +end | ... | ... |
... | ... | @@ -0,0 +1,44 @@ |
1 | +module Projects | |
2 | + class ForkService < BaseService | |
3 | + include Gitlab::ShellAdapter | |
4 | + | |
5 | + def initialize(project, user) | |
6 | + @from_project, @current_user = project, user | |
7 | + end | |
8 | + | |
9 | + def execute | |
10 | + project = @from_project.dup | |
11 | + project.name = @from_project.name | |
12 | + project.path = @from_project.path | |
13 | + project.namespace = current_user.namespace | |
14 | + project.creator = current_user | |
15 | + | |
16 | + # If the project cannot save, we do not want to trigger the project destroy | |
17 | + # as this can have the side effect of deleting a repo attached to an existing | |
18 | + # project with the same name and namespace | |
19 | + if project.valid? | |
20 | + begin | |
21 | + Project.transaction do | |
22 | + #First save the DB entries as they can be rolled back if the repo fork fails | |
23 | + project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id) | |
24 | + if project.save | |
25 | + project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) | |
26 | + end | |
27 | + #Now fork the repo | |
28 | + unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path) | |
29 | + raise "forking failed in gitlab-shell" | |
30 | + end | |
31 | + project.ensure_satellite_exists | |
32 | + end | |
33 | + rescue => ex | |
34 | + project.errors.add(:base, "Fork transaction failed.") | |
35 | + project.destroy | |
36 | + end | |
37 | + else | |
38 | + project.errors.add(:base, "Invalid fork destination") | |
39 | + end | |
40 | + project | |
41 | + | |
42 | + end | |
43 | + end | |
44 | +end | ... | ... |
... | ... | @@ -0,0 +1,22 @@ |
1 | +module Projects | |
2 | + class TransferService < BaseService | |
3 | + def execute(role = :default) | |
4 | + namespace_id = params[:project].delete(:namespace_id) | |
5 | + allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin | |
6 | + | |
7 | + if allowed_transfer && namespace_id.present? | |
8 | + if namespace_id.to_i != project.namespace_id | |
9 | + # Transfer to someone namespace | |
10 | + namespace = Namespace.find(namespace_id) | |
11 | + project.transfer(namespace) | |
12 | + end | |
13 | + end | |
14 | + | |
15 | + rescue ProjectTransferService::TransferError => ex | |
16 | + project.reload | |
17 | + project.errors.add(:namespace_id, ex.message) | |
18 | + false | |
19 | + end | |
20 | + end | |
21 | +end | |
22 | + | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +module Projects | |
2 | + class UpdateService < BaseService | |
3 | + def execute(role = :default) | |
4 | + params[:project].delete(:namespace_id) | |
5 | + # check that user is allowed to set specified visibility_level | |
6 | + unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:project][:visibility_level]) | |
7 | + params[:project].delete(:visibility_level) | |
8 | + end | |
9 | + | |
10 | + new_branch = params[:project].delete(:default_branch) | |
11 | + | |
12 | + if project.repository.exists? && new_branch && new_branch != project.default_branch | |
13 | + project.change_head(new_branch) | |
14 | + end | |
15 | + | |
16 | + project.update_attributes(params[:project], as: role) | |
17 | + end | |
18 | + end | |
19 | +end | ... | ... |
... | ... | @@ -0,0 +1,40 @@ |
1 | +module Search | |
2 | + class GlobalService | |
3 | + attr_accessor :current_user, :params | |
4 | + | |
5 | + def initialize(user, params) | |
6 | + @current_user, @params = user, params.dup | |
7 | + end | |
8 | + | |
9 | + def execute | |
10 | + query = params[:search] | |
11 | + query = Shellwords.shellescape(query) if query.present? | |
12 | + return result unless query.present? | |
13 | + | |
14 | + authorized_projects_ids = [] | |
15 | + authorized_projects_ids += current_user.authorized_projects.pluck(:id) if current_user | |
16 | + authorized_projects_ids += Project.public_or_internal_only(current_user).pluck(:id) | |
17 | + | |
18 | + group = Group.find_by_id(params[:group_id]) if params[:group_id].present? | |
19 | + projects = Project.where(id: authorized_projects_ids) | |
20 | + projects = projects.where(namespace_id: group.id) if group | |
21 | + projects = projects.search(query) | |
22 | + project_ids = projects.pluck(:id) | |
23 | + | |
24 | + result[:projects] = projects.limit(20) | |
25 | + result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20) | |
26 | + result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20) | |
27 | + result[:total_results] = %w(projects issues merge_requests).sum { |items| result[items.to_sym].size } | |
28 | + result | |
29 | + end | |
30 | + | |
31 | + def result | |
32 | + @result ||= { | |
33 | + projects: [], | |
34 | + merge_requests: [], | |
35 | + issues: [], | |
36 | + total_results: 0, | |
37 | + } | |
38 | + end | |
39 | + end | |
40 | +end | ... | ... |
... | ... | @@ -0,0 +1,37 @@ |
1 | +module Search | |
2 | + class ProjectService | |
3 | + attr_accessor :project, :current_user, :params | |
4 | + | |
5 | + def initialize(project, user, params) | |
6 | + @project, @current_user, @params = project, user, params.dup | |
7 | + end | |
8 | + | |
9 | + def execute | |
10 | + query = params[:search] | |
11 | + query = Shellwords.shellescape(query) if query.present? | |
12 | + return result unless query.present? | |
13 | + | |
14 | + if params[:search_code].present? | |
15 | + blobs = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo? | |
16 | + blobs = Kaminari.paginate_array(blobs).page(params[:page]).per(20) | |
17 | + result[:blobs] = blobs | |
18 | + result[:total_results] = blobs.total_count | |
19 | + else | |
20 | + result[:merge_requests] = project.merge_requests.search(query).order('updated_at DESC').limit(20) | |
21 | + result[:issues] = project.issues.search(query).order('updated_at DESC').limit(20) | |
22 | + result[:total_results] = %w(issues merge_requests).sum { |items| result[items.to_sym].size } | |
23 | + end | |
24 | + | |
25 | + result | |
26 | + end | |
27 | + | |
28 | + def result | |
29 | + @result ||= { | |
30 | + merge_requests: [], | |
31 | + issues: [], | |
32 | + blobs: [], | |
33 | + total_results: 0, | |
34 | + } | |
35 | + end | |
36 | + end | |
37 | +end | ... | ... |