summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorJarka Košanová <jarka@gitlab.com>2018-10-29 10:05:47 +0100
committerJarka Košanová <jarka@gitlab.com>2018-11-12 08:57:25 +0100
commit4af1712d01efb7295cc069dca0045b01c7b4cb40 (patch)
treed32a325b8d7e0a7ee00e032e8927e4ba9af9c29d /app
parent2e690c8208e9da5e7152e77cd77efdade5260be1 (diff)
downloadgitlab-ce-4af1712d01efb7295cc069dca0045b01c7b4cb40.tar.gz
Extract code from Issues::MoveServicece-3777-promote-to-epic
Extract code to make it easier reusable - introduce AttributesRewriter and ContentRewriter - support group entites when rewriting content - make Uploader copy_to working for Namespaces
Diffstat (limited to 'app')
-rw-r--r--app/services/issuable/clone/attributes_rewriter.rb62
-rw-r--r--app/services/issuable/clone/base_service.rb60
-rw-r--r--app/services/issuable/clone/content_rewriter.rb65
-rw-r--r--app/services/issues/move_service.rb157
-rw-r--r--app/uploaders/file_uploader.rb6
5 files changed, 219 insertions, 131 deletions
diff --git a/app/services/issuable/clone/attributes_rewriter.rb b/app/services/issuable/clone/attributes_rewriter.rb
new file mode 100644
index 00000000000..0300cc0d8d3
--- /dev/null
+++ b/app/services/issuable/clone/attributes_rewriter.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module Issuable
+ module Clone
+ class AttributesRewriter < ::Issuable::Clone::BaseService
+ def initialize(current_user, original_entity, new_entity)
+ @current_user = current_user
+ @original_entity = original_entity
+ @new_entity = new_entity
+ end
+
+ def execute
+ new_entity.update(milestone: cloneable_milestone, labels: cloneable_labels)
+ copy_resource_label_events
+ end
+
+ private
+
+ def cloneable_milestone
+ title = original_entity.milestone&.title
+ return unless title
+
+ params = { title: title, project_ids: new_entity.project&.id, group_ids: group&.id }
+
+ milestones = MilestonesFinder.new(params).execute
+ milestones.first
+ end
+
+ def cloneable_labels
+ params = {
+ project_id: new_entity.project&.id,
+ group_id: group&.id,
+ title: original_entity.labels.select(:title),
+ include_ancestor_groups: true
+ }
+
+ params[:only_group_labels] = true if new_parent.is_a?(Group)
+
+ LabelsFinder.new(current_user, params).execute
+ end
+
+ def copy_resource_label_events
+ original_entity.resource_label_events.find_in_batches do |batch|
+ events = batch.map do |event|
+ entity_key = new_entity.is_a?(Issue) ? 'issue_id' : 'epic_id'
+ # rubocop: disable CodeReuse/ActiveRecord
+ event.attributes
+ .except('id', 'reference', 'reference_html')
+ .merge(entity_key => new_entity.id, 'action' => ResourceLabelEvent.actions[event.action])
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+
+ Gitlab::Database.bulk_insert(ResourceLabelEvent.table_name, events)
+ end
+ end
+
+ def entity_key
+ new_entity.class.name.parameterize('_').foreign_key
+ end
+ end
+ end
+end
diff --git a/app/services/issuable/clone/base_service.rb b/app/services/issuable/clone/base_service.rb
new file mode 100644
index 00000000000..42dd9c666f5
--- /dev/null
+++ b/app/services/issuable/clone/base_service.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module Issuable
+ module Clone
+ class BaseService < IssuableBaseService
+ attr_reader :original_entity, :new_entity
+
+ alias_method :old_project, :project
+
+ def execute(original_entity, new_project = nil)
+ @original_entity = original_entity
+
+ # Using transaction because of a high resources footprint
+ # on rewriting notes (unfolding references)
+ #
+ ActiveRecord::Base.transaction do
+ @new_entity = create_new_entity
+
+ update_new_entity
+ update_old_entity
+ create_notes
+ end
+ end
+
+ private
+
+ def update_new_entity
+ rewriters = [ContentRewriter, AttributesRewriter]
+
+ rewriters.each do |rewriter|
+ rewriter.new(current_user, original_entity, new_entity).execute
+ end
+ end
+
+ def update_old_entity
+ close_issue
+ end
+
+ def create_notes
+ add_note_from
+ add_note_to
+ end
+
+ def close_issue
+ close_service = Issues::CloseService.new(old_project, current_user)
+ close_service.execute(original_entity, notifications: false, system_note: false)
+ end
+
+ def new_parent
+ new_entity.project ? new_entity.project : new_entity.group
+ end
+
+ def group
+ if new_entity.project&.group && current_user.can?(:read_group, new_entity.project.group)
+ new_entity.project.group
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/issuable/clone/content_rewriter.rb b/app/services/issuable/clone/content_rewriter.rb
new file mode 100644
index 00000000000..e1e0b75085d
--- /dev/null
+++ b/app/services/issuable/clone/content_rewriter.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+module Issuable
+ module Clone
+ class ContentRewriter < ::Issuable::Clone::BaseService
+ def initialize(current_user, original_entity, new_entity)
+ @current_user = current_user
+ @original_entity = original_entity
+ @new_entity = new_entity
+ @project = original_entity.project
+ end
+
+ def execute
+ rewrite_description
+ rewrite_award_emoji(original_entity, new_entity)
+ rewrite_notes
+ end
+
+ private
+
+ def rewrite_description
+ new_entity.update(description: rewrite_content(original_entity.description))
+ end
+
+ def rewrite_notes
+ original_entity.notes_with_associations.find_each do |note|
+ new_note = note.dup
+ new_params = {
+ project: new_entity.project, noteable: new_entity,
+ note: rewrite_content(new_note.note),
+ created_at: note.created_at,
+ updated_at: note.updated_at
+ }
+
+ if note.system_note_metadata
+ new_params[:system_note_metadata] = note.system_note_metadata.dup
+ end
+
+ new_note.update(new_params)
+
+ rewrite_award_emoji(note, new_note)
+ end
+ end
+
+ def rewrite_content(content)
+ return unless content
+
+ rewriters = [Gitlab::Gfm::ReferenceRewriter, Gitlab::Gfm::UploadsRewriter]
+
+ rewriters.inject(content) do |text, klass|
+ rewriter = klass.new(text, old_project, current_user)
+ rewriter.rewrite(new_parent)
+ end
+ end
+
+ def rewrite_award_emoji(old_awardable, new_awardable)
+ old_awardable.award_emoji.each do |award|
+ new_award = award.dup
+ new_award.awardable = new_awardable
+ new_award.save
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb
index d2bdba1e627..41b6a96b005 100644
--- a/app/services/issues/move_service.rb
+++ b/app/services/issues/move_service.rb
@@ -1,165 +1,66 @@
# frozen_string_literal: true
module Issues
- class MoveService < Issues::BaseService
+ class MoveService < Issuable::Clone::BaseService
MoveError = Class.new(StandardError)
- def execute(issue, new_project)
- @old_issue = issue
- @old_project = @project
- @new_project = new_project
+ def execute(issue, target_project)
+ @target_project = target_project
- unless issue.can_move?(current_user, new_project)
+ unless issue.can_move?(current_user, @target_project)
raise MoveError, 'Cannot move issue due to insufficient permissions!'
end
- if @project == new_project
+ if @project == @target_project
raise MoveError, 'Cannot move issue to project it originates from!'
end
- # Using transaction because of a high resources footprint
- # on rewriting notes (unfolding references)
- #
- ActiveRecord::Base.transaction do
- @new_issue = create_new_issue
-
- update_new_issue
- update_old_issue
- end
+ super
notify_participants
- @new_issue
+ new_entity
end
private
- def update_new_issue
- rewrite_notes
- copy_resource_label_events
- rewrite_issue_award_emoji
- add_note_moved_from
- end
+ def update_old_entity
+ super
- def update_old_issue
- add_note_moved_to
- close_issue
mark_as_moved
end
- def create_new_issue
- new_params = { id: nil, iid: nil, label_ids: cloneable_label_ids,
- milestone_id: cloneable_milestone_id,
- project: @new_project, author: @old_issue.author,
- description: rewrite_content(@old_issue.description),
- assignee_ids: @old_issue.assignee_ids }
-
- new_params = @old_issue.serializable_hash.symbolize_keys.merge(new_params)
- CreateService.new(@new_project, @current_user, new_params).execute
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def cloneable_label_ids
- params = {
- project_id: @new_project.id,
- title: @old_issue.labels.pluck(:title),
- include_ancestor_groups: true
- }
+ def create_new_entity
+ new_params = {
+ id: nil,
+ iid: nil,
+ project: @target_project,
+ author: original_entity.author,
+ assignee_ids: original_entity.assignee_ids
+ }
- LabelsFinder.new(current_user, params).execute.pluck(:id)
+ new_params = original_entity.serializable_hash.symbolize_keys.merge(new_params)
+ CreateService.new(@target_project, @current_user, new_params).execute
end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def cloneable_milestone_id
- title = @old_issue.milestone&.title
- return unless title
-
- if @new_project.group && can?(current_user, :read_group, @new_project.group)
- group_id = @new_project.group.id
- end
-
- params =
- { title: title, project_ids: @new_project.id, group_ids: group_id }
- milestones = MilestonesFinder.new(params).execute
- milestones.first&.id
- end
-
- def rewrite_notes
- @old_issue.notes_with_associations.find_each do |note|
- new_note = note.dup
- new_params = { project: @new_project, noteable: @new_issue,
- note: rewrite_content(new_note.note),
- created_at: note.created_at,
- updated_at: note.updated_at }
-
- new_note.update(new_params)
-
- rewrite_award_emoji(note, new_note)
- end
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def copy_resource_label_events
- @old_issue.resource_label_events.find_in_batches do |batch|
- events = batch.map do |event|
- event.attributes
- .except('id', 'reference', 'reference_html')
- .merge('issue_id' => @new_issue.id, 'action' => ResourceLabelEvent.actions[event.action])
- end
-
- Gitlab::Database.bulk_insert(ResourceLabelEvent.table_name, events)
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def rewrite_issue_award_emoji
- rewrite_award_emoji(@old_issue, @new_issue)
- end
-
- def rewrite_award_emoji(old_awardable, new_awardable)
- old_awardable.award_emoji.each do |award|
- new_award = award.dup
- new_award.awardable = new_awardable
- new_award.save
- end
- end
-
- def rewrite_content(content)
- return unless content
-
- rewriters = [Gitlab::Gfm::ReferenceRewriter,
- Gitlab::Gfm::UploadsRewriter]
-
- rewriters.inject(content) do |text, klass|
- rewriter = klass.new(text, @old_project, @current_user)
- rewriter.rewrite(@new_project)
- end
+ def mark_as_moved
+ original_entity.update(moved_to: new_entity)
end
- def close_issue
- close_service = CloseService.new(@old_project, @current_user)
- close_service.execute(@old_issue, notifications: false, system_note: false)
+ def notify_participants
+ notification_service.async.issue_moved(original_entity, new_entity, @current_user)
end
- def add_note_moved_from
- SystemNoteService.noteable_moved(@new_issue, @new_project,
- @old_issue, @current_user,
+ def add_note_from
+ SystemNoteService.noteable_moved(new_entity, @target_project,
+ original_entity, current_user,
direction: :from)
end
- def add_note_moved_to
- SystemNoteService.noteable_moved(@old_issue, @old_project,
- @new_issue, @current_user,
+ def add_note_to
+ SystemNoteService.noteable_moved(original_entity, old_project,
+ new_entity, current_user,
direction: :to)
end
-
- def mark_as_moved
- @old_issue.update(moved_to: @new_issue)
- end
-
- def notify_participants
- notification_service.async.issue_moved(@old_issue, @new_issue, @current_user)
- end
end
end
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index ffc1e5f75ca..e90599f2505 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -149,9 +149,9 @@ class FileUploader < GitlabUploader
# return a new uploader with a file copy on another project
def self.copy_to(uploader, to_project)
- moved = uploader.dup.tap do |u|
- u.model = to_project
- end
+ moved = self.new(to_project)
+ moved.object_store = uploader.object_store
+ moved.filename = uploader.filename
moved.copy_file(uploader.file)
moved