From 6566b2f11a30da71128264413a357f86b038d691 Mon Sep 17 00:00:00 2001
From: David Taylor <david@taylorhq.com>
Date: Mon, 30 Jul 2018 14:38:53 +0100
Subject: [PATCH] FEATURE: Allow revoke and connect for Instagram logins

---
 .../discourse/models/login-method.js.es6      | 11 +++++--
 lib/auth/instagram_authenticator.rb           | 31 ++++++++++++++++---
 2 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/app/assets/javascripts/discourse/models/login-method.js.es6 b/app/assets/javascripts/discourse/models/login-method.js.es6
index 51051791048..9b4d83d423a 100644
--- a/app/assets/javascripts/discourse/models/login-method.js.es6
+++ b/app/assets/javascripts/discourse/models/login-method.js.es6
@@ -128,9 +128,14 @@ export function findAll(siteSettings, capabilities, isMobileDevice) {
       }
 
       if (
-        ["facebook", "google_oauth2", "twitter", "yahoo", "github"].includes(
-          name
-        )
+        [
+          "facebook",
+          "google_oauth2",
+          "twitter",
+          "yahoo",
+          "github",
+          "instagram"
+        ].includes(name)
       ) {
         params.canConnect = true;
       }
diff --git a/lib/auth/instagram_authenticator.rb b/lib/auth/instagram_authenticator.rb
index ca4f41ebc84..515616fbbcc 100644
--- a/lib/auth/instagram_authenticator.rb
+++ b/lib/auth/instagram_authenticator.rb
@@ -13,9 +13,23 @@ class Auth::InstagramAuthenticator < Auth::Authenticator
     info&.screen_name || ""
   end
 
-  # TODO twitter provides all sorts of extra info, like website/bio etc.
-  #  it may be worth considering pulling some of it in.
-  def after_authenticate(auth_token)
+  def can_revoke?
+    true
+  end
+
+  def revoke(user, skip_remote: false)
+    info = InstagramUserInfo.find_by(user_id: user.id)
+    raise Discourse::NotFound if info.nil?
+    # Instagram does not have any way for us to revoke tokens on their end
+    info.destroy!
+    true
+  end
+
+  def can_connect_existing_user?
+    true
+  end
+
+  def after_authenticate(auth_token, existing_account: nil)
 
     result = Auth::Result.new
 
@@ -32,7 +46,16 @@ class Auth::InstagramAuthenticator < Auth::Authenticator
 
     user_info = InstagramUserInfo.find_by(instagram_user_id: instagram_user_id)
 
-    result.user = user_info.try(:user)
+    if existing_account && (user_info.nil? || existing_account.id != user_info.user_id)
+      user_info.destroy! if user_info
+      user_info = InstagramUserInfo.create!(
+        user_id: existing_account.id,
+        screen_name: screen_name,
+        instagram_user_id: instagram_user_id
+      )
+    end
+
+    result.user = user_info&.user
 
     result
   end