mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-14 21:28:03 +08:00
When multiple admins are working in the review queue, it's quite easy for two people to try and handle the same reviewable at the same time. This change addresses the two major situations where this can occur. The `ReviewableClaimedTopic` model has been extended to allow the system to mark a reviewable as claimed as soon as the first moderator starts handling the reviewable, even when the `reviewable_claiming` setting is disabled. This ensures that reviewable actions with client-site activity (for example, `agree_and_suspend`) will lock the reviewable before another moderator starts working on it. When someone handles handles a reviewable, we now use `MessageBus` to inform other moderators that it's changed. If any of the other moderator have that reviewable open (either individually, or on the list screen), it will automatically refresh that data.
121 lines
3.6 KiB
JavaScript
121 lines
3.6 KiB
JavaScript
import { action } from "@ember/object";
|
|
import Service, { service } from "@ember/service";
|
|
import { htmlSafe } from "@ember/template";
|
|
import { Promise } from "rsvp";
|
|
import { ajax } from "discourse/lib/ajax";
|
|
import I18n, { i18n } from "discourse-i18n";
|
|
import PenalizeUserModal from "admin/components/modal/penalize-user";
|
|
import AdminUser from "admin/models/admin-user";
|
|
|
|
// A service that can act as a bridge between the front end Discourse application
|
|
// and the admin application. Use this if you need front end code to access admin
|
|
// modules. Inject it optionally, and if it exists go to town!
|
|
export default class AdminToolsService extends Service {
|
|
@service dialog;
|
|
@service modal;
|
|
@service router;
|
|
|
|
showActionLogs(target, filters) {
|
|
this.router.transitionTo("adminLogs.staffActionLogs", {
|
|
queryParams: { filters },
|
|
});
|
|
}
|
|
|
|
checkSpammer(userId) {
|
|
return AdminUser.find(userId).then((au) => this.spammerDetails(au));
|
|
}
|
|
|
|
deleteUser(id, formData) {
|
|
return AdminUser.find(id).then((user) => user.destroy(formData));
|
|
}
|
|
|
|
spammerDetails(adminUser) {
|
|
return {
|
|
deleteUser: () => this._deleteSpammer(adminUser),
|
|
canDelete:
|
|
adminUser.get("can_be_deleted") &&
|
|
adminUser.get("can_delete_all_posts"),
|
|
};
|
|
}
|
|
|
|
@action
|
|
async showControlModal(type, user, opts) {
|
|
opts = opts || {};
|
|
const loadedUser = user.adminUserView
|
|
? user
|
|
: await AdminUser.find(user.get("id"));
|
|
return this.modal.show(PenalizeUserModal, {
|
|
model: {
|
|
penaltyType: type,
|
|
postId: opts.postId,
|
|
postEdit: opts.postEdit,
|
|
user: loadedUser,
|
|
before: opts.before,
|
|
successCallback: opts.successCallback,
|
|
},
|
|
});
|
|
}
|
|
|
|
showSilenceModal(user, opts) {
|
|
return this.showControlModal("silence", user, opts);
|
|
}
|
|
|
|
showSuspendModal(user, opts) {
|
|
return this.showControlModal("suspend", user, opts);
|
|
}
|
|
|
|
_deleteSpammer(adminUser) {
|
|
// Try loading the email if the site supports it
|
|
let tryEmail = this.siteSettings.moderators_view_emails
|
|
? adminUser.checkEmail()
|
|
: Promise.resolve();
|
|
|
|
return tryEmail.then(() => {
|
|
let message = htmlSafe(
|
|
I18n.messageFormat("flagging.delete_confirm_MF", {
|
|
POSTS: adminUser.get("post_count"),
|
|
TOPICS: adminUser.get("topic_count"),
|
|
email:
|
|
adminUser.get("email") || i18n("flagging.hidden_email_address"),
|
|
ip_address:
|
|
adminUser.get("ip_address") || i18n("flagging.ip_address_missing"),
|
|
})
|
|
);
|
|
|
|
let userId = adminUser.get("id");
|
|
|
|
return new Promise((resolve, reject) => {
|
|
this.dialog.deleteConfirm({
|
|
message,
|
|
class: "flagging-delete-spammer",
|
|
confirmButtonLabel: "flagging.yes_delete_spammer",
|
|
confirmButtonIcon: "triangle-exclamation",
|
|
didConfirm: () => {
|
|
return ajax(`/admin/users/${userId}.json`, {
|
|
type: "DELETE",
|
|
data: {
|
|
delete_posts: true,
|
|
block_email: true,
|
|
block_urls: true,
|
|
block_ip: true,
|
|
delete_as_spammer: true,
|
|
context: window.location.pathname,
|
|
},
|
|
})
|
|
.then((result) => {
|
|
if (result.deleted) {
|
|
resolve();
|
|
} else {
|
|
throw new Error("failed to delete");
|
|
}
|
|
})
|
|
.catch(() => {
|
|
this.dialog.alert(i18n("admin.user.delete_failed"));
|
|
reject();
|
|
});
|
|
},
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|