# frozen_string_literal: true module AuthorizedProjectUpdate class ProjectGroupLinkCreateService < BaseService include Gitlab::Utils::StrongMemoize BATCH_SIZE = 1000 def initialize(project, group, group_access = nil) @project = project @group = group @group_access = group_access end def execute group.members_from_self_and_ancestors_with_effective_access_level .each_batch(of: BATCH_SIZE, column: :user_id) do |members| existing_authorizations = existing_project_authorizations(members) authorizations_to_create = [] user_ids_to_delete = [] members.each do |member| new_access_level = access_level(member.access_level) existing_access_level = existing_authorizations[member.user_id] if existing_access_level # User might already have access to the project unrelated to the # current project share next if existing_access_level >= new_access_level user_ids_to_delete << member.user_id end authorizations_to_create << { user_id: member.user_id, project_id: project.id, access_level: new_access_level } end update_authorizations(user_ids_to_delete, authorizations_to_create) end ServiceResponse.success end private attr_reader :project, :group, :group_access def access_level(membership_access_level) return membership_access_level unless group_access # access level must not be higher than the max access level set when # creating the project share [membership_access_level, group_access].min end def existing_project_authorizations(members) user_ids = members.map(&:user_id) ProjectAuthorization.where(project_id: project.id, user_id: user_ids) # rubocop: disable CodeReuse/ActiveRecord .select(:user_id, :access_level) .each_with_object({}) do |authorization, hash| hash[authorization.user_id] = authorization.access_level end end def update_authorizations(user_ids_to_delete, authorizations_to_create) ProjectAuthorization.transaction do if user_ids_to_delete.any? ProjectAuthorization.where(project_id: project.id, user_id: user_ids_to_delete) # rubocop: disable CodeReuse/ActiveRecord .delete_all end if authorizations_to_create.any? ProjectAuthorization.insert_all(authorizations_to_create) end end end end end