106 lines
3.3 KiB
Ruby
106 lines
3.3 KiB
Ruby
class Auth::ManagedAuthenticator < Auth::Authenticator
|
|
def description_for_user(user)
|
|
info = UserAssociatedAccount.find_by(provider_name: name, user_id: user.id)&.info
|
|
return "" if info.nil?
|
|
info["email"] || info["nickname"] || info["name"] || ""
|
|
end
|
|
|
|
# These three methods are designed to be overriden by child classes
|
|
def match_by_email
|
|
true
|
|
end
|
|
|
|
def can_revoke?
|
|
true
|
|
end
|
|
|
|
def can_connect_existing_user?
|
|
true
|
|
end
|
|
|
|
def revoke(user, skip_remote: false)
|
|
association = UserAssociatedAccount.find_by(provider_name: name, user_id: user.id)
|
|
raise Discourse::NotFound if association.nil?
|
|
association.destroy!
|
|
true
|
|
end
|
|
|
|
def after_authenticate(auth_token, existing_account: nil)
|
|
result = Auth::Result.new
|
|
|
|
# Store all the metadata for later, in case the `after_create_account` hook is used
|
|
result.extra_data = {
|
|
provider: auth_token[:provider],
|
|
uid: auth_token[:uid],
|
|
info: auth_token[:info],
|
|
extra: auth_token[:extra],
|
|
credentials: auth_token[:credentials]
|
|
}
|
|
|
|
# Build the Auth::Result object
|
|
info = auth_token[:info]
|
|
result.email = email = info[:email]
|
|
result.name = name = "#{info[:first_name]} #{info[:last_name]}"
|
|
result.username = info[:nickname]
|
|
|
|
# Try and find an association for this account
|
|
association = UserAssociatedAccount.find_by(provider_name: auth_token[:provider], provider_uid: auth_token[:uid])
|
|
result.user = association&.user
|
|
|
|
# Reconnecting to existing account
|
|
if can_connect_existing_user? && existing_account && (association.nil? || existing_account.id != association.user_id)
|
|
association.destroy! if association
|
|
association = nil
|
|
result.user = existing_account
|
|
end
|
|
|
|
# Matching an account by email
|
|
if match_by_email && association.nil? && (user = User.find_by_email(email))
|
|
UserAssociatedAccount.where(user: user, provider_name: auth_token[:provider]).destroy_all # Destroy existing associations for the new user
|
|
result.user = user
|
|
end
|
|
|
|
# Add the association to the database if it doesn't already exist
|
|
if association.nil? && result.user
|
|
association = create_association!(result.extra_data.merge(user: result.user))
|
|
end
|
|
|
|
# Update all the metadata in the association:
|
|
if association
|
|
association.update!(
|
|
info: auth_token[:info] || {},
|
|
credentials: auth_token[:credentials] || {},
|
|
extra: auth_token[:extra] || {}
|
|
)
|
|
retrieve_avatar(result.user, auth_token[:info][:image])
|
|
end
|
|
|
|
result.email_valid = true if result.email
|
|
|
|
result
|
|
end
|
|
|
|
def create_association!(hash)
|
|
association = UserAssociatedAccount.create!(
|
|
user: hash[:user],
|
|
provider_name: hash[:provider],
|
|
provider_uid: hash[:uid],
|
|
info: hash[:info] || {},
|
|
credentials: hash[:credentials] || {},
|
|
extra: hash[:extra] || {}
|
|
)
|
|
end
|
|
|
|
def after_create_account(user, auth)
|
|
data = auth[:extra_data]
|
|
create_association!(data.merge(user: user))
|
|
retrieve_avatar(user, data&.[]("info")&.[]("image"))
|
|
end
|
|
|
|
def retrieve_avatar(user, url)
|
|
return unless user && url
|
|
return if user.user_avatar.try(:custom_upload_id).present?
|
|
Jobs.enqueue(:download_avatar_from_url, url: url, user_id: user.id, override_gravatar: false)
|
|
end
|
|
end
|