DEV: Convert second-factor-add-totp modal to component-based API (#22358)

This PR converts the `second-factor-add-totp` modal to make use of the new component-based API
This commit is contained in:
Isaac Janzen 2023-07-05 09:56:04 -05:00 committed by GitHub
parent 760668dfde
commit 2a598db08a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 151 additions and 162 deletions

View File

@ -0,0 +1,79 @@
<DModal
@closeModal={{@closeModal}}
@title={{i18n "user.second_factor.totp.add"}}
{{did-insert this.totpRequested}}
>
<:body>
<ConditionalLoadingSpinner @condition={{this.loading}}>
{{#if this.errorMessage}}
<div class="control-group">
<div class="controls">
<div class="alert alert-error">{{this.errorMessage}}</div>
</div>
</div>
{{/if}}
<div class="control-group">
<div class="controls">
{{html-safe (i18n "user.second_factor.enable_description")}}
</div>
</div>
<div class="control-group">
<div class="controls">
<div class="qr-code">
<img src={{html-safe this.secondFactorImage}} />
</div>
<p>
{{#if this.showSecondFactorKey}}
{{this.secondFactorKey}}
{{else}}
<a href {{on "click" this.enableShowSecondFactorKey}}>{{i18n
"user.second_factor.show_key_description"
}}</a>
{{/if}}
</p>
</div>
</div>
<div class="control-group">
<label class="control-label input-prepend">{{i18n
"user.second_factor.name"
}}</label>
<div class="controls">
<SecondFactorInput
@value={{this.secondFactorName}}
@inputId="second-factor-name"
@placeholder={{i18n "user.second_factor.totp.default_name"}}
/>
</div>
<label class="control-label input-prepend">{{i18n
"user.second_factor.label"
}}</label>
<div class="controls">
<TextField
class="second-factor-token-input"
maxlength={{6}}
@value={{this.secondFactorToken}}
@inputId="second-factor-token"
placeholder="123456"
autocorrect="off"
autocapitalize="off"
autofocus="autofocus"
/>
</div>
</div>
<div class="control-group">
<div class="controls">
<DButton
class="btn-primary add-totp"
@action={{this.enableSecondFactor}}
@label="enable"
/>
</div>
</div>
</ConditionalLoadingSpinner>
</:body>
</DModal>

View File

@ -0,0 +1,63 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";
import I18n from "I18n";
export default class SecondFactorAddTotp extends Component {
@tracked loading = false;
@tracked secondFactorImage;
@tracked secondFactorKey;
@tracked showSecondFactorKey = false;
@tracked errorMessage;
@tracked secondFactorToken;
@action
totpRequested() {
this.args.model.secondFactor
.createSecondFactorTotp()
.then((response) => {
if (response.error) {
this.errorMessage = response.error;
return;
}
this.errorMessage = null;
this.secondFactorKey = response.key;
this.secondFactorImage = response.qr;
})
.catch((error) => {
this.args.closeModal();
this.args.model.onError(error);
})
.finally(() => (this.loading = false));
}
@action
enableShowSecondFactorKey() {
this.showSecondFactorKey = true;
}
@action
enableSecondFactor() {
if (!this.secondFactorToken || !this.secondFactorName) {
this.errorMessage = I18n.t(
"user.second_factor.totp.name_and_code_required_error"
);
return;
}
this.loading = true;
this.args.model.secondFactor
.enableSecondFactorTotp(this.secondFactorToken, this.secondFactorName)
.then((response) => {
if (response.error) {
this.errorMessage = response.error;
return;
}
this.args.model.markDirty();
this.errorMessage = null;
this.args.closeModal();
})
.catch((error) => this.args.model.onError(error))
.finally(() => (this.loading = false));
}
}

View File

@ -14,6 +14,7 @@ import SecondFactorConfirmPhrase from "discourse/components/dialog-messages/seco
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";
export default Controller.extend(CanCheckEmails, {
dialog: service(),
@ -263,16 +264,15 @@ export default Controller.extend(CanCheckEmails, {
});
},
createTotp() {
const controller = showModal("second-factor-add-totp", {
model: this.model,
title: "user.second_factor.totp.add",
});
controller.setProperties({
onClose: () => this.loadSecondFactors(),
async createTotp() {
await this.modal.show(SecondFactorAddTotp, {
model: {
secondFactor: this.model,
markDirty: () => this.markDirty(),
onError: (e) => this.handleError(e),
},
});
this.loadSecondFactors();
},
async createSecurityKey() {

View File

@ -1,80 +0,0 @@
import Controller from "@ember/controller";
import { action } from "@ember/object";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
export default Controller.extend(ModalFunctionality, {
loading: false,
secondFactorImage: null,
secondFactorKey: null,
showSecondFactorKey: false,
errorMessage: null,
onShow() {
this.setProperties({
errorMessage: null,
secondFactorKey: null,
secondFactorName: null,
secondFactorToken: null,
showSecondFactorKey: false,
secondFactorImage: null,
loading: true,
});
this.model
.createSecondFactorTotp()
.then((response) => {
if (response.error) {
this.set("errorMessage", response.error);
return;
}
this.setProperties({
errorMessage: null,
secondFactorKey: response.key,
secondFactorImage: response.qr,
});
})
.catch((error) => {
this.send("closeModal");
this.onError(error);
})
.finally(() => this.set("loading", false));
},
@action
enableShowSecondFactorKey(event) {
event?.preventDefault();
this.set("showSecondFactorKey", true);
},
actions: {
showSecondFactorKey() {
this.enableShowSecondFactorKey();
},
enableSecondFactor() {
if (!this.secondFactorToken || !this.secondFactorName) {
this.set(
"errorMessage",
I18n.t("user.second_factor.totp.name_and_code_required_error")
);
return;
}
this.set("loading", true);
this.model
.enableSecondFactorTotp(this.secondFactorToken, this.secondFactorName)
.then((response) => {
if (response.error) {
this.set("errorMessage", response.error);
return;
}
this.markDirty();
this.set("errorMessage", null);
this.send("closeModal");
})
.catch((error) => this.onError(error))
.finally(() => this.set("loading", false));
},
},
});

View File

@ -1,73 +0,0 @@
<DModalBody>
<ConditionalLoadingSpinner @condition={{this.loading}}>
{{#if this.errorMessage}}
<div class="control-group">
<div class="controls">
<div class="alert alert-error">{{this.errorMessage}}</div>
</div>
</div>
{{/if}}
<div class="control-group">
<div class="controls">
{{html-safe (i18n "user.second_factor.enable_description")}}
</div>
</div>
<div class="control-group">
<div class="controls">
<div class="qr-code">
<img src={{html-safe this.secondFactorImage}} />
</div>
<p>
{{#if this.showSecondFactorKey}}
{{this.secondFactorKey}}
{{else}}
<a href {{on "click" this.enableShowSecondFactorKey}}>{{i18n
"user.second_factor.show_key_description"
}}</a>
{{/if}}
</p>
</div>
</div>
<div class="control-group">
<label class="control-label input-prepend">{{i18n
"user.second_factor.name"
}}</label>
<div class="controls">
<SecondFactorInput
@value={{this.secondFactorName}}
@inputId="second-factor-name"
@placeholder={{i18n "user.second_factor.totp.default_name"}}
/>
</div>
<label class="control-label input-prepend">{{i18n
"user.second_factor.label"
}}</label>
<div class="controls">
<TextField
@class="second-factor-token-input"
@maxlength={{6}}
@value={{this.secondFactorToken}}
@inputId="second-factor-token"
@placeholder="123456"
@autocorrect="off"
@autocapitalize="off"
@autofocus="autofocus"
/>
</div>
</div>
<div class="control-group">
<div class="controls">
<DButton
@class="btn-primary add-totp"
@action={{action "enableSecondFactor"}}
@label="enable"
/>
</div>
</div>
</ConditionalLoadingSpinner>
</DModalBody>