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:
parent
760668dfde
commit
2a598db08a
|
@ -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>
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import SecondFactorConfirmPhrase from "discourse/components/dialog-messages/seco
|
||||||
import SecondFactorAddSecurityKey from "discourse/components/modal/second-factor-add-security-key";
|
import SecondFactorAddSecurityKey from "discourse/components/modal/second-factor-add-security-key";
|
||||||
import SecondFactorEditSecurityKey from "discourse/components/modal/second-factor-edit-security-key";
|
import SecondFactorEditSecurityKey from "discourse/components/modal/second-factor-edit-security-key";
|
||||||
import SecondFactorEdit from "discourse/components/modal/second-factor-edit";
|
import SecondFactorEdit from "discourse/components/modal/second-factor-edit";
|
||||||
|
import SecondFactorAddTotp from "discourse/components/modal/second-factor-add-totp";
|
||||||
|
|
||||||
export default Controller.extend(CanCheckEmails, {
|
export default Controller.extend(CanCheckEmails, {
|
||||||
dialog: service(),
|
dialog: service(),
|
||||||
|
@ -263,16 +264,15 @@ export default Controller.extend(CanCheckEmails, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
createTotp() {
|
async createTotp() {
|
||||||
const controller = showModal("second-factor-add-totp", {
|
await this.modal.show(SecondFactorAddTotp, {
|
||||||
model: this.model,
|
model: {
|
||||||
title: "user.second_factor.totp.add",
|
secondFactor: this.model,
|
||||||
});
|
|
||||||
controller.setProperties({
|
|
||||||
onClose: () => this.loadSecondFactors(),
|
|
||||||
markDirty: () => this.markDirty(),
|
markDirty: () => this.markDirty(),
|
||||||
onError: (e) => this.handleError(e),
|
onError: (e) => this.handleError(e),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
this.loadSecondFactors();
|
||||||
},
|
},
|
||||||
|
|
||||||
async createSecurityKey() {
|
async createSecurityKey() {
|
||||||
|
|
|
@ -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));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -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>
|
|
Loading…
Reference in New Issue