diff options
Diffstat (limited to 'app/models/user.rb')
-rw-r--r-- | app/models/user.rb | 76 |
1 files changed, 55 insertions, 21 deletions
diff --git a/app/models/user.rb b/app/models/user.rb index 11046bdabe4..507e8cc2cf5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -103,6 +103,8 @@ class User < ApplicationRecord # Profile has_many :keys, -> { regular_keys }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + has_many :expired_today_and_unnotified_keys, -> { expired_today_and_not_notified }, class_name: 'Key' + has_many :expiring_soon_and_unnotified_keys, -> { expiring_soon_and_not_notified }, class_name: 'Key' has_many :deploy_keys, -> { where(type: 'DeployKey') }, dependent: :nullify # rubocop:disable Cop/ActiveRecordDependent has_many :group_deploy_keys has_many :gpg_keys @@ -125,7 +127,7 @@ class User < ApplicationRecord # Groups has_many :members - has_many :group_members, -> { where(requested_at: nil).where("access_level >= ?", Gitlab::Access::GUEST) }, source: 'GroupMember' + has_many :group_members, -> { where(requested_at: nil).where("access_level >= ?", Gitlab::Access::GUEST) }, class_name: 'GroupMember' has_many :groups, through: :group_members has_many :owned_groups, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :group has_many :maintainers_groups, -> { where(members: { access_level: Gitlab::Access::MAINTAINER }) }, through: :group_members, source: :group @@ -139,7 +141,7 @@ class User < ApplicationRecord -> { where(members: { access_level: [Gitlab::Access::REPORTER, Gitlab::Access::DEVELOPER, Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER] }) }, through: :group_members, source: :group - has_many :minimal_access_group_members, -> { where(access_level: [Gitlab::Access::MINIMAL_ACCESS]) }, source: 'GroupMember', class_name: 'GroupMember' + has_many :minimal_access_group_members, -> { where(access_level: [Gitlab::Access::MINIMAL_ACCESS]) }, class_name: 'GroupMember' has_many :minimal_access_groups, through: :minimal_access_group_members, source: :group # Projects @@ -199,6 +201,8 @@ class User < ApplicationRecord has_many :reviews, foreign_key: :author_id, inverse_of: :author + has_many :in_product_marketing_emails, class_name: '::Users::InProductMarketingEmail' + # # Validations # @@ -350,7 +354,8 @@ class User < ApplicationRecord # this state transition object in order to do a rollback. # For this reason the tradeoff is to disable this cop. after_transition any => :blocked do |user| - Ci::CancelUserPipelinesService.new.execute(user) + Ci::DropPipelineService.new.execute_async_for_all(user.pipelines, :user_blocked, user) + Ci::DisableUserPipelineSchedulesService.new.execute(user) end # rubocop: enable CodeReuse/ServiceClass end @@ -390,6 +395,22 @@ class User < ApplicationRecord .without_impersonation .expired_today_and_not_notified) end + scope :with_ssh_key_expired_today, -> do + includes(:expired_today_and_unnotified_keys) + .where('EXISTS (?)', + ::Key + .select(1) + .where('keys.user_id = users.id') + .expired_today_and_not_notified) + end + scope :with_ssh_key_expiring_soon, -> do + includes(:expiring_soon_and_unnotified_keys) + .where('EXISTS (?)', + ::Key + .select(1) + .where('keys.user_id = users.id') + .expiring_soon_and_not_notified) + 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')) } @@ -743,6 +764,7 @@ class User < ApplicationRecord u.bio = 'The GitLab support bot used for Service Desk' u.name = 'GitLab Support Bot' u.avatar = bot_avatar(image: 'support-bot.png') + u.confirmed_at = Time.zone.now end end @@ -1024,7 +1046,7 @@ class User < ApplicationRecord [ Project.where(namespace: namespace), Project.joins(:project_authorizations) - .where("projects.namespace_id <> ?", namespace.id) + .where.not('projects.namespace_id' => namespace.id) .where(project_authorizations: { user_id: id, access_level: Gitlab::Access::OWNER }) ], remove_duplicates: false @@ -1337,9 +1359,11 @@ class User < ApplicationRecord end def public_verified_emails - emails = verified_emails(include_private_email: false) - emails << email unless temp_oauth_email? - emails.uniq + strong_memoize(:public_verified_emails) do + emails = verified_emails(include_private_email: false) + emails << email unless temp_oauth_email? + emails.uniq + end end def any_email?(check_email) @@ -1595,32 +1619,40 @@ class User < ApplicationRecord @global_notification_setting end + def count_cache_validity_period + if Feature.enabled?(:longer_count_cache_validity, self, default_enabled: :yaml) + 24.hours + else + 20.minutes + end + end + def assigned_open_merge_requests_count(force: false) - Rails.cache.fetch(['users', id, 'assigned_open_merge_requests_count'], force: force, expires_in: 20.minutes) do + Rails.cache.fetch(['users', id, 'assigned_open_merge_requests_count'], force: force, expires_in: count_cache_validity_period) do MergeRequestsFinder.new(self, assignee_id: self.id, state: 'opened', non_archived: true).execute.count end end def review_requested_open_merge_requests_count(force: false) - Rails.cache.fetch(['users', id, 'review_requested_open_merge_requests_count'], force: force, expires_in: 20.minutes) do + Rails.cache.fetch(['users', id, 'review_requested_open_merge_requests_count'], force: force, expires_in: count_cache_validity_period) do MergeRequestsFinder.new(self, reviewer_id: id, state: 'opened', non_archived: true).execute.count end end def assigned_open_issues_count(force: false) - Rails.cache.fetch(['users', id, 'assigned_open_issues_count'], force: force, expires_in: 20.minutes) do + Rails.cache.fetch(['users', id, 'assigned_open_issues_count'], force: force, expires_in: count_cache_validity_period) do IssuesFinder.new(self, assignee_id: self.id, state: 'opened', non_archived: true).execute.count end end def todos_done_count(force: false) - Rails.cache.fetch(['users', id, 'todos_done_count'], force: force, expires_in: 20.minutes) do + Rails.cache.fetch(['users', id, 'todos_done_count'], force: force, expires_in: count_cache_validity_period) do TodosFinder.new(self, state: :done).execute.count end end def todos_pending_count(force: false) - Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force, expires_in: 20.minutes) do + Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force, expires_in: count_cache_validity_period) do TodosFinder.new(self, state: :pending).execute.count end end @@ -1639,8 +1671,7 @@ class User < ApplicationRecord def invalidate_cache_counts invalidate_issue_cache_counts invalidate_merge_request_cache_counts - invalidate_todos_done_count - invalidate_todos_pending_count + invalidate_todos_cache_counts invalidate_personal_projects_count end @@ -1653,11 +1684,8 @@ class User < ApplicationRecord Rails.cache.delete(['users', id, 'review_requested_open_merge_requests_count']) end - def invalidate_todos_done_count + def invalidate_todos_cache_counts Rails.cache.delete(['users', id, 'todos_done_count']) - end - - def invalidate_todos_pending_count Rails.cache.delete(['users', id, 'todos_pending_count']) end @@ -1835,10 +1863,12 @@ class User < ApplicationRecord end def dismissed_callout?(feature_name:, ignore_dismissal_earlier_than: nil) - callouts = self.callouts.with_feature_name(feature_name) - callouts = callouts.with_dismissed_after(ignore_dismissal_earlier_than) if ignore_dismissal_earlier_than + callout = callouts_by_feature_name[feature_name] + + return false unless callout + return callout.dismissed_after?(ignore_dismissal_earlier_than) if ignore_dismissal_earlier_than - callouts.any? + true end # Load the current highest access by looking directly at the user's memberships @@ -1901,6 +1931,10 @@ class User < ApplicationRecord private + def callouts_by_feature_name + @callouts_by_feature_name ||= callouts.index_by(&:feature_name) + end + def authorized_groups_without_shared_membership Group.from_union([ groups, |