2018-08-03 13:22:24 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2015-04-23 11:27:45 -04:00
|
|
|
# == 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.
|
|
|
|
#
|
|
|
|
# Usage:
|
|
|
|
#
|
2019-03-28 09:17:42 -04:00
|
|
|
# class Issue < ApplicationRecord
|
2015-04-23 11:27:45 -04:00
|
|
|
# include Participable
|
|
|
|
#
|
|
|
|
# # ...
|
|
|
|
#
|
2016-05-26 07:38:28 -04:00
|
|
|
# participant :author
|
|
|
|
# participant :assignee
|
|
|
|
# participant :notes
|
|
|
|
#
|
|
|
|
# participant -> (current_user, ext) do
|
|
|
|
# ext.analyze('...')
|
|
|
|
# end
|
2015-04-23 11:27:45 -04:00
|
|
|
# end
|
2015-06-24 06:49:34 -04:00
|
|
|
#
|
2015-04-23 11:27:45 -04:00
|
|
|
# issue = Issue.last
|
|
|
|
# users = issue.participants
|
2015-04-21 09:23:20 -04:00
|
|
|
module Participable
|
|
|
|
extend ActiveSupport::Concern
|
2018-08-27 08:35:31 -04:00
|
|
|
class_methods do
|
2016-05-26 07:38:28 -04:00
|
|
|
# Adds a list of participant attributes. Attributes can either be symbols or
|
|
|
|
# Procs.
|
|
|
|
#
|
|
|
|
# When using a Proc instead of a Symbol the Proc will be given two
|
|
|
|
# arguments:
|
|
|
|
#
|
|
|
|
# 1. The current user (as an instance of User)
|
|
|
|
# 2. An instance of `Gitlab::ReferenceExtractor`
|
|
|
|
#
|
|
|
|
# It is expected that a Proc populates the given reference extractor
|
|
|
|
# instance with data. The return value of the Proc is ignored.
|
|
|
|
#
|
|
|
|
# attr - The name of the attribute or a Proc
|
|
|
|
def participant(attr)
|
|
|
|
participant_attrs << attr
|
2015-04-21 09:23:20 -04:00
|
|
|
end
|
2016-07-13 23:28:58 -04:00
|
|
|
end
|
2015-04-21 09:23:20 -04:00
|
|
|
|
2016-07-13 23:28:58 -04:00
|
|
|
included do
|
|
|
|
# Accessor for participant attributes.
|
|
|
|
cattr_accessor :participant_attrs, instance_accessor: false do
|
|
|
|
[]
|
2015-04-21 09:23:20 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-05-26 07:38:28 -04:00
|
|
|
# Returns the users participating in a discussion.
|
|
|
|
#
|
|
|
|
# This method processes attributes of objects in breadth-first order.
|
|
|
|
#
|
|
|
|
# Returns an Array of User instances.
|
|
|
|
def participants(current_user = nil)
|
2017-09-18 13:25:23 -04:00
|
|
|
all_participants[current_user]
|
2016-06-20 11:49:15 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2017-09-18 13:25:23 -04:00
|
|
|
def all_participants
|
|
|
|
@all_participants ||= Hash.new do |hash, user|
|
|
|
|
hash[user] = raw_participants(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-20 11:49:15 -04:00
|
|
|
def raw_participants(current_user = nil)
|
2016-05-26 07:38:28 -04:00
|
|
|
current_user ||= author
|
|
|
|
ext = Gitlab::ReferenceExtractor.new(project, current_user)
|
|
|
|
participants = Set.new
|
|
|
|
process = [self]
|
2015-04-21 09:23:20 -04:00
|
|
|
|
2016-05-26 07:38:28 -04:00
|
|
|
until process.empty?
|
|
|
|
source = process.pop
|
2015-10-14 03:17:05 -04:00
|
|
|
|
2016-05-26 07:38:28 -04:00
|
|
|
case source
|
|
|
|
when User
|
|
|
|
participants << source
|
|
|
|
when Participable
|
|
|
|
source.class.participant_attrs.each do |attr|
|
|
|
|
if attr.respond_to?(:call)
|
|
|
|
source.instance_exec(current_user, ext, &attr)
|
|
|
|
else
|
2017-08-10 12:39:26 -04:00
|
|
|
process << source.__send__(attr) # rubocop:disable GitlabSecurity/PublicSend
|
2016-05-26 07:38:28 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
when Enumerable, ActiveRecord::Relation
|
|
|
|
# This uses reverse_each so we can use "pop" to get the next value to
|
|
|
|
# process (in order). Using unshift instead of pop would require
|
|
|
|
# moving all Array values one index to the left (which can be
|
|
|
|
# expensive).
|
|
|
|
source.reverse_each { |obj| process << obj }
|
2015-05-15 06:45:45 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-05-26 07:38:28 -04:00
|
|
|
participants.merge(ext.users)
|
2015-06-24 06:49:34 -04:00
|
|
|
|
2018-04-26 15:53:13 -04:00
|
|
|
filter_by_ability(participants)
|
|
|
|
end
|
|
|
|
|
|
|
|
def filter_by_ability(participants)
|
2017-01-20 05:28:40 -05:00
|
|
|
case self
|
|
|
|
when PersonalSnippet
|
2017-01-05 08:36:06 -05:00
|
|
|
Ability.users_that_can_read_personal_snippet(participants.to_a, self)
|
|
|
|
else
|
|
|
|
Ability.users_that_can_read_project(participants.to_a, project)
|
|
|
|
end
|
2015-04-21 11:41:18 -04:00
|
|
|
end
|
2015-04-21 09:23:20 -04:00
|
|
|
end
|
2019-09-13 09:26:31 -04:00
|
|
|
|
|
|
|
Participable.prepend_if_ee('EE::Participable')
|