Welcome to mirror list, hosted at ThFree Co, Russian Federation.

time_tracking_service.rb « system_notes « services « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c5bdbc6799e6c5f4691393954d1365a677608fa4 (plain)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# frozen_string_literal: true

module SystemNotes
  class TimeTrackingService < ::SystemNotes::BaseService
    # Called when the start_date or due_date of an Issue/WorkItem is changed
    #
    # start_date  - Start date being assigned, or nil
    # due_date  - Due date being assigned, or nil
    #
    # Example Note text:
    #
    #   "removed due date"
    #
    #   "changed due date to September 20, 2018"

    #   "changed start date to September 20, 2018 and changed due date to September 25, 2018"
    #
    # Returns the created Note object
    def change_start_date_or_due_date(changed_dates = {})
      return if changed_dates.empty?

      # Using instance_of because WorkItem < Issue. We don't want to track work item updates as issue updates
      if noteable.instance_of?(Issue) && changed_dates.key?('due_date')
        issue_activity_counter.track_issue_due_date_changed_action(author: author, project: project)
      end

      work_item_activity_counter.track_work_item_date_changed_action(author: author) if noteable.is_a?(WorkItem)

      create_note(
        NoteSummary.new(noteable, project, author, changed_date_body(changed_dates), action: 'start_date_or_due_date')
      )
    end

    # Called when the estimated time of a Noteable is changed
    #
    # time_estimate - Estimated time
    #
    # Example Note text:
    #
    #   "removed time estimate"
    #
    #   "changed time estimate to 3d 5h"
    #
    # Returns the created Note object
    def change_time_estimate
      parsed_time = Gitlab::TimeTrackingFormatter.output(noteable.time_estimate)
      body = if noteable.time_estimate == 0
               "removed time estimate"
             else
               "changed time estimate to #{parsed_time}"
             end

      if noteable.is_a?(Issue)
        issue_activity_counter.track_issue_time_estimate_changed_action(author: author, project: project)
      end

      create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
    end

    # Called when the spent time of a Noteable is changed
    #
    # time_spent - Spent time
    #
    # Example Note text:
    #
    #   "removed time spent"
    #
    #   "added 2h 30m of time spent"
    #
    # Returns the created Note object
    def change_time_spent
      time_spent = noteable.time_spent

      if time_spent == :reset
        body = "removed time spent"
      else
        spent_at = noteable.spent_at&.to_date
        parsed_time = Gitlab::TimeTrackingFormatter.output(time_spent.abs)
        action = time_spent > 0 ? 'added' : 'subtracted'

        text_parts = ["#{action} #{parsed_time} of time spent"]
        text_parts << "at #{spent_at}" if spent_at && spent_at != DateTime.current.to_date
        body = text_parts.join(' ')
      end

      if noteable.is_a?(Issue)
        issue_activity_counter.track_issue_time_spent_changed_action(author: author, project: project)
      end

      create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
    end

    # Called when a timelog is added to an issuable
    #
    # timelog - Added timelog
    #
    # Example Note text:
    #
    #   "subtracted 1h 15m of time spent"
    #
    #   "added 2h 30m of time spent"
    #
    # Returns the created Note object
    def created_timelog(timelog)
      time_spent = timelog.time_spent
      spent_at = timelog.spent_at&.to_date
      parsed_time = Gitlab::TimeTrackingFormatter.output(time_spent.abs)
      action = time_spent > 0 ? 'added' : 'subtracted'

      text_parts = ["#{action} #{parsed_time} of time spent"]
      text_parts << "at #{spent_at}" if spent_at && spent_at != DateTime.current.to_date
      body = text_parts.join(' ')

      if noteable.is_a?(Issue)
        issue_activity_counter.track_issue_time_spent_changed_action(author: author, project: project)
      end

      create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
    end

    def remove_timelog(timelog)
      time_spent = timelog.time_spent
      spent_at = timelog.spent_at&.to_date

      parsed_time = Gitlab::TimeTrackingFormatter.output(time_spent)

      body = "deleted #{parsed_time} of spent time"
      body += " from #{spent_at}" if spent_at

      create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
    end

    private

    def changed_date_body(changed_dates)
      %w[start_date due_date].each_with_object([]) do |date_field, word_array|
        next unless changed_dates.key?(date_field)

        word_array << 'and' if word_array.any?

        word_array << message_for_changed_date(changed_dates, date_field)
      end.join(' ')
    end

    def message_for_changed_date(changed_dates, date_key)
      changed_date = changed_dates[date_key].last
      readable_date = date_key.humanize.downcase

      if changed_date.nil?
        "removed #{readable_date}"
      else
        "changed #{readable_date} to #{changed_date.to_s(:long)}"
      end
    end

    def issue_activity_counter
      Gitlab::UsageDataCounters::IssueActivityUniqueCounter
    end

    def work_item_activity_counter
      Gitlab::UsageDataCounters::WorkItemActivityUniqueCounter
    end
  end
end