From c05e54e4610d05c2ff6081994c1511e294044908 Mon Sep 17 00:00:00 2001
From: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com>
Date: Thu, 6 Jul 2023 11:03:18 -0500
Subject: [PATCH] DEV: Convert second-factor-backup-edit modal to
component-based API (#22366)
This PR converts the `second-factor-backup-edit` modal to make use of the new component-based API
---
.../modal/second-factor-backup-edit.hbs | 62 +++++++++++++++
.../modal/second-factor-backup-edit.js | 63 +++++++++++++++
.../controllers/preferences/second-factor.js | 24 +++---
.../controllers/second-factor-backup-edit.js | 79 -------------------
.../modal/second-factor-backup-edit.hbs | 61 --------------
...r-preferences-second-factor-backup-test.js | 10 +--
6 files changed, 143 insertions(+), 156 deletions(-)
create mode 100644 app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.hbs
create mode 100644 app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.js
delete mode 100644 app/assets/javascripts/discourse/app/controllers/second-factor-backup-edit.js
delete mode 100644 app/assets/javascripts/discourse/app/templates/modal/second-factor-backup-edit.hbs
diff --git a/app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.hbs b/app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.hbs
new file mode 100644
index 00000000000..66b315c86d3
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.hbs
@@ -0,0 +1,62 @@
+
+ <:body>
+ {{#if this.successMessage}}
+
+ {{this.successMessage}}
+
+ {{/if}}
+
+ {{#if this.errorMessage}}
+
+ {{this.errorMessage}}
+
+ {{/if}}
+
+
+ {{#if this.backupCodes}}
+ {{i18n "user.second_factor_backup.codes.title"}}
+ {{i18n "user.second_factor_backup.codes.description"}}
+
+ {{/if}}
+
+
+ {{#if this.backupEnabled}}
+ {{html-safe
+ (i18n
+ "user.second_factor_backup.remaining_codes" count=this.remainingCodes
+ )
+ }}
+ {{else}}
+ {{html-safe (i18n "user.second_factor_backup.not_enabled")}}
+ {{/if}}
+
+ <:footer>
+
+ {{#if this.backupEnabled}}
+
+ {{else}}
+
+ {{/if}}
+
+
+
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.js b/app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.js
new file mode 100644
index 00000000000..dcfbb09fa26
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/modal/second-factor-backup-edit.js
@@ -0,0 +1,63 @@
+import Component from "@glimmer/component";
+import I18n from "I18n";
+import { SECOND_FACTOR_METHODS } from "discourse/models/user";
+import { debounce } from "discourse-common/utils/decorators";
+import { tracked } from "@glimmer/tracking";
+import { action } from "@ember/object";
+
+export default class SecondFactorBackupEdit extends Component {
+ @tracked loading = false;
+ @tracked errorMessage;
+ @tracked successMessage;
+ @tracked backupEnabled =
+ this.args.model.secondFactor.second_factor_backup_enabled;
+ @tracked remainingCodes =
+ this.args.model.secondFactor.second_factor_remaining_backup_codes;
+ @tracked backupCodes;
+ @tracked secondFactorMethod = SECOND_FACTOR_METHODS.TOTP;
+
+ @action
+ copyBackupCode(successful) {
+ if (successful) {
+ this.successMessage = I18n.t(
+ "user.second_factor_backup.copied_to_clipboard"
+ );
+ } else {
+ this.errorMessage = I18n.t(
+ "user.second_factor_backup.copy_to_clipboard_error"
+ );
+ }
+ this._hideCopyMessage();
+ }
+
+ @action
+ generateSecondFactorCodes() {
+ this.loading = true;
+ this.args.model.secondFactor
+ .generateSecondFactorCodes()
+ .then((response) => {
+ if (response.error) {
+ this.errorMessage = response.error;
+ return;
+ }
+
+ this.args.model.markDirty();
+ this.errorMessage = null;
+ this.backupCodes = response.backup_codes;
+ this.args.model.setBackupEnabled(true);
+ this.backupEnabled = true;
+ this.remainingCodes = response.backup_codes.length;
+ })
+ .catch((error) => {
+ this.args.closeModal();
+ this.args.model.onError(error);
+ })
+ .finally(() => (this.loading = false));
+ }
+
+ @debounce(2000)
+ _hideCopyMessage() {
+ this.successMessage = null;
+ this.errorMessage = null;
+ }
+}
diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/second-factor.js b/app/assets/javascripts/discourse/app/controllers/preferences/second-factor.js
index 0d95914b415..6f62530195c 100644
--- a/app/assets/javascripts/discourse/app/controllers/preferences/second-factor.js
+++ b/app/assets/javascripts/discourse/app/controllers/preferences/second-factor.js
@@ -8,13 +8,13 @@ import { alias } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators";
import { findAll } from "discourse/models/login-method";
import { popupAjaxError } from "discourse/lib/ajax-error";
-import showModal from "discourse/lib/show-modal";
import { inject as service } from "@ember/service";
import SecondFactorConfirmPhrase from "discourse/components/dialog-messages/second-factor-confirm-phrase";
import SecondFactorAddSecurityKey from "discourse/components/modal/second-factor-add-security-key";
import SecondFactorEditSecurityKey from "discourse/components/modal/second-factor-edit-security-key";
import SecondFactorEdit from "discourse/components/modal/second-factor-edit";
import SecondFactorAddTotp from "discourse/components/modal/second-factor-add-totp";
+import SecondFactorBackupEdit from "discourse/components/modal/second-factor-backup-edit";
export default Controller.extend(CanCheckEmails, {
dialog: service(),
@@ -63,6 +63,11 @@ export default Controller.extend(CanCheckEmails, {
}
},
+ @action
+ setBackupEnabled(value) {
+ this.set("backupEnabled", value);
+ },
+
@action
loadSecondFactors() {
if (this.dirty === false) {
@@ -310,15 +315,14 @@ export default Controller.extend(CanCheckEmails, {
this.loadSecondFactors();
},
- editSecondFactorBackup() {
- const controller = showModal("second-factor-backup-edit", {
- model: this.model,
- title: "user.second_factor_backup.title",
- });
- controller.setProperties({
- onClose: () => this.loadSecondFactors(),
- markDirty: () => this.markDirty(),
- onError: (e) => this.handleError(e),
+ async editSecondFactorBackup() {
+ await this.modal.show(SecondFactorBackupEdit, {
+ model: {
+ secondFactor: this.model,
+ markDirty: () => this.markDirty(),
+ onError: (e) => this.handleError(e),
+ setBackupEnabled: (e) => this.setBackupEnabled(e),
+ },
});
},
},
diff --git a/app/assets/javascripts/discourse/app/controllers/second-factor-backup-edit.js b/app/assets/javascripts/discourse/app/controllers/second-factor-backup-edit.js
deleted file mode 100644
index 6854102fe0b..00000000000
--- a/app/assets/javascripts/discourse/app/controllers/second-factor-backup-edit.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import Controller from "@ember/controller";
-import I18n from "I18n";
-import ModalFunctionality from "discourse/mixins/modal-functionality";
-import { SECOND_FACTOR_METHODS } from "discourse/models/user";
-import { alias } from "@ember/object/computed";
-import discourseLater from "discourse-common/lib/later";
-
-export default Controller.extend(ModalFunctionality, {
- loading: false,
- errorMessage: null,
- successMessage: null,
- backupEnabled: alias("model.second_factor_backup_enabled"),
- remainingCodes: alias("model.second_factor_remaining_backup_codes"),
- backupCodes: null,
- secondFactorMethod: SECOND_FACTOR_METHODS.TOTP,
-
- onShow() {
- this.setProperties({
- loading: false,
- errorMessage: null,
- successMessage: null,
- backupCodes: null,
- });
- },
-
- actions: {
- copyBackupCode(successful) {
- if (successful) {
- this.set(
- "successMessage",
- I18n.t("user.second_factor_backup.copied_to_clipboard")
- );
- } else {
- this.set(
- "errorMessage",
- I18n.t("user.second_factor_backup.copy_to_clipboard_error")
- );
- }
-
- this._hideCopyMessage();
- },
-
- generateSecondFactorCodes() {
- this.set("loading", true);
- this.model
- .generateSecondFactorCodes()
- .then((response) => {
- if (response.error) {
- this.set("errorMessage", response.error);
- return;
- }
-
- this.markDirty();
- this.setProperties({
- errorMessage: null,
- backupCodes: response.backup_codes,
- backupEnabled: true,
- remainingCodes: response.backup_codes.length,
- });
- })
- .catch((error) => {
- this.send("closeModal");
- this.onError(error);
- })
- .finally(() => {
- this.setProperties({
- loading: false,
- });
- });
- },
- },
-
- _hideCopyMessage() {
- discourseLater(
- () => this.setProperties({ successMessage: null, errorMessage: null }),
- 2000
- );
- },
-});
diff --git a/app/assets/javascripts/discourse/app/templates/modal/second-factor-backup-edit.hbs b/app/assets/javascripts/discourse/app/templates/modal/second-factor-backup-edit.hbs
deleted file mode 100644
index 1e1633ef87e..00000000000
--- a/app/assets/javascripts/discourse/app/templates/modal/second-factor-backup-edit.hbs
+++ /dev/null
@@ -1,61 +0,0 @@
-
- {{#if this.successMessage}}
-
- {{this.successMessage}}
-
- {{/if}}
-
- {{#if this.errorMessage}}
-
- {{this.errorMessage}}
-
- {{/if}}
-
-
- {{#if this.backupCodes}}
- {{i18n "user.second_factor_backup.codes.title"}}
-
-
- {{i18n "user.second_factor_backup.codes.description"}}
-
-
-
- {{/if}}
-
-
- {{#if this.backupEnabled}}
- {{html-safe
- (i18n
- "user.second_factor_backup.remaining_codes" count=this.remainingCodes
- )
- }}
- {{else}}
- {{html-safe (i18n "user.second_factor_backup.not_enabled")}}
- {{/if}}
-
-
-
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-second-factor-backup-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-second-factor-backup-test.js
index 71642244377..1da4c77afd7 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-second-factor-backup-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-second-factor-backup-test.js
@@ -48,12 +48,10 @@ acceptance("User Preferences - Second Factor Backup", function (needs) {
updateCurrentUser({ second_factor_enabled: true });
await visit("/u/eviltrout/preferences/second-factor");
- if (exists(".new-second-factor-backup")) {
- // if codes don't exist yet, create them
- await click(".new-second-factor-backup");
- await click(".second-factor-backup-edit-modal .btn-primary");
- await click(".modal-close");
- }
+ // create backup codes
+ await click(".new-second-factor-backup");
+ await click(".second-factor-backup-edit-modal .btn-primary");
+ await click(".second-factor-backup-edit-modal .modal-close");
await click(".two-factor-backup-dropdown .select-kit-header");
await click("li[data-name='Disable'");