diff options
Diffstat (limited to 'app/models/user.rb')
-rw-r--r-- | app/models/user.rb | 105 |
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 |