diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-19 21:09:17 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-19 21:09:17 +0000 |
commit | 49a923c646a2c24b5377cfde8236c73094c60d42 (patch) | |
tree | 8e4ef094e6a338c80123765d8cd2a707c82bdc7b /app/models/concerns | |
parent | 0eb4fd2f32e6804bc85868ba167170238e346279 (diff) | |
download | gitlab-ce-49a923c646a2c24b5377cfde8236c73094c60d42.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models/concerns')
-rw-r--r-- | app/models/concerns/has_unique_internal_users.rb | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/app/models/concerns/has_unique_internal_users.rb b/app/models/concerns/has_unique_internal_users.rb new file mode 100644 index 00000000000..4d60cfa03b0 --- /dev/null +++ b/app/models/concerns/has_unique_internal_users.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module HasUniqueInternalUsers + extend ActiveSupport::Concern + + class_methods do + private + + def unique_internal(scope, username, email_pattern, &block) + scope.first || create_unique_internal(scope, username, email_pattern, &block) + end + + def create_unique_internal(scope, username, email_pattern, &creation_block) + # Since we only want a single one of these in an instance, we use an + # exclusive lease to ensure than this block is never run concurrently. + lease_key = "user:unique_internal:#{username}" + lease = Gitlab::ExclusiveLease.new(lease_key, timeout: 1.minute.to_i) + + until uuid = lease.try_obtain + # Keep trying until we obtain the lease. To prevent hammering Redis too + # much we'll wait for a bit between retries. + sleep(1) + end + + # Recheck if the user is already present. One might have been + # added between the time we last checked (first line of this method) + # and the time we acquired the lock. + existing_user = uncached { scope.first } + return existing_user if existing_user.present? + + uniquify = Uniquify.new + + username = uniquify.string(username) { |s| User.find_by_username(s) } + + email = uniquify.string(-> (n) { Kernel.sprintf(email_pattern, n) }) do |s| + User.find_by_email(s) + end + + user = scope.build( + username: username, + email: email, + &creation_block + ) + + Users::UpdateService.new(user, user: user).execute(validate: false) + user + ensure + Gitlab::ExclusiveLease.cancel(lease_key, uuid) + end + end +end |