debian-mirror-gitlab/app/services/quick_actions/interpret_service.rb

185 lines
5.4 KiB
Ruby
Raw Normal View History

2018-11-18 11:00:15 +05:30
# frozen_string_literal: true
2017-09-10 17:25:29 +05:30
module QuickActions
2016-09-13 17:45:13 +05:30
class InterpretService < BaseService
2019-02-15 15:39:39 +05:30
include Gitlab::Utils::StrongMemoize
2017-09-10 17:25:29 +05:30
include Gitlab::QuickActions::Dsl
2019-07-07 11:18:12 +05:30
include Gitlab::QuickActions::IssueActions
include Gitlab::QuickActions::IssuableActions
2019-12-04 20:38:33 +05:30
include Gitlab::QuickActions::IssueAndMergeRequestActions
2019-07-07 11:18:12 +05:30
include Gitlab::QuickActions::MergeRequestActions
include Gitlab::QuickActions::CommitActions
include Gitlab::QuickActions::CommonActions
2020-11-24 15:15:51 +05:30
include Gitlab::QuickActions::RelateActions
2016-09-13 17:45:13 +05:30
2019-07-07 11:18:12 +05:30
attr_reader :quick_action_target
2016-09-13 17:45:13 +05:30
2019-07-07 11:18:12 +05:30
# Counts how many commands have been executed.
# Used to display relevant feedback on UI when a note
# with only commands has been processed.
attr_accessor :commands_executed_count
2017-09-10 17:25:29 +05:30
2019-07-07 11:18:12 +05:30
# Takes an quick_action_target and returns an array of all the available commands
2018-03-27 19:54:05 +05:30
# represented with .to_h
2019-07-07 11:18:12 +05:30
def available_commands(quick_action_target)
@quick_action_target = quick_action_target
2018-03-27 19:54:05 +05:30
self.class.command_definitions.map do |definition|
next unless definition.available?(self)
definition.to_h(self)
end.compact
end
2016-09-13 17:45:13 +05:30
# Takes a text and interprets the commands that are extracted from it.
2019-10-12 21:52:04 +05:30
# Returns the content without commands, a hash of changes to be applied to a record
# and a string containing the execution_message to show to the user.
2019-07-07 11:18:12 +05:30
def execute(content, quick_action_target, only: nil)
2019-10-12 21:52:04 +05:30
return [content, {}, ''] unless current_user.can?(:use_quick_actions)
2017-08-17 22:00:37 +05:30
2019-07-07 11:18:12 +05:30
@quick_action_target = quick_action_target
2016-09-13 17:45:13 +05:30
@updates = {}
2019-10-12 21:52:04 +05:30
@execution_message = {}
2016-09-13 17:45:13 +05:30
2018-12-13 13:39:08 +05:30
content, commands = extractor.extract_commands(content, only: only)
2018-03-27 19:54:05 +05:30
extract_updates(commands)
2017-09-10 17:25:29 +05:30
2019-10-12 21:52:04 +05:30
[content, @updates, execution_messages_for(commands)]
2017-08-17 22:00:37 +05:30
end
2016-09-13 17:45:13 +05:30
2017-08-17 22:00:37 +05:30
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and array of changes explained.
2019-07-07 11:18:12 +05:30
def explain(content, quick_action_target)
2017-09-10 17:25:29 +05:30
return [content, []] unless current_user.can?(:use_quick_actions)
2016-09-13 17:45:13 +05:30
2019-07-07 11:18:12 +05:30
@quick_action_target = quick_action_target
2016-09-13 17:45:13 +05:30
2018-03-27 19:54:05 +05:30
content, commands = extractor.extract_commands(content)
commands = explain_commands(commands)
2017-08-17 22:00:37 +05:30
[content, commands]
2016-09-13 17:45:13 +05:30
end
private
def extractor
2017-09-10 17:25:29 +05:30
Gitlab::QuickActions::Extractor.new(self.class.command_definitions)
2016-09-13 17:45:13 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
def extract_users(params)
return [] if params.nil?
users = extract_references(params, :user)
if users.empty?
2017-09-10 17:25:29 +05:30
users =
2018-12-13 13:39:08 +05:30
if params.strip == 'me'
2017-09-10 17:25:29 +05:30
[current_user]
else
User.where(username: params.split(' ').map(&:strip))
end
2017-08-17 22:00:37 +05:30
end
users
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2017-08-17 22:00:37 +05:30
2018-03-27 19:54:05 +05:30
def find_milestones(project, params = {})
2020-03-13 15:44:24 +05:30
group_ids = project.group.self_and_ancestors.select(:id) if project.group
MilestonesFinder.new(params.merge(project_ids: [project.id], group_ids: group_ids)).execute
2018-03-27 19:54:05 +05:30
end
2019-02-15 15:39:39 +05:30
def parent
project || group
end
def group
strong_memoize(:group) do
2019-07-07 11:18:12 +05:30
quick_action_target.group if quick_action_target.respond_to?(:group)
2019-02-15 15:39:39 +05:30
end
end
def find_labels(labels_params = nil)
2019-07-07 11:18:12 +05:30
extract_references(labels_params, :label) | find_labels_by_name_no_tilde(labels_params)
end
def find_labels_by_name_no_tilde(labels_params)
return Label.none if label_with_tilde?(labels_params)
2019-02-15 15:39:39 +05:30
finder_params = { include_ancestor_groups: true }
finder_params[:project_id] = project.id if project
finder_params[:group_id] = group.id if group
2019-07-07 11:18:12 +05:30
finder_params[:name] = extract_label_names(labels_params) if labels_params
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
LabelsFinder.new(current_user, finder_params).execute
end
def label_with_tilde?(labels_params)
labels_params&.include?('~')
end
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
def extract_label_names(labels_params)
# '"A" "A B C" A B' => ["A", "A B C", "A", "B"]
labels_params.scan(/"([^"]+)"|([^ ]+)/).flatten.compact
2017-08-17 22:00:37 +05:30
end
2019-10-12 21:52:04 +05:30
def find_label_references(labels_param, format = :id)
labels_to_reference(find_labels(labels_param), format)
end
def labels_to_reference(labels, format = :id)
labels.map { |l| l.to_reference(format: format) }
2017-08-17 22:00:37 +05:30
end
2016-09-13 17:45:13 +05:30
def find_label_ids(labels_param)
2017-08-17 22:00:37 +05:30
find_labels(labels_param).map(&:id)
end
2018-03-27 19:54:05 +05:30
def explain_commands(commands)
2019-10-12 21:52:04 +05:30
map_commands(commands, :explain)
end
def execution_messages_for(commands)
map_commands(commands, :execute_message).join(' ')
end
def map_commands(commands, method)
2017-08-17 22:00:37 +05:30
commands.map do |name, arg|
definition = self.class.definition_by_name(name)
next unless definition
2016-09-13 17:45:13 +05:30
2019-10-12 21:52:04 +05:30
case method
when :explain
definition.explain(self, arg)
when :execute_message
@execution_message[name.to_sym] || definition.execute_message(self, arg)
end
2017-08-17 22:00:37 +05:30
end.compact
end
2018-03-27 19:54:05 +05:30
def extract_updates(commands)
2017-08-17 22:00:37 +05:30
commands.each do |name, arg|
definition = self.class.definition_by_name(name)
next unless definition
2018-03-27 19:54:05 +05:30
definition.execute(self, arg)
2017-08-17 22:00:37 +05:30
end
2016-09-13 17:45:13 +05:30
end
2018-12-05 23:21:45 +05:30
# rubocop: disable CodeReuse/ActiveRecord
2016-09-13 17:45:13 +05:30
def extract_references(arg, type)
2019-02-15 15:39:39 +05:30
return [] unless arg
2016-09-13 17:45:13 +05:30
ext = Gitlab::ReferenceExtractor.new(project, current_user)
2018-05-09 12:01:36 +05:30
2019-02-15 15:39:39 +05:30
ext.analyze(arg, author: current_user, group: group)
2016-09-13 17:45:13 +05:30
ext.references(type)
end
2018-12-05 23:21:45 +05:30
# rubocop: enable CodeReuse/ActiveRecord
2016-09-13 17:45:13 +05:30
end
end
2019-12-04 20:38:33 +05:30
QuickActions::InterpretService.prepend_if_ee('EE::QuickActions::InterpretService')