From 039d0d3641e4c2d7ebc9c2ce17d5353fb5a9dce1 Mon Sep 17 00:00:00 2001 From: Bianca Nenciu Date: Wed, 3 Mar 2021 11:09:22 +0200 Subject: [PATCH] FEATURE: Move security related user preferences to different tab (#12264) --- .../app/controllers/preferences/account.js | 96 --------------- .../app/controllers/preferences/security.js | 114 ++++++++++++++++++ .../discourse/app/routes/app-route-map.js | 1 + .../app/routes/preferences-security.js | 5 + .../discourse/app/templates/preferences.hbs | 5 + .../app/templates/preferences/account.hbs | 107 +++------------- .../app/templates/preferences/security.hbs | 80 ++++++++++++ .../tests/acceptance/preferences-test.js | 87 ++++++------- config/locales/client.en.yml | 1 + config/routes.rb | 1 + 10 files changed, 269 insertions(+), 228 deletions(-) create mode 100644 app/assets/javascripts/discourse/app/controllers/preferences/security.js create mode 100644 app/assets/javascripts/discourse/app/routes/preferences-security.js create mode 100644 app/assets/javascripts/discourse/app/templates/preferences/security.hbs diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/account.js b/app/assets/javascripts/discourse/app/controllers/preferences/account.js index 0a663156183..d78d084324a 100644 --- a/app/assets/javascripts/discourse/app/controllers/preferences/account.js +++ b/app/assets/javascripts/discourse/app/controllers/preferences/account.js @@ -4,19 +4,12 @@ import CanCheckEmails from "discourse/mixins/can-check-emails"; import Controller from "@ember/controller"; import EmberObject from "@ember/object"; import I18n from "I18n"; -import { ajax } from "discourse/lib/ajax"; import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import { findAll } from "discourse/models/login-method"; import getURL from "discourse-common/lib/get-url"; import { iconHTML } from "discourse-common/lib/icon-library"; -import logout from "discourse/lib/logout"; import { popupAjaxError } from "discourse/lib/ajax-error"; -import showModal from "discourse/lib/show-modal"; -import { userPath } from "discourse/lib/url"; - -// Number of tokens shown by default. -const DEFAULT_AUTH_TOKENS_COUNT = 2; export default Controller.extend(CanCheckEmails, { init() { @@ -33,10 +26,6 @@ export default Controller.extend(CanCheckEmails, { newTitleInput: null, newPrimaryGroupInput: null, - passwordProgress: null, - - showAllAuthTokens: false, - revoking: null, cannotDeleteAccount: not("currentUser.can_delete_account"), @@ -65,18 +54,6 @@ export default Controller.extend(CanCheckEmails, { ); }, - @discourseComputed("model.is_anonymous") - canChangePassword(isAnonymous) { - if (isAnonymous) { - return false; - } else { - return ( - !this.siteSettings.enable_discourse_connect && - this.siteSettings.enable_local_logins - ); - } - }, - @discourseComputed("model.associated_accounts") associatedAccountsLoaded(associatedAccounts) { return typeof associatedAccounts !== "undefined"; @@ -147,28 +124,6 @@ export default Controller.extend(CanCheckEmails, { return findAll().length > 0; }, - @discourseComputed("showAllAuthTokens", "model.user_auth_tokens") - authTokens(showAllAuthTokens, tokens) { - tokens.sort((a, b) => { - if (a.is_active) { - return -1; - } else if (b.is_active) { - return 1; - } else { - return b.seen_at.localeCompare(a.seen_at); - } - }); - - return showAllAuthTokens - ? tokens - : tokens.slice(0, DEFAULT_AUTH_TOKENS_COUNT); - }, - - canShowAllAuthTokens: gt( - "model.user_auth_tokens.length", - DEFAULT_AUTH_TOKENS_COUNT - ), - actions: { save() { this.set("saved", false); @@ -205,31 +160,6 @@ export default Controller.extend(CanCheckEmails, { }); }, - changePassword() { - if (!this.passwordProgress) { - this.set( - "passwordProgress", - I18n.t("user.change_password.in_progress") - ); - return this.model - .changePassword() - .then(() => { - // password changed - this.setProperties({ - changePasswordProgress: false, - passwordProgress: I18n.t("user.change_password.success"), - }); - }) - .catch(() => { - // password failed to change - this.setProperties({ - changePasswordProgress: false, - passwordProgress: I18n.t("user.change_password.error"), - }); - }); - } - }, - delete() { this.set("deleting", true); const message = I18n.t("user.delete_account_confirm"), @@ -282,32 +212,6 @@ export default Controller.extend(CanCheckEmails, { .finally(() => this.set(`revoking.${account.name}`, false)); }, - toggleShowAllAuthTokens() { - this.toggleProperty("showAllAuthTokens"); - }, - - revokeAuthToken(token) { - ajax( - userPath( - `${this.get("model.username_lower")}/preferences/revoke-auth-token` - ), - { - type: "POST", - data: token ? { token_id: token.id } : {}, - } - ) - .then(() => { - if (!token) { - logout(); - } // All sessions revoked - }) - .catch(popupAjaxError); - }, - - showToken(token) { - showModal("auth-token", { model: token }); - }, - connectAccount(method) { method.doLogin({ reconnect: true }); }, diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/security.js b/app/assets/javascripts/discourse/app/controllers/preferences/security.js new file mode 100644 index 00000000000..c1e7dc52c0b --- /dev/null +++ b/app/assets/javascripts/discourse/app/controllers/preferences/security.js @@ -0,0 +1,114 @@ +import Controller from "@ember/controller"; +import { gt } from "@ember/object/computed"; +import discourseComputed from "discourse-common/utils/decorators"; +import { ajax } from "discourse/lib/ajax"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import logout from "discourse/lib/logout"; +import showModal from "discourse/lib/show-modal"; +import { userPath } from "discourse/lib/url"; +import CanCheckEmails from "discourse/mixins/can-check-emails"; +import I18n from "I18n"; + +// Number of tokens shown by default. +const DEFAULT_AUTH_TOKENS_COUNT = 2; + +export default Controller.extend(CanCheckEmails, { + passwordProgress: null, + + showAllAuthTokens: false, + + @discourseComputed("model.is_anonymous") + canChangePassword(isAnonymous) { + if (isAnonymous) { + return false; + } else { + return ( + !this.siteSettings.enable_discourse_connect && + this.siteSettings.enable_local_logins + ); + } + }, + + @discourseComputed("showAllAuthTokens", "model.user_auth_tokens") + authTokens(showAllAuthTokens, tokens) { + tokens.sort((a, b) => { + if (a.is_active) { + return -1; + } else if (b.is_active) { + return 1; + } else { + return b.seen_at.localeCompare(a.seen_at); + } + }); + + return showAllAuthTokens + ? tokens + : tokens.slice(0, DEFAULT_AUTH_TOKENS_COUNT); + }, + + canShowAllAuthTokens: gt( + "model.user_auth_tokens.length", + DEFAULT_AUTH_TOKENS_COUNT + ), + + actions: { + save() { + this.set("saved", false); + + return this.model + .then(() => this.set("saved", true)) + .catch(popupAjaxError); + }, + + changePassword() { + if (!this.passwordProgress) { + this.set( + "passwordProgress", + I18n.t("user.change_password.in_progress") + ); + return this.model + .changePassword() + .then(() => { + // password changed + this.setProperties({ + changePasswordProgress: false, + passwordProgress: I18n.t("user.change_password.success"), + }); + }) + .catch(() => { + // password failed to change + this.setProperties({ + changePasswordProgress: false, + passwordProgress: I18n.t("user.change_password.error"), + }); + }); + } + }, + + toggleShowAllAuthTokens() { + this.toggleProperty("showAllAuthTokens"); + }, + + revokeAuthToken(token) { + ajax( + userPath( + `${this.get("model.username_lower")}/preferences/revoke-auth-token` + ), + { + type: "POST", + data: token ? { token_id: token.id } : {}, + } + ) + .then(() => { + if (!token) { + logout(); + } // All sessions revoked + }) + .catch(popupAjaxError); + }, + + showToken(token) { + showModal("auth-token", { model: token }); + }, + }, +}); diff --git a/app/assets/javascripts/discourse/app/routes/app-route-map.js b/app/assets/javascripts/discourse/app/routes/app-route-map.js index 67c6acc41fe..2bce5afc37d 100644 --- a/app/assets/javascripts/discourse/app/routes/app-route-map.js +++ b/app/assets/javascripts/discourse/app/routes/app-route-map.js @@ -158,6 +158,7 @@ export default function () { this.route("preferences", { resetNamespace: true }, function () { this.route("account"); + this.route("security"); this.route("profile"); this.route("emails"); this.route("notifications"); diff --git a/app/assets/javascripts/discourse/app/routes/preferences-security.js b/app/assets/javascripts/discourse/app/routes/preferences-security.js new file mode 100644 index 00000000000..bfec0d17c4c --- /dev/null +++ b/app/assets/javascripts/discourse/app/routes/preferences-security.js @@ -0,0 +1,5 @@ +import RestrictedUserRoute from "discourse/routes/restricted-user"; + +export default RestrictedUserRoute.extend({ + showFooter: true, +}); diff --git a/app/assets/javascripts/discourse/app/templates/preferences.hbs b/app/assets/javascripts/discourse/app/templates/preferences.hbs index 324517821a3..45f82f56c9a 100644 --- a/app/assets/javascripts/discourse/app/templates/preferences.hbs +++ b/app/assets/javascripts/discourse/app/templates/preferences.hbs @@ -5,6 +5,11 @@ {{i18n "user.preferences_nav.account"}} {{/link-to}} +