debian-mirror-gitlab/app/finders/projects/members/effective_access_level_finder.rb

128 lines
3.7 KiB
Ruby
Raw Normal View History

2021-06-08 01:23:25 +05:30
# frozen_string_literal: true
module Projects
module Members
class EffectiveAccessLevelFinder
include Gitlab::Utils::StrongMemoize
USER_ID_AND_ACCESS_LEVEL = [:user_id, :access_level].freeze
BATCH_SIZE = 5
def initialize(project)
@project = project
end
def execute
return Member.none if no_members?
# rubocop: disable CodeReuse/ActiveRecord
Member.from(generate_from_statement(user_ids_and_access_levels_from_all_memberships))
.select([:user_id, 'MAX(access_level) AS access_level'])
.group(:user_id)
# rubocop: enable CodeReuse/ActiveRecord
end
private
attr_reader :project
def generate_from_statement(user_ids_and_access_levels)
2022-03-02 08:16:31 +05:30
values_list = Arel::Nodes::ValuesList.new(user_ids_and_access_levels).to_sql
2021-06-08 01:23:25 +05:30
2022-03-02 08:16:31 +05:30
"(#{values_list}) members (user_id, access_level)"
2021-06-08 01:23:25 +05:30
end
def no_members?
user_ids_and_access_levels_from_all_memberships.blank?
end
def all_possible_avenues_of_membership
avenues = [authorizable_project_members]
avenues << if project.personal?
2022-05-07 20:08:51 +05:30
project_owner
2021-06-08 01:23:25 +05:30
else
authorizable_group_members
end
if include_membership_from_project_group_shares?
avenues << members_from_project_group_shares
end
avenues
end
# @return [Array<[user_id, access_level]>]
def user_ids_and_access_levels_from_all_memberships
strong_memoize(:user_ids_and_access_levels_from_all_memberships) do
2021-10-27 15:23:28 +05:30
all_possible_avenues_of_membership.flat_map do |members|
apply_scopes(members).pluck(*USER_ID_AND_ACCESS_LEVEL) # rubocop: disable CodeReuse/ActiveRecord
2021-06-08 01:23:25 +05:30
end
end
end
def authorizable_project_members
project.members.authorizable
end
def authorizable_group_members
project.group.authorizable_members_with_parents
end
def members_from_project_group_shares
members = []
project.project_group_links.each_batch(of: BATCH_SIZE) do |relation|
members_per_batch = []
relation.includes(:group).each do |link| # rubocop: disable CodeReuse/ActiveRecord
members_per_batch << link.group.authorizable_members_with_parents.select(*user_id_and_access_level_for_project_group_shares(link))
end
members << Member.from_union(members_per_batch)
end
2021-10-27 15:23:28 +05:30
Member.from_union(members)
2021-06-08 01:23:25 +05:30
end
2022-05-07 20:08:51 +05:30
# workaround until we migrate Project#owners to have membership with
# OWNER access level
def project_owner
2021-06-08 01:23:25 +05:30
user_id = project.namespace.owner.id
2022-05-07 20:08:51 +05:30
access_level = Gitlab::Access::OWNER
2021-06-08 01:23:25 +05:30
Member
.from(generate_from_statement([[user_id, access_level]])) # rubocop: disable CodeReuse/ActiveRecord
.limit(1)
end
def include_membership_from_project_group_shares?
2021-11-18 22:05:49 +05:30
!project.namespace.share_with_group_lock && project.project_group_links.any?
2021-06-08 01:23:25 +05:30
end
# methods for `select` options
def user_id_and_access_level_for_project_group_shares(link)
least_access_level_among_group_membership_and_project_share =
smallest_value_arel([link.group_access, GroupMember.arel_table[:access_level]], 'access_level')
[
:user_id,
least_access_level_among_group_membership_and_project_share
]
end
def smallest_value_arel(args, column_alias)
Arel::Nodes::As.new(
Arel::Nodes::NamedFunction.new('LEAST', args),
Arel.sql(column_alias)
)
end
2021-10-27 15:23:28 +05:30
def apply_scopes(members)
members
end
2021-06-08 01:23:25 +05:30
end
end
end