diff options
Diffstat (limited to 'app/services/work_items/related_work_item_links')
-rw-r--r-- | app/services/work_items/related_work_item_links/destroy_service.rb | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/app/services/work_items/related_work_item_links/destroy_service.rb b/app/services/work_items/related_work_item_links/destroy_service.rb new file mode 100644 index 00000000000..6d1920d01b2 --- /dev/null +++ b/app/services/work_items/related_work_item_links/destroy_service.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module WorkItems + module RelatedWorkItemLinks + class DestroyService < BaseService + def initialize(work_item, user, params) + @work_item = work_item + @current_user = user + @params = params.dup + @failed_ids = [] + @removed_ids = [] + end + + def execute + return error(_('No work item found.'), 403) unless can?(current_user, :admin_work_item_link, work_item) + return error(_('No work item IDs provided.'), 409) if params[:item_ids].empty? + + destroy_links_for(params[:item_ids]) + + if removed_ids.any? + success(message: response_message, items_removed: removed_ids, items_with_errors: failed_ids.flatten) + else + error(error_message) + end + end + + private + + attr_reader :work_item, :current_user, :failed_ids, :removed_ids + + def destroy_links_for(item_ids) + destroy_links(source: work_item, target: item_ids, direction: :target) + destroy_links(source: item_ids, target: work_item, direction: :source) + end + + def destroy_links(source:, target:, direction:) + WorkItems::RelatedWorkItemLink.for_source_and_target(source, target).each do |link| + linked_item = link.try(direction) + + if can?(current_user, :admin_work_item_link, linked_item) + link.destroy! + removed_ids << linked_item.id + create_notes(link) + else + failed_ids << linked_item.id + end + end + end + + def create_notes(link) + SystemNoteService.unrelate_issuable(link.source, link.target, current_user) + SystemNoteService.unrelate_issuable(link.target, link.source, current_user) + end + + def error_message + not_linked = params[:item_ids] - (removed_ids + failed_ids) + error_messages = [] + + if failed_ids.any? + error_messages << format( + _('%{item_ids} could not be removed due to insufficient permissions'), item_ids: failed_ids.to_sentence + ) + end + + if not_linked.any? + error_messages << format( + _('%{item_ids} could not be removed due to not being linked'), item_ids: not_linked.to_sentence + ) + end + + return '' unless error_messages.any? + + format(_('IDs with errors: %{error_messages}.'), error_messages: error_messages.join(', ')) + end + + def response_message + success_message = format(_('Successfully unlinked IDs: %{item_ids}.'), item_ids: removed_ids.to_sentence) + + return success_message unless error_message.present? + + "#{success_message} #{error_message}" + end + end + end +end |