# frozen_string_literal: true class Auth::Result ATTRIBUTES = [ :user, :name, :username, :email, :email_valid, :extra_data, :awaiting_activation, :awaiting_approval, :authenticated, :authenticator_name, :requires_invite, :not_allowed_from_ip_address, :admin_not_allowed_from_ip_address, :skip_email_validation, :destination_url, :omniauth_disallow_totp, :failed, :failed_reason, :failed_code, :associated_groups, :overrides_email, :overrides_username, :overrides_name, ] attr_accessor *ATTRIBUTES # These are stored in the session during # account creation. The user cannot read or modify them SESSION_ATTRIBUTES = [ :email, :username, :email_valid, :name, :authenticator_name, :extra_data, :skip_email_validation, :associated_groups, :overrides_email, :overrides_username, :overrides_name, ] def [](key) key = key.to_sym public_send(key) if ATTRIBUTES.include?(key) end def initialize @failed = false end def email @email&.downcase end def email_valid=(val) if !val.in? [true, false, nil] raise ArgumentError, "email_valid should be boolean or nil" end @email_valid = !!val end def failed? !!@failed end def session_data SESSION_ATTRIBUTES.map { |att| [att, public_send(att)] }.to_h end def self.from_session_data(data, user:) result = new data = data.with_indifferent_access SESSION_ATTRIBUTES.each { |att| result.public_send("#{att}=", data[att]) } result.user = user result end def apply_user_attributes! change_made = false if (SiteSetting.auth_overrides_username? || overrides_username) && (resolved_username = resolve_username).present? change_made = UsernameChanger.override(user, resolved_username) end if (SiteSetting.auth_overrides_email || overrides_email || user&.email&.ends_with?(".invalid")) && email_valid && email.present? && user.email != Email.downcase(email) user.email = email change_made = true end if (SiteSetting.auth_overrides_name || overrides_name) && name.present? && user.name != name user.name = name change_made = true end change_made end def apply_associated_attributes! if authenticator&.provides_groups? && !associated_groups.nil? associated_group_ids = [] associated_groups.uniq.each do |associated_group| begin associated_group = AssociatedGroup.find_or_create_by( name: associated_group[:name], provider_id: associated_group[:id], provider_name: extra_data[:provider] ) rescue ActiveRecord::RecordNotUnique retry end associated_group_ids.push(associated_group.id) end user.update(associated_group_ids: associated_group_ids) AssociatedGroup.where(id: associated_group_ids).update_all("last_used = CURRENT_TIMESTAMP") end end def can_edit_name !(SiteSetting.auth_overrides_name || overrides_name) end def can_edit_username !(SiteSetting.auth_overrides_username || overrides_username) end def to_client_hash if requires_invite return { requires_invite: true } end if user&.suspended? return { suspended: true, suspended_message: user.suspended_message } end if omniauth_disallow_totp return { omniauth_disallow_totp: !!omniauth_disallow_totp, email: email } end if user result = { authenticated: !!authenticated, awaiting_activation: !!awaiting_activation, awaiting_approval: !!awaiting_approval, not_allowed_from_ip_address: !!not_allowed_from_ip_address, admin_not_allowed_from_ip_address: !!admin_not_allowed_from_ip_address } result[:destination_url] = destination_url if authenticated && destination_url.present? return result end result = { email: email, username: resolve_username, auth_provider: authenticator_name, email_valid: !!email_valid, can_edit_username: can_edit_username, can_edit_name: can_edit_name } result[:destination_url] = destination_url if destination_url.present? if SiteSetting.enable_names? result[:name] = name.presence result[:name] ||= User.suggest_name(username || email) if can_edit_name end result end private def staged_user return @staged_user if defined?(@staged_user) if email.present? && email_valid @staged_user = User.where(staged: true).find_by_email(email) end end def username_suggester_attributes attributes = [username] attributes << name if SiteSetting.use_name_for_username_suggestions attributes << email if SiteSetting.use_email_for_username_and_name_suggestions attributes end def authenticator @authenticator ||= Discourse.enabled_authenticators.find { |a| a.name == authenticator_name } end def resolve_username if staged_user if !username.present? || UserNameSuggester.fix_username(username) == staged_user.username return staged_user.username end end UserNameSuggester.suggest(*username_suggester_attributes, current_username: user&.username) end end