diff options
Diffstat (limited to 'app/services/work_items')
4 files changed, 145 insertions, 1 deletions
diff --git a/app/services/work_items/export_csv_service.rb b/app/services/work_items/export_csv_service.rb index 9bef75e2c40..a715aab1b30 100644 --- a/app/services/work_items/export_csv_service.rb +++ b/app/services/work_items/export_csv_service.rb @@ -11,7 +11,7 @@ module WorkItems end def email(mail_to_user) - # TODO - will be implemented as part of https://gitlab.com/gitlab-org/gitlab/-/issues/379082 + Notify.export_work_items_csv_email(mail_to_user, resource_parent, csv_data, csv_builder.status).deliver_now end private diff --git a/app/services/work_items/import_csv_service.rb b/app/services/work_items/import_csv_service.rb new file mode 100644 index 00000000000..e7043cc882a --- /dev/null +++ b/app/services/work_items/import_csv_service.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module WorkItems + class ImportCsvService < ImportCsv::BaseService + extend ::Gitlab::Utils::Override + + FeatureNotAvailableError = StandardError.new( + 'This feature is currently behind a feature flag and it is not available.' + ) + NotAuthorizedError = StandardError.new('You do not have permission to import work items in this project.') + + override :initialize + def initialize(*args) + super + + @type_errors = { + blank: [], + missing: {}, + disallowed: {} + } + end + + def self.required_headers + %w[title type].freeze + end + + def execute + raise FeatureNotAvailableError if ::Feature.disabled?(:import_export_work_items_csv, project) + raise NotAuthorizedError unless Ability.allowed?(user, :import_work_items, project) + + super + end + + def email_results_to_user + Notify.import_work_items_csv_email(user.id, project.id, results).deliver_later + end + + private + + attr_accessor :type_errors + + def create_object(attributes) + super[:work_item] + end + + def create_object_class + ::WorkItems::CreateService + end + + override :attributes_for + def attributes_for(row) + { + title: row[:title], + work_item_type: match_work_item_type(row[:type]) + } + end + + override :validate_headers_presence! + def validate_headers_presence!(headers) + required_headers = self.class.required_headers + + headers.downcase! + return if headers && required_headers.all? { |rh| headers.include?(rh) } + + required_headers_message = "Required headers are missing. Required headers are #{required_headers.join(', ')}" + raise CSV::MalformedCSVError.new(required_headers_message, 1) + end + + def match_work_item_type(work_item_type) + match = available_work_item_types[work_item_type&.downcase] + match[:type] if match + end + + def available_work_item_types + { + issue: { + allowed: Ability.allowed?(user, :create_issue, project), + type: WorkItems::Type.default_by_type(:issue) + } + }.with_indifferent_access + end + strong_memoize_attr :available_work_item_types + + def preprocess! + with_csv_lines.each do |row, line_no| + work_item_type = row[:type]&.strip&.downcase + + if work_item_type.blank? + type_errors[:blank] << line_no + elsif missing?(work_item_type) + # does this work item exist in the range of work items we support? + (type_errors[:missing][work_item_type] ||= []) << line_no + elsif !allowed?(work_item_type) + (type_errors[:disallowed][work_item_type] ||= []) << line_no + end + end + + return if type_errors[:blank].empty? && + type_errors[:missing].blank? && + type_errors[:disallowed].blank? + + results[:type_errors] = type_errors + raise PreprocessError + end + + def missing?(work_item_type_name) + !available_work_item_types.key?(work_item_type_name) + end + + def allowed?(work_item_type_name) + !!available_work_item_types[work_item_type_name][:allowed] + end + end +end + +WorkItems::ImportCsvService.prepend_mod diff --git a/app/services/work_items/parent_links/create_service.rb b/app/services/work_items/parent_links/create_service.rb index 288ca152f93..85b470c47ca 100644 --- a/app/services/work_items/parent_links/create_service.rb +++ b/app/services/work_items/parent_links/create_service.rb @@ -10,6 +10,8 @@ module WorkItems link = WorkItems::ParentLink.find_or_initialize_by(work_item: work_item) link.work_item_parent = issuable + link.move_to_end + if link.changed? && link.save create_notes(work_item) end diff --git a/app/services/work_items/widgets/notifications_service/update_service.rb b/app/services/work_items/widgets/notifications_service/update_service.rb new file mode 100644 index 00000000000..b301e2ca7db --- /dev/null +++ b/app/services/work_items/widgets/notifications_service/update_service.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module WorkItems + module Widgets + module NotificationsService + class UpdateService < WorkItems::Widgets::BaseService + def before_update_in_transaction(params:) + return unless params.present? && params.key?(:subscribed) + return unless has_permission?(:update_subscription) + + update_subscription(work_item, params) + end + + private + + def update_subscription(work_item, subscription_params) + work_item.set_subscription( + current_user, + subscription_params[:subscribed], + work_item.project + ) + end + end + end + end +end |