diff options
Diffstat (limited to 'app/models/member.rb')
-rw-r--r-- | app/models/member.rb | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/app/models/member.rb b/app/models/member.rb index 25dae518406..8bec64932b3 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -276,9 +276,11 @@ class Member < ApplicationRecord after_create :send_invite, if: :invite?, unless: :importing? after_create :create_notification_setting, unless: [:pending?, :importing?] after_create :post_create_hook, unless: [:pending?, :importing?], if: :hook_prerequisites_met? + after_create :update_two_factor_requirement, unless: :invite? after_update :post_update_hook, unless: [:pending?, :importing?], if: :hook_prerequisites_met? after_destroy :destroy_notification_setting after_destroy :post_destroy_hook, unless: :pending?, if: :hook_prerequisites_met? + after_destroy :update_two_factor_requirement, unless: :invite? after_save :log_invitation_token_cleanup after_commit :send_request, if: :request?, unless: :importing?, on: [:create] @@ -286,6 +288,14 @@ class Member < ApplicationRecord refresh_member_authorized_projects end + after_create if: :update_organization_user? do + Organizations::OrganizationUser.upsert( + { organization_id: source.organization_id, user_id: user_id, access_level: :default }, + unique_by: [:organization_id, :user_id], + on_duplicate: :skip # Do not change access_level, could make :owner :default + ) + end + attribute :notification_level, default: -> { NotificationSetting.levels[:global] } class << self @@ -486,7 +496,10 @@ class Member < ApplicationRecord strong_memoize(:highest_group_member) do next unless user_id && source&.ancestors&.any? - GroupMember.where(source: source.ancestors, user_id: user_id).order(:access_level).last + GroupMember + .where(source: source.ancestors, user_id: user_id) + .non_request + .order(:access_level).last end end @@ -498,6 +511,17 @@ class Member < ApplicationRecord created_by&.name end + def update_two_factor_requirement + return unless source.is_a?(Group) + return unless user + + Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction( + %w[users user_details user_preferences], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424288' + ) do + user.update_two_factor_requirement + end + end + private # TODO: https://gitlab.com/groups/gitlab-org/-/epics/7054 @@ -513,7 +537,7 @@ class Member < ApplicationRecord end def send_invite - # override in subclass + run_after_commit_or_now { notification_service.invite_member(self, @raw_invite_token) } end def send_request @@ -522,10 +546,26 @@ class Member < ApplicationRecord end def post_create_hook + # The creator of a personal project gets added as a `ProjectMember` + # with `OWNER` access during creation of a personal project, + # but we do not want to trigger notifications to the same person who created the personal project. + unless source.is_a?(Project) && source.personal_namespace_holder?(user) + event_service.join_source(source, user) + run_after_commit_or_now { notification_service.new_member(self) } + end + system_hook_service.execute_hooks_for(self, :create) end def post_update_hook + if saved_change_to_access_level? + run_after_commit { notification_service.updated_member_access_level(self) } + end + + if saved_change_to_expires_at? + run_after_commit { notification_service.updated_member_expiration(self) } + end + system_hook_service.execute_hooks_for(self, :update) end @@ -548,6 +588,12 @@ class Member < ApplicationRecord # rubocop: enable CodeReuse/ServiceClass def after_accept_invite + run_after_commit_or_now do + notification_service.accept_invite(self) + end + + update_two_factor_requirement + post_create_hook end @@ -578,7 +624,12 @@ class Member < ApplicationRecord # rubocop: enable CodeReuse/ServiceClass def notifiable_options - {} + case source + when Group + { group: source } + when Project + { project: source } + end end def higher_access_level_than_group @@ -617,12 +668,22 @@ class Member < ApplicationRecord user&.project_bot? end + def update_organization_user? + return false unless Feature.enabled?(:update_organization_users, source.root_ancestor, type: :gitlab_com_derisk) + + !invite? && source.organization.present? + end + def log_invitation_token_cleanup return true unless Gitlab.com? && invite? && invite_accepted_at? error = StandardError.new("Invitation token is present but invite was already accepted!") Gitlab::ErrorTracking.track_exception(error, attributes.slice(%w["invite_accepted_at created_at source_type source_id user_id id"])) end + + def event_service + EventCreateService.new # rubocop:todo CodeReuse/ServiceClass -- Legacy, convert to value object eventually + end end Member.prepend_mod_with('Member') |