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:
David Taylor 2024-08-07 14:48:29 +01:00 committed by GitHub
parent 854b8b7093
commit 75d11bfeba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 1560 additions and 1519 deletions

View File

@ -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,
},
});
}
}

View File

@ -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, {
}); });
} }
); );
}, }
}); }

View File

@ -1,3 +1,3 @@
import Controller from "@ember/controller"; import Controller from "@ember/controller";
export default Controller.extend({}); export default class PreferencesController extends Controller {}

View File

@ -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);
}
}

View File

@ -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),
})); }));
}, }
}); }

View File

@ -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 });
}, }
}); }

View File

@ -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");
}, }
}, }
});

View File

@ -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");
}, }
}, }
});

View File

@ -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");
}, }
}, }
});

View File

@ -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