summaryrefslogtreecommitdiff
path: root/app/services/work_items
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/work_items')
-rw-r--r--app/services/work_items/export_csv_service.rb2
-rw-r--r--app/services/work_items/import_csv_service.rb116
-rw-r--r--app/services/work_items/parent_links/create_service.rb2
-rw-r--r--app/services/work_items/widgets/notifications_service/update_service.rb26
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