participable.rb 2.03 KB
Newer Older
Douwe Maan's avatar
Douwe Maan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# == Participable concern
#
# Contains functionality related to objects that can have participants, such as
# an author, an assignee and people mentioned in its description or comments.
#
# Used by Issue, Note, MergeRequest, Snippet and Commit.
#
# Usage:
#
#     class Issue < ActiveRecord::Base
#       include Participable
#
#       # ...
#
15
#       participant :author, :assignee, :notes, ->(current_user) { mentioned_users(current_user) }
Douwe Maan's avatar
Douwe Maan committed
16
#     end
17
#
Douwe Maan's avatar
Douwe Maan committed
18 19 20 21 22 23 24
#     issue = Issue.last
#     users = issue.participants
#     # `users` will contain the issue's author, its assignee,
#     # all users returned by its #mentioned_users method,
#     # as well as all participants to all of the issue's notes,
#     # since Note implements Participable as well.
#
25 26 27 28 29
module Participable
  extend ActiveSupport::Concern

  module ClassMethods
    def participant(*attrs)
30
      participant_attrs.concat(attrs)
31 32 33 34 35 36 37
    end

    def participant_attrs
      @participant_attrs ||= []
    end
  end

38 39
  # Be aware that this method makes a lot of sql queries.
  # Save result into variable if you are going to reuse it inside same request
40
  def participants(current_user = self.author, load_lazy_references: true)
41
    participants = self.class.participant_attrs.flat_map do |attr|
42
      value =
43 44
        if attr.respond_to?(:call)
          instance_exec(current_user, &attr)
45
        else
46
          send(attr)
47 48
        end

49
      participants_for(value, current_user)
50
    end.compact.uniq
51

52 53 54
    if load_lazy_references
      participants = Gitlab::Markdown::ReferenceFilter::LazyReference.load(participants).uniq

55 56
      participants.select! do |user|
        user.can?(:read_project, project)
57 58 59 60
      end
    end

    participants
61 62 63
  end

  private
64

65
  def participants_for(value, current_user = nil)
Douwe Maan's avatar
Douwe Maan committed
66
    case value
67
    when User, Gitlab::Markdown::ReferenceFilter::LazyReference
Douwe Maan's avatar
Douwe Maan committed
68
      [value]
69
    when Enumerable, ActiveRecord::Relation
70
      value.flat_map { |v| participants_for(v, current_user) }
Douwe Maan's avatar
Douwe Maan committed
71
    when Participable
72
      value.participants(current_user, load_lazy_references: false)
73
    end
Douwe Maan's avatar
Douwe Maan committed
74
  end
75
end