b5042e5301
The NotificationService has to do quite a lot of work to calculate the recipients for an email. Where possible, we should try to avoid doing this in an HTTP request, because the mail are sent by Sidekiq anyway, so there's no need to schedule those emails immediately. This commit creates a generic Sidekiq worker that uses Global ID to serialise and deserialise its arguments, then forwards them to the NotificationService. The NotificationService gains an `#async` method, so you can replace: notification_service.new_issue(issue, current_user) With: notification_service.async.new_issue(issue, current_user) And have everything else work as normal, except that calculating the recipients will be done by Sidekiq, which will then schedule further Sidekiq jobs to send each email.
145 lines
4 KiB
Ruby
145 lines
4 KiB
Ruby
module Issues
|
|
class MoveService < Issues::BaseService
|
|
MoveError = Class.new(StandardError)
|
|
|
|
def execute(issue, new_project)
|
|
@old_issue = issue
|
|
@old_project = @project
|
|
@new_project = new_project
|
|
|
|
unless issue.can_move?(current_user, new_project)
|
|
raise MoveError, 'Cannot move issue due to insufficient permissions!'
|
|
end
|
|
|
|
if @project == new_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
|
|
|
|
notify_participants
|
|
|
|
@new_issue
|
|
end
|
|
|
|
private
|
|
|
|
def update_new_issue
|
|
rewrite_notes
|
|
rewrite_issue_award_emoji
|
|
add_note_moved_from
|
|
end
|
|
|
|
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
|
|
|
|
def cloneable_label_ids
|
|
params = {
|
|
project_id: @new_project.id,
|
|
title: @old_issue.labels.pluck(:title)
|
|
}
|
|
|
|
LabelsFinder.new(current_user, params).execute.pluck(:id)
|
|
end
|
|
|
|
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
|
|
|
|
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
|
|
end
|
|
|
|
def close_issue
|
|
close_service = CloseService.new(@old_project, @current_user)
|
|
close_service.execute(@old_issue, notifications: false, system_note: false)
|
|
end
|
|
|
|
def add_note_moved_from
|
|
SystemNoteService.noteable_moved(@new_issue, @new_project,
|
|
@old_issue, @current_user,
|
|
direction: :from)
|
|
end
|
|
|
|
def add_note_moved_to
|
|
SystemNoteService.noteable_moved(@old_issue, @old_project,
|
|
@new_issue, @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
|