todo_service.rb 4.8 KB
Newer Older
1
# TodoService class
2
#
3
# Used for creating todos after certain user actions
4 5
#
# Ex.
6
#   TodoService.new.new_issue(issue, current_user)
7
#
8
class TodoService
9 10
  # When create an issue we should:
  #
11 12
  #  * create a todo for assignee if issue is assigned
  #  * create a todo for each mentioned user on issue
13 14
  #
  def new_issue(issue, current_user)
15
    new_issuable(issue, current_user)
16 17
  end

18 19
  # When update an issue we should:
  #
20
  #  * mark all pending todos related to the issue for the current user as done
21 22
  #
  def update_issue(issue, current_user)
23
    create_mention_todos(issue.project, issue, current_user)
24 25
  end

26 27
  # When close an issue we should:
  #
28
  #  * mark all pending todos related to the target for the current user as done
29 30
  #
  def close_issue(issue, current_user)
31
    mark_pending_todos_as_done(issue, current_user)
32 33
  end

34 35
  # When we reassign an issue we should:
  #
36
  #  * create a pending todo for new assignee if issue is assigned
37 38
  #
  def reassigned_issue(issue, current_user)
39
    create_assignment_todo(issue, current_user)
40 41 42 43
  end

  # When create a merge request we should:
  #
44 45
  #  * creates a pending todo for assignee if merge request is assigned
  #  * create a todo for each mentioned user on merge request
46 47 48 49 50
  #
  def new_merge_request(merge_request, current_user)
    new_issuable(merge_request, current_user)
  end

51 52
  # When update a merge request we should:
  #
53
  #  * create a todo for each mentioned user on merge request
54 55
  #
  def update_merge_request(merge_request, current_user)
56
    create_mention_todos(merge_request.project, merge_request, current_user)
57 58
  end

59 60
  # When close a merge request we should:
  #
61
  #  * mark all pending todos related to the target for the current user as done
62 63
  #
  def close_merge_request(merge_request, current_user)
64
    mark_pending_todos_as_done(merge_request, current_user)
65 66 67
  end

  # When we reassign a merge request we should:
68
  #
69
  #  * creates a pending todo for new assignee if merge request is assigned
70 71
  #
  def reassigned_merge_request(merge_request, current_user)
72
    create_assignment_todo(merge_request, current_user)
73 74
  end

75 76
  # When merge a merge request we should:
  #
77
  #  * mark all pending todos related to the target for the current user as done
78 79
  #
  def merge_merge_request(merge_request, current_user)
80
    mark_pending_todos_as_done(merge_request, current_user)
81 82
  end

83 84
  # When create a note we should:
  #
85 86
  #  * mark all pending todos related to the noteable for the note author as done
  #  * create a todo for each mentioned user on note
87
  #
88 89
  def new_note(note, current_user)
    handle_note(note, current_user)
90 91
  end

92 93
  # When update a note we should:
  #
94 95
  #  * mark all pending todos related to the noteable for the current user as done
  #  * create a todo for each new user mentioned on note
96 97
  #
  def update_note(note, current_user)
98 99 100
    handle_note(note, current_user)
  end

101
  # When marking pending todos as done we should:
102
  #
103
  #  * mark all pending todos related to the target for the current user as done
104
  #
105 106
  def mark_pending_todos_as_done(target, user)
    pending_todos(user, target.project, target).update_all(state: :done)
107 108 109 110
  end

  private

111
  def create_todos(project, target, author, users, action, note = nil)
112
    Array(users).each do |user|
113
      next if pending_todos(user, project, target).exists?
114

115
      Todo.create(
116 117 118 119 120 121 122 123 124 125 126 127
        project: project,
        user_id: user.id,
        author_id: author.id,
        target_id: target.id,
        target_type: target.class.name,
        action: action,
        note: note
      )
    end
  end

  def new_issuable(issuable, author)
128 129
    create_assignment_todo(issuable, author)
    create_mention_todos(issuable.project, issuable, author)
130 131 132
  end

  def handle_note(note, author)
133 134
    # Skip system notes, notes on commit, and notes on project snippet
    return if note.system? || ['Commit', 'Snippet'].include?(note.noteable_type)
135

136 137
    project = note.project
    target  = note.noteable
138

139 140
    mark_pending_todos_as_done(target, author)
    create_mention_todos(project, target, author, note)
141
  end
142

143
  def create_assignment_todo(issuable, author)
144
    if issuable.assignee && issuable.assignee != author
145
      create_todos(issuable.project, issuable, author, issuable.assignee, Todo::ASSIGNED)
146 147 148
    end
  end

149
  def create_mention_todos(project, issuable, author, note = nil)
150
    mentioned_users = filter_mentioned_users(project, note || issuable, author)
151
    create_todos(project, issuable, author, mentioned_users, Todo::MENTIONED, note)
152
  end
153

154
  def filter_mentioned_users(project, target, author)
155 156 157 158 159 160 161 162
    mentioned_users = target.mentioned_users.select do |user|
      user.can?(:read_project, project)
    end

    mentioned_users.delete(author)
    mentioned_users.uniq
  end

163 164
  def pending_todos(user, project, target)
    user.todos.pending.where(
165 166 167
      project_id: project.id,
      target_id: target.id,
      target_type: target.class.name
168
    )
169
  end
170
end