gitlab-org--gitlab-foss/app/finders/members_finder.rb

69 lines
2.2 KiB
Ruby
Raw Normal View History

class MembersFinder
attr_reader :project, :current_user, :group
def initialize(project, current_user)
@project = project
@current_user = current_user
@group = project.group
end
def execute(include_descendants: false)
project_members = project.project_members
project_members = project_members.non_invite unless can?(current_user, :admin_project, project)
if group
group_members = GroupMembersFinder.new(group).execute(include_descendants: include_descendants)
group_members = group_members.non_invite
union = Gitlab::SQL::Union.new([project_members, group_members], remove_duplicates: false)
sql = distinct_on(union)
Member.includes(:user).from("(#{sql}) AS #{Member.table_name}")
else
project_members
end
end
def can?(*args)
Ability.allowed?(*args)
end
private
def distinct_on(union)
# We're interested in a list of members without duplicates by user_id.
# We prefer project members over group members, project members should go first.
if Gitlab::Database.postgresql?
<<~SQL
SELECT DISTINCT ON (user_id, invite_email) member_union.*
FROM (#{union.to_sql}) AS member_union
2018-02-21 07:54:35 -05:00
ORDER BY user_id,
invite_email,
CASE
WHEN type = 'ProjectMember' THEN 1
WHEN type = 'GroupMember' THEN 2
ELSE 3
END
SQL
else
# Older versions of MySQL do not support window functions (and DISTINCT ON is postgres-specific).
<<~SQL
SELECT t1.*
FROM (#{union.to_sql}) AS t1
JOIN (
SELECT
COALESCE(user_id, -1) AS user_id,
COALESCE(invite_email, 'NULL') AS invite_email,
MIN(CASE WHEN type = 'ProjectMember' THEN 1 WHEN type = 'GroupMember' THEN 2 ELSE 3 END) AS type_number
FROM
(#{union.to_sql}) AS t3
GROUP BY COALESCE(user_id, -1), COALESCE(invite_email, 'NULL')
) AS t2 ON COALESCE(t1.user_id, -1) = t2.user_id
AND COALESCE(t1.invite_email, 'NULL') = t2.invite_email
AND CASE WHEN t1.type = 'ProjectMember' THEN 1 WHEN t1.type = 'GroupMember' THEN 2 ELSE 3 END = t2.type_number
SQL
end
end
end