From 8b10fc2f8c29cd6676e3b4e8aec1634a8899405d Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Wed, 20 Jan 2021 16:04:21 +1100 Subject: [PATCH] FIX: remove rendering UX from ember models (#11724) Fix for `admin-user.js` and `backup.js` models. --- .../addon/controllers/admin-user-index.js | 301 ++++++++++++++++- .../admin-delete-user-posts-progress.js | 6 + .../modals/admin-merge-users-progress.js | 31 ++ .../admin/addon/models/admin-user.js | 308 ++---------------- .../javascripts/admin/addon/models/backup.js | 30 +- .../admin/addon/routes/admin-backups-index.js | 4 +- .../admin/addon/routes/admin-backups.js | 38 ++- .../admin-delete-user-posts-progress.hbs | 4 + .../modal/admin-merge-users-progress.hbs | 3 + app/assets/stylesheets/common/base/modal.scss | 2 +- config/locales/client.en.yml | 5 + 11 files changed, 391 insertions(+), 341 deletions(-) create mode 100644 app/assets/javascripts/admin/addon/controllers/modals/admin-delete-user-posts-progress.js create mode 100644 app/assets/javascripts/admin/addon/controllers/modals/admin-merge-users-progress.js create mode 100644 app/assets/javascripts/admin/addon/templates/modal/admin-delete-user-posts-progress.hbs create mode 100644 app/assets/javascripts/admin/addon/templates/modal/admin-merge-users-progress.hbs diff --git a/app/assets/javascripts/admin/addon/controllers/admin-user-index.js b/app/assets/javascripts/admin/addon/controllers/admin-user-index.js index 4912c3a3970..81a42481e2e 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-user-index.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-user-index.js @@ -1,16 +1,19 @@ +import DiscourseURL, { userPath } from "discourse/lib/url"; import { and, notEmpty } from "@ember/object/computed"; import { fmt, propertyNotEqual, setting } from "discourse/lib/computed"; +import AdminUser from "admin/models/admin-user"; import CanCheckEmails from "discourse/mixins/can-check-emails"; import Controller from "@ember/controller"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; +import getURL from "discourse-common/lib/get-url"; import { htmlSafe } from "@ember/template"; +import { iconHTML } from "discourse-common/lib/icon-library"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { inject as service } from "@ember/service"; import showModal from "discourse/lib/show-modal"; -import { userPath } from "discourse/lib/url"; export default Controller.extend(CanCheckEmails, { adminTools: service(), @@ -141,10 +144,21 @@ export default Controller.extend(CanCheckEmails, { actions: { impersonate() { - return this.model.impersonate(); + return this.model + .impersonate() + .then(() => DiscourseURL.redirectTo("/")) + .catch((e) => { + if (e.status === 404) { + bootbox.alert(I18n.t("admin.impersonate.not_found")); + } else { + bootbox.alert(I18n.t("admin.impersonate.invalid")); + } + }); }, logOut() { - return this.model.logOut(); + return this.model + .logOut() + .then(() => bootbox.alert(I18n.t("admin.user.logged_out"))); }, resetBounceScore() { return this.model.resetBounceScore(); @@ -152,20 +166,56 @@ export default Controller.extend(CanCheckEmails, { approve() { return this.model.approve(this.currentUser); }, + + _formatError(event) { + return `http: ${event.status} - ${event.body}`; + }, + deactivate() { - return this.model.deactivate(); + return this.model + .deactivate() + .then(() => + this.model.setProperties({ active: false, can_activate: true }) + ) + .catch((e) => { + const error = I18n.t("admin.user.deactivate_failed", { + error: this._formatError(e), + }); + bootbox.alert(error); + }); }, sendActivationEmail() { - return this.model.sendActivationEmail(); + return this.model + .sendActivationEmail() + .then(() => bootbox.alert(I18n.t("admin.user.activation_email_sent"))) + .catch(popupAjaxError); }, activate() { - return this.model.activate(); + return this.model + .activate() + .then(() => + this.model.setProperties({ + active: true, + can_deactivate: !this.model.staff, + }) + ) + .catch((e) => { + const error = I18n.t("admin.user.activate_failed", { + error: this._formatError(e), + }); + bootbox.alert(error); + }); }, revokeAdmin() { return this.model.revokeAdmin(); }, grantAdmin() { - return this.model.grantAdmin(); + return this.model + .grantAdmin() + .then(() => { + bootbox.alert(I18n.t("admin.user.grant_admin_confirm")); + }) + .catch(popupAjaxError); }, revokeModeration() { return this.model.revokeModeration(); @@ -174,13 +224,41 @@ export default Controller.extend(CanCheckEmails, { return this.model.grantModeration(); }, saveTrustLevel() { - return this.model.saveTrustLevel(); + return this.model + .saveTrustLevel() + .then(() => window.location.reload()) + .catch((e) => { + let error; + if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) { + error = e.jqXHR.responseJSON.errors[0]; + } + error = + error || + I18n.t("admin.user.trust_level_change_failed", { + error: this._formatError(e), + }); + bootbox.alert(error); + }); }, restoreTrustLevel() { return this.model.restoreTrustLevel(); }, lockTrustLevel(locked) { - return this.model.lockTrustLevel(locked); + return this.model + .lockTrustLevel(locked) + .then(() => window.location.reload()) + .catch((e) => { + let error; + if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) { + error = e.jqXHR.responseJSON.errors[0]; + } + error = + error || + I18n.t("admin.user.trust_level_change_failed", { + error: this._formatError(e), + }); + bootbox.alert(error); + }); }, unsilence() { return this.model.unsilence(); @@ -189,11 +267,119 @@ export default Controller.extend(CanCheckEmails, { return this.model.silence(); }, deleteAllPosts() { - return this.model.deleteAllPosts(); + let deletedPosts = 0; + let deletedPercentage = 0; + const user = this.model; + const message = I18n.messageFormat( + "admin.user.delete_all_posts_confirm_MF", + { + POSTS: user.get("post_count"), + TOPICS: user.get("topic_count"), + } + ); + + const performDelete = (progressModal) => { + this.model + .deleteAllPosts() + .then(({ posts_deleted }) => { + if (posts_deleted === 0) { + user.set("post_count", 0); + progressModal.send("closeModal"); + } else { + deletedPosts += posts_deleted; + deletedPercentage = Math.floor( + (deletedPosts * 100) / user.get("post_count") + ); + progressModal.setProperties({ + deletedPercentage: deletedPercentage, + }); + performDelete(progressModal); + } + }) + .catch((e) => { + progressModal.send("closeModal"); + let error; + AdminUser.find(user.get("id")).then((u) => user.setProperties(u)); + if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) { + error = e.jqXHR.responseJSON.errors[0]; + } + error = error || I18n.t("admin.user.delete_posts_failed"); + bootbox.alert(error); + }); + }; + + const buttons = [ + { + label: I18n.t("composer.cancel"), + class: "d-modal-cancel", + link: true, + }, + { + label: + `${iconHTML("exclamation-triangle")} ` + + I18n.t("admin.user.delete_all_posts"), + class: "btn btn-danger", + callback: () => { + const progressModal = openProgressModal(); + performDelete(progressModal); + }, + }, + ]; + + const openProgressModal = () => { + return showModal("admin-delete-user-posts-progress", { + admin: true, + }); + }; + + bootbox.dialog(message, buttons, { classes: "delete-all-posts" }); }, + anonymize() { - return this.model.anonymize(); + const user = this.model; + const message = I18n.t("admin.user.anonymize_confirm"); + + const performAnonymize = () => { + this.model + .anonymize() + .then((data) => { + if (data.success) { + if (data.username) { + document.location = getURL( + `/admin/users/${user.get("id")}/${data.username}` + ); + } else { + document.location = getURL("/admin/users/list/active"); + } + } else { + bootbox.alert(I18n.t("admin.user.anonymize_failed")); + if (data.user) { + user.setProperties(data.user); + } + } + }) + .catch(() => bootbox.alert(I18n.t("admin.user.anonymize_failed"))); + }; + const buttons = [ + { + label: I18n.t("composer.cancel"), + class: "cancel", + link: true, + }, + { + label: + `${iconHTML("exclamation-triangle")} ` + + I18n.t("admin.user.anonymize_yes"), + class: "btn btn-danger", + callback: () => { + performAnonymize(); + }, + }, + ]; + + bootbox.dialog(message, buttons, { classes: "delete-user-modal" }); }, + disableSecondFactor() { return this.model.disableSecondFactor(); }, @@ -210,11 +396,68 @@ export default Controller.extend(CanCheckEmails, { destroy() { const postCount = this.get("model.post_count"); const maxPostCount = this.siteSettings.delete_all_posts_max; - if (postCount <= maxPostCount) { - return this.model.destroy({ deletePosts: true }); - } else { - return this.model.destroy(); - } + const user = this.model; + const message = I18n.t("admin.user.delete_confirm"); + const location = document.location.pathname; + + const performDestroy = (block) => { + bootbox.dialog(I18n.t("admin.user.deleting_user")); + let formData = { context: location }; + if (block) { + formData["block_email"] = true; + formData["block_urls"] = true; + formData["block_ip"] = true; + } + if (postCount <= maxPostCount) { + formData["delete_posts"] = true; + } + this.model + .destroy(formData) + .then((data) => { + if (data.deleted) { + if (/^\/admin\/users\/list\//.test(location)) { + document.location = location; + } else { + document.location = getURL("/admin/users/list/active"); + } + } else { + bootbox.alert(I18n.t("admin.user.delete_failed")); + if (data.user) { + user.setProperties(data.user); + } + } + }) + .catch(() => { + AdminUser.find(user.get("id")).then((u) => user.setProperties(u)); + bootbox.alert(I18n.t("admin.user.delete_failed")); + }); + }; + + const buttons = [ + { + label: I18n.t("composer.cancel"), + class: "btn", + link: true, + }, + { + label: + `${iconHTML("exclamation-triangle")} ` + + I18n.t("admin.user.delete_and_block"), + class: "btn btn-danger", + callback: () => { + performDestroy(true); + }, + }, + { + label: I18n.t("admin.user.delete_dont_block"), + class: "btn btn-primary", + callback: () => { + performDestroy(false); + }, + }, + ]; + + bootbox.dialog(message, buttons, { classes: "delete-user-modal" }); }, promptTargetUser() { @@ -235,7 +478,31 @@ export default Controller.extend(CanCheckEmails, { }, merge(targetUsername) { - return this.model.merge({ targetUsername }); + const user = this.model; + const location = document.location.pathname; + + let formData = { context: location }; + + if (targetUsername) { + formData["target_username"] = targetUsername; + } + + this.model + .merge(formData) + .then((response) => { + if (response.success) { + showModal("admin-merge-users-progress", { + admin: true, + model: this.model, + }); + } else { + bootbox.alert(I18n.t("admin.user.merge_failed")); + } + }) + .catch(() => { + AdminUser.find(user.id).then((u) => user.setProperties(u)); + bootbox.alert(I18n.t("admin.user.merge_failed")); + }); }, viewActionLogs() { diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-delete-user-posts-progress.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-delete-user-posts-progress.js new file mode 100644 index 00000000000..61b9bae999c --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/modals/admin-delete-user-posts-progress.js @@ -0,0 +1,6 @@ +import Controller from "@ember/controller"; +import ModalFunctionality from "discourse/mixins/modal-functionality"; + +export default Controller.extend(ModalFunctionality, { + deletedPercentage: 0, +}); diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-merge-users-progress.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-merge-users-progress.js new file mode 100644 index 00000000000..3d9248d36d5 --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/modals/admin-merge-users-progress.js @@ -0,0 +1,31 @@ +import Controller from "@ember/controller"; +import DiscourseURL from "discourse/lib/url"; +import I18n from "I18n"; +import ModalFunctionality from "discourse/mixins/modal-functionality"; +import messageBus from "message-bus-client"; + +export default Controller.extend(ModalFunctionality, { + message: I18n.t("admin.user.merging_user"), + + onShow() { + messageBus.subscribe("/merge_user", (data) => { + if (data.merged) { + if (/^\/admin\/users\/list\//.test(location)) { + DiscourseURL.redirectTo(location); + } else { + DiscourseURL.redirectTo( + `/admin/users/${data.user.id}/${data.user.username}` + ); + } + } else if (data.message) { + this.set("message", data.message); + } else if (data.failed) { + this.set("message", I18n.t("admin.user.merge_failed")); + } + }); + }, + + onClose() { + this.messageBus.unsubscribe("/merge_user"); + }, +}); diff --git a/app/assets/javascripts/admin/addon/models/admin-user.js b/app/assets/javascripts/admin/addon/models/admin-user.js index a2686912aeb..1a86426c5be 100644 --- a/app/assets/javascripts/admin/addon/models/admin-user.js +++ b/app/assets/javascripts/admin/addon/models/admin-user.js @@ -1,17 +1,14 @@ -import DiscourseURL, { userPath } from "discourse/lib/url"; import { filter, gt, lt, not, or } from "@ember/object/computed"; import Group from "discourse/models/group"; import I18n from "I18n"; import { Promise } from "rsvp"; import User from "discourse/models/user"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; import discourseComputed from "discourse-common/utils/decorators"; import getURL from "discourse-common/lib/get-url"; -import { iconHTML } from "discourse-common/lib/icon-library"; -import messageBus from "message-bus-client"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { propertyNotEqual } from "discourse/lib/computed"; +import { userPath } from "discourse/lib/url"; const wrapAdmin = (user) => (user ? AdminUser.create(user) : null); @@ -81,74 +78,9 @@ const AdminUser = User.extend({ }, deleteAllPosts() { - let deletedPosts = 0; - const user = this; - const message = I18n.messageFormat( - "admin.user.delete_all_posts_confirm_MF", - { - POSTS: user.get("post_count"), - TOPICS: user.get("topic_count"), - } - ); - const buttons = [ - { - label: I18n.t("composer.cancel"), - class: "d-modal-cancel", - link: true, - }, - { - label: - `${iconHTML("exclamation-triangle")} ` + - I18n.t("admin.user.delete_all_posts"), - class: "btn btn-danger", - callback: () => { - openProgressModal(); - performDelete(); - }, - }, - ]; - const openProgressModal = () => { - bootbox.dialog( - `

${I18n.t( - "admin.user.delete_posts_progress" - )}

`, - [], - { classes: "delete-posts-progress" } - ); - }; - const performDelete = () => { - let deletedPercentage = 0; - return ajax(`/admin/users/${user.get("id")}/delete_posts_batch`, { - type: "PUT", - }) - .then(({ posts_deleted }) => { - if (posts_deleted === 0) { - user.set("post_count", 0); - bootbox.hideAll(); - } else { - deletedPosts += posts_deleted; - deletedPercentage = Math.floor( - (deletedPosts * 100) / user.get("post_count") - ); - $(".delete-posts-progress .progress-bar > span").css({ - width: `${deletedPercentage}%`, - }); - performDelete(); - } - }) - .catch((e) => { - bootbox.hideAll(); - let error; - AdminUser.find(user.get("id")).then((u) => user.setProperties(u)); - if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) { - error = e.jqXHR.responseJSON.errors[0]; - } - error = error || I18n.t("admin.user.delete_posts_failed"); - bootbox.alert(error); - }); - }; - - bootbox.dialog(message, buttons, { classes: "delete-all-posts" }); + return ajax(`/admin/users/${this.get("id")}/delete_posts_batch`, { + type: "PUT", + }); }, revokeAdmin() { @@ -166,11 +98,7 @@ const AdminUser = User.extend({ grantAdmin() { return ajax(`/admin/users/${this.id}/grant_admin`, { type: "PUT", - }) - .then(() => { - bootbox.alert(I18n.t("admin.user.grant_admin_confirm")); - }) - .catch(popupAjaxError); + }); }, revokeModeration() { @@ -233,20 +161,7 @@ const AdminUser = User.extend({ return ajax(`/admin/users/${this.id}/trust_level`, { type: "PUT", data: { level: this.trust_level }, - }) - .then(() => window.location.reload()) - .catch((e) => { - let error; - if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) { - error = e.jqXHR.responseJSON.errors[0]; - } - error = - error || - I18n.t("admin.user.trust_level_change_failed", { - error: this._formatError(e), - }); - bootbox.alert(error); - }); + }); }, restoreTrustLevel() { @@ -257,20 +172,7 @@ const AdminUser = User.extend({ return ajax(`/admin/users/${this.id}/trust_level_lock`, { type: "PUT", data: { locked: !!locked }, - }) - .then(() => window.location.reload()) - .catch((e) => { - let error; - if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) { - error = e.jqXHR.responseJSON.errors[0]; - } - error = - error || - I18n.t("admin.user.trust_level_change_failed", { - error: this._formatError(e), - }); - bootbox.alert(error); - }); + }); }, canLockTrustLevel: lt("trust_level", 4), @@ -301,49 +203,27 @@ const AdminUser = User.extend({ return ajax("/admin/users/" + this.id + "/log_out", { type: "POST", data: { username_or_email: this.username }, - }).then(() => bootbox.alert(I18n.t("admin.user.logged_out"))); + }); }, impersonate() { return ajax("/admin/impersonate", { type: "POST", data: { username_or_email: this.username }, - }) - .then(() => (document.location = getURL("/"))) - .catch((e) => { - if (e.status === 404) { - bootbox.alert(I18n.t("admin.impersonate.not_found")); - } else { - bootbox.alert(I18n.t("admin.impersonate.invalid")); - } - }); + }); }, activate() { return ajax(`/admin/users/${this.id}/activate`, { type: "PUT", - }) - .then(() => window.location.reload()) - .catch((e) => { - const error = I18n.t("admin.user.activate_failed", { - error: this._formatError(e), - }); - bootbox.alert(error); - }); + }); }, deactivate() { return ajax(`/admin/users/${this.id}/deactivate`, { type: "PUT", data: { context: document.location.pathname }, - }) - .then(() => window.location.reload()) - .catch((e) => { - const error = I18n.t("admin.user.deactivate_failed", { - error: this._formatError(e), - }); - bootbox.alert(error); - }); + }); }, unsilence() { @@ -371,165 +251,27 @@ const AdminUser = User.extend({ return ajax(userPath("action/send_activation_email"), { type: "POST", data: { username: this.username }, - }) - .then(() => bootbox.alert(I18n.t("admin.user.activation_email_sent"))) - .catch(popupAjaxError); + }); }, anonymize() { - const user = this; - const message = I18n.t("admin.user.anonymize_confirm"); - - const performAnonymize = function () { - return ajax(`/admin/users/${user.get("id")}/anonymize.json`, { - type: "PUT", - }) - .then(function (data) { - if (data.success) { - if (data.username) { - document.location = getURL( - `/admin/users/${user.get("id")}/${data.username}` - ); - } else { - document.location = getURL("/admin/users/list/active"); - } - } else { - bootbox.alert(I18n.t("admin.user.anonymize_failed")); - if (data.user) { - user.setProperties(data.user); - } - } - }) - .catch(() => bootbox.alert(I18n.t("admin.user.anonymize_failed"))); - }; - - const buttons = [ - { - label: I18n.t("composer.cancel"), - class: "cancel", - link: true, - }, - { - label: - `${iconHTML("exclamation-triangle")} ` + - I18n.t("admin.user.anonymize_yes"), - class: "btn btn-danger", - callback: function () { - performAnonymize(); - }, - }, - ]; - - bootbox.dialog(message, buttons, { classes: "delete-user-modal" }); + return ajax(`/admin/users/${this.id}/anonymize.json`, { + type: "PUT", + }); }, - destroy(opts) { - const user = this; - const message = I18n.t("admin.user.delete_confirm"); - const location = document.location.pathname; - - const performDestroy = function (block) { - bootbox.dialog(I18n.t("admin.user.deleting_user")); - let formData = { context: location }; - if (block) { - formData["block_email"] = true; - formData["block_urls"] = true; - formData["block_ip"] = true; - } - if (opts && opts.deletePosts) { - formData["delete_posts"] = true; - } - return ajax(`/admin/users/${user.get("id")}.json`, { - type: "DELETE", - data: formData, - }) - .then(function (data) { - if (data.deleted) { - if (/^\/admin\/users\/list\//.test(location)) { - document.location = location; - } else { - document.location = getURL("/admin/users/list/active"); - } - } else { - bootbox.alert(I18n.t("admin.user.delete_failed")); - if (data.user) { - user.setProperties(data.user); - } - } - }) - .catch(function () { - AdminUser.find(user.get("id")).then((u) => user.setProperties(u)); - bootbox.alert(I18n.t("admin.user.delete_failed")); - }); - }; - - const buttons = [ - { - label: I18n.t("composer.cancel"), - class: "btn", - link: true, - }, - { - label: - `${iconHTML("exclamation-triangle")} ` + - I18n.t("admin.user.delete_and_block"), - class: "btn btn-danger", - callback: function () { - performDestroy(true); - }, - }, - { - label: I18n.t("admin.user.delete_dont_block"), - class: "btn btn-primary", - callback: function () { - performDestroy(false); - }, - }, - ]; - - bootbox.dialog(message, buttons, { classes: "delete-user-modal" }); + destroy(formData) { + return ajax(`/admin/users/${this.id}.json`, { + type: "DELETE", + data: formData, + }); }, - merge(opts) { - const user = this; - const location = document.location.pathname; - - const bootboxDiv = bootbox.dialog(I18n.t("admin.user.merging_user")); - let formData = { context: location }; - - if (opts && opts.targetUsername) { - formData["target_username"] = opts.targetUsername; - } - - return ajax(`/admin/users/${user.id}/merge.json`, { + merge(formData) { + return ajax(`/admin/users/${this.id}/merge.json`, { type: "POST", data: formData, - }) - .then((response) => { - if (response.success) { - messageBus.subscribe("/merge_user", (data) => { - if (data.merged) { - if (/^\/admin\/users\/list\//.test(location)) { - DiscourseURL.redirectTo(location); - } else { - DiscourseURL.redirectTo( - `/admin/users/${data.user.id}/${data.user.username}` - ); - } - } else if (data.message) { - bootboxDiv.find(".modal-body").html(data.message); - } else if (data.failed) { - bootbox.alert(I18n.t("admin.user.merge_failed")); - } - }); - } else { - bootbox.alert(I18n.t("admin.user.merge_failed")); - } - }) - .catch(() => { - AdminUser.find(user.id).then((u) => user.setProperties(u)); - bootbox.alert(I18n.t("admin.user.merge_failed")); - }); + }); }, loadDetails() { @@ -559,10 +301,6 @@ const AdminUser = User.extend({ @discourseComputed("approved_by") approvedBy: wrapAdmin, - _formatError(event) { - return `http: ${event.status} - ${event.body}`; - }, - deleteSSORecord() { return ajax(`/admin/users/${this.id}/sso_record.json`, { type: "DELETE", diff --git a/app/assets/javascripts/admin/addon/models/backup.js b/app/assets/javascripts/admin/addon/models/backup.js index 2d2b88152c1..717192e8ac3 100644 --- a/app/assets/javascripts/admin/addon/models/backup.js +++ b/app/assets/javascripts/admin/addon/models/backup.js @@ -1,10 +1,6 @@ import EmberObject from "@ember/object"; -import I18n from "I18n"; import MessageBus from "message-bus-client"; import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; -import { extractError } from "discourse/lib/ajax-error"; -import getURL from "discourse-common/lib/get-url"; const Backup = EmberObject.extend({ destroy() { @@ -21,16 +17,7 @@ const Backup = EmberObject.extend({ Backup.reopenClass({ find() { - return ajax("/admin/backups.json") - .then((backups) => backups.map((backup) => Backup.create(backup))) - .catch((error) => { - bootbox.alert( - I18n.t("admin.backups.backup_storage_error", { - error_message: extractError(error), - }) - ); - return []; - }); + return ajax("/admin/backups.json"); }, start(withUploads) { @@ -43,33 +30,18 @@ Backup.reopenClass({ with_uploads: withUploads, client_id: MessageBus.clientId, }, - }).then((result) => { - if (!result.success) { - bootbox.alert(result.message); - } }); }, cancel() { return ajax("/admin/backups/cancel.json", { type: "DELETE", - }).then((result) => { - if (!result.success) { - bootbox.alert(result.message); - } }); }, rollback() { return ajax("/admin/backups/rollback.json", { type: "POST", - }).then((result) => { - if (!result.success) { - bootbox.alert(result.message); - } else { - // redirect to homepage (session might be lost) - window.location = getURL("/"); - } }); }, }); diff --git a/app/assets/javascripts/admin/addon/routes/admin-backups-index.js b/app/assets/javascripts/admin/addon/routes/admin-backups-index.js index 08f68952d08..cb05c26580f 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-backups-index.js +++ b/app/assets/javascripts/admin/addon/routes/admin-backups-index.js @@ -12,7 +12,9 @@ export default Route.extend({ }, model() { - return Backup.find(); + return Backup.find().then((backups) => + backups.map((backup) => Backup.create(backup)) + ); }, deactivate() { diff --git a/app/assets/javascripts/admin/addon/routes/admin-backups.js b/app/assets/javascripts/admin/addon/routes/admin-backups.js index 1e26c0221db..063eeec9d77 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-backups.js +++ b/app/assets/javascripts/admin/addon/routes/admin-backups.js @@ -7,6 +7,7 @@ import PreloadStore from "discourse/lib/preload-store"; import User from "discourse/models/user"; import { ajax } from "discourse/lib/ajax"; import bootbox from "bootbox"; +import { extractError } from "discourse/lib/ajax-error"; import getURL from "discourse-common/lib/get-url"; import showModal from "discourse/lib/show-modal"; @@ -74,7 +75,11 @@ export default DiscourseRoute.extend({ startBackup(withUploads) { this.transitionTo("admin.backups.logs"); - Backup.start(withUploads); + Backup.start(withUploads).then((result) => { + if (!result.success) { + bootbox.alert(result.message); + } + }); }, destroyBackup(backup) { @@ -135,7 +140,14 @@ export default DiscourseRoute.extend({ I18n.t("yes_value"), (confirmed) => { if (confirmed) { - Backup.rollback(); + Backup.rollback().then((result) => { + if (!result.success) { + bootbox.alert(result.message); + } else { + // redirect to homepage (session might be lost) + window.location = getURL("/"); + } + }); } } ); @@ -152,12 +164,22 @@ export default DiscourseRoute.extend({ }, remoteUploadSuccess() { - Backup.find().then((backups) => { - this.controllerFor("adminBackupsIndex").set( - "model", - backups.map((backup) => Backup.create(backup)) - ); - }); + Backup.find() + .then((backups) => backups.map((backup) => Backup.create(backup))) + .then((backups) => { + this.controllerFor("adminBackupsIndex").set( + "model", + backups.map((backup) => Backup.create(backup)) + ); + }) + .catch((error) => { + bootbox.alert( + I18n.t("admin.backups.backup_storage_error", { + error_message: extractError(error), + }) + ); + return []; + }); }, }, }); diff --git a/app/assets/javascripts/admin/addon/templates/modal/admin-delete-user-posts-progress.hbs b/app/assets/javascripts/admin/addon/templates/modal/admin-delete-user-posts-progress.hbs new file mode 100644 index 00000000000..8f381db8471 --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/modal/admin-delete-user-posts-progress.hbs @@ -0,0 +1,4 @@ +{{#d-modal-body title="admin.user.delete_posts.progress.title" dismissable=false}} +

{{I18n "admin.user.delete_posts_progress"}}

+
+{{/d-modal-body}} diff --git a/app/assets/javascripts/admin/addon/templates/modal/admin-merge-users-progress.hbs b/app/assets/javascripts/admin/addon/templates/modal/admin-merge-users-progress.hbs new file mode 100644 index 00000000000..40c3c160daf --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/modal/admin-merge-users-progress.hbs @@ -0,0 +1,3 @@ +{{#d-modal-body title="admin.user.merge.progress.title" dismissable=false}} + {{ message }} +{{/d-modal-body}} diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index 2120796c849..77c2bdccd95 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -322,7 +322,7 @@ } } -.delete-posts-progress { +.admin-delete-user-posts-progress-modal { .progress-bar { height: 15px; position: relative; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1210de3237f..f427e96a591 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4663,6 +4663,9 @@ en: anonymize_yes: "Yes, anonymize this account" anonymize_failed: "There was a problem anonymizing the account." delete: "Delete User" + delete_posts: + progress: + title: "Progress of deleting posts" merge: button: "Merge" prompt: @@ -4675,6 +4678,8 @@ en: target_username_placeholder: "Username of new owner" transfer_and_delete: "Transfer & Delete @%{username}" cancel: "Cancel" + progress: + title: "Merge progress" confirmation: title: "Transfer & Delete @%{username}" description: |