4d7fa59af2
When moving a project, it's possible that some users who had access to the project in old path can not access the project in the new path. Because `project_authorizations` records are updated asynchronously, when we send the notification about moved project the list of project team members contains old project members, we want to notify all these members except the old users who can not access the new location.
206 lines
4.8 KiB
Ruby
206 lines
4.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class ProjectTeam
|
|
include BulkMemberAccessLoad
|
|
|
|
attr_accessor :project
|
|
|
|
def initialize(project)
|
|
@project = project
|
|
end
|
|
|
|
def add_guest(user, current_user: nil)
|
|
add_user(user, :guest, current_user: current_user)
|
|
end
|
|
|
|
def add_reporter(user, current_user: nil)
|
|
add_user(user, :reporter, current_user: current_user)
|
|
end
|
|
|
|
def add_developer(user, current_user: nil)
|
|
add_user(user, :developer, current_user: current_user)
|
|
end
|
|
|
|
def add_maintainer(user, current_user: nil)
|
|
add_user(user, :maintainer, current_user: current_user)
|
|
end
|
|
|
|
# @deprecated
|
|
alias_method :add_master, :add_maintainer
|
|
|
|
def add_role(user, role, current_user: nil)
|
|
public_send(:"add_#{role}", user, current_user: current_user) # rubocop:disable GitlabSecurity/PublicSend
|
|
end
|
|
|
|
def find_member(user_id)
|
|
member = project.members.find_by(user_id: user_id)
|
|
|
|
# If user is not in project members
|
|
# we should check for group membership
|
|
if group && !member
|
|
member = group.members.find_by(user_id: user_id)
|
|
end
|
|
|
|
member
|
|
end
|
|
|
|
def add_users(users, access_level, current_user: nil, expires_at: nil)
|
|
ProjectMember.add_users(
|
|
project,
|
|
users,
|
|
access_level,
|
|
current_user: current_user,
|
|
expires_at: expires_at
|
|
)
|
|
end
|
|
|
|
def add_user(user, access_level, current_user: nil, expires_at: nil)
|
|
ProjectMember.add_user(
|
|
project,
|
|
user,
|
|
access_level,
|
|
current_user: current_user,
|
|
expires_at: expires_at
|
|
)
|
|
end
|
|
|
|
# Remove all users from project team
|
|
def truncate
|
|
ProjectMember.truncate_team(project)
|
|
end
|
|
|
|
def members
|
|
@members ||= fetch_members
|
|
end
|
|
alias_method :users, :members
|
|
|
|
# `members` method uses project_authorizations table which
|
|
# is updated asynchronously, on project move it still contains
|
|
# old members who may not have access to the new location,
|
|
# so we filter out only members of project or project's group
|
|
def members_in_project_and_ancestors
|
|
members.where(id: member_user_ids)
|
|
end
|
|
|
|
def guests
|
|
@guests ||= fetch_members(Gitlab::Access::GUEST)
|
|
end
|
|
|
|
def reporters
|
|
@reporters ||= fetch_members(Gitlab::Access::REPORTER)
|
|
end
|
|
|
|
def developers
|
|
@developers ||= fetch_members(Gitlab::Access::DEVELOPER)
|
|
end
|
|
|
|
def maintainers
|
|
@maintainers ||= fetch_members(Gitlab::Access::MAINTAINER)
|
|
end
|
|
|
|
# @deprecated
|
|
alias_method :masters, :maintainers
|
|
|
|
def owners
|
|
@owners ||=
|
|
if group
|
|
group.owners
|
|
else
|
|
[project.owner]
|
|
end
|
|
end
|
|
|
|
def import(source_project, current_user = nil)
|
|
target_project = project
|
|
|
|
source_members = source_project.project_members.to_a
|
|
target_user_ids = target_project.project_members.pluck(:user_id)
|
|
|
|
source_members.reject! do |member|
|
|
# Skip if user already present in team
|
|
!member.invite? && target_user_ids.include?(member.user_id)
|
|
end
|
|
|
|
source_members.map! do |member|
|
|
new_member = member.dup
|
|
new_member.id = nil
|
|
new_member.source = target_project
|
|
new_member.created_by = current_user
|
|
new_member
|
|
end
|
|
|
|
ProjectMember.transaction do
|
|
source_members.each do |member|
|
|
member.save
|
|
end
|
|
end
|
|
|
|
true
|
|
rescue
|
|
false
|
|
end
|
|
|
|
def guest?(user)
|
|
max_member_access(user.id) == Gitlab::Access::GUEST
|
|
end
|
|
|
|
def reporter?(user)
|
|
max_member_access(user.id) == Gitlab::Access::REPORTER
|
|
end
|
|
|
|
def developer?(user)
|
|
max_member_access(user.id) == Gitlab::Access::DEVELOPER
|
|
end
|
|
|
|
def maintainer?(user)
|
|
max_member_access(user.id) == Gitlab::Access::MAINTAINER
|
|
end
|
|
|
|
# @deprecated
|
|
alias_method :master?, :maintainer?
|
|
|
|
# Checks if `user` is authorized for this project, with at least the
|
|
# `min_access_level` (if given).
|
|
def member?(user, min_access_level = Gitlab::Access::GUEST)
|
|
return false unless user
|
|
|
|
max_member_access(user.id) >= min_access_level
|
|
end
|
|
|
|
def human_max_access(user_id)
|
|
Gitlab::Access.human_access(max_member_access(user_id))
|
|
end
|
|
|
|
# Determine the maximum access level for a group of users in bulk.
|
|
#
|
|
# Returns a Hash mapping user ID -> maximum access level.
|
|
def max_member_access_for_user_ids(user_ids)
|
|
max_member_access_for_resource_ids(User, user_ids, project.id) do |user_ids|
|
|
project.project_authorizations
|
|
.where(user: user_ids)
|
|
.group(:user_id)
|
|
.maximum(:access_level)
|
|
end
|
|
end
|
|
|
|
def max_member_access(user_id)
|
|
max_member_access_for_user_ids([user_id])[user_id]
|
|
end
|
|
|
|
private
|
|
|
|
def fetch_members(level = nil)
|
|
members = project.authorized_users
|
|
members = members.where(project_authorizations: { access_level: level }) if level
|
|
|
|
members
|
|
end
|
|
|
|
def group
|
|
project.group
|
|
end
|
|
|
|
def member_user_ids
|
|
Member.on_project_and_ancestors(project).select(:user_id)
|
|
end
|
|
end
|