summaryrefslogtreecommitdiff
path: root/app/models/user.rb
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 14:34:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 14:34:42 +0000
commit9f46488805e86b1bc341ea1620b866016c2ce5ed (patch)
treef9748c7e287041e37d6da49e0a29c9511dc34768 /app/models/user.rb
parentdfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff)
downloadgitlab-ce-9f46488805e86b1bc341ea1620b866016c2ce5ed.tar.gz
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'app/models/user.rb')
-rw-r--r--app/models/user.rb105
1 files changed, 34 insertions, 71 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
index 1b087da3a2f..b2d3978551e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -24,6 +24,7 @@ class User < ApplicationRecord
include HasUniqueInternalUsers
include IgnorableColumns
include UpdateHighestRole
+ include HasUserType
DEFAULT_NOTIFICATION_LEVEL = :participating
@@ -57,6 +58,10 @@ class User < ApplicationRecord
devise :lockable, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable
+ # This module adds async behaviour to Devise emails
+ # and should be added after Devise modules are initialized.
+ include AsyncDeviseEmail
+
BLOCKED_MESSAGE = "Your account has been blocked. Please contact your GitLab " \
"administrator if you think this is an error."
LOGIN_FORBIDDEN = "Your account does not have the required permission to login. Please contact your GitLab " \
@@ -64,9 +69,8 @@ class User < ApplicationRecord
MINIMUM_INACTIVE_DAYS = 180
- enum user_type: ::UserTypeEnums.types
-
- ignore_column :bot_type, remove_with: '12.11', remove_after: '2020-04-22'
+ ignore_column :bot_type, remove_with: '13.1', remove_after: '2020-05-22'
+ ignore_column :ghost, remove_with: '13.2', remove_after: '2020-06-22'
# Override Devise::Models::Trackable#update_tracked_fields!
# to limit database writes to at most once every hour
@@ -88,6 +92,9 @@ class User < ApplicationRecord
# Virtual attribute for authenticating by either username or email
attr_accessor :login
+ # Virtual attribute for impersonator
+ attr_accessor :impersonator
+
#
# Relations
#
@@ -166,6 +173,8 @@ class User < ApplicationRecord
has_many :term_agreements
belongs_to :accepted_term, class_name: 'ApplicationSetting::Term'
+ has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :user
+
has_one :status, class_name: 'UserStatus'
has_one :user_preference
has_one :user_detail
@@ -246,15 +255,12 @@ class User < ApplicationRecord
enum layout: { fixed: 0, fluid: 1 }
# User's Dashboard preference
- # Note: When adding an option, it MUST go on the end of the array.
enum dashboard: { projects: 0, stars: 1, project_activity: 2, starred_project_activity: 3, groups: 4, todos: 5, issues: 6, merge_requests: 7, operations: 8 }
# User's Project preference
- # Note: When adding an option, it MUST go on the end of the array.
enum project_view: { readme: 0, activity: 1, files: 2 }
# User's role
- # Note: When adding an option, it MUST go on the end of the array.
enum role: { software_developer: 0, development_team_lead: 1, devops_engineer: 2, systems_administrator: 3, security_analyst: 4, data_analyst: 5, product_manager: 6, product_designer: 7, other: 8 }, _suffix: true
delegate :path, to: :namespace, allow_nil: true, prefix: true
@@ -321,32 +327,26 @@ class User < ApplicationRecord
scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_states(:blocked, :ldap_blocked) }
scope :external, -> { where(external: true) }
+ scope :confirmed, -> { where.not(confirmed_at: nil) }
scope :active, -> { with_state(:active).non_internal }
scope :active_without_ghosts, -> { with_state(:active).without_ghosts }
- scope :without_ghosts, -> { where('ghost IS NOT TRUE') }
scope :deactivated, -> { with_state(:deactivated).non_internal }
scope :without_projects, -> { joins('LEFT JOIN project_authorizations ON users.id = project_authorizations.user_id').where(project_authorizations: { user_id: nil }) }
- scope :order_recent_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'DESC')) }
- scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) }
- scope :order_recent_last_activity, -> { reorder(Gitlab::Database.nulls_last_order('last_activity_on', 'DESC')) }
- scope :order_oldest_last_activity, -> { reorder(Gitlab::Database.nulls_first_order('last_activity_on', 'ASC')) }
- scope :confirmed, -> { where.not(confirmed_at: nil) }
scope :by_username, -> (usernames) { iwhere(username: Array(usernames).map(&:to_s)) }
scope :for_todos, -> (todos) { where(id: todos.select(:user_id)) }
scope :with_emails, -> { preload(:emails) }
scope :with_dashboard, -> (dashboard) { where(dashboard: dashboard) }
scope :with_public_profile, -> { where(private_profile: false) }
- scope :bots, -> { where(user_type: UserTypeEnums.bots.values) }
- scope :bots_without_project_bot, -> { bots.where.not(user_type: UserTypeEnums.bots[:project_bot]) }
- scope :with_project_bots, -> { humans.or(where.not(user_type: UserTypeEnums.bots.except(:project_bot).values)) }
- scope :humans, -> { where(user_type: nil) }
-
scope :with_expiring_and_not_notified_personal_access_tokens, ->(at) do
where('EXISTS (?)',
::PersonalAccessToken
.where('personal_access_tokens.user_id = users.id')
.expiring_and_not_notified(at).select(1))
end
+ scope :order_recent_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'DESC')) }
+ scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) }
+ scope :order_recent_last_activity, -> { reorder(Gitlab::Database.nulls_last_order('last_activity_on', 'DESC')) }
+ scope :order_oldest_last_activity, -> { reorder(Gitlab::Database.nulls_first_order('last_activity_on', 'ASC')) }
def active_for_authentication?
super && can?(:log_in)
@@ -624,7 +624,7 @@ class User < ApplicationRecord
# owns records previously belonging to deleted users.
def ghost
email = 'ghost%s@example.com'
- unique_internal(where(ghost: true, user_type: :ghost), 'ghost', email) do |u|
+ unique_internal(where(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
@@ -639,6 +639,16 @@ class User < ApplicationRecord
end
end
+ def migration_bot
+ email_pattern = "noreply+gitlab-migration-bot%s@#{Settings.gitlab.host}"
+
+ unique_internal(where(user_type: :migration_bot), 'migration-bot', email_pattern) do |u|
+ u.bio = 'The GitLab migration bot'
+ u.name = 'GitLab Migration Bot'
+ u.confirmed_at = Time.zone.now
+ end
+ end
+
# Return true if there is only single non-internal user in the deployment,
# ghost user is ignored.
def single_user?
@@ -650,43 +660,14 @@ class User < ApplicationRecord
end
end
- def full_path
- username
- end
-
- def bot?
- UserTypeEnums.bots.has_key?(user_type)
- end
-
- # The explicit check for project_bot will be removed with Bot Categorization
- # Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
- def internal?
- ghost? || (bot? && !project_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
-
- # The explicit check for project_bot will be removed with Bot Categorization
- # Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
- def self.internal
- where(ghost: true).or(bots_without_project_bot)
- end
-
- # The explicit check for project_bot will be removed with Bot Categorization
- # Ref: https://gitlab.com/gitlab-org/gitlab/-/issues/213945
- def self.non_internal
- without_ghosts.with_project_bots
- end
-
#
# Instance methods
#
+ def full_path
+ username
+ end
+
def to_param
username
end
@@ -1700,16 +1681,6 @@ class User < ApplicationRecord
callouts.any?
end
- def gitlab_employee?
- strong_memoize(:gitlab_employee) do
- if Feature.enabled?(:gitlab_employee_badge) && Gitlab.com?
- Mail::Address.new(email).domain == "gitlab.com" && confirmed?
- else
- false
- end
- end
- end
-
# Load the current highest access by looking directly at the user's memberships
def current_highest_access_level
members.non_request.maximum(:access_level)
@@ -1719,8 +1690,8 @@ class User < ApplicationRecord
!confirmed? && !confirmation_period_valid?
end
- def organization
- gitlab_employee? ? 'GitLab' : super
+ def impersonated?
+ impersonator.present?
end
protected
@@ -1779,13 +1750,6 @@ class User < ApplicationRecord
ApplicationSetting.current_without_cache&.usage_stats_set_by_user_id == self.id
end
- # Added according to https://github.com/plataformatec/devise/blob/7df57d5081f9884849ca15e4fde179ef164a575f/README.md#activejob-integration
- def send_devise_notification(notification, *args)
- return true unless can?(:receive_notifications)
-
- devise_mailer.__send__(notification, self, *args).deliver_later # rubocop:disable GitlabSecurity/PublicSend
- end
-
def ensure_user_rights_and_limits
if external?
self.can_create_group = false
@@ -1834,7 +1798,6 @@ class User < ApplicationRecord
end
def check_email_restrictions
- return unless Feature.enabled?(:email_restrictions)
return unless Gitlab::CurrentSettings.email_restrictions_enabled?
restrictions = Gitlab::CurrentSettings.email_restrictions