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 | |
parent | 0eb4fd2f32e6804bc85868ba167170238e346279 (diff) | |
download | gitlab-ce-49a923c646a2c24b5377cfde8236c73094c60d42.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/models/concerns/has_unique_internal_users.rb | 51 | ||||
-rw-r--r-- | app/models/user.rb | 52 | ||||
-rw-r--r-- | app/models/user_type_enums.rb | 6 |
3 files changed, 62 insertions, 47 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 diff --git a/app/models/user.rb b/app/models/user.rb index 6972a465c30..48438d0e7e2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -21,6 +21,7 @@ class User < ApplicationRecord include OptionallySearch include FromUnion include BatchDestroyDependentAssociations + include HasUniqueInternalUsers include IgnorableColumns DEFAULT_NOTIFICATION_LEVEL = :participating @@ -612,7 +613,7 @@ class User < ApplicationRecord # owns records previously belonging to deleted users. def ghost email = 'ghost%s@example.com' - unique_internal(where(ghost: true), 'ghost', email) do |u| + unique_internal(where(ghost: true, user_type: :ghost), 'ghost', email) do |u| u.bio = _('This is a "Ghost User", created to hold all issues authored by users that have since been deleted. This user cannot be removed.') u.name = 'Ghost User' end @@ -650,6 +651,13 @@ class User < ApplicationRecord ghost? || bot? end + # We are transitioning from ghost boolean column to user_type + # so we need to read from old column for now + # @see https://gitlab.com/gitlab-org/gitlab/-/issues/210025 + def ghost? + ghost + end + def self.internal where(ghost: true).or(bots) end @@ -1793,48 +1801,6 @@ class User < ApplicationRecord end end - def self.unique_internal(scope, username, email_pattern, &block) - scope.first || create_unique_internal(scope, username, email_pattern, &block) - end - - def self.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) # rubocop: disable CodeReuse/ServiceClass - user - ensure - Gitlab::ExclusiveLease.cancel(lease_key, uuid) - end - def groups_with_developer_maintainer_project_access project_creation_levels = [::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS] diff --git a/app/models/user_type_enums.rb b/app/models/user_type_enums.rb index 2d0d2f3a4ce..795cc4b2889 100644 --- a/app/models/user_type_enums.rb +++ b/app/models/user_type_enums.rb @@ -2,13 +2,11 @@ module UserTypeEnums def self.types - bots.merge(human: nil) + @types ||= bots.merge(human: nil, ghost: 5) end def self.bots - { - alert_bot: 2 - }.with_indifferent_access + @bots ||= { alert_bot: 2 }.with_indifferent_access end end |