interpret_service.rb 3.2 KB
Newer Older
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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
module SlashCommands
  class InterpretService < BaseService
    include Gitlab::SlashCommands::Dsl

    # Takes a text and interpret the commands that are extracted from it.
    # Returns a hash of changes to be applied to a record.
    def execute(content)
      @updates = {}

      commands = extractor.extract_commands!(content)
      commands.each do |command|
        __send__(*command)
      end

      @updates
    end

    private

    def extractor
      @extractor ||= Gitlab::SlashCommands::Extractor.new(self.class.command_names)
    end

    desc 'Close this issue or merge request'
    command :close do
      @updates[:state_event] = 'close'
    end

    desc 'Reopen this issue or merge request'
    command :open, :reopen do
      @updates[:state_event] = 'reopen'
    end

    desc 'Reassign'
    params '@user'
    command :assign, :reassign do |assignee_param|
      user = extract_references(assignee_param, :user).first
      return unless user

      @updates[:assignee_id] = user.id
    end

    desc 'Remove assignee'
    command :unassign, :remove_assignee do
      @updates[:assignee_id] = nil
    end

    desc 'Change milestone'
    params '%"milestone"'
    command :milestone do |milestone_param|
      milestone = extract_references(milestone_param, :milestone).first
      return unless milestone

      @updates[:milestone_id] = milestone.id
    end

    desc 'Remove milestone'
    command :clear_milestone, :remove_milestone do
      @updates[:milestone_id] = nil
    end

    desc 'Add label(s)'
    params '~label1 ~"label 2"'
    command :label, :labels do |labels_param|
      label_ids = find_label_ids(labels_param)
      return if label_ids.empty?

      @updates[:add_label_ids] = label_ids
    end

    desc 'Remove label(s)'
    params '~label1 ~"label 2"'
    command :unlabel, :remove_label, :remove_labels do |labels_param|
      label_ids = find_label_ids(labels_param)
      return if label_ids.empty?

      @updates[:remove_label_ids] = label_ids
    end

    desc 'Remove all labels'
    command :clear_labels, :clear_label do
      @updates[:label_ids] = []
    end

    desc 'Add a todo'
    command :todo do
      @updates[:todo_event] = 'mark'
    end

    desc 'Mark todo as done'
    command :done do
      @updates[:todo_event] = 'done'
    end

    desc 'Subscribe'
    command :subscribe do
      @updates[:subscription_event] = 'subscribe'
    end

    desc 'Unsubscribe'
    command :unsubscribe do
      @updates[:subscription_event] = 'unsubscribe'
    end

    desc 'Set a due date'
    params '<YYYY-MM-DD> | <N days>'
    command :due_date do |due_date_param|
      due_date = begin
        Time.now + ChronicDuration.parse(due_date_param)
      rescue ChronicDuration::DurationParseError
        Date.parse(due_date_param) rescue nil
      end

      @updates[:due_date] = due_date if due_date
    end

    desc 'Remove due date'
    command :clear_due_date do
      @updates[:due_date] = nil
    end

    def find_label_ids(labels_param)
      extract_references(labels_param, :label).map(&:id)
    end

    def extract_references(cmd_arg, type)
      ext = Gitlab::ReferenceExtractor.new(project, current_user)
      ext.analyze(cmd_arg, author: current_user)

      ext.references(type)
    end
  end
end