Commit 1d2bdb4d5880bb1ad39b62c81ff2971aa0cb3798

Authored by Dmitriy Zaporozhets
1 parent dba98240

Move all Context classes into Services

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
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
... ... @@ -1,10 +0,0 @@
1   -module Notes
2   - class CreateContext < BaseContext
3   - def execute
4   - note = project.notes.new(params[:note])
5   - note.author = current_user
6   - note.save
7   - note
8   - end
9   - end
10   -end
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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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
... ...
app/services/base_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/files/base_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/files/create_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/files/delete_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/files/update_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/issues/bulk_update_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/notes/create_service.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +module Notes
  2 + class CreateService < BaseService
  3 + def execute
  4 + note = project.notes.new(params[:note])
  5 + note.author = current_user
  6 + note.save
  7 + note
  8 + end
  9 + end
  10 +end
... ...
app/services/notes/load_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/projects/create_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/projects/fork_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/projects/transfer_service.rb 0 → 100644
... ... @@ -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 +
... ...
app/services/projects/update_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/search/global_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/search/project_service.rb 0 → 100644
... ... @@ -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
... ...