Class: Issues::CreateService

Inherits:
BaseService show all
Includes:
ResolveDiscussions, RateLimitedService, Services::ReturnServiceResponses
Defined in:
app/services/issues/create_service.rb

Direct Known Subclasses

WorkItems::CreateService

Constant Summary

Constants included from RateLimitedService

RateLimitedService::RateLimitedNotSetupError

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 included from ResolveDiscussions

#discussion_to_resolve_id, #merge_request_to_resolve_discussions_of_iid

Attributes inherited from BaseContainerService

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

Instance Method Summary collapse

Methods included from Services::ReturnServiceResponses

#error, #success

Methods included from ResolveDiscussions

#discussions_to_resolve, #filter_resolve_discussion_params, #merge_request_to_resolve_discussions_of

Methods included from RateLimitedService

#execute_without_rate_limiting

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: {}, build_service: nil, perform_spam_check: true) ⇒ CreateService

Returns a new instance of CreateService.



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

def initialize(container:, current_user: nil, params: {}, build_service: nil, perform_spam_check: true)
  @extra_params = params.delete(:extra_params) || {}
  super(container: container, current_user: current_user, params: params)
  @perform_spam_check = perform_spam_check
  @build_service = build_service ||
    BuildService.new(container: project, current_user: current_user, params: params)
end

Instance Method Details

#after_create(issue) ⇒ Object

Add new items to Issues::AfterCreateService if they can be performed in Sidekiq



64
65
66
67
68
69
70
71
72
73
# File 'app/services/issues/create_service.rb', line 64

def after_create(issue)
  user_agent_detail_service.create
  handle_add_related_issue(issue)
  resolve_discussions_with_issue(issue)
  handle_escalation_status_change(issue)
  create_timeline_event(issue)
  try_to_associate_contacts(issue)

  super
end

#before_create(issue) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'app/services/issues/create_service.rb', line 49

def before_create(issue)
  issue.check_for_spam(user: current_user, action: :create) if perform_spam_check

  # current_user (defined in BaseService) is not available within run_after_commit block
  user = current_user
  assign_description_from_template(issue)
  issue.run_after_commit do
    NewIssueWorker.perform_async(issue.id, user.id, issue.class.to_s)
    Issues::PlacementWorker.perform_async(nil, issue.project_id)
    # issue.namespace_id can point to either a project through project namespace or a group.
    Onboarding::IssueCreatedWorker.perform_async(issue.namespace_id)
  end
end

#execute(skip_system_notes: false) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'app/services/issues/create_service.rb', line 20

def execute(skip_system_notes: false)
  return error(_('Operation not allowed'), 403) unless @current_user.can?(authorization_action, container)

  # We should not initialize the callback classes during the build service execution because these will be
  # initialized when we call #create below
  @issue = @build_service.execute(initialize_callbacks: false)

  # issue_type and work_item_type are set in BuildService, so we can delete it from params, in later phase
  # it can be set also from quick actions
  [:issue_type, :work_item_type, :work_item_type_id].each { |attribute| params.delete(attribute) }

  handle_move_between_ids(@issue)

  @add_related_issue ||= params.delete(:add_related_issue)
  filter_resolve_discussion_params

  issue = create(@issue, skip_system_notes: skip_system_notes)

  if issue.persisted?
    success(issue: issue)
  else
    error(issue.errors.full_messages, 422, pass_back: { issue: issue })
  end
end

#external_authorObject



45
46
47
# File 'app/services/issues/create_service.rb', line 45

def external_author
  params[:external_author] # present when creating an issue using service desk (email: from)
end

#handle_assignee_changes(issue, old_assignees) ⇒ Object



83
84
85
86
87
88
# File 'app/services/issues/create_service.rb', line 83

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
end

#handle_changes(issue, options) ⇒ Object



75
76
77
78
79
80
81
# File 'app/services/issues/create_service.rb', line 75

def handle_changes(issue, options)
  super
  old_associations = options.fetch(:old_associations, {})
  old_assignees = old_associations.fetch(:assignees, [])

  handle_assignee_changes(issue, old_assignees)
end

#resolve_discussions_with_issue(issue) ⇒ Object



90
91
92
93
94
95
96
97
98
99
# File 'app/services/issues/create_service.rb', line 90

def resolve_discussions_with_issue(issue)
  return if discussions_to_resolve.empty?

  Discussions::ResolveService.new(
    project,
    current_user,
    one_or_more_discussions: discussions_to_resolve,
    follow_up_issue: issue
  ).execute
end