Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/members/update_service.rb')
-rw-r--r--app/services/members/update_service.rb89
1 files changed, 68 insertions, 21 deletions
diff --git a/app/services/members/update_service.rb b/app/services/members/update_service.rb
index 8ef3e307519..0e6b02f7a80 100644
--- a/app/services/members/update_service.rb
+++ b/app/services/members/update_service.rb
@@ -2,37 +2,84 @@
module Members
class UpdateService < Members::BaseService
- # returns the updated member
- def execute(member, permission: :update)
- raise Gitlab::Access::AccessDeniedError unless can?(current_user, action_member_permission(permission, member), member)
- raise Gitlab::Access::AccessDeniedError if prevent_upgrade_to_owner?(member) || prevent_downgrade_from_owner?(member)
+ # @param members [Member, Array<Member>]
+ # returns the updated member(s)
+ def execute(members, permission: :update)
+ members = Array.wrap(members)
- return success(member: member) if update_results_in_no_change?(member)
-
- old_access_level = member.human_access
- old_expiry = member.expires_at
-
- if member.update(params)
- after_execute(action: permission, old_access_level: old_access_level, old_expiry: old_expiry, member: member)
-
- # Deletes only confidential issues todos for guests
- enqueue_delete_todos(member) if downgrading_to_guest?
+ old_access_level_expiry_map = members.to_h do |member|
+ [member.id, { human_access: member.human_access, expires_at: member.expires_at }]
end
- if member.errors.any?
- error(member.errors.full_messages.to_sentence, pass_back: { member: member })
+ if Feature.enabled?(:bulk_update_membership_roles, current_user)
+ multiple_members_update(members, permission, old_access_level_expiry_map)
else
- success(member: member)
+ single_member_update(members.first, permission, old_access_level_expiry_map)
end
+
+ prepare_response(members)
end
private
- def update_results_in_no_change?(member)
- return false if params[:expires_at]&.to_date != member.expires_at
- return false if params[:access_level] != member.access_level
+ def single_member_update(member, permission, old_access_level_expiry_map)
+ raise Gitlab::Access::AccessDeniedError unless has_update_permissions?(member, permission)
+
+ member.attributes = params
+ return success(member: member) unless member.changed?
+
+ post_update(member, permission, old_access_level_expiry_map) if member.save
+ end
+
+ def multiple_members_update(members, permission, old_access_level_expiry_map)
+ begin
+ updated_members =
+ Member.transaction do
+ # Using `next` with `filter_map` avoids the `post_update` call for the member that resulted in no change
+ members.filter_map do |member|
+ raise Gitlab::Access::AccessDeniedError unless has_update_permissions?(member, permission)
+
+ member.attributes = params
+ next unless member.changed?
+
+ member.save!
+ member
+ end
+ end
+ rescue ActiveRecord::RecordInvalid
+ return
+ end
+
+ updated_members.each { |member| post_update(member, permission, old_access_level_expiry_map) }
+ end
+
+ def post_update(member, permission, old_access_level_expiry_map)
+ old_access_level = old_access_level_expiry_map[member.id][:human_access]
+ old_expiry = old_access_level_expiry_map[member.id][:expires_at]
+
+ after_execute(action: permission, old_access_level: old_access_level, old_expiry: old_expiry, member: member)
+ enqueue_delete_todos(member) if downgrading_to_guest? # Deletes only confidential issues todos for guests
+ end
+
+ def prepare_response(members)
+ errored_member = members.detect { |member| member.errors.any? }
+ if errored_member.present?
+ return error(errored_member.errors.full_messages.to_sentence, pass_back: { member: errored_member })
+ end
+
+ # TODO: Remove the :member key when removing the bulk_update_membership_roles FF and update where it's used.
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/373257
+ if members.one?
+ success(member: members.first)
+ else
+ success(members: members)
+ end
+ end
- true
+ def has_update_permissions?(member, permission)
+ can?(current_user, action_member_permission(permission, member), member) &&
+ !prevent_upgrade_to_owner?(member) &&
+ !prevent_downgrade_from_owner?(member)
end
def downgrading_to_guest?