Class: Issues::UpdateService

Inherits:
BaseService show all
Defined in:
app/services/issues/update_service.rb

Direct Known Subclasses

WorkItems::UpdateService

Constant Summary

Constants inherited from BaseService

BaseService::NO_REBALANCING_NEEDED

Constants included from Gitlab::Utils::UsageData

Gitlab::Utils::UsageData::DISTRIBUTED_HLL_FALLBACK, Gitlab::Utils::UsageData::FALLBACK, Gitlab::Utils::UsageData::HISTOGRAM_FALLBACK, Gitlab::Utils::UsageData::MAX_BUCKET_SIZE

Instance Attribute Summary

Attributes inherited from BaseContainerService

#container, #current_user, #group, #params, #project

Instance Method Summary collapse

Methods inherited from BaseService

#close_service, #hook_data, #rebalance_if_needed, #reopen_service

Methods included from Gitlab::Utils::Override

#extended, extensions, #included, #method_added, #override, #prepended, #queue_verification, verify!

Methods included from IssueTypeHelpers

#create_issue_type_allowed?

Methods included from IncidentManagement::UsageData

#track_incident_action

Methods included from Gitlab::Utils::UsageData

#add, #add_metric, #alt_usage_data, #average, #count, #distinct_count, #estimate_batch_distinct_count, #histogram, #maximum_id, #measure_duration, #minimum_id, #redis_usage_data, #sum, #track_usage_event, #with_finished_at, #with_metadata, #with_prometheus_client

Methods inherited from BaseContainerService

#group_container?, #namespace_container?, #project_container?, #project_group

Methods included from BaseServiceUtility

#deny_visibility_level, #event_service, #log_error, #log_info, #notification_service, #system_hook_service, #todo_service, #visibility_level

Methods included from Gitlab::Allowable

#can?

Constructor Details

#initialize(container:, current_user: nil, params: {}, perform_spam_check: false) ⇒ UpdateService

NOTE: For Issues::UpdateService, we default perform_spam_check to false, because spam_checking is not necessary in many cases, and we don’t want to require every caller to explicitly pass it to disable spam checking.



8
9
10
11
# File 'app/services/issues/update_service.rb', line 8

def initialize(container:, current_user: nil, params: {}, perform_spam_check: false)
  super(container: container, current_user: current_user, params: params)
  @perform_spam_check = perform_spam_check
end

Instance Method Details

#before_update(issue, skip_spam_check: false) ⇒ Object



26
27
28
29
30
31
32
# File 'app/services/issues/update_service.rb', line 26

def before_update(issue, skip_spam_check: false)
  change_work_item_type(issue)

  return if skip_spam_check || !perform_spam_check

  issue.check_for_spam(user: current_user, action: :update)
end

#change_issue_duplicate(issue) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord



87
88
89
90
91
92
93
94
95
96
# File 'app/services/issues/update_service.rb', line 87

def change_issue_duplicate(issue)
  canonical_issue_id = params.delete(:canonical_issue_id)
  return unless canonical_issue_id

  canonical_issue = IssuesFinder.new(current_user).find_by(id: canonical_issue_id)

  if canonical_issue
    Issues::DuplicateService.new(container: project, current_user: current_user).execute(issue, canonical_issue)
  end
end

#change_work_item_type(issue) ⇒ Object



34
35
36
37
38
39
40
# File 'app/services/issues/update_service.rb', line 34

def change_work_item_type(issue)
  return unless params[:issue_type].present?

  type_id = find_work_item_type_id(params[:issue_type])

  issue.work_item_type_id = type_id
end

#execute(issue) ⇒ Object



13
14
15
16
17
18
# File 'app/services/issues/update_service.rb', line 13

def execute(issue)
  handle_move_between_ids(issue)

  change_issue_duplicate(issue)
  move_issue_to_new_project(issue) || clone_issue(issue) || update_task_event(issue) || update(issue)
end

#handle_assignee_changes(issue, old_assignees) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
# File 'app/services/issues/update_service.rb', line 69

def handle_assignee_changes(issue, old_assignees)
  return if issue.assignees == old_assignees

  create_assignee_note(issue, old_assignees)
  Gitlab::ResourceEvents::AssignmentEventRecorder.new(parent: issue, old_assignees: old_assignees).record
  notification_service.async.reassigned_issue(issue, current_user, old_assignees)
  todo_service.reassigned_assignable(issue, current_user, old_assignees)
  track_incident_action(current_user, issue, :incident_assigned)

  GraphqlTriggers.issuable_assignees_updated(issue)
end

#handle_changes(issue, options) ⇒ Object



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
# File 'app/services/issues/update_service.rb', line 42

def handle_changes(issue, options)
  super
  old_associations = options.fetch(:old_associations, {})
  old_labels = old_associations.fetch(:labels, [])
  old_mentioned_users = old_associations.fetch(:mentioned_users, [])
  old_assignees = old_associations.fetch(:assignees, [])
  old_severity = old_associations[:severity]

  if has_changes?(issue, old_labels: old_labels, old_assignees: old_assignees)
    todo_service.resolve_todos_for_target(issue, current_user)
  end

  if issue.previous_changes.include?('title') ||
      issue.previous_changes.include?('description')
    todo_service.update_issue(issue, current_user, old_mentioned_users)
  end

  handle_assignee_changes(issue, old_assignees)
  handle_confidential_change(issue)
  handle_added_labels(issue, old_labels)
  handle_added_mentions(issue, old_mentioned_users)
  handle_severity_change(issue, old_severity)
  handle_escalation_status_change(issue)
  handle_issue_type_change(issue)
  handle_date_changes(issue)
end

#handle_task_changes(issuable) ⇒ Object



81
82
83
84
# File 'app/services/issues/update_service.rb', line 81

def handle_task_changes(issuable)
  todo_service.resolve_todos_for_target(issuable, current_user)
  todo_service.update_issue(issuable, current_user)
end

#move_issue_to_new_project(issue) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord



99
100
101
102
103
104
105
106
107
108
# File 'app/services/issues/update_service.rb', line 99

def move_issue_to_new_project(issue)
  target_project = params.delete(:target_project)

  return unless target_project &&
      issue.can_move?(current_user, target_project) &&
      target_project != issue.project

  update(issue)
  Issues::MoveService.new(container: project, current_user: current_user).execute(issue, target_project)
end

#update(issue) ⇒ Object



20
21
22
23
24
# File 'app/services/issues/update_service.rb', line 20

def update(issue)
  create_merge_request_from_quick_action

  super
end