1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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
|