170 lines
5.8 KiB
Ruby
170 lines
5.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module IncidentManagement
|
|
module TimelineEvents
|
|
DEFAULT_ACTION = 'comment'
|
|
DEFAULT_EDITABLE = false
|
|
DEFAULT_AUTO_CREATED = false
|
|
|
|
class CreateService < TimelineEvents::BaseService
|
|
def initialize(incident, user, params)
|
|
@project = incident.project
|
|
@incident = incident
|
|
@user = user
|
|
@params = params
|
|
@auto_created = !!params.fetch(:auto_created, DEFAULT_AUTO_CREATED)
|
|
end
|
|
|
|
class << self
|
|
def create_incident(incident, user)
|
|
note = "@#{user.username} created the incident"
|
|
occurred_at = incident.created_at
|
|
action = 'issues'
|
|
|
|
new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
|
|
end
|
|
|
|
def reopen_incident(incident, user)
|
|
note = "@#{user.username} reopened the incident"
|
|
occurred_at = incident.updated_at
|
|
action = 'issues'
|
|
|
|
new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
|
|
end
|
|
|
|
def resolve_incident(incident, user)
|
|
note = "@#{user.username} resolved the incident"
|
|
occurred_at = incident.updated_at
|
|
action = 'status'
|
|
|
|
new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
|
|
end
|
|
|
|
def change_incident_status(incident, user, escalation_status)
|
|
status = escalation_status.status_name.to_s.titleize
|
|
note = "@#{user.username} changed the incident status to **#{status}**"
|
|
occurred_at = incident.updated_at
|
|
action = 'status'
|
|
|
|
new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
|
|
end
|
|
|
|
def change_severity(incident, user)
|
|
severity_label = IssuableSeverity::SEVERITY_LABELS[incident.severity.to_sym]
|
|
note = "@#{user.username} changed the incident severity to **#{severity_label}**"
|
|
occurred_at = incident.updated_at
|
|
action = 'severity'
|
|
|
|
new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
|
|
end
|
|
|
|
def change_labels(incident, user, added_labels: [], removed_labels: [])
|
|
return if Feature.disabled?(:incident_timeline_events_from_labels, incident.project)
|
|
|
|
if added_labels.blank? && removed_labels.blank?
|
|
return ServiceResponse.error(message: _('There are no changed labels'))
|
|
end
|
|
|
|
labels_note = -> (verb, labels) {
|
|
"#{verb} #{labels.map(&:to_reference).join(' ')} #{'label'.pluralize(labels.count)}" if labels.present?
|
|
}
|
|
|
|
added_note = labels_note.call('added', added_labels)
|
|
removed_note = labels_note.call('removed', removed_labels)
|
|
note = "@#{user.username} #{[added_note, removed_note].compact.join(' and ')}"
|
|
occurred_at = incident.updated_at
|
|
action = 'label'
|
|
|
|
new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
|
|
end
|
|
end
|
|
|
|
def execute
|
|
return error_no_permissions unless allowed?
|
|
|
|
timeline_event_params = {
|
|
project: project,
|
|
incident: incident,
|
|
author: user,
|
|
note: params[:note],
|
|
action: params.fetch(:action, DEFAULT_ACTION),
|
|
note_html: params[:note_html].presence || params[:note],
|
|
occurred_at: params[:occurred_at],
|
|
promoted_from_note: params[:promoted_from_note],
|
|
editable: params.fetch(:editable, DEFAULT_EDITABLE)
|
|
}
|
|
|
|
non_existing_tags = validate_tags(project, params[:timeline_event_tag_names])
|
|
|
|
return error("#{_("Following tags don't exist")}: #{non_existing_tags}") unless non_existing_tags.empty?
|
|
|
|
timeline_event = IncidentManagement::TimelineEvent.new(timeline_event_params)
|
|
|
|
if timeline_event.save(context: validation_context)
|
|
add_system_note(timeline_event)
|
|
|
|
create_timeline_event_tag_links(timeline_event, params[:timeline_event_tag_names])
|
|
|
|
track_timeline_event("incident_management_timeline_event_created", project)
|
|
|
|
success(timeline_event)
|
|
else
|
|
error_in_save(timeline_event)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :project, :user, :incident, :params, :auto_created
|
|
|
|
def allowed?
|
|
return true if auto_created
|
|
|
|
super
|
|
end
|
|
|
|
def add_system_note(timeline_event)
|
|
return if auto_created
|
|
|
|
SystemNoteService.add_timeline_event(timeline_event)
|
|
end
|
|
|
|
def validation_context
|
|
:user_input if !auto_created && params[:promoted_from_note].blank?
|
|
end
|
|
|
|
def create_timeline_event_tag_links(timeline_event, tag_names)
|
|
return unless tag_names&.any?
|
|
|
|
auto_create_predefined_tags(tag_names)
|
|
|
|
# Refetches the tag objects to consider predefined tags as well
|
|
tags = project.incident_management_timeline_event_tags.by_names(tag_names)
|
|
|
|
tag_links = tags.select(:id).map do |tag|
|
|
{
|
|
timeline_event_id: timeline_event.id,
|
|
timeline_event_tag_id: tag.id,
|
|
created_at: DateTime.current
|
|
}
|
|
end
|
|
|
|
IncidentManagement::TimelineEventTagLink.insert_all(tag_links) if tag_links.any?
|
|
end
|
|
|
|
def validate_tags(project, tag_names)
|
|
return [] unless tag_names&.any?
|
|
|
|
start_time_tag = AUTOCREATE_TAGS[0].downcase
|
|
end_time_tag = AUTOCREATE_TAGS[1].downcase
|
|
|
|
tag_names_downcased = tag_names.map(&:downcase)
|
|
|
|
tags = project.incident_management_timeline_event_tags.by_names(tag_names).pluck_names.map(&:downcase)
|
|
|
|
# remove tags from given tag_names and also remove predefined tags which can be auto created
|
|
tag_names_downcased - tags - [start_time_tag, end_time_tag]
|
|
end
|
|
end
|
|
end
|
|
end
|