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 I18n from "discourse-i18n";
export default Controller.extend(
export default class InvitesShowController extends Controller.extend(
PasswordValidation,
UsernameValidation,
NameValidation,
UserFieldsValidation,
{
queryParams: ["t"],
UserFieldsValidation
) {
queryParams = ["t"];
invitedBy: readOnly("model.invited_by"),
email: alias("model.email"),
accountEmail: alias("email"),
existingUserId: readOnly("model.existing_user_id"),
existingUserCanRedeem: readOnly("model.existing_user_can_redeem"),
existingUserCanRedeemError: readOnly(
"model.existing_user_can_redeem_error"
),
existingUserRedeeming: bool("existingUserId"),
hiddenEmail: alias("model.hidden_email"),
emailVerifiedByLink: alias("model.email_verified_by_link"),
differentExternalEmail: alias("model.different_external_email"),
accountUsername: alias("model.username"),
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,
@readOnly("model.invited_by") invitedBy;
@alias("model.email") email;
@alias("email") accountEmail;
@readOnly("model.existing_user_id") existingUserId;
@readOnly("model.existing_user_can_redeem") existingUserCanRedeem;
@readOnly("model.existing_user_can_redeem_error") existingUserCanRedeemError;
@bool("existingUserId") existingUserRedeeming;
@alias("model.hidden_email") hiddenEmail;
@alias("model.email_verified_by_link") emailVerifiedByLink;
@alias("model.different_external_email") differentExternalEmail;
@alias("model.username") accountUsername;
@not("externalAuthsOnly") passwordRequired;
@readOnly("model.is_invite_link") isInviteLink;
init() {
this._super(...arguments);
successMessage = null;
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) {
const props = {
accountUsername: options.username,
accountName: options.name,
authOptions: EmberObject.create(options),
};
if (this.isInviteLink) {
props.email = options.email;
}
if (this.isInviteLink) {
props.email = options.email;
}
this.setProperties(props);
}
this.setProperties(props);
},
@discourseComputed
discourseConnectEnabled() {
return this.siteSettings.enable_discourse_connect;
}
@discourseComputed
discourseConnectEnabled() {
return this.siteSettings.enable_discourse_connect;
},
@discourseComputed
welcomeTitle() {
return I18n.t("invites.welcome_to", {
site_name: this.siteSettings.title,
});
}
@discourseComputed
welcomeTitle() {
return I18n.t("invites.welcome_to", {
site_name: this.siteSettings.title,
@discourseComputed("existingUserId")
subheaderMessage(existingUserId) {
if (existingUserId) {
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")
subheaderMessage(existingUserId) {
if (existingUserId) {
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"),
});
}
// 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 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"),
});
},
}
authProviderDisplayName(providerName) {
const matchingProvider = findLoginMethods().find((provider) => {
return provider.name === providerName;
});
return matchingProvider
? matchingProvider.get("prettyName")
: providerName;
},
if (externalAuthEmail && externalAuthEmailValid) {
const provider = this.authProviderDisplayName(
this.get("authOptions.auth_provider")
);
@discourseComputed
wavingHandURL: () => wavingHandURL(),
@discourseComputed
ssoPath: () => 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,
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,
}),
});
}
},
}
@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`),
if (emailVerifiedByLink) {
return EmberObject.create({
ok: true,
reason: I18n.t("user.email.authenticated_by_invite"),
});
},
}
@action
togglePasswordMask() {
this.toggleProperty("maskPassword");
},
if (emailValid(email)) {
return EmberObject.create({
ok: true,
reason: I18n.t("user.email.ok"),
});
}
actions: {
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));
});
},
externalLogin(provider) {
provider.doLogin({
signup: true,
params: {
origin: window.location.href,
},
});
},
},
return EmberObject.create({
failed: true,
reason: I18n.t("user.email.invalid"),
});
}
);
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 I18n from "discourse-i18n";
export default Controller.extend(PasswordValidation, {
isDeveloper: alias("model.is_developer"),
admin: alias("model.admin"),
secondFactorRequired: alias("model.second_factor_required"),
securityKeyRequired: alias("model.security_key_required"),
backupEnabled: alias("model.backup_enabled"),
securityKeyOrSecondFactorRequired: or(
"model.second_factor_required",
"model.security_key_required"
),
otherMethodAllowed: readOnly("model.multiple_second_factor_methods"),
passwordRequired: true,
errorMessage: null,
successMessage: null,
requiresApproval: false,
redirected: false,
maskPassword: true,
export default class PasswordResetController extends Controller.extend(
PasswordValidation
) {
@alias("model.is_developer") isDeveloper;
@alias("model.admin") admin;
@alias("model.second_factor_required") secondFactorRequired;
@alias("model.security_key_required") securityKeyRequired;
@alias("model.backup_enabled") backupEnabled;
@or("model.second_factor_required", "model.security_key_required")
securityKeyOrSecondFactorRequired;
@readOnly("model.multiple_second_factor_methods") otherMethodAllowed;
passwordRequired = true;
errorMessage = null;
successMessage = null;
requiresApproval = false;
redirected = false;
maskPassword = true;
lockImageUrl = getURL("/images/lock.svg");
@discourseComputed("securityKeyRequired", "selectedSecondFactorMethod")
displaySecurityKeyForm(securityKeyRequired, selectedSecondFactorMethod) {
@ -35,7 +38,7 @@ export default Controller.extend(PasswordValidation, {
securityKeyRequired &&
selectedSecondFactorMethod === SECOND_FACTOR_METHODS.SECURITY_KEY
);
},
}
initSelectedSecondFactorMethod() {
if (this.model.security_key_required) {
@ -48,21 +51,19 @@ export default Controller.extend(PasswordValidation, {
} else if (this.model.backup_enabled) {
this.set("selectedSecondFactorMethod", SECOND_FACTOR_METHODS.BACKUP_CODE);
}
},
}
@discourseComputed()
continueButtonText() {
return I18n.t("password_reset.continue", {
site_name: this.siteSettings.title,
});
},
}
@discourseComputed("redirectTo")
redirectHref(redirectTo) {
return getURL(redirectTo || "/");
},
lockImageUrl: getURL("/images/lock.svg"),
}
@action
done(event) {
@ -73,12 +74,12 @@ export default Controller.extend(PasswordValidation, {
event.preventDefault();
this.set("redirected", true);
DiscourseURL.redirectTo(this.redirectTo || "/");
},
}
@action
togglePasswordMask() {
this.toggleProperty("maskPassword");
},
}
@action
async submit() {
@ -138,7 +139,7 @@ export default Controller.extend(PasswordValidation, {
throw new Error(e);
}
}
},
}
@action
authenticateSecurityKey() {
@ -159,5 +160,5 @@ export default Controller.extend(PasswordValidation, {
});
}
);
},
});
}
}

View File

@ -1,3 +1,3 @@
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 { action } from "@ember/object";
import { next } from "@ember/runloop";
import { underscore } from "@ember/string";
import { isPresent } from "@ember/utils";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
export default Controller.extend({
queryParams: [
export default class ReviewIndexController extends Controller {
queryParams = [
"priority",
"type",
"status",
@ -18,26 +19,21 @@ export default Controller.extend({
"to_date",
"sort_order",
"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) {
this._super(...args);
this.set("priority", this.siteSettings.reviewable_default_visibility);
this.set("filtersExpanded", this.site.desktopView);
},
type = null;
status = "pending";
priority = this.siteSettings.reviewable_default_visibility;
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")
allTypes() {
@ -49,7 +45,7 @@ export default Controller.extend({
name: I18n.t(`review.types.${translationKey}.title`),
};
});
},
}
@discourseComputed
priorities() {
@ -59,7 +55,7 @@ export default Controller.extend({
name: I18n.t(`review.filters.priority.${priority}`),
};
});
},
}
@discourseComputed
sortOrders() {
@ -71,7 +67,7 @@ export default Controller.extend({
};
}
);
},
}
@discourseComputed
statuses() {
@ -86,110 +82,115 @@ export default Controller.extend({
].map((id) => {
return { id, name: I18n.t(`review.statuses.${id}.title`) };
});
},
}
@discourseComputed("filtersExpanded")
toggleFiltersIcon(filtersExpanded) {
return filtersExpanded ? "chevron-up" : "chevron-down";
},
}
setRange(range) {
this.setProperties(range);
},
}
refreshModel() {
next(() => this.send("refreshRoute"));
},
}
actions: {
remove(ids) {
if (!ids) {
return;
}
@action
remove(ids) {
if (!ids) {
return;
}
let newList = this.reviewables.reject((reviewable) => {
return ids.includes(reviewable.id);
});
let newList = this.reviewables.reject((reviewable) => {
return ids.includes(reviewable.id);
});
if (newList.length === 0) {
this.refreshModel();
} else {
this.reviewables.setObjects(newList);
}
},
resetTopic() {
this.set("topic_id", null);
if (newList.length === 0) {
this.refreshModel();
},
} else {
this.reviewables.setObjects(newList);
}
}
refresh() {
const currentStatus = this.status;
const nextStatus = this.filterStatus;
const currentOrder = this.sort_order;
let nextOrder = this.filterSortOrder;
@action
resetTopic() {
this.set("topic_id", null);
this.refreshModel();
}
const createdAtStatuses = ["reviewed", "all"];
const priorityStatuses = [
"approved",
"rejected",
"deleted",
"ignored",
"pending",
];
@action
refresh() {
const currentStatus = this.status;
const nextStatus = this.filterStatus;
const currentOrder = this.sort_order;
let nextOrder = this.filterSortOrder;
if (
createdAtStatuses.includes(currentStatus) &&
currentOrder === "created_at" &&
priorityStatuses.includes(nextStatus) &&
nextOrder === "created_at"
) {
nextOrder = "score";
}
const createdAtStatuses = ["reviewed", "all"];
const priorityStatuses = [
"approved",
"rejected",
"deleted",
"ignored",
"pending",
];
if (
priorityStatuses.includes(currentStatus) &&
currentOrder === "score" &&
createdAtStatuses.includes(nextStatus) &&
nextOrder === "score"
) {
nextOrder = "created_at";
}
if (
createdAtStatuses.includes(currentStatus) &&
currentOrder === "created_at" &&
priorityStatuses.includes(nextStatus) &&
nextOrder === "created_at"
) {
nextOrder = "score";
}
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),
});
if (
priorityStatuses.includes(currentStatus) &&
currentOrder === "score" &&
createdAtStatuses.includes(nextStatus) &&
nextOrder === "score"
) {
nextOrder = "created_at";
}
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() {
return this.reviewables.loadMore();
},
this.refreshModel();
}
toggleFilters() {
this.toggleProperty("filtersExpanded");
},
@action
loadMore() {
return this.reviewables.loadMore();
}
updateFilterReviewedBy(selected) {
this.set("filterReviewedBy", selected.firstObject);
},
@action
toggleFilters() {
this.toggleProperty("filtersExpanded");
}
updateFilterUsername(selected) {
this.set("filterUsername", selected.firstObject);
},
},
});
@action
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 { action } from "@ember/object";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
export default Controller.extend({
saving: false,
saved: false,
export default class ReviewSettingsController extends Controller {
saving = false;
saved = false;
actions: {
save() {
let priorities = {};
this.scoreTypes.forEach((st) => {
priorities[st.id] = parseFloat(st.reviewable_priority);
});
@action
save() {
let priorities = {};
this.scoreTypes.forEach((st) => {
priorities[st.id] = parseFloat(st.reviewable_priority);
});
this.set("saving", true);
ajax("/review/settings", {
type: "PUT",
data: { reviewable_priorities: priorities },
this.set("saving", true);
ajax("/review/settings", {
type: "PUT",
data: { reviewable_priorities: priorities },
})
.then(() => {
this.set("saved", true);
})
.then(() => {
this.set("saved", true);
})
.catch(popupAjaxError)
.finally(() => this.set("saving", false));
},
},
.catch(popupAjaxError)
.finally(() => this.set("saving", false));
}
@discourseComputed("settings.reviewable_score_types")
scoreTypes(types) {
@ -36,5 +36,5 @@ export default Controller.extend({
...type,
title: type.title.replace("%{username}", username),
}));
},
});
}
}

View File

@ -10,45 +10,42 @@ import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
const { TOTP, BACKUP_CODE, SECURITY_KEY } = SECOND_FACTOR_METHODS;
export default Controller.extend({
TOTP,
BACKUP_CODE,
SECURITY_KEY,
export default class SecondFactorAuthController extends Controller {
TOTP = TOTP;
BACKUP_CODE = BACKUP_CODE;
SECURITY_KEY = SECURITY_KEY;
queryParams = ["nonce"];
message = null;
loadError = false;
messageIsError = false;
secondFactorToken = null;
userSelectedMethod = null;
queryParams: ["nonce"],
message: null,
loadError: false,
messageIsError: false,
secondFactorToken: null,
userSelectedMethod: null,
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),
@readOnly("model.totp_enabled") totpEnabled;
@readOnly("model.backup_enabled") backupCodesEnabled;
@readOnly("model.security_keys_enabled") securityKeysEnabled;
@readOnly("model.allowed_methods") allowedMethods;
@readOnly("model.description") customDescription;
@equal("shownSecondFactorMethod", TOTP) showTotpForm;
@equal("shownSecondFactorMethod", SECURITY_KEY) showSecurityKeyForm;
@equal("shownSecondFactorMethod", BACKUP_CODE) showBackupCodesForm;
@discourseComputed("allowedMethods.[]", "totpEnabled")
totpAvailable() {
return this.totpEnabled && this.allowedMethods.includes(TOTP);
},
}
@discourseComputed("allowedMethods.[]", "backupCodesEnabled")
backupCodesAvailable() {
return this.backupCodesEnabled && this.allowedMethods.includes(BACKUP_CODE);
},
}
@discourseComputed("allowedMethods.[]", "securityKeysEnabled")
securityKeysAvailable() {
return (
this.securityKeysEnabled && this.allowedMethods.includes(SECURITY_KEY)
);
},
}
@discourseComputed(
"userSelectedMethod",
@ -75,7 +72,7 @@ export default Controller.extend({
throw new Error("unexpected state of user 2fa settings!");
}
}
},
}
@discourseComputed(
"shownSecondFactorMethod",
@ -115,7 +112,7 @@ export default Controller.extend({
}
return alts;
},
}
@discourseComputed("shownSecondFactorMethod")
secondFactorTitle(shownSecondFactorMethod) {
@ -127,7 +124,7 @@ export default Controller.extend({
case BACKUP_CODE:
return I18n.t("login.second_factor_backup_title");
}
},
}
@discourseComputed("shownSecondFactorMethod")
secondFactorDescription(shownSecondFactorMethod) {
@ -139,7 +136,7 @@ export default Controller.extend({
case BACKUP_CODE:
return I18n.t("login.second_factor_backup_description");
}
},
}
@discourseComputed("messageIsError")
alertClass(messageIsError) {
@ -148,7 +145,7 @@ export default Controller.extend({
} else {
return "alert-success";
}
},
}
@discourseComputed("showTotpForm", "showBackupCodesForm")
inputFormClass(showTotpForm, showBackupCodesForm) {
@ -157,7 +154,7 @@ export default Controller.extend({
} else if (showBackupCodesForm) {
return "backup-code-token";
}
},
}
resetState() {
this.set("message", null);
@ -165,17 +162,17 @@ export default Controller.extend({
this.set("secondFactorToken", null);
this.set("userSelectedMethod", null);
this.set("loadError", false);
},
}
displayError(message) {
this.set("message", message);
this.set("messageIsError", true);
},
}
displaySuccess(message) {
this.set("message", message);
this.set("messageIsError", false);
},
}
verifySecondFactor(data) {
return ajax("/session/2fa", {
@ -207,13 +204,13 @@ export default Controller.extend({
.catch((error) => {
this.displayError(extractError(error));
});
},
}
@action
useAnotherMethod(newMethod, event) {
event?.preventDefault();
this.set("userSelectedMethod", newMethod);
},
}
@action
authenticateSecurityKey() {
@ -227,10 +224,10 @@ export default Controller.extend({
this.displayError(errorMessage);
}
);
},
}
@action
authenticateToken() {
this.verifySecondFactor({ second_factor_token: this.secondFactorToken });
},
});
}
}

View File

@ -1,16 +1,16 @@
import Controller, { inject as controller } from "@ember/controller";
import { action } from "@ember/object";
import { service } from "@ember/service";
export default Controller.extend({
router: service(),
tagGroups: controller(),
export default class TagGroupsEditController extends Controller {
@service router;
@controller tagGroups;
actions: {
onDestroy() {
const tagGroups = this.tagGroups.model;
tagGroups.removeObject(this.model);
@action
onDestroy() {
const tagGroups = this.tagGroups.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 { action } from "@ember/object";
import { service } from "@ember/service";
export default Controller.extend({
router: service(),
tagGroups: controller(),
export default class TagGroupsNewController extends Controller {
@service router;
@controller tagGroups;
actions: {
onSave() {
const tagGroups = this.tagGroups.model;
tagGroups.pushObject(this.model);
@action
onSave() {
const tagGroups = this.tagGroups.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 { action } from "@ember/object";
import { service } from "@ember/service";
export default Controller.extend({
router: service(),
export default class TagGroupsController extends Controller {
@service router;
actions: {
newTagGroup() {
this.router.transitionTo("tagGroups.new");
},
},
});
@action
newTagGroup() {
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 I18n from "discourse-i18n";
export default Controller.extend({
dialog: service(),
modal: service(),
sortedByCount: true,
sortedByName: false,
sortAlphabetically: alias("siteSettings.tags_sort_alphabetically"),
canAdminTags: alias("currentUser.staff"),
groupedByCategory: notEmpty("model.extras.categories"),
groupedByTagGroup: notEmpty("model.extras.tag_groups"),
export default class TagsIndexController extends Controller {
@service dialog;
@service modal;
sortedByCount = true;
sortedByName = false;
@alias("siteSettings.tags_sort_alphabetically") sortAlphabetically;
@alias("currentUser.staff") canAdminTags;
@notEmpty("model.extras.categories") groupedByCategory;
@notEmpty("model.extras.tag_groups") groupedByTagGroup;
init() {
this._super(...arguments);
super.init(...arguments);
const isAlphaSort = this.sortAlphabetically;
@ -28,7 +30,7 @@ export default Controller.extend({
sortedByName: isAlphaSort ? true : false,
sortProperties: isAlphaSort ? ["id"] : ["totalCount:desc", "id"],
});
},
}
@discourseComputed("groupedByCategory", "groupedByTagGroup")
otherTagsTitleKey(groupedByCategory, groupedByTagGroup) {
@ -37,7 +39,7 @@ export default Controller.extend({
} else {
return "tagging.other_tags";
}
},
}
@discourseComputed
actionsMapping() {
@ -46,7 +48,7 @@ export default Controller.extend({
uploadTags: () => this.send("showUploader"),
deleteUnusedTags: () => this.send("deleteUnused"),
};
},
}
@action
sortByCount(event) {
@ -56,7 +58,7 @@ export default Controller.extend({
sortedByCount: true,
sortedByName: false,
});
},
}
@action
sortById(event) {
@ -66,53 +68,53 @@ export default Controller.extend({
sortedByCount: false,
sortedByName: true,
});
},
}
actions: {
showUploader() {
this.modal.show(TagUpload);
},
@action
showUploader() {
this.modal.show(TagUpload);
}
deleteUnused() {
ajax("/tags/unused", { type: "GET" })
.then((result) => {
const displayN = 20;
const tags = result["tags"];
@action
deleteUnused() {
ajax("/tags/unused", { type: "GET" })
.then((result) => {
const displayN = 20;
const tags = result["tags"];
if (tags.length === 0) {
this.dialog.alert(I18n.t("tagging.delete_no_unused_tags"));
return;
}
if (tags.length === 0) {
this.dialog.alert(I18n.t("tagging.delete_no_unused_tags"));
return;
}
const joinedTags = tags
.slice(0, displayN)
.join(I18n.t("tagging.tag_list_joiner"));
const more = Math.max(0, tags.length - displayN);
const joinedTags = tags
.slice(0, displayN)
.join(I18n.t("tagging.tag_list_joiner"));
const more = Math.max(0, tags.length - displayN);
const tagsString =
more === 0
? joinedTags
: I18n.t("tagging.delete_unused_confirmation_more_tags", {
count: more,
tags: joinedTags,
});
const tagsString =
more === 0
? joinedTags
: I18n.t("tagging.delete_unused_confirmation_more_tags", {
count: more,
tags: joinedTags,
});
const message = I18n.t("tagging.delete_unused_confirmation", {
count: tags.length,
tags: tagsString,
});
const message = I18n.t("tagging.delete_unused_confirmation", {
count: tags.length,
tags: tagsString,
});
this.dialog.deleteConfirm({
message,
confirmButtonLabel: "tagging.delete_unused",
didConfirm: () => {
return ajax("/tags/unused", { type: "DELETE" })
.then(() => this.send("triggerRefresh"))
.catch(popupAjaxError);
},
});
})
.catch(popupAjaxError);
},
},
});
this.dialog.deleteConfirm({
message,
confirmButtonLabel: "tagging.delete_unused",
didConfirm: () => {
return ajax("/tags/unused", { type: "DELETE" })
.then(() => this.send("triggerRefresh"))
.catch(popupAjaxError);
},
});
})
.catch(popupAjaxError);
}
}

File diff suppressed because it is too large Load Diff