FEATURE: Optionally skip the create account popup for external auth

FEATURE: Optionally skip the create account popup for external auth

diff --git a/app/assets/javascripts/discourse/app/controllers/create-account.js b/app/assets/javascripts/discourse/app/controllers/create-account.js
index a74aa54..f1fd1c6 100644
--- a/app/assets/javascripts/discourse/app/controllers/create-account.js
+++ b/app/assets/javascripts/discourse/app/controllers/create-account.js
@@ -20,6 +20,7 @@ import { userPath } from "discourse/lib/url";
 import { findAll } from "discourse/models/login-method";
 import EmberObject from "@ember/object";
 import User from "discourse/models/user";
+import { Promise } from "rsvp";
 
 export default Controller.extend(
   ModalFunctionality,
@@ -41,9 +42,13 @@ export default Controller.extend(
 
     hasAuthOptions: notEmpty("authOptions"),
     canCreateLocal: setting("enable_local_logins"),
-    showCreateForm: or("hasAuthOptions", "canCreateLocal"),
     requireInviteCode: setting("require_invite_code"),
 
+    @discourseComputed("hasAuthOptions", "canCreateLocal", "skipConfirmation")
+    showCreateForm(hasAuthOptions, canCreateLocal, skipConfirmation) {
+      return (hasAuthOptions || canCreateLocal) && !skipConfirmation;
+    },
+
     resetForm() {
       // We wrap the fields in a structure so we can assign a value
       this.setProperties({
@@ -197,26 +202,44 @@ export default Controller.extend(
 
     @on("init")
     fetchConfirmationValue() {
-      return ajax(userPath("hp.json")).then(json => {
-        this._challengeDate = new Date();
-        // remove 30 seconds for jitter, make sure this works for at least
-        // 30 seconds so we don't have hard loops
-        this._challengeExpiry = parseInt(json.expires_in, 10) - 30;
-        if (this._challengeExpiry < 30) {
-          this._challengeExpiry = 30;
-        }
+      if (this._challengeDate === undefined && this._hpPromise) {
+        // Request already in progress
+        return this._hpPromise;
+      }
 
-        this.setProperties({
-          accountHoneypot: json.value,
-          accountChallenge: json.challenge
-            .split("")
-            .reverse()
-            .join("")
-        });
-      });
+      this._hpPromise = ajax(userPath("hp.json"))
+        .then(json => {
+          this._challengeDate = new Date();
+          // remove 30 seconds for jitter, make sure this works for at least
+          // 30 seconds so we don't have hard loops
+          this._challengeExpiry = parseInt(json.expires_in, 10) - 30;
+          if (this._challengeExpiry < 30) {
+            this._challengeExpiry = 30;
+          }
+
+          this.setProperties({
+            accountHoneypot: json.value,
+            accountChallenge: json.challenge
+              .split("")
+              .reverse()
+              .join("")
+          });
+        })
+        .finally(() => (this._hpPromise = undefined));
+
+      return this._hpPromise;
     },
 
     performAccountCreation() {
+      if (
+        !this._challengeDate ||
+        new Date() - this._challengeDate > 1000 * this._challengeExpiry
+      ) {
+        return this.fetchConfirmationValue().then(() =>
+          this.performAccountCreation()
+        );
+      }
+
       const attrs = this.getProperties(
         "accountName",
         "accountEmail",
@@ -263,6 +286,7 @@ export default Controller.extend(
               .find("input[name=redirect]")
               .val(userPath("account-created"));
             $hidden_login_form.submit();
+            return new Promise(() => {}); // This will never resolve, the page will reload instead
           } else {
             this.flash(
               result.message || I18n.t("create_account.failed"),
@@ -298,6 +322,14 @@ export default Controller.extend(
       );
     },
 
+    onShow() {
+      if (this.skipConfirmation) {
+        this.performAccountCreation().finally(() =>
+          this.set("skipConfirmation", false)
+        );
+      }
+    },
+
     actions: {
       externalLogin(provider) {
         this.login.send("externalLogin", provider);
@@ -332,13 +364,7 @@ export default Controller.extend(
           return;
         }
 
-        if (new Date() - this._challengeDate > 1000 * this._challengeExpiry) {
-          this.fetchConfirmationValue().then(() =>
-            this.performAccountCreation()
-          );
-        } else {
-          this.performAccountCreation();
-        }
+        this.performAccountCreation();
       }
     }
   }
diff --git a/app/assets/javascripts/discourse/app/controllers/login.js b/app/assets/javascripts/discourse/app/controllers/login.js
index 36e686d..870c75d 100644
--- a/app/assets/javascripts/discourse/app/controllers/login.js
+++ b/app/assets/javascripts/discourse/app/controllers/login.js
@@ -381,12 +381,16 @@ export default Controller.extend(ModalFunctionality, {
       return;
     }
 
+    const skipConfirmation =
+      options && this.siteSettings.external_auth_skip_create_confirm;
+
     const createAccountController = this.createAccount;
     createAccountController.setProperties({
       accountEmail: options.email,
       accountUsername: options.username,
       accountName: options.name,
-      authOptions: EmberObject.create(options)
+      authOptions: EmberObject.create(options),
+      skipConfirmation
     });
 
     showModal("createAccount", { modalClass: "create-account" });
diff --git a/app/assets/javascripts/discourse/app/templates/modal/create-account.hbs b/app/assets/javascripts/discourse/app/templates/modal/create-account.hbs
index eb2c794..2edb94b 100644
--- a/app/assets/javascripts/discourse/app/templates/modal/create-account.hbs
+++ b/app/assets/javascripts/discourse/app/templates/modal/create-account.hbs
@@ -7,6 +7,10 @@
         {{login-buttons externalLogin=(action "externalLogin")}}
       {{/unless}}
 
+      {{#if skipConfirmation}}
+        {{loading-spinner size="large"}}
+      {{/if}}
+
       {{#if showCreateForm}}
         <div class="login-form">
           <form>
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 1b03951..8a9c42f 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -1624,6 +1624,8 @@ en:
     password_unique_characters: "Minimum number of unique characters that a password must have."
     block_common_passwords: "Don't allow passwords that are in the 10,000 most common passwords."
 
+    external_auth_skip_create_confirm: When signing up via external auth, skip the create account popup. Best used alongside sso_overrides_email, sso_overrides_username and sso_overrides_name.
+
     enable_sso: "Enable single sign on via an external site (WARNING: USERS' EMAIL ADDRESSES *MUST* BE VALIDATED BY THE EXTERNAL SITE!)"
     verbose_sso_logging: "Log verbose SSO related diagnostics to <a href='%{base_path}/logs' target='_blank'>/logs</a>"
     enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_provider_secrets to be set"
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 98ddb57..ecaf08d 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -379,6 +379,9 @@ login:
   discord_trusted_guilds:
     default: ""
     type: list
+  external_auth_skip_create_confirm: 
+    default: false
+    client: true
   enable_sso:
     client: true
     default: false
diff --git a/test/javascripts/acceptance/create-account-external-test.js b/test/javascripts/acceptance/create-account-external-test.js
new file mode 100644
index 0000000..cd64fe1
--- /dev/null
+++ b/test/javascripts/acceptance/create-account-external-test.js
@@ -0,0 +1,43 @@
+import { acceptance } from "helpers/qunit-helpers";
+
+acceptance("Create Account - external auth", {
+  beforeEach() {
+    const node = document.createElement("meta");
+    node.dataset.authenticationData = JSON.stringify({
+      auth_provider: "test",
+      email: "blah@example.com",
+      can_edit_username: true,
+      can_edit_name: true
+    });
+    node.id = "data-authentication";

[... diff too long, it was truncated ...]

GitHub sha: 5284d41a

1 Like