DEV: Refactor CanCheckEmails mixin to helper class (#30315)

* port CanCheckEmails mixin to helper class with explicit dependencies
* move isCurrentUser getter to components
* anonymous users should not be able to see sensitive information
This commit is contained in:
Kelv 2024-12-18 10:29:51 +08:00 committed by GitHub
parent b5e2005d60
commit f8837e1a8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 133 additions and 47 deletions

View File

@ -1,13 +1,13 @@
import Controller from "@ember/controller";
import { action } from "@ember/object";
import { action, computed } from "@ember/object";
import { and, notEmpty } from "@ember/object/computed";
import { service } from "@ember/service";
import { htmlSafe } from "@ember/template";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import CanCheckEmailsHelper from "discourse/lib/can-check-emails-helper";
import { fmt, propertyNotEqual, setting } from "discourse/lib/computed";
import DiscourseURL, { userPath } from "discourse/lib/url";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import getURL from "discourse-common/lib/get-url";
import discourseComputed from "discourse-common/utils/decorators";
import { i18n } from "discourse-i18n";
@ -18,9 +18,7 @@ import MergeUsersConfirmationModal from "../components/modal/merge-users-confirm
import MergeUsersProgressModal from "../components/modal/merge-users-progress";
import MergeUsersPromptModal from "../components/modal/merge-users-prompt";
export default class AdminUserIndexController extends Controller.extend(
CanCheckEmails
) {
export default class AdminUserIndexController extends Controller {
@service router;
@service dialog;
@service adminTools;
@ -34,6 +32,7 @@ export default class AdminUserIndexController extends Controller.extend(
ssoLastPayload = null;
@setting("enable_badges") showBadges;
@setting("moderators_view_emails") canModeratorsViewEmails;
@notEmpty("model.manual_locked_trust_level") hasLockedTrustLevel;
@propertyNotEqual("originalPrimaryGroupId", "model.primary_group_id")
@ -131,6 +130,24 @@ export default class AdminUserIndexController extends Controller.extend(
return { editor: username };
}
@computed("model.id", "currentUser.id")
get canCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canCheckEmails;
}
@computed("model.id", "currentUser.id")
get canAdminCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canAdminCheckEmails;
}
groupAdded(added) {
this.model
.groupAdded(added)

View File

@ -1,9 +1,9 @@
import { tracked } from "@glimmer/tracking";
import Controller from "@ember/controller";
import { action } from "@ember/object";
import { action, computed } from "@ember/object";
import { service } from "@ember/service";
import { computedI18n } from "discourse/lib/computed";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import CanCheckEmailsHelper from "discourse/lib/can-check-emails-helper";
import { computedI18n, setting } from "discourse/lib/computed";
import { INPUT_DELAY } from "discourse-common/config/environment";
import discourseDebounce from "discourse-common/lib/debounce";
import discourseComputed, { bind } from "discourse-common/utils/decorators";
@ -13,9 +13,7 @@ import AdminUser from "admin/models/admin-user";
const MAX_BULK_SELECT_LIMIT = 100;
export default class AdminUsersListShowController extends Controller.extend(
CanCheckEmails
) {
export default class AdminUsersListShowController extends Controller {
@service dialog;
@service modal;
@service toasts;
@ -24,6 +22,7 @@ export default class AdminUsersListShowController extends Controller.extend(
@tracked displayBulkActions = false;
@tracked bulkSelectedUserIdsSet = new Set();
@tracked bulkSelectedUsersMap = {};
@setting("moderators_view_emails") canModeratorsViewEmails;
query = null;
order = null;
@ -60,6 +59,24 @@ export default class AdminUsersListShowController extends Controller.extend(
return colCount;
}
@computed("model.id", "currentUser.id")
get canCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canCheckEmails;
}
@computed("model.id", "currentUser.id")
get canAdminCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canAdminCheckEmails;
}
resetFilters() {
this._page = 1;
this._results = [];

View File

@ -9,13 +9,13 @@ import {
} from "@ember-decorators/component";
import { observes, on } from "@ember-decorators/object";
import CardContentsBase from "discourse/components/card-contents-base";
import CanCheckEmailsHelper from "discourse/lib/can-check-emails-helper";
import { setting } from "discourse/lib/computed";
import { durationTiny } from "discourse/lib/formatter";
import { wantsNewWindow } from "discourse/lib/intercept-click";
import { prioritizeNameInUx } from "discourse/lib/settings";
import { emojiUnescape } from "discourse/lib/text";
import { escapeExpression } from "discourse/lib/utilities";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import User from "discourse/models/user";
import { getURLWithCDN } from "discourse-common/lib/get-url";
import discourseComputed from "discourse-common/utils/decorators";
@ -31,9 +31,7 @@ import { i18n } from "discourse-i18n";
"primaryGroup"
)
@attributeBindings("ariaLabel:aria-label")
export default class UserCardContents extends CardContentsBase.extend(
CanCheckEmails
) {
export default class UserCardContents extends CardContentsBase {
elementId = "user-card";
avatarSelector = "[data-user-card]";
avatarDataAttrKey = "userCard";
@ -43,6 +41,7 @@ export default class UserCardContents extends CardContentsBase.extend(
@setting("allow_profile_backgrounds") allowBackgrounds;
@setting("enable_badges") showBadges;
@setting("display_local_time_in_user_card") showUserLocalTime;
@setting("moderators_view_emails") canModeratorsViewEmails;
@alias("topic.postStream") postStream;
@ -74,6 +73,15 @@ export default class UserCardContents extends CardContentsBase.extend(
return this.user.name !== this.user.username;
}
@computed("model.id", "currentUser.id")
get canCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canCheckEmails;
}
@discourseComputed("user")
hasLocaleOrWebsite(user) {
return user.location || user.website_name || this.userTimezone;

View File

@ -1,29 +1,27 @@
import Controller, { inject as controller } from "@ember/controller";
import EmberObject, { action } from "@ember/object";
import EmberObject, { action, computed } from "@ember/object";
import { alias, gt, not, or } from "@ember/object/computed";
import { next } from "@ember/runloop";
import { service } from "@ember/service";
import UserStatusModal from "discourse/components/modal/user-status";
import { popupAjaxError } from "discourse/lib/ajax-error";
import CanCheckEmailsHelper from "discourse/lib/can-check-emails-helper";
import { propertyNotEqual, setting } from "discourse/lib/computed";
import { exportUserArchive } from "discourse/lib/export-csv";
import DiscourseURL from "discourse/lib/url";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import { findAll } from "discourse/models/login-method";
import getURL from "discourse-common/lib/get-url";
import discourseComputed from "discourse-common/utils/decorators";
import { i18n } from "discourse-i18n";
export default class AccountController extends Controller.extend(
CanCheckEmails
) {
export default class AccountController extends Controller {
@service dialog;
@service modal;
@controller user;
@setting("enable_names") canEditName;
@setting("enable_user_status") canSelectUserStatus;
@setting("moderators_view_emails") canModeratorsViewEmails;
@alias("user.viewingSelf") canDownloadPosts;
@not("currentUser.can_delete_account") cannotDeleteAccount;
@ -56,6 +54,15 @@ export default class AccountController extends Controller.extend(
this.set("passwordProgress", null);
}
@computed("model.id", "currentUser.id")
get canCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canCheckEmails;
}
@discourseComputed()
nameInstructions() {
return i18n(

View File

@ -11,15 +11,12 @@ import SecondFactorEdit from "discourse/components/modal/second-factor-edit";
import SecondFactorEditSecurityKey from "discourse/components/modal/second-factor-edit-security-key";
import { popupAjaxError } from "discourse/lib/ajax-error";
import DiscourseURL, { userPath } from "discourse/lib/url";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import { findAll } from "discourse/models/login-method";
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
import discourseComputed from "discourse-common/utils/decorators";
import { i18n } from "discourse-i18n";
export default class SecondFactorController extends Controller.extend(
CanCheckEmails
) {
export default class SecondFactorController extends Controller {
@service dialog;
@service modal;
@service siteSettings;
@ -35,6 +32,10 @@ export default class SecondFactorController extends Controller.extend(
totps = [];
security_keys = [];
get isCurrentUser() {
return this.currentUser?.id === this.model.id;
}
@discourseComputed
hasOAuth() {
return findAll().length > 0;

View File

@ -1,27 +1,29 @@
import Controller from "@ember/controller";
import { action } from "@ember/object";
import { action, computed } from "@ember/object";
import { gt } from "@ember/object/computed";
import { service } from "@ember/service";
import ConfirmSession from "discourse/components/dialog-messages/confirm-session";
import AuthTokenModal from "discourse/components/modal/auth-token";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import CanCheckEmailsHelper from "discourse/lib/can-check-emails-helper";
import { setting } from "discourse/lib/computed";
import logout from "discourse/lib/logout";
import { userPath } from "discourse/lib/url";
import { isWebauthnSupported } from "discourse/lib/webauthn";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import discourseComputed from "discourse-common/utils/decorators";
import { i18n } from "discourse-i18n";
// Number of tokens shown by default.
const DEFAULT_AUTH_TOKENS_COUNT = 2;
export default class SecurityController extends Controller.extend(
CanCheckEmails
) {
export default class SecurityController extends Controller {
@service modal;
@service dialog;
@service router;
@service currentUser;
@setting("moderators_view_emails") canModeratorsViewEmails;
passwordProgress = null;
subpageTitle = i18n("user.preferences_nav.security");
@ -30,6 +32,19 @@ export default class SecurityController extends Controller.extend(
@gt("model.user_auth_tokens.length", DEFAULT_AUTH_TOKENS_COUNT)
canShowAllAuthTokens;
@computed("model.id", "currentUser.id")
get canCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canCheckEmails;
}
get isCurrentUser() {
return this.currentUser?.id === this.model.id;
}
get canUsePasskeys() {
return (
!this.siteSettings.enable_discourse_connect &&

View File

@ -4,20 +4,22 @@ import { and, equal, gt, not, or, readOnly } from "@ember/object/computed";
import { service } from "@ember/service";
import { dasherize } from "@ember/string";
import { isEmpty } from "@ember/utils";
import CanCheckEmailsHelper from "discourse/lib/can-check-emails-helper";
import { setting } from "discourse/lib/computed";
import optionalService from "discourse/lib/optional-service";
import { prioritizeNameInUx } from "discourse/lib/settings";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import getURL from "discourse-common/lib/get-url";
import discourseComputed from "discourse-common/utils/decorators";
import { i18n } from "discourse-i18n";
export default class UserController extends Controller.extend(CanCheckEmails) {
export default class UserController extends Controller {
@service currentUser;
@service router;
@service dialog;
@optionalService adminTools;
@controller("user-notifications") userNotifications;
@setting("moderators_view_emails") canModeratorsViewEmails;
@equal("router.currentRouteName", "user.summary") isSummaryRoute;
@or("model.can_ignore_user", "model.can_mute_user") canMuteOrIgnoreUser;
@ -190,6 +192,15 @@ export default class UserController extends Controller.extend(CanCheckEmails) {
/* noop */
}
@computed("model.id", "currentUser.id")
get canCheckEmails() {
return new CanCheckEmailsHelper(
this.model,
this.canModeratorsViewEmails,
this.currentUser
).canCheckEmails;
}
get displayTopLevelAdminButton() {
if (!this.currentUser?.staff) {
return false;

View File

@ -0,0 +1,25 @@
export default class CanCheckEmailsHelper {
constructor(model, can_moderators_view_emails, currentUser) {
this.model = model;
this.can_moderators_view_emails = can_moderators_view_emails;
this.currentUser = currentUser;
}
get canAdminCheckEmails() {
return this.currentUser.admin;
}
get canCheckEmails() {
if (!this.currentUser) {
return false;
}
const canStaffCheckEmails =
this.can_moderators_view_emails && this.currentUser.staff;
return (
this.model.id === this.currentUser.id ||
this.canAdminCheckEmails ||
canStaffCheckEmails
);
}
}

View File

@ -1,15 +0,0 @@
import { alias, and, or } from "@ember/object/computed";
import Mixin from "@ember/object/mixin";
import { propertyEqual, setting } from "discourse/lib/computed";
export default Mixin.create({
isCurrentUser: propertyEqual("model.id", "currentUser.id"),
showEmailOnProfile: setting("moderators_view_emails"),
canStaffCheckEmails: and("showEmailOnProfile", "currentUser.staff"),
canAdminCheckEmails: alias("currentUser.admin"),
canCheckEmails: or(
"isCurrentUser",
"canStaffCheckEmails",
"canAdminCheckEmails"
),
});