DEV: Convert core controllers to native class syntax (batch 3) (#28224)
Changes made using the ember-native-class-codemod, plus some manual tweaks
This commit is contained in:
parent
854b8b7093
commit
75d11bfeba
|
@ -16,368 +16,362 @@ import getUrl from "discourse-common/lib/get-url";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
export default Controller.extend(
|
export default class InvitesShowController extends Controller.extend(
|
||||||
PasswordValidation,
|
PasswordValidation,
|
||||||
UsernameValidation,
|
UsernameValidation,
|
||||||
NameValidation,
|
NameValidation,
|
||||||
UserFieldsValidation,
|
UserFieldsValidation
|
||||||
{
|
) {
|
||||||
queryParams: ["t"],
|
queryParams = ["t"];
|
||||||
|
|
||||||
invitedBy: readOnly("model.invited_by"),
|
@readOnly("model.invited_by") invitedBy;
|
||||||
email: alias("model.email"),
|
@alias("model.email") email;
|
||||||
accountEmail: alias("email"),
|
@alias("email") accountEmail;
|
||||||
existingUserId: readOnly("model.existing_user_id"),
|
@readOnly("model.existing_user_id") existingUserId;
|
||||||
existingUserCanRedeem: readOnly("model.existing_user_can_redeem"),
|
@readOnly("model.existing_user_can_redeem") existingUserCanRedeem;
|
||||||
existingUserCanRedeemError: readOnly(
|
@readOnly("model.existing_user_can_redeem_error") existingUserCanRedeemError;
|
||||||
"model.existing_user_can_redeem_error"
|
@bool("existingUserId") existingUserRedeeming;
|
||||||
),
|
@alias("model.hidden_email") hiddenEmail;
|
||||||
existingUserRedeeming: bool("existingUserId"),
|
@alias("model.email_verified_by_link") emailVerifiedByLink;
|
||||||
hiddenEmail: alias("model.hidden_email"),
|
@alias("model.different_external_email") differentExternalEmail;
|
||||||
emailVerifiedByLink: alias("model.email_verified_by_link"),
|
@alias("model.username") accountUsername;
|
||||||
differentExternalEmail: alias("model.different_external_email"),
|
@not("externalAuthsOnly") passwordRequired;
|
||||||
accountUsername: alias("model.username"),
|
@readOnly("model.is_invite_link") isInviteLink;
|
||||||
passwordRequired: not("externalAuthsOnly"),
|
|
||||||
successMessage: null,
|
|
||||||
errorMessage: null,
|
|
||||||
userFields: null,
|
|
||||||
authOptions: null,
|
|
||||||
inviteImageUrl: getUrl("/images/envelope.svg"),
|
|
||||||
isInviteLink: readOnly("model.is_invite_link"),
|
|
||||||
rejectedEmails: null,
|
|
||||||
maskPassword: true,
|
|
||||||
|
|
||||||
init() {
|
successMessage = null;
|
||||||
this._super(...arguments);
|
errorMessage = null;
|
||||||
|
userFields = null;
|
||||||
|
authOptions = null;
|
||||||
|
inviteImageUrl = getUrl("/images/envelope.svg");
|
||||||
|
rejectedEmails = [];
|
||||||
|
maskPassword = true;
|
||||||
|
|
||||||
this.rejectedEmails = [];
|
authenticationComplete(options) {
|
||||||
},
|
const props = {
|
||||||
|
accountUsername: options.username,
|
||||||
|
accountName: options.name,
|
||||||
|
authOptions: EmberObject.create(options),
|
||||||
|
};
|
||||||
|
|
||||||
authenticationComplete(options) {
|
if (this.isInviteLink) {
|
||||||
const props = {
|
props.email = options.email;
|
||||||
accountUsername: options.username,
|
}
|
||||||
accountName: options.name,
|
|
||||||
authOptions: EmberObject.create(options),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.isInviteLink) {
|
this.setProperties(props);
|
||||||
props.email = options.email;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.setProperties(props);
|
@discourseComputed
|
||||||
},
|
discourseConnectEnabled() {
|
||||||
|
return this.siteSettings.enable_discourse_connect;
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
discourseConnectEnabled() {
|
welcomeTitle() {
|
||||||
return this.siteSettings.enable_discourse_connect;
|
return I18n.t("invites.welcome_to", {
|
||||||
},
|
site_name: this.siteSettings.title,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed("existingUserId")
|
||||||
welcomeTitle() {
|
subheaderMessage(existingUserId) {
|
||||||
return I18n.t("invites.welcome_to", {
|
if (existingUserId) {
|
||||||
site_name: this.siteSettings.title,
|
return I18n.t("invites.existing_user_can_redeem");
|
||||||
|
} else {
|
||||||
|
return I18n.t("create_account.subheader_title");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed("email")
|
||||||
|
yourEmailMessage(email) {
|
||||||
|
return I18n.t("invites.your_email", { email });
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
externalAuthsEnabled() {
|
||||||
|
return findLoginMethods().length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
externalAuthsOnly() {
|
||||||
|
return (
|
||||||
|
!this.siteSettings.enable_local_logins &&
|
||||||
|
this.externalAuthsEnabled &&
|
||||||
|
!this.siteSettings.enable_discourse_connect
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed(
|
||||||
|
"emailValidation.failed",
|
||||||
|
"usernameValidation.failed",
|
||||||
|
"passwordValidation.failed",
|
||||||
|
"nameValidation.failed",
|
||||||
|
"userFieldsValidation.failed",
|
||||||
|
"existingUserRedeeming",
|
||||||
|
"existingUserCanRedeem"
|
||||||
|
)
|
||||||
|
submitDisabled(
|
||||||
|
emailValidationFailed,
|
||||||
|
usernameValidationFailed,
|
||||||
|
passwordValidationFailed,
|
||||||
|
nameValidationFailed,
|
||||||
|
userFieldsValidationFailed,
|
||||||
|
existingUserRedeeming,
|
||||||
|
existingUserCanRedeem
|
||||||
|
) {
|
||||||
|
if (existingUserRedeeming) {
|
||||||
|
return !existingUserCanRedeem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
emailValidationFailed ||
|
||||||
|
usernameValidationFailed ||
|
||||||
|
passwordValidationFailed ||
|
||||||
|
nameValidationFailed ||
|
||||||
|
userFieldsValidationFailed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed(
|
||||||
|
"externalAuthsEnabled",
|
||||||
|
"externalAuthsOnly",
|
||||||
|
"discourseConnectEnabled"
|
||||||
|
)
|
||||||
|
showSocialLoginAvailable(
|
||||||
|
externalAuthsEnabled,
|
||||||
|
externalAuthsOnly,
|
||||||
|
discourseConnectEnabled
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
externalAuthsEnabled && !externalAuthsOnly && !discourseConnectEnabled
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed(
|
||||||
|
"externalAuthsOnly",
|
||||||
|
"authOptions",
|
||||||
|
"emailValidation.failed",
|
||||||
|
"existingUserRedeeming"
|
||||||
|
)
|
||||||
|
shouldDisplayForm(
|
||||||
|
externalAuthsOnly,
|
||||||
|
authOptions,
|
||||||
|
emailValidationFailed,
|
||||||
|
existingUserRedeeming
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
(this.siteSettings.enable_local_logins ||
|
||||||
|
(externalAuthsOnly && authOptions && !emailValidationFailed)) &&
|
||||||
|
!this.siteSettings.enable_discourse_connect &&
|
||||||
|
!existingUserRedeeming
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
fullnameRequired() {
|
||||||
|
return (
|
||||||
|
this.siteSettings.full_name_required || this.siteSettings.enable_names
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed(
|
||||||
|
"email",
|
||||||
|
"rejectedEmails.[]",
|
||||||
|
"authOptions.email",
|
||||||
|
"authOptions.email_valid",
|
||||||
|
"hiddenEmail",
|
||||||
|
"emailVerifiedByLink",
|
||||||
|
"differentExternalEmail"
|
||||||
|
)
|
||||||
|
emailValidation(
|
||||||
|
email,
|
||||||
|
rejectedEmails,
|
||||||
|
externalAuthEmail,
|
||||||
|
externalAuthEmailValid,
|
||||||
|
hiddenEmail,
|
||||||
|
emailVerifiedByLink,
|
||||||
|
differentExternalEmail
|
||||||
|
) {
|
||||||
|
if (hiddenEmail && !differentExternalEmail) {
|
||||||
|
return EmberObject.create({
|
||||||
|
ok: true,
|
||||||
|
reason: I18n.t("user.email.ok"),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("existingUserId")
|
// If blank, fail without a reason
|
||||||
subheaderMessage(existingUserId) {
|
if (isEmpty(email)) {
|
||||||
if (existingUserId) {
|
return EmberObject.create({
|
||||||
return I18n.t("invites.existing_user_can_redeem");
|
failed: true,
|
||||||
} else {
|
});
|
||||||
return I18n.t("create_account.subheader_title");
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("email")
|
|
||||||
yourEmailMessage(email) {
|
|
||||||
return I18n.t("invites.your_email", { email });
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed
|
|
||||||
externalAuthsEnabled() {
|
|
||||||
return findLoginMethods().length > 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed
|
|
||||||
externalAuthsOnly() {
|
|
||||||
return (
|
|
||||||
!this.siteSettings.enable_local_logins &&
|
|
||||||
this.externalAuthsEnabled &&
|
|
||||||
!this.siteSettings.enable_discourse_connect
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed(
|
|
||||||
"emailValidation.failed",
|
|
||||||
"usernameValidation.failed",
|
|
||||||
"passwordValidation.failed",
|
|
||||||
"nameValidation.failed",
|
|
||||||
"userFieldsValidation.failed",
|
|
||||||
"existingUserRedeeming",
|
|
||||||
"existingUserCanRedeem"
|
|
||||||
)
|
|
||||||
submitDisabled(
|
|
||||||
emailValidationFailed,
|
|
||||||
usernameValidationFailed,
|
|
||||||
passwordValidationFailed,
|
|
||||||
nameValidationFailed,
|
|
||||||
userFieldsValidationFailed,
|
|
||||||
existingUserRedeeming,
|
|
||||||
existingUserCanRedeem
|
|
||||||
) {
|
|
||||||
if (existingUserRedeeming) {
|
|
||||||
return !existingUserCanRedeem;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
emailValidationFailed ||
|
|
||||||
usernameValidationFailed ||
|
|
||||||
passwordValidationFailed ||
|
|
||||||
nameValidationFailed ||
|
|
||||||
userFieldsValidationFailed
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed(
|
|
||||||
"externalAuthsEnabled",
|
|
||||||
"externalAuthsOnly",
|
|
||||||
"discourseConnectEnabled"
|
|
||||||
)
|
|
||||||
showSocialLoginAvailable(
|
|
||||||
externalAuthsEnabled,
|
|
||||||
externalAuthsOnly,
|
|
||||||
discourseConnectEnabled
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
externalAuthsEnabled && !externalAuthsOnly && !discourseConnectEnabled
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed(
|
|
||||||
"externalAuthsOnly",
|
|
||||||
"authOptions",
|
|
||||||
"emailValidation.failed",
|
|
||||||
"existingUserRedeeming"
|
|
||||||
)
|
|
||||||
shouldDisplayForm(
|
|
||||||
externalAuthsOnly,
|
|
||||||
authOptions,
|
|
||||||
emailValidationFailed,
|
|
||||||
existingUserRedeeming
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
(this.siteSettings.enable_local_logins ||
|
|
||||||
(externalAuthsOnly && authOptions && !emailValidationFailed)) &&
|
|
||||||
!this.siteSettings.enable_discourse_connect &&
|
|
||||||
!existingUserRedeeming
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed
|
|
||||||
fullnameRequired() {
|
|
||||||
return (
|
|
||||||
this.siteSettings.full_name_required || this.siteSettings.enable_names
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed(
|
|
||||||
"email",
|
|
||||||
"rejectedEmails.[]",
|
|
||||||
"authOptions.email",
|
|
||||||
"authOptions.email_valid",
|
|
||||||
"hiddenEmail",
|
|
||||||
"emailVerifiedByLink",
|
|
||||||
"differentExternalEmail"
|
|
||||||
)
|
|
||||||
emailValidation(
|
|
||||||
email,
|
|
||||||
rejectedEmails,
|
|
||||||
externalAuthEmail,
|
|
||||||
externalAuthEmailValid,
|
|
||||||
hiddenEmail,
|
|
||||||
emailVerifiedByLink,
|
|
||||||
differentExternalEmail
|
|
||||||
) {
|
|
||||||
if (hiddenEmail && !differentExternalEmail) {
|
|
||||||
return EmberObject.create({
|
|
||||||
ok: true,
|
|
||||||
reason: I18n.t("user.email.ok"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// If blank, fail without a reason
|
|
||||||
if (isEmpty(email)) {
|
|
||||||
return EmberObject.create({
|
|
||||||
failed: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rejectedEmails.includes(email)) {
|
|
||||||
return EmberObject.create({
|
|
||||||
failed: true,
|
|
||||||
reason: I18n.t("user.email.invalid"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (externalAuthEmail && externalAuthEmailValid) {
|
|
||||||
const provider = this.authProviderDisplayName(
|
|
||||||
this.get("authOptions.auth_provider")
|
|
||||||
);
|
|
||||||
|
|
||||||
if (externalAuthEmail === email) {
|
|
||||||
return EmberObject.create({
|
|
||||||
ok: true,
|
|
||||||
reason: I18n.t("user.email.authenticated", {
|
|
||||||
provider,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return EmberObject.create({
|
|
||||||
failed: true,
|
|
||||||
reason: I18n.t("user.email.invite_auth_email_invalid", {
|
|
||||||
provider,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (emailVerifiedByLink) {
|
|
||||||
return EmberObject.create({
|
|
||||||
ok: true,
|
|
||||||
reason: I18n.t("user.email.authenticated_by_invite"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (emailValid(email)) {
|
|
||||||
return EmberObject.create({
|
|
||||||
ok: true,
|
|
||||||
reason: I18n.t("user.email.ok"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (rejectedEmails.includes(email)) {
|
||||||
return EmberObject.create({
|
return EmberObject.create({
|
||||||
failed: true,
|
failed: true,
|
||||||
reason: I18n.t("user.email.invalid"),
|
reason: I18n.t("user.email.invalid"),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
authProviderDisplayName(providerName) {
|
if (externalAuthEmail && externalAuthEmailValid) {
|
||||||
const matchingProvider = findLoginMethods().find((provider) => {
|
const provider = this.authProviderDisplayName(
|
||||||
return provider.name === providerName;
|
this.get("authOptions.auth_provider")
|
||||||
});
|
);
|
||||||
return matchingProvider
|
|
||||||
? matchingProvider.get("prettyName")
|
|
||||||
: providerName;
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed
|
if (externalAuthEmail === email) {
|
||||||
wavingHandURL: () => wavingHandURL(),
|
return EmberObject.create({
|
||||||
|
ok: true,
|
||||||
@discourseComputed
|
reason: I18n.t("user.email.authenticated", {
|
||||||
ssoPath: () => getUrl("/session/sso"),
|
provider,
|
||||||
|
}),
|
||||||
@discourseComputed
|
});
|
||||||
disclaimerHtml() {
|
} else {
|
||||||
if (this.site.tos_url && this.site.privacy_policy_url) {
|
return EmberObject.create({
|
||||||
return I18n.t("create_account.disclaimer", {
|
failed: true,
|
||||||
tos_link: this.site.tos_url,
|
reason: I18n.t("user.email.invite_auth_email_invalid", {
|
||||||
privacy_link: this.site.privacy_policy_url,
|
provider,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("authOptions.associate_url", "authOptions.auth_provider")
|
if (emailVerifiedByLink) {
|
||||||
associateHtml(url, provider) {
|
return EmberObject.create({
|
||||||
if (!url) {
|
ok: true,
|
||||||
return;
|
reason: I18n.t("user.email.authenticated_by_invite"),
|
||||||
}
|
|
||||||
return I18n.t("create_account.associate", {
|
|
||||||
associate_link: url,
|
|
||||||
provider: I18n.t(`login.${provider}.name`),
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
if (emailValid(email)) {
|
||||||
togglePasswordMask() {
|
return EmberObject.create({
|
||||||
this.toggleProperty("maskPassword");
|
ok: true,
|
||||||
},
|
reason: I18n.t("user.email.ok"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
actions: {
|
return EmberObject.create({
|
||||||
submit() {
|
failed: true,
|
||||||
const userFields = this.userFields;
|
reason: I18n.t("user.email.invalid"),
|
||||||
let userCustomFields = {};
|
});
|
||||||
if (!isEmpty(userFields)) {
|
|
||||||
userFields.forEach(function (f) {
|
|
||||||
userCustomFields[f.get("field.id")] = f.get("value");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
username: this.accountUsername,
|
|
||||||
name: this.accountName,
|
|
||||||
password: this.accountPassword,
|
|
||||||
user_custom_fields: userCustomFields,
|
|
||||||
timezone: moment.tz.guess(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.isInviteLink) {
|
|
||||||
data.email = this.email;
|
|
||||||
} else {
|
|
||||||
data.email_token = this.t;
|
|
||||||
}
|
|
||||||
|
|
||||||
ajax({
|
|
||||||
url: `/invites/show/${this.get("model.token")}.json`,
|
|
||||||
type: "PUT",
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
.then((result) => {
|
|
||||||
if (result.success) {
|
|
||||||
this.set(
|
|
||||||
"successMessage",
|
|
||||||
result.message || I18n.t("invites.success")
|
|
||||||
);
|
|
||||||
if (result.redirect_to) {
|
|
||||||
DiscourseURL.redirectTo(result.redirect_to);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
result.errors &&
|
|
||||||
result.errors.email &&
|
|
||||||
result.errors.email.length > 0 &&
|
|
||||||
result.values
|
|
||||||
) {
|
|
||||||
this.rejectedEmails.pushObject(result.values.email);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
result.errors &&
|
|
||||||
result.errors.password &&
|
|
||||||
result.errors.password.length > 0
|
|
||||||
) {
|
|
||||||
this.rejectedPasswords.pushObject(this.accountPassword);
|
|
||||||
this.rejectedPasswordsMessages.set(
|
|
||||||
this.accountPassword,
|
|
||||||
result.errors.password[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (result.message) {
|
|
||||||
this.set("errorMessage", result.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.set("errorMessage", extractError(error));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
externalLogin(provider) {
|
|
||||||
provider.doLogin({
|
|
||||||
signup: true,
|
|
||||||
params: {
|
|
||||||
origin: window.location.href,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
authProviderDisplayName(providerName) {
|
||||||
|
const matchingProvider = findLoginMethods().find((provider) => {
|
||||||
|
return provider.name === providerName;
|
||||||
|
});
|
||||||
|
return matchingProvider ? matchingProvider.get("prettyName") : providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
wavingHandURL() {
|
||||||
|
return wavingHandURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
ssoPath() {
|
||||||
|
return getUrl("/session/sso");
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
disclaimerHtml() {
|
||||||
|
if (this.site.tos_url && this.site.privacy_policy_url) {
|
||||||
|
return I18n.t("create_account.disclaimer", {
|
||||||
|
tos_link: this.site.tos_url,
|
||||||
|
privacy_link: this.site.privacy_policy_url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed("authOptions.associate_url", "authOptions.auth_provider")
|
||||||
|
associateHtml(url, provider) {
|
||||||
|
if (!url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return I18n.t("create_account.associate", {
|
||||||
|
associate_link: url,
|
||||||
|
provider: I18n.t(`login.${provider}.name`),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
togglePasswordMask() {
|
||||||
|
this.toggleProperty("maskPassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
submit() {
|
||||||
|
const userFields = this.userFields;
|
||||||
|
let userCustomFields = {};
|
||||||
|
if (!isEmpty(userFields)) {
|
||||||
|
userFields.forEach(function (f) {
|
||||||
|
userCustomFields[f.get("field.id")] = f.get("value");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
username: this.accountUsername,
|
||||||
|
name: this.accountName,
|
||||||
|
password: this.accountPassword,
|
||||||
|
user_custom_fields: userCustomFields,
|
||||||
|
timezone: moment.tz.guess(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.isInviteLink) {
|
||||||
|
data.email = this.email;
|
||||||
|
} else {
|
||||||
|
data.email_token = this.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
ajax({
|
||||||
|
url: `/invites/show/${this.get("model.token")}.json`,
|
||||||
|
type: "PUT",
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result.success) {
|
||||||
|
this.set(
|
||||||
|
"successMessage",
|
||||||
|
result.message || I18n.t("invites.success")
|
||||||
|
);
|
||||||
|
if (result.redirect_to) {
|
||||||
|
DiscourseURL.redirectTo(result.redirect_to);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
result.errors &&
|
||||||
|
result.errors.email &&
|
||||||
|
result.errors.email.length > 0 &&
|
||||||
|
result.values
|
||||||
|
) {
|
||||||
|
this.rejectedEmails.pushObject(result.values.email);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
result.errors &&
|
||||||
|
result.errors.password &&
|
||||||
|
result.errors.password.length > 0
|
||||||
|
) {
|
||||||
|
this.rejectedPasswords.pushObject(this.accountPassword);
|
||||||
|
this.rejectedPasswordsMessages.set(
|
||||||
|
this.accountPassword,
|
||||||
|
result.errors.password[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (result.message) {
|
||||||
|
this.set("errorMessage", result.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.set("errorMessage", extractError(error));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
externalLogin(provider) {
|
||||||
|
provider.doLogin({
|
||||||
|
signup: true,
|
||||||
|
params: {
|
||||||
|
origin: window.location.href,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,23 +11,26 @@ import getURL from "discourse-common/lib/get-url";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
export default Controller.extend(PasswordValidation, {
|
export default class PasswordResetController extends Controller.extend(
|
||||||
isDeveloper: alias("model.is_developer"),
|
PasswordValidation
|
||||||
admin: alias("model.admin"),
|
) {
|
||||||
secondFactorRequired: alias("model.second_factor_required"),
|
@alias("model.is_developer") isDeveloper;
|
||||||
securityKeyRequired: alias("model.security_key_required"),
|
@alias("model.admin") admin;
|
||||||
backupEnabled: alias("model.backup_enabled"),
|
@alias("model.second_factor_required") secondFactorRequired;
|
||||||
securityKeyOrSecondFactorRequired: or(
|
@alias("model.security_key_required") securityKeyRequired;
|
||||||
"model.second_factor_required",
|
@alias("model.backup_enabled") backupEnabled;
|
||||||
"model.security_key_required"
|
@or("model.second_factor_required", "model.security_key_required")
|
||||||
),
|
securityKeyOrSecondFactorRequired;
|
||||||
otherMethodAllowed: readOnly("model.multiple_second_factor_methods"),
|
@readOnly("model.multiple_second_factor_methods") otherMethodAllowed;
|
||||||
passwordRequired: true,
|
|
||||||
errorMessage: null,
|
passwordRequired = true;
|
||||||
successMessage: null,
|
errorMessage = null;
|
||||||
requiresApproval: false,
|
successMessage = null;
|
||||||
redirected: false,
|
requiresApproval = false;
|
||||||
maskPassword: true,
|
redirected = false;
|
||||||
|
maskPassword = true;
|
||||||
|
|
||||||
|
lockImageUrl = getURL("/images/lock.svg");
|
||||||
|
|
||||||
@discourseComputed("securityKeyRequired", "selectedSecondFactorMethod")
|
@discourseComputed("securityKeyRequired", "selectedSecondFactorMethod")
|
||||||
displaySecurityKeyForm(securityKeyRequired, selectedSecondFactorMethod) {
|
displaySecurityKeyForm(securityKeyRequired, selectedSecondFactorMethod) {
|
||||||
|
@ -35,7 +38,7 @@ export default Controller.extend(PasswordValidation, {
|
||||||
securityKeyRequired &&
|
securityKeyRequired &&
|
||||||
selectedSecondFactorMethod === SECOND_FACTOR_METHODS.SECURITY_KEY
|
selectedSecondFactorMethod === SECOND_FACTOR_METHODS.SECURITY_KEY
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
initSelectedSecondFactorMethod() {
|
initSelectedSecondFactorMethod() {
|
||||||
if (this.model.security_key_required) {
|
if (this.model.security_key_required) {
|
||||||
|
@ -48,21 +51,19 @@ export default Controller.extend(PasswordValidation, {
|
||||||
} else if (this.model.backup_enabled) {
|
} else if (this.model.backup_enabled) {
|
||||||
this.set("selectedSecondFactorMethod", SECOND_FACTOR_METHODS.BACKUP_CODE);
|
this.set("selectedSecondFactorMethod", SECOND_FACTOR_METHODS.BACKUP_CODE);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
continueButtonText() {
|
continueButtonText() {
|
||||||
return I18n.t("password_reset.continue", {
|
return I18n.t("password_reset.continue", {
|
||||||
site_name: this.siteSettings.title,
|
site_name: this.siteSettings.title,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("redirectTo")
|
@discourseComputed("redirectTo")
|
||||||
redirectHref(redirectTo) {
|
redirectHref(redirectTo) {
|
||||||
return getURL(redirectTo || "/");
|
return getURL(redirectTo || "/");
|
||||||
},
|
}
|
||||||
|
|
||||||
lockImageUrl: getURL("/images/lock.svg"),
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
done(event) {
|
done(event) {
|
||||||
|
@ -73,12 +74,12 @@ export default Controller.extend(PasswordValidation, {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.set("redirected", true);
|
this.set("redirected", true);
|
||||||
DiscourseURL.redirectTo(this.redirectTo || "/");
|
DiscourseURL.redirectTo(this.redirectTo || "/");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
togglePasswordMask() {
|
togglePasswordMask() {
|
||||||
this.toggleProperty("maskPassword");
|
this.toggleProperty("maskPassword");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async submit() {
|
async submit() {
|
||||||
|
@ -138,7 +139,7 @@ export default Controller.extend(PasswordValidation, {
|
||||||
throw new Error(e);
|
throw new Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
authenticateSecurityKey() {
|
authenticateSecurityKey() {
|
||||||
|
@ -159,5 +160,5 @@ export default Controller.extend(PasswordValidation, {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
export default Controller.extend({});
|
export default class PreferencesController extends Controller {}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
import { action } from "@ember/object";
|
||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
import { underscore } from "@ember/string";
|
import { underscore } from "@ember/string";
|
||||||
import { isPresent } from "@ember/utils";
|
import { isPresent } from "@ember/utils";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class ReviewIndexController extends Controller {
|
||||||
queryParams: [
|
queryParams = [
|
||||||
"priority",
|
"priority",
|
||||||
"type",
|
"type",
|
||||||
"status",
|
"status",
|
||||||
|
@ -18,26 +19,21 @@ export default Controller.extend({
|
||||||
"to_date",
|
"to_date",
|
||||||
"sort_order",
|
"sort_order",
|
||||||
"additional_filters",
|
"additional_filters",
|
||||||
],
|
];
|
||||||
type: null,
|
|
||||||
status: "pending",
|
|
||||||
priority: "low",
|
|
||||||
category_id: null,
|
|
||||||
reviewables: null,
|
|
||||||
topic_id: null,
|
|
||||||
filtersExpanded: false,
|
|
||||||
username: "",
|
|
||||||
reviewed_by: "",
|
|
||||||
from_date: null,
|
|
||||||
to_date: null,
|
|
||||||
sort_order: null,
|
|
||||||
additional_filters: null,
|
|
||||||
|
|
||||||
init(...args) {
|
type = null;
|
||||||
this._super(...args);
|
status = "pending";
|
||||||
this.set("priority", this.siteSettings.reviewable_default_visibility);
|
priority = this.siteSettings.reviewable_default_visibility;
|
||||||
this.set("filtersExpanded", this.site.desktopView);
|
category_id = null;
|
||||||
},
|
reviewables = null;
|
||||||
|
topic_id = null;
|
||||||
|
filtersExpanded = this.site.desktopView;
|
||||||
|
username = "";
|
||||||
|
reviewed_by = "";
|
||||||
|
from_date = null;
|
||||||
|
to_date = null;
|
||||||
|
sort_order = null;
|
||||||
|
additional_filters = null;
|
||||||
|
|
||||||
@discourseComputed("reviewableTypes")
|
@discourseComputed("reviewableTypes")
|
||||||
allTypes() {
|
allTypes() {
|
||||||
|
@ -49,7 +45,7 @@ export default Controller.extend({
|
||||||
name: I18n.t(`review.types.${translationKey}.title`),
|
name: I18n.t(`review.types.${translationKey}.title`),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
priorities() {
|
priorities() {
|
||||||
|
@ -59,7 +55,7 @@ export default Controller.extend({
|
||||||
name: I18n.t(`review.filters.priority.${priority}`),
|
name: I18n.t(`review.filters.priority.${priority}`),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
sortOrders() {
|
sortOrders() {
|
||||||
|
@ -71,7 +67,7 @@ export default Controller.extend({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
statuses() {
|
statuses() {
|
||||||
|
@ -86,110 +82,115 @@ export default Controller.extend({
|
||||||
].map((id) => {
|
].map((id) => {
|
||||||
return { id, name: I18n.t(`review.statuses.${id}.title`) };
|
return { id, name: I18n.t(`review.statuses.${id}.title`) };
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("filtersExpanded")
|
@discourseComputed("filtersExpanded")
|
||||||
toggleFiltersIcon(filtersExpanded) {
|
toggleFiltersIcon(filtersExpanded) {
|
||||||
return filtersExpanded ? "chevron-up" : "chevron-down";
|
return filtersExpanded ? "chevron-up" : "chevron-down";
|
||||||
},
|
}
|
||||||
|
|
||||||
setRange(range) {
|
setRange(range) {
|
||||||
this.setProperties(range);
|
this.setProperties(range);
|
||||||
},
|
}
|
||||||
|
|
||||||
refreshModel() {
|
refreshModel() {
|
||||||
next(() => this.send("refreshRoute"));
|
next(() => this.send("refreshRoute"));
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
remove(ids) {
|
remove(ids) {
|
||||||
if (!ids) {
|
if (!ids) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let newList = this.reviewables.reject((reviewable) => {
|
let newList = this.reviewables.reject((reviewable) => {
|
||||||
return ids.includes(reviewable.id);
|
return ids.includes(reviewable.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newList.length === 0) {
|
if (newList.length === 0) {
|
||||||
this.refreshModel();
|
|
||||||
} else {
|
|
||||||
this.reviewables.setObjects(newList);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
resetTopic() {
|
|
||||||
this.set("topic_id", null);
|
|
||||||
this.refreshModel();
|
this.refreshModel();
|
||||||
},
|
} else {
|
||||||
|
this.reviewables.setObjects(newList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
refresh() {
|
@action
|
||||||
const currentStatus = this.status;
|
resetTopic() {
|
||||||
const nextStatus = this.filterStatus;
|
this.set("topic_id", null);
|
||||||
const currentOrder = this.sort_order;
|
this.refreshModel();
|
||||||
let nextOrder = this.filterSortOrder;
|
}
|
||||||
|
|
||||||
const createdAtStatuses = ["reviewed", "all"];
|
@action
|
||||||
const priorityStatuses = [
|
refresh() {
|
||||||
"approved",
|
const currentStatus = this.status;
|
||||||
"rejected",
|
const nextStatus = this.filterStatus;
|
||||||
"deleted",
|
const currentOrder = this.sort_order;
|
||||||
"ignored",
|
let nextOrder = this.filterSortOrder;
|
||||||
"pending",
|
|
||||||
];
|
|
||||||
|
|
||||||
if (
|
const createdAtStatuses = ["reviewed", "all"];
|
||||||
createdAtStatuses.includes(currentStatus) &&
|
const priorityStatuses = [
|
||||||
currentOrder === "created_at" &&
|
"approved",
|
||||||
priorityStatuses.includes(nextStatus) &&
|
"rejected",
|
||||||
nextOrder === "created_at"
|
"deleted",
|
||||||
) {
|
"ignored",
|
||||||
nextOrder = "score";
|
"pending",
|
||||||
}
|
];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
priorityStatuses.includes(currentStatus) &&
|
createdAtStatuses.includes(currentStatus) &&
|
||||||
currentOrder === "score" &&
|
currentOrder === "created_at" &&
|
||||||
createdAtStatuses.includes(nextStatus) &&
|
priorityStatuses.includes(nextStatus) &&
|
||||||
nextOrder === "score"
|
nextOrder === "created_at"
|
||||||
) {
|
) {
|
||||||
nextOrder = "created_at";
|
nextOrder = "score";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setProperties({
|
if (
|
||||||
type: this.filterType,
|
priorityStatuses.includes(currentStatus) &&
|
||||||
priority: this.filterPriority,
|
currentOrder === "score" &&
|
||||||
status: this.filterStatus,
|
createdAtStatuses.includes(nextStatus) &&
|
||||||
category_id: this.filterCategoryId,
|
nextOrder === "score"
|
||||||
username: this.filterUsername,
|
) {
|
||||||
reviewed_by: this.filterReviewedBy,
|
nextOrder = "created_at";
|
||||||
from_date: isPresent(this.filterFromDate)
|
}
|
||||||
? this.filterFromDate.toISOString(true).split("T")[0]
|
|
||||||
: null,
|
|
||||||
to_date: isPresent(this.filterToDate)
|
|
||||||
? this.filterToDate.toISOString(true).split("T")[0]
|
|
||||||
: null,
|
|
||||||
sort_order: nextOrder,
|
|
||||||
additional_filters: JSON.stringify(this.additionalFilters),
|
|
||||||
});
|
|
||||||
|
|
||||||
this.refreshModel();
|
this.setProperties({
|
||||||
},
|
type: this.filterType,
|
||||||
|
priority: this.filterPriority,
|
||||||
|
status: this.filterStatus,
|
||||||
|
category_id: this.filterCategoryId,
|
||||||
|
username: this.filterUsername,
|
||||||
|
reviewed_by: this.filterReviewedBy,
|
||||||
|
from_date: isPresent(this.filterFromDate)
|
||||||
|
? this.filterFromDate.toISOString(true).split("T")[0]
|
||||||
|
: null,
|
||||||
|
to_date: isPresent(this.filterToDate)
|
||||||
|
? this.filterToDate.toISOString(true).split("T")[0]
|
||||||
|
: null,
|
||||||
|
sort_order: nextOrder,
|
||||||
|
additional_filters: JSON.stringify(this.additionalFilters),
|
||||||
|
});
|
||||||
|
|
||||||
loadMore() {
|
this.refreshModel();
|
||||||
return this.reviewables.loadMore();
|
}
|
||||||
},
|
|
||||||
|
|
||||||
toggleFilters() {
|
@action
|
||||||
this.toggleProperty("filtersExpanded");
|
loadMore() {
|
||||||
},
|
return this.reviewables.loadMore();
|
||||||
|
}
|
||||||
|
|
||||||
updateFilterReviewedBy(selected) {
|
@action
|
||||||
this.set("filterReviewedBy", selected.firstObject);
|
toggleFilters() {
|
||||||
},
|
this.toggleProperty("filtersExpanded");
|
||||||
|
}
|
||||||
|
|
||||||
updateFilterUsername(selected) {
|
@action
|
||||||
this.set("filterUsername", selected.firstObject);
|
updateFilterReviewedBy(selected) {
|
||||||
},
|
this.set("filterReviewedBy", selected.firstObject);
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
@action
|
||||||
|
updateFilterUsername(selected) {
|
||||||
|
this.set("filterUsername", selected.firstObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
import { action } from "@ember/object";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class ReviewSettingsController extends Controller {
|
||||||
saving: false,
|
saving = false;
|
||||||
saved: false,
|
saved = false;
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
save() {
|
save() {
|
||||||
let priorities = {};
|
let priorities = {};
|
||||||
this.scoreTypes.forEach((st) => {
|
this.scoreTypes.forEach((st) => {
|
||||||
priorities[st.id] = parseFloat(st.reviewable_priority);
|
priorities[st.id] = parseFloat(st.reviewable_priority);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set("saving", true);
|
this.set("saving", true);
|
||||||
ajax("/review/settings", {
|
ajax("/review/settings", {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { reviewable_priorities: priorities },
|
data: { reviewable_priorities: priorities },
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.set("saved", true);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.catch(popupAjaxError)
|
||||||
this.set("saved", true);
|
.finally(() => this.set("saving", false));
|
||||||
})
|
}
|
||||||
.catch(popupAjaxError)
|
|
||||||
.finally(() => this.set("saving", false));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("settings.reviewable_score_types")
|
@discourseComputed("settings.reviewable_score_types")
|
||||||
scoreTypes(types) {
|
scoreTypes(types) {
|
||||||
|
@ -36,5 +36,5 @@ export default Controller.extend({
|
||||||
...type,
|
...type,
|
||||||
title: type.title.replace("%{username}", username),
|
title: type.title.replace("%{username}", username),
|
||||||
}));
|
}));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -10,45 +10,42 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
const { TOTP, BACKUP_CODE, SECURITY_KEY } = SECOND_FACTOR_METHODS;
|
const { TOTP, BACKUP_CODE, SECURITY_KEY } = SECOND_FACTOR_METHODS;
|
||||||
export default Controller.extend({
|
export default class SecondFactorAuthController extends Controller {
|
||||||
TOTP,
|
TOTP = TOTP;
|
||||||
BACKUP_CODE,
|
BACKUP_CODE = BACKUP_CODE;
|
||||||
SECURITY_KEY,
|
SECURITY_KEY = SECURITY_KEY;
|
||||||
|
queryParams = ["nonce"];
|
||||||
|
message = null;
|
||||||
|
loadError = false;
|
||||||
|
messageIsError = false;
|
||||||
|
secondFactorToken = null;
|
||||||
|
userSelectedMethod = null;
|
||||||
|
|
||||||
queryParams: ["nonce"],
|
@readOnly("model.totp_enabled") totpEnabled;
|
||||||
|
@readOnly("model.backup_enabled") backupCodesEnabled;
|
||||||
message: null,
|
@readOnly("model.security_keys_enabled") securityKeysEnabled;
|
||||||
loadError: false,
|
@readOnly("model.allowed_methods") allowedMethods;
|
||||||
messageIsError: false,
|
@readOnly("model.description") customDescription;
|
||||||
secondFactorToken: null,
|
@equal("shownSecondFactorMethod", TOTP) showTotpForm;
|
||||||
userSelectedMethod: null,
|
@equal("shownSecondFactorMethod", SECURITY_KEY) showSecurityKeyForm;
|
||||||
|
@equal("shownSecondFactorMethod", BACKUP_CODE) showBackupCodesForm;
|
||||||
totpEnabled: readOnly("model.totp_enabled"),
|
|
||||||
backupCodesEnabled: readOnly("model.backup_enabled"),
|
|
||||||
securityKeysEnabled: readOnly("model.security_keys_enabled"),
|
|
||||||
allowedMethods: readOnly("model.allowed_methods"),
|
|
||||||
customDescription: readOnly("model.description"),
|
|
||||||
|
|
||||||
showTotpForm: equal("shownSecondFactorMethod", TOTP),
|
|
||||||
showSecurityKeyForm: equal("shownSecondFactorMethod", SECURITY_KEY),
|
|
||||||
showBackupCodesForm: equal("shownSecondFactorMethod", BACKUP_CODE),
|
|
||||||
|
|
||||||
@discourseComputed("allowedMethods.[]", "totpEnabled")
|
@discourseComputed("allowedMethods.[]", "totpEnabled")
|
||||||
totpAvailable() {
|
totpAvailable() {
|
||||||
return this.totpEnabled && this.allowedMethods.includes(TOTP);
|
return this.totpEnabled && this.allowedMethods.includes(TOTP);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("allowedMethods.[]", "backupCodesEnabled")
|
@discourseComputed("allowedMethods.[]", "backupCodesEnabled")
|
||||||
backupCodesAvailable() {
|
backupCodesAvailable() {
|
||||||
return this.backupCodesEnabled && this.allowedMethods.includes(BACKUP_CODE);
|
return this.backupCodesEnabled && this.allowedMethods.includes(BACKUP_CODE);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("allowedMethods.[]", "securityKeysEnabled")
|
@discourseComputed("allowedMethods.[]", "securityKeysEnabled")
|
||||||
securityKeysAvailable() {
|
securityKeysAvailable() {
|
||||||
return (
|
return (
|
||||||
this.securityKeysEnabled && this.allowedMethods.includes(SECURITY_KEY)
|
this.securityKeysEnabled && this.allowedMethods.includes(SECURITY_KEY)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"userSelectedMethod",
|
"userSelectedMethod",
|
||||||
|
@ -75,7 +72,7 @@ export default Controller.extend({
|
||||||
throw new Error("unexpected state of user 2fa settings!");
|
throw new Error("unexpected state of user 2fa settings!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"shownSecondFactorMethod",
|
"shownSecondFactorMethod",
|
||||||
|
@ -115,7 +112,7 @@ export default Controller.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return alts;
|
return alts;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("shownSecondFactorMethod")
|
@discourseComputed("shownSecondFactorMethod")
|
||||||
secondFactorTitle(shownSecondFactorMethod) {
|
secondFactorTitle(shownSecondFactorMethod) {
|
||||||
|
@ -127,7 +124,7 @@ export default Controller.extend({
|
||||||
case BACKUP_CODE:
|
case BACKUP_CODE:
|
||||||
return I18n.t("login.second_factor_backup_title");
|
return I18n.t("login.second_factor_backup_title");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("shownSecondFactorMethod")
|
@discourseComputed("shownSecondFactorMethod")
|
||||||
secondFactorDescription(shownSecondFactorMethod) {
|
secondFactorDescription(shownSecondFactorMethod) {
|
||||||
|
@ -139,7 +136,7 @@ export default Controller.extend({
|
||||||
case BACKUP_CODE:
|
case BACKUP_CODE:
|
||||||
return I18n.t("login.second_factor_backup_description");
|
return I18n.t("login.second_factor_backup_description");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("messageIsError")
|
@discourseComputed("messageIsError")
|
||||||
alertClass(messageIsError) {
|
alertClass(messageIsError) {
|
||||||
|
@ -148,7 +145,7 @@ export default Controller.extend({
|
||||||
} else {
|
} else {
|
||||||
return "alert-success";
|
return "alert-success";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("showTotpForm", "showBackupCodesForm")
|
@discourseComputed("showTotpForm", "showBackupCodesForm")
|
||||||
inputFormClass(showTotpForm, showBackupCodesForm) {
|
inputFormClass(showTotpForm, showBackupCodesForm) {
|
||||||
|
@ -157,7 +154,7 @@ export default Controller.extend({
|
||||||
} else if (showBackupCodesForm) {
|
} else if (showBackupCodesForm) {
|
||||||
return "backup-code-token";
|
return "backup-code-token";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
resetState() {
|
resetState() {
|
||||||
this.set("message", null);
|
this.set("message", null);
|
||||||
|
@ -165,17 +162,17 @@ export default Controller.extend({
|
||||||
this.set("secondFactorToken", null);
|
this.set("secondFactorToken", null);
|
||||||
this.set("userSelectedMethod", null);
|
this.set("userSelectedMethod", null);
|
||||||
this.set("loadError", false);
|
this.set("loadError", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
displayError(message) {
|
displayError(message) {
|
||||||
this.set("message", message);
|
this.set("message", message);
|
||||||
this.set("messageIsError", true);
|
this.set("messageIsError", true);
|
||||||
},
|
}
|
||||||
|
|
||||||
displaySuccess(message) {
|
displaySuccess(message) {
|
||||||
this.set("message", message);
|
this.set("message", message);
|
||||||
this.set("messageIsError", false);
|
this.set("messageIsError", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
verifySecondFactor(data) {
|
verifySecondFactor(data) {
|
||||||
return ajax("/session/2fa", {
|
return ajax("/session/2fa", {
|
||||||
|
@ -207,13 +204,13 @@ export default Controller.extend({
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.displayError(extractError(error));
|
this.displayError(extractError(error));
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
useAnotherMethod(newMethod, event) {
|
useAnotherMethod(newMethod, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.set("userSelectedMethod", newMethod);
|
this.set("userSelectedMethod", newMethod);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
authenticateSecurityKey() {
|
authenticateSecurityKey() {
|
||||||
|
@ -227,10 +224,10 @@ export default Controller.extend({
|
||||||
this.displayError(errorMessage);
|
this.displayError(errorMessage);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
authenticateToken() {
|
authenticateToken() {
|
||||||
this.verifySecondFactor({ second_factor_token: this.secondFactorToken });
|
this.verifySecondFactor({ second_factor_token: this.secondFactorToken });
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
|
import { action } from "@ember/object";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class TagGroupsEditController extends Controller {
|
||||||
router: service(),
|
@service router;
|
||||||
tagGroups: controller(),
|
@controller tagGroups;
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
const tagGroups = this.tagGroups.model;
|
const tagGroups = this.tagGroups.model;
|
||||||
tagGroups.removeObject(this.model);
|
tagGroups.removeObject(this.model);
|
||||||
|
|
||||||
this.router.transitionTo("tagGroups.index");
|
this.router.transitionTo("tagGroups.index");
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
|
import { action } from "@ember/object";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class TagGroupsNewController extends Controller {
|
||||||
router: service(),
|
@service router;
|
||||||
tagGroups: controller(),
|
@controller tagGroups;
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
onSave() {
|
onSave() {
|
||||||
const tagGroups = this.tagGroups.model;
|
const tagGroups = this.tagGroups.model;
|
||||||
tagGroups.pushObject(this.model);
|
tagGroups.pushObject(this.model);
|
||||||
|
|
||||||
this.router.transitionTo("tagGroups.index");
|
this.router.transitionTo("tagGroups.index");
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
import { action } from "@ember/object";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class TagGroupsController extends Controller {
|
||||||
router: service(),
|
@service router;
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
newTagGroup() {
|
newTagGroup() {
|
||||||
this.router.transitionTo("tagGroups.new");
|
this.router.transitionTo("tagGroups.new");
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
|
@ -8,18 +8,20 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class TagsIndexController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
modal: service(),
|
@service modal;
|
||||||
sortedByCount: true,
|
|
||||||
sortedByName: false,
|
sortedByCount = true;
|
||||||
sortAlphabetically: alias("siteSettings.tags_sort_alphabetically"),
|
sortedByName = false;
|
||||||
canAdminTags: alias("currentUser.staff"),
|
|
||||||
groupedByCategory: notEmpty("model.extras.categories"),
|
@alias("siteSettings.tags_sort_alphabetically") sortAlphabetically;
|
||||||
groupedByTagGroup: notEmpty("model.extras.tag_groups"),
|
@alias("currentUser.staff") canAdminTags;
|
||||||
|
@notEmpty("model.extras.categories") groupedByCategory;
|
||||||
|
@notEmpty("model.extras.tag_groups") groupedByTagGroup;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
super.init(...arguments);
|
||||||
|
|
||||||
const isAlphaSort = this.sortAlphabetically;
|
const isAlphaSort = this.sortAlphabetically;
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ export default Controller.extend({
|
||||||
sortedByName: isAlphaSort ? true : false,
|
sortedByName: isAlphaSort ? true : false,
|
||||||
sortProperties: isAlphaSort ? ["id"] : ["totalCount:desc", "id"],
|
sortProperties: isAlphaSort ? ["id"] : ["totalCount:desc", "id"],
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("groupedByCategory", "groupedByTagGroup")
|
@discourseComputed("groupedByCategory", "groupedByTagGroup")
|
||||||
otherTagsTitleKey(groupedByCategory, groupedByTagGroup) {
|
otherTagsTitleKey(groupedByCategory, groupedByTagGroup) {
|
||||||
|
@ -37,7 +39,7 @@ export default Controller.extend({
|
||||||
} else {
|
} else {
|
||||||
return "tagging.other_tags";
|
return "tagging.other_tags";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
actionsMapping() {
|
actionsMapping() {
|
||||||
|
@ -46,7 +48,7 @@ export default Controller.extend({
|
||||||
uploadTags: () => this.send("showUploader"),
|
uploadTags: () => this.send("showUploader"),
|
||||||
deleteUnusedTags: () => this.send("deleteUnused"),
|
deleteUnusedTags: () => this.send("deleteUnused"),
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
sortByCount(event) {
|
sortByCount(event) {
|
||||||
|
@ -56,7 +58,7 @@ export default Controller.extend({
|
||||||
sortedByCount: true,
|
sortedByCount: true,
|
||||||
sortedByName: false,
|
sortedByName: false,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
sortById(event) {
|
sortById(event) {
|
||||||
|
@ -66,53 +68,53 @@ export default Controller.extend({
|
||||||
sortedByCount: false,
|
sortedByCount: false,
|
||||||
sortedByName: true,
|
sortedByName: true,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
showUploader() {
|
showUploader() {
|
||||||
this.modal.show(TagUpload);
|
this.modal.show(TagUpload);
|
||||||
},
|
}
|
||||||
|
|
||||||
deleteUnused() {
|
@action
|
||||||
ajax("/tags/unused", { type: "GET" })
|
deleteUnused() {
|
||||||
.then((result) => {
|
ajax("/tags/unused", { type: "GET" })
|
||||||
const displayN = 20;
|
.then((result) => {
|
||||||
const tags = result["tags"];
|
const displayN = 20;
|
||||||
|
const tags = result["tags"];
|
||||||
|
|
||||||
if (tags.length === 0) {
|
if (tags.length === 0) {
|
||||||
this.dialog.alert(I18n.t("tagging.delete_no_unused_tags"));
|
this.dialog.alert(I18n.t("tagging.delete_no_unused_tags"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const joinedTags = tags
|
const joinedTags = tags
|
||||||
.slice(0, displayN)
|
.slice(0, displayN)
|
||||||
.join(I18n.t("tagging.tag_list_joiner"));
|
.join(I18n.t("tagging.tag_list_joiner"));
|
||||||
const more = Math.max(0, tags.length - displayN);
|
const more = Math.max(0, tags.length - displayN);
|
||||||
|
|
||||||
const tagsString =
|
const tagsString =
|
||||||
more === 0
|
more === 0
|
||||||
? joinedTags
|
? joinedTags
|
||||||
: I18n.t("tagging.delete_unused_confirmation_more_tags", {
|
: I18n.t("tagging.delete_unused_confirmation_more_tags", {
|
||||||
count: more,
|
count: more,
|
||||||
tags: joinedTags,
|
tags: joinedTags,
|
||||||
});
|
});
|
||||||
|
|
||||||
const message = I18n.t("tagging.delete_unused_confirmation", {
|
const message = I18n.t("tagging.delete_unused_confirmation", {
|
||||||
count: tags.length,
|
count: tags.length,
|
||||||
tags: tagsString,
|
tags: tagsString,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dialog.deleteConfirm({
|
this.dialog.deleteConfirm({
|
||||||
message,
|
message,
|
||||||
confirmButtonLabel: "tagging.delete_unused",
|
confirmButtonLabel: "tagging.delete_unused",
|
||||||
didConfirm: () => {
|
didConfirm: () => {
|
||||||
return ajax("/tags/unused", { type: "DELETE" })
|
return ajax("/tags/unused", { type: "DELETE" })
|
||||||
.then(() => this.send("triggerRefresh"))
|
.then(() => this.send("triggerRefresh"))
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue