DEV: Add profile fetching support to `ManagedAuthenticator`

DEV: Add profile fetching support to `ManagedAuthenticator`
From 3cad3f9df16c8f1dae76e1e858f3597dbe928128 Mon Sep 17 00:00:00 2001
From: David Taylor <david@taylorhq.com>
Date: Fri, 7 Dec 2018 14:04:21 +0000
Subject: [PATCH] DEV: Add profile fetching support to `ManagedAuthenticator`


diff --git a/lib/auth/managed_authenticator.rb b/lib/auth/managed_authenticator.rb
index 9805623..95746b6 100644
--- a/lib/auth/managed_authenticator.rb
+++ b/lib/auth/managed_authenticator.rb
@@ -73,6 +73,7 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
         extra: auth_token[:extra] || {}
       )
       retrieve_avatar(result.user, auth_token.dig(:info, :image))
+      retrieve_profile(result.user, auth_token[:info])
     end
 
     result.email_valid = true if result.email
@@ -95,6 +96,7 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
     data = auth[:extra_data]
     create_association!(data.merge(user: user))
     retrieve_avatar(user, data.dig(:info, :image))
+    retrieve_profile(user, data[:info])
   end
 
   def retrieve_avatar(user, url)
@@ -102,4 +104,18 @@ class Auth::ManagedAuthenticator < Auth::Authenticator
     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
+
+  def retrieve_profile(user, info)
+    return unless user
+
+    bio = info[:description]
+    location = info[:location]
+
+    if bio || location
+      profile = user.user_profile
+      profile.bio_raw  = bio      unless profile.bio_raw.present?
+      profile.location = location unless profile.location.present?
+      profile.save
+    end
+  end
 end
diff --git a/spec/components/auth/managed_authenticator_spec.rb b/spec/components/auth/managed_authenticator_spec.rb
index 6fed762..5153deb 100644
--- a/spec/components/auth/managed_authenticator_spec.rb
+++ b/spec/components/auth/managed_authenticator_spec.rb
@@ -136,6 +136,30 @@ describe Auth::ManagedAuthenticator do
       end
     end
 
+    describe "profile on update" do
+      let(:user) { Fabricate(:user) }
+      let!(:associated) { UserAssociatedAccount.create!(user: user, provider_name: 'myauth', provider_uid: "1234") }
+
+      it "updates the user's location and bio, unless already set" do
+        { description: :bio_raw, location: :location }.each do |auth_hash_key, profile_key|
+          user.user_profile.update(profile_key => "Initial Value")
+          # No value supplied, do not overwrite
+          expect { result = authenticator.after_authenticate(hash) }
+            .not_to change { user.user_profile.reload; user.user_profile[profile_key] }
+
+          # Value supplied, still do not overwrite
+          expect { result = authenticator.after_authenticate(hash.deep_merge(info: { auth_hash_key => "New Value" })) }
+            .not_to change { user.user_profile.reload; user.user_profile[profile_key] }
+
+          # User has not set a value, so overwrite
+          user.user_profile.update(profile_key => "")
+          authenticator.after_authenticate(hash.deep_merge(info: { auth_hash_key => "New Value" }))
+          user.user_profile.reload
+          expect(user.user_profile[profile_key]).to eq("New Value")
+        end
+      end
+    end
+
     describe "avatar on create" do
       let(:user) { Fabricate(:user) }
       it "doesn't schedule with no image" do
@@ -148,6 +172,19 @@ describe Auth::ManagedAuthenticator do
           .to change { Jobs::DownloadAvatarFromUrl.jobs.count }.by(1)
       end
     end
+
+    describe "profile on create" do
+      let(:user) { Fabricate(:user) }
+      it "doesn't explode without profile" do
+        authenticator.after_create_account(user, extra_data: hash)
+      end
+
+      it "works with profile" do
+        authenticator.after_create_account(user, extra_data: hash.deep_merge(info: { location: "DiscourseVille", description: "Online forum expert" }))
+        expect(user.user_profile.bio_raw).to eq("Online forum expert")
+        expect(user.user_profile.location).to eq("DiscourseVille")
+      end
+    end
   end
 
   describe 'description_for_user' do

GitHub