mirror of
https://github.com/discourse/discourse.git
synced 2024-11-24 15:49:55 +08:00
485fc4636a
If the identity provider does not provide a precise username value, then we should use our UserNameSuggester to generate one and use it for the override. This makes the override consistent with initial account creation.
219 lines
5.3 KiB
Ruby
219 lines
5.3 KiB
Ruby
# 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
|