|  | 
|  | 1 | +class Auth::ManagedAuthenticator < Auth::Authenticator | 
|  | 2 | + def description_for_user(user) | 
|  | 3 | + info = UserAssociatedAccount.find_by(provider_name: name, user_id: user.id).info | 
|  | 4 | + info["name"] || info["email"] || info["nickname"] || "" | 
|  | 5 | + end | 
|  | 6 | + | 
|  | 7 | + # These three methods are designed to be overriden by child classes | 
|  | 8 | + def match_by_email | 
|  | 9 | + true | 
|  | 10 | + end | 
|  | 11 | + | 
|  | 12 | + def can_revoke? | 
|  | 13 | + true | 
|  | 14 | + end | 
|  | 15 | + | 
|  | 16 | + def can_connect_existing_user? | 
|  | 17 | + true | 
|  | 18 | + end | 
|  | 19 | + | 
|  | 20 | + def revoke(user, skip_remote: false) | 
|  | 21 | + association = UserAssociatedAccount.find_by(provider_name: name, user_id: user.id) | 
|  | 22 | + raise Discourse::NotFound if association.nil? | 
|  | 23 | + association.destroy! | 
|  | 24 | + true | 
|  | 25 | + end | 
|  | 26 | + | 
|  | 27 | + def after_authenticate(auth_token, existing_account: nil) | 
|  | 28 | + result = Auth::Result.new | 
|  | 29 | + | 
|  | 30 | + # Store all the metadata for later, in case the `after_create_account` hook is used | 
|  | 31 | + result.extra_data = { | 
|  | 32 | + provider: auth_token[:provider], | 
|  | 33 | + uid: auth_token[:uid], | 
|  | 34 | + info: auth_token[:info], | 
|  | 35 | + extra: auth_token[:extra], | 
|  | 36 | + credentials: auth_token[:credentials] | 
|  | 37 | + } | 
|  | 38 | + | 
|  | 39 | + # Build the Auth::Result object | 
|  | 40 | + info = auth_token[:info] | 
|  | 41 | + result.email = email = info[:email] | 
|  | 42 | + result.name = name = "#{info[:first_name]} #{info[:last_name]}" | 
|  | 43 | + result.username = info[:nickname] | 
|  | 44 | + | 
|  | 45 | + # Try and find an association for this account | 
|  | 46 | + association = UserAssociatedAccount.find_by(provider_name: auth_token[:provider], provider_uid: auth_token[:uid]) | 
|  | 47 | + result.user = association&.user | 
|  | 48 | + | 
|  | 49 | + # Reconnecting to existing account | 
|  | 50 | + if can_connect_existing_user? && existing_account && (association.nil? || existing_account.id != association.user_id) | 
|  | 51 | + association.destroy! if association | 
|  | 52 | + association = nil | 
|  | 53 | + result.user = existing_account | 
|  | 54 | + end | 
|  | 55 | + | 
|  | 56 | + # Matching an account by email | 
|  | 57 | + if match_by_email && association.nil? && (user = User.find_by_email(email)) | 
|  | 58 | + UserAssociatedAccount.where(user: user, provider_name: auth_token[:provider]).destroy_all # Destroy existing associations for the new user | 
|  | 59 | + result.user = user | 
|  | 60 | + end | 
|  | 61 | + | 
|  | 62 | + # Add the association to the database if it doesn't already exist | 
|  | 63 | + if association.nil? && result.user | 
|  | 64 | + association = create_association!(result.extra_data.merge(user: result.user)) | 
|  | 65 | + end | 
|  | 66 | + | 
|  | 67 | + # Update all the metadata in the association: | 
|  | 68 | + if association | 
|  | 69 | + association.update!( | 
|  | 70 | + info: auth_token[:info], | 
|  | 71 | + credentials: auth_token[:credentials], | 
|  | 72 | + extra: auth_token[:extra] | 
|  | 73 | + ) | 
|  | 74 | + end | 
|  | 75 | + | 
|  | 76 | + result.email_valid = true | 
|  | 77 | + | 
|  | 78 | + result | 
|  | 79 | + end | 
|  | 80 | + | 
|  | 81 | + def create_association!(hash) | 
|  | 82 | + association = UserAssociatedAccount.create!( | 
|  | 83 | + user: hash[:user], | 
|  | 84 | + provider_name: hash[:provider], | 
|  | 85 | + provider_uid: hash[:uid], | 
|  | 86 | + info: hash[:info], | 
|  | 87 | + credentials: hash[:credentials], | 
|  | 88 | + extra: hash[:extra] | 
|  | 89 | + ) | 
|  | 90 | + end | 
|  | 91 | + | 
|  | 92 | + def after_create_account(user, auth) | 
|  | 93 | + data = auth[:extra_data] | 
|  | 94 | + create_association!(data.merge(user: user)) | 
|  | 95 | + end | 
|  | 96 | +end | 
0 commit comments