mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-13 18:17:42 +01:00
feat: closes #13961, rename ban-reasons to custom reasons
use them for ban, mute and post queue depending on the type selected if type is set to all, the reason is displayed in ban/mute and post queue move reason label + dropdown + textarea to a partial
This commit is contained in:
104
.tx/config
104
.tx/config
@@ -1266,60 +1266,60 @@ trans.vi = public/language/vi/admin/manage/uploads.json
|
||||
trans.zh_CN = public/language/zh-CN/admin/manage/uploads.json
|
||||
trans.zh_TW = public/language/zh-TW/admin/manage/uploads.json
|
||||
|
||||
[o:nodebb:p:nodebb:r:admin-manage-user-ban-reasons]
|
||||
file_filter = public/language/<lang>/admin/manage/ban-reasons.json
|
||||
source_file = public/language/en-GB/admin/manage/ban-reasons.json
|
||||
[o:nodebb:p:nodebb:r:admin-manage-user-custom-reasons]
|
||||
file_filter = public/language/<lang>/admin/manage/custom-reasons.json
|
||||
source_file = public/language/en-GB/admin/manage/custom-reasons.json
|
||||
source_lang = en_GB
|
||||
type = KEYVALUEJSON
|
||||
trans.ar = public/language/ar/admin/manage/ban-reasons.json
|
||||
trans.az = public/language/az/admin/manage/ban-reasons.json
|
||||
trans.bg = public/language/bg/admin/manage/ban-reasons.json
|
||||
trans.bn = public/language/bn/admin/manage/ban-reasons.json
|
||||
trans.cs = public/language/cs/admin/manage/ban-reasons.json
|
||||
trans.da = public/language/da/admin/manage/ban-reasons.json
|
||||
trans.de = public/language/de/admin/manage/ban-reasons.json
|
||||
trans.el = public/language/el/admin/manage/ban-reasons.json
|
||||
trans.en_US = public/language/en-US/admin/manage/ban-reasons.json
|
||||
trans.en@pirate = public/language/en-x-pirate/admin/manage/ban-reasons.json
|
||||
trans.es = public/language/es/admin/manage/ban-reasons.json
|
||||
trans.et = public/language/et/admin/manage/ban-reasons.json
|
||||
trans.fa_IR = public/language/fa-IR/admin/manage/ban-reasons.json
|
||||
trans.fi = public/language/fi/admin/manage/ban-reasons.json
|
||||
trans.fr = public/language/fr/admin/manage/ban-reasons.json
|
||||
trans.gl = public/language/gl/admin/manage/ban-reasons.json
|
||||
trans.he = public/language/he/admin/manage/ban-reasons.json
|
||||
trans.hr = public/language/hr/admin/manage/ban-reasons.json
|
||||
trans.hu = public/language/hu/admin/manage/ban-reasons.json
|
||||
trans.hy = public/language/hy/admin/manage/ban-reasons.json
|
||||
trans.id = public/language/id/admin/manage/ban-reasons.json
|
||||
trans.it = public/language/it/admin/manage/ban-reasons.json
|
||||
trans.ja = public/language/ja/admin/manage/ban-reasons.json
|
||||
trans.ko = public/language/ko/admin/manage/ban-reasons.json
|
||||
trans.lt = public/language/lt/admin/manage/ban-reasons.json
|
||||
trans.lv = public/language/lv/admin/manage/ban-reasons.json
|
||||
trans.ms = public/language/ms/admin/manage/ban-reasons.json
|
||||
trans.nb = public/language/nb/admin/manage/ban-reasons.json
|
||||
trans.nl = public/language/nl/admin/manage/ban-reasons.json
|
||||
trans.nn_NO = public/language/nn-NO/admin/manage/ban-reasons.json
|
||||
trans.pl = public/language/pl/admin/manage/ban-reasons.json
|
||||
trans.pt_BR = public/language/pt-BR/admin/manage/ban-reasons.json
|
||||
trans.pt_PT = public/language/pt-PT/admin/manage/ban-reasons.json
|
||||
trans.ro = public/language/ro/admin/manage/ban-reasons.json
|
||||
trans.ru = public/language/ru/admin/manage/ban-reasons.json
|
||||
trans.rw = public/language/rw/admin/manage/ban-reasons.json
|
||||
trans.sc = public/language/sc/admin/manage/ban-reasons.json
|
||||
trans.sk = public/language/sk/admin/manage/ban-reasons.json
|
||||
trans.sl = public/language/sl/admin/manage/ban-reasons.json
|
||||
trans.sq_AL = public/language/sq-AL/admin/manage/ban-reasons.json
|
||||
trans.sr = public/language/sr/admin/manage/ban-reasons.json
|
||||
trans.sv = public/language/sv/admin/manage/ban-reasons.json
|
||||
trans.th = public/language/th/admin/manage/ban-reasons.json
|
||||
trans.tr = public/language/tr/admin/manage/ban-reasons.json
|
||||
trans.uk = public/language/uk/admin/manage/ban-reasons.json
|
||||
trans.ur = public/language/ur/admin/manage/ban-reasons.json
|
||||
trans.vi = public/language/vi/admin/manage/ban-reasons.json
|
||||
trans.zh_CN = public/language/zh-CN/admin/manage/ban-reasons.json
|
||||
trans.zh_TW = public/language/zh-TW/admin/manage/ban-reasons.json
|
||||
trans.ar = public/language/ar/admin/manage/custom-reasons.json
|
||||
trans.az = public/language/az/admin/manage/custom-reasons.json
|
||||
trans.bg = public/language/bg/admin/manage/custom-reasons.json
|
||||
trans.bn = public/language/bn/admin/manage/custom-reasons.json
|
||||
trans.cs = public/language/cs/admin/manage/custom-reasons.json
|
||||
trans.da = public/language/da/admin/manage/custom-reasons.json
|
||||
trans.de = public/language/de/admin/manage/custom-reasons.json
|
||||
trans.el = public/language/el/admin/manage/custom-reasons.json
|
||||
trans.en_US = public/language/en-US/admin/manage/custom-reasons.json
|
||||
trans.en@pirate = public/language/en-x-pirate/admin/manage/custom-reasons.json
|
||||
trans.es = public/language/es/admin/manage/custom-reasons.json
|
||||
trans.et = public/language/et/admin/manage/custom-reasons.json
|
||||
trans.fa_IR = public/language/fa-IR/admin/manage/custom-reasons.json
|
||||
trans.fi = public/language/fi/admin/manage/custom-reasons.json
|
||||
trans.fr = public/language/fr/admin/manage/custom-reasons.json
|
||||
trans.gl = public/language/gl/admin/manage/custom-reasons.json
|
||||
trans.he = public/language/he/admin/manage/custom-reasons.json
|
||||
trans.hr = public/language/hr/admin/manage/custom-reasons.json
|
||||
trans.hu = public/language/hu/admin/manage/custom-reasons.json
|
||||
trans.hy = public/language/hy/admin/manage/custom-reasons.json
|
||||
trans.id = public/language/id/admin/manage/custom-reasons.json
|
||||
trans.it = public/language/it/admin/manage/custom-reasons.json
|
||||
trans.ja = public/language/ja/admin/manage/custom-reasons.json
|
||||
trans.ko = public/language/ko/admin/manage/custom-reasons.json
|
||||
trans.lt = public/language/lt/admin/manage/custom-reasons.json
|
||||
trans.lv = public/language/lv/admin/manage/custom-reasons.json
|
||||
trans.ms = public/language/ms/admin/manage/custom-reasons.json
|
||||
trans.nb = public/language/nb/admin/manage/custom-reasons.json
|
||||
trans.nl = public/language/nl/admin/manage/custom-reasons.json
|
||||
trans.nn_NO = public/language/nn-NO/admin/manage/custom-reasons.json
|
||||
trans.pl = public/language/pl/admin/manage/custom-reasons.json
|
||||
trans.pt_BR = public/language/pt-BR/admin/manage/custom-reasons.json
|
||||
trans.pt_PT = public/language/pt-PT/admin/manage/custom-reasons.json
|
||||
trans.ro = public/language/ro/admin/manage/custom-reasons.json
|
||||
trans.ru = public/language/ru/admin/manage/custom-reasons.json
|
||||
trans.rw = public/language/rw/admin/manage/custom-reasons.json
|
||||
trans.sc = public/language/sc/admin/manage/custom-reasons.json
|
||||
trans.sk = public/language/sk/admin/manage/custom-reasons.json
|
||||
trans.sl = public/language/sl/admin/manage/custom-reasons.json
|
||||
trans.sq_AL = public/language/sq-AL/admin/manage/custom-reasons.json
|
||||
trans.sr = public/language/sr/admin/manage/custom-reasons.json
|
||||
trans.sv = public/language/sv/admin/manage/custom-reasons.json
|
||||
trans.th = public/language/th/admin/manage/custom-reasons.json
|
||||
trans.tr = public/language/tr/admin/manage/custom-reasons.json
|
||||
trans.uk = public/language/uk/admin/manage/custom-reasons.json
|
||||
trans.ur = public/language/ur/admin/manage/custom-reasons.json
|
||||
trans.vi = public/language/vi/admin/manage/custom-reasons.json
|
||||
trans.zh_CN = public/language/zh-CN/admin/manage/custom-reasons.json
|
||||
trans.zh_TW = public/language/zh-TW/admin/manage/custom-reasons.json
|
||||
|
||||
[o:nodebb:p:nodebb:r:admin-manage-user-custom-fields]
|
||||
file_filter = public/language/<lang>/admin/manage/user-custom-fields.json
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"title": "Manage Ban Reasons",
|
||||
"create-reason": "Create Reason",
|
||||
"edit-reason": "Edit Reason",
|
||||
"reason-title": "Title",
|
||||
"reason-body": "Body",
|
||||
"ban-reasons-saved": "Ban reasons saved successfully",
|
||||
"delete-reason-confirm-x": "Are you sure you want to delete the ban reason with the title <strong>%1</strong>?"
|
||||
}
|
||||
16
public/language/en-GB/admin/manage/custom-reasons.json
Normal file
16
public/language/en-GB/admin/manage/custom-reasons.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"title": "Manage Custom Reasons",
|
||||
"create-reason": "Create Reason",
|
||||
"edit-reason": "Edit Reason",
|
||||
"reasons-help": "Reasons are predefined explanations used when banning or muting users, or when rejecting posts in the post queue.",
|
||||
"reason-title": "Title",
|
||||
"reason-type": "Type",
|
||||
"reason-body": "Body",
|
||||
"reason-all": "All",
|
||||
"reason-ban": "Ban",
|
||||
"reason-mute": "Mute",
|
||||
"reason-post-queue": "Post Queue",
|
||||
"reason-type-help": "The type of action this reason applies to. If 'All' is selected, this reason will be available for all action types.",
|
||||
"custom-reasons-saved": "Custom reasons saved successfully",
|
||||
"delete-reason-confirm-x": "Are you sure you want to delete the custom reason with the title <strong>%1</strong>?"
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
"purge": "Delete <strong>User(s)</strong> and <strong>Content</strong>",
|
||||
"download-csv": "Download CSV",
|
||||
"custom-user-fields": "Custom User Fields",
|
||||
"ban-reasons": "Ban Reasons",
|
||||
"custom-reasons": "Custom Reasons",
|
||||
"manage-groups": "Manage Groups",
|
||||
"set-reputation": "Set Reputation",
|
||||
"add-group": "Add Group",
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
"users-csv-exported": "Users csv exported, click to download",
|
||||
"post-queue-accepted": "Your queued post has been accepted. Click here to see your post.",
|
||||
"post-queue-rejected": "Your queued post has been rejected.",
|
||||
"post-queue-rejected-for-reason": "Your queued post has been rejected for the following reason: \"%1\"",
|
||||
"post-queue-notify": "Queued post received a notification: \"%1\"",
|
||||
|
||||
"email-confirmed": "Email Confirmed",
|
||||
|
||||
@@ -260,7 +260,7 @@ define('admin/manage/users', [
|
||||
alerts.error('[[error:no-users-selected]]');
|
||||
return false; // specifically to keep the menu open
|
||||
}
|
||||
const reasons = await socket.emit('user.getBanReasons');
|
||||
const reasons = await socket.emit('user.getCustomReasons', { type: 'ban' });
|
||||
const html = await app.parseAndTranslate('modals/temporary-ban', { reasons });
|
||||
const modal = bootbox.dialog({
|
||||
title: '[[user:ban-account]]',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
define('admin/manage/user/ban-reasons', [
|
||||
define('admin/manage/user/custom-reasons', [
|
||||
'benchpress', 'bootbox', 'alerts', 'translator', 'jquery-ui/widgets/sortable',
|
||||
], function (benchpress, bootbox, alerts, translator) {
|
||||
const manageBanReasons = {};
|
||||
const manageCustomReasons = {};
|
||||
|
||||
manageBanReasons.init = function () {
|
||||
manageCustomReasons.init = function () {
|
||||
const table = $('table');
|
||||
|
||||
$('#new').on('click', () => showModal());
|
||||
@@ -16,7 +16,7 @@ define('admin/manage/user/ban-reasons', [
|
||||
table.on('click', '[data-action="delete"]', function () {
|
||||
const row = $(this).parents('[data-key]');
|
||||
const title = row.attr('data-title');
|
||||
bootbox.confirm(`[[admin/manage/ban-reasons:delete-reason-confirm-x, "${title}"]]`, function (ok) {
|
||||
bootbox.confirm(`[[admin/manage/custom-reasons:delete-reason-confirm-x, "${title}"]]`, function (ok) {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
@@ -35,11 +35,11 @@ define('admin/manage/user/ban-reasons', [
|
||||
$('tbody tr[data-key]').each((index, el) => {
|
||||
reasons.push(getDataFromEl($(el)));
|
||||
});
|
||||
socket.emit('admin.user.saveBanReasons', reasons, function (err) {
|
||||
socket.emit('admin.user.saveCustomReasons', reasons, function (err) {
|
||||
if (err) {
|
||||
return alerts.error(err);
|
||||
}
|
||||
alerts.success('[[admin/manage/ban-reasons:ban-reasons-saved]]');
|
||||
alerts.success('[[admin/manage/custom-reasons:custom-reasons-saved]]');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -48,18 +48,19 @@ define('admin/manage/user/ban-reasons', [
|
||||
return {
|
||||
key: el.attr('data-key'),
|
||||
title: el.attr('data-title'),
|
||||
type: el.attr('data-type'),
|
||||
body: el.attr('data-body'),
|
||||
};
|
||||
}
|
||||
|
||||
async function showModal(reason = null) {
|
||||
const html = await benchpress.render('admin/partials/manage-ban-reasons-modal', reason);
|
||||
const html = await benchpress.render('admin/partials/manage-custom-reasons-modal', reason);
|
||||
const modal = bootbox.dialog({
|
||||
message: html,
|
||||
onEscape: true,
|
||||
title: reason ?
|
||||
'[[admin/manage/ban-reasons:edit-reason]]' :
|
||||
'[[admin/manage/ban-reasons:create-reason]]',
|
||||
'[[admin/manage/custom-reasons:edit-reason]]' :
|
||||
'[[admin/manage/custom-reasons:create-reason]]',
|
||||
buttons: {
|
||||
submit: {
|
||||
label: '[[global:save]]',
|
||||
@@ -69,7 +70,7 @@ define('admin/manage/user/ban-reasons', [
|
||||
formData.body = translator.escape(formData.body);
|
||||
formData.parsedBody = translator.escape(await socket.emit('admin.parseRaw', formData.body));
|
||||
|
||||
app.parseAndTranslate('admin/manage/users/ban-reasons', 'reasons', {
|
||||
app.parseAndTranslate('admin/manage/users/custom-reasons', 'reasons', {
|
||||
reasons: [formData],
|
||||
}, (html) => {
|
||||
if (reason) {
|
||||
@@ -90,7 +91,7 @@ define('admin/manage/user/ban-reasons', [
|
||||
}
|
||||
|
||||
|
||||
return manageBanReasons;
|
||||
return manageCustomReasons;
|
||||
});
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
|
||||
define('forum/post-queue', [
|
||||
'categoryFilter', 'categorySelector', 'api', 'alerts', 'bootbox',
|
||||
'accounts/moderate', 'accounts/delete',
|
||||
'categoryFilter', 'categorySelector', 'api', 'alerts', 'translator',
|
||||
'bootbox', 'accounts/moderate', 'accounts/delete',
|
||||
], function (
|
||||
categoryFilter, categorySelector, api, alerts, bootbox,
|
||||
AccountModerate, AccountsDelete
|
||||
categoryFilter, categorySelector, api, alerts, translator,
|
||||
bootbox, AccountModerate, AccountsDelete
|
||||
) {
|
||||
const PostQueue = {};
|
||||
|
||||
@@ -158,70 +158,122 @@ define('forum/post-queue', [
|
||||
AccountsDelete.purge(uid, ajaxify.go.bind(null, 'post-queue'));
|
||||
break;
|
||||
|
||||
default:
|
||||
handleQueueActions.call(e.target);
|
||||
case 'accept':
|
||||
handleAccept(subselector);
|
||||
break;
|
||||
|
||||
case 'reject':
|
||||
handleReject(subselector);
|
||||
break;
|
||||
|
||||
case 'notify':
|
||||
handleNotify(subselector);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown action: ${action}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleQueueActions() {
|
||||
// accept, reject, notify
|
||||
|
||||
const parent = $(this).parents('[data-id]');
|
||||
const action = $(this).attr('data-action');
|
||||
function handleAccept(btn) {
|
||||
const parent = $(btn).parents('[data-id]');
|
||||
const id = parent.attr('data-id');
|
||||
const listContainer = parent.get(0).parentNode;
|
||||
doAction('accept', id).then(() => removePostQueueElement(parent)).catch(alerts.error);
|
||||
}
|
||||
|
||||
if ((!['accept', 'reject', 'notify'].includes(action)) ||
|
||||
(action === 'reject' && !await confirmReject(ajaxify.data.canAccept ? '[[post-queue:confirm-reject]]' : '[[post-queue:confirm-remove]]'))) {
|
||||
async function handleReject(btn) {
|
||||
const parent = $(btn).parents('[data-id]');
|
||||
const id = parent.attr('data-id');
|
||||
const translationString = ajaxify.data.canAccept ?
|
||||
'[[post-queue:confirm-reject]]' :
|
||||
'[[post-queue:confirm-remove]]';
|
||||
|
||||
const message = await getMessage(translationString);
|
||||
if (message === false) {
|
||||
return;
|
||||
}
|
||||
doAction('reject', id, message).then(() => removePostQueueElement(parent)).catch(alerts.error);
|
||||
}
|
||||
|
||||
function removePostQueueElement(parent) {
|
||||
const listContainer = parent.get(0).parentNode;
|
||||
parent.remove();
|
||||
if (listContainer.childElementCount === 0) {
|
||||
if (ajaxify.data.singlePost) {
|
||||
ajaxify.go('/post-queue' + window.location.search);
|
||||
} else {
|
||||
ajaxify.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleNotify(btn) {
|
||||
const parent = $(btn).parents('[data-id]');
|
||||
const id = parent.attr('data-id');
|
||||
const message = await getMessage('[[post-queue:notify-user]]');
|
||||
if (message === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
doAction(action, id).then(function () {
|
||||
if (action === 'accept' || action === 'reject') {
|
||||
parent.remove();
|
||||
}
|
||||
|
||||
if (listContainer.childElementCount === 0) {
|
||||
if (ajaxify.data.singlePost) {
|
||||
ajaxify.go('/post-queue' + window.location.search);
|
||||
} else {
|
||||
ajaxify.refresh();
|
||||
}
|
||||
}
|
||||
}).catch(alerts.error);
|
||||
|
||||
return false;
|
||||
doAction('notify', id, message).catch(alerts.error);
|
||||
}
|
||||
|
||||
async function doAction(action, id) {
|
||||
function getMessage() {
|
||||
return new Promise((resolve) => {
|
||||
const modal = bootbox.dialog({
|
||||
title: '[[post-queue:notify-user]]',
|
||||
message: '<textarea class="form-control"></textarea>',
|
||||
buttons: {
|
||||
OK: {
|
||||
label: '[[modules:bootbox.send]]',
|
||||
callback: function () {
|
||||
const val = modal.find('textarea').val();
|
||||
if (val) {
|
||||
resolve(val);
|
||||
}
|
||||
},
|
||||
async function getMessage(title) {
|
||||
const reasons = await socket.emit('user.getCustomReasons', { type: 'post-queue' });
|
||||
const html = await app.parseAndTranslate('partials/custom-reason', { reasons });
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let resolved = false;
|
||||
const done = (value) => {
|
||||
if (resolved) {
|
||||
return;
|
||||
}
|
||||
resolved = true;
|
||||
resolve(value);
|
||||
};
|
||||
|
||||
const modal = bootbox.dialog({
|
||||
title: title,
|
||||
message: `<form class="form">${html.html()}</form>`,
|
||||
show: true,
|
||||
onEscape: true,
|
||||
buttons: {
|
||||
close: {
|
||||
label: '[[global:close]]',
|
||||
className: 'btn-link',
|
||||
callback: function () {
|
||||
done(false);
|
||||
},
|
||||
},
|
||||
});
|
||||
submit: {
|
||||
label: '[[modules:bootbox.confirm]]',
|
||||
callback: function () {
|
||||
done(modal.find('[name="reason"]').val());
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
modal.on('hidden.bs.modal', () => {
|
||||
done(false);
|
||||
});
|
||||
modal.find('[data-key]').on('click', function () {
|
||||
const reason = reasons.find(r => String(r.key) === $(this).attr('data-key'));
|
||||
if (reason && reason.body) {
|
||||
modal.find('[name="reason"]').val(translator.unescape(reason.body));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function doAction(action, id, message = '') {
|
||||
const actionsMap = {
|
||||
accept: () => api.post(`/posts/queue/${id}`, {}),
|
||||
reject: () => api.del(`/posts/queue/${id}`, {}),
|
||||
notify: async () => api.post(`/posts/queue/${id}/notify`, { message: await getMessage() }),
|
||||
reject: () => api.del(`/posts/queue/${id}`, { message }),
|
||||
notify: () => api.post(`/posts/queue/${id}/notify`, { message }),
|
||||
};
|
||||
if (actionsMap[action]) {
|
||||
const result = actionsMap[action]();
|
||||
|
||||
@@ -14,6 +14,7 @@ define('forum/account/moderate', [
|
||||
throwModal({
|
||||
tpl: 'modals/temporary-ban',
|
||||
title: '[[user:ban-account]]',
|
||||
type: 'ban',
|
||||
onSubmit: function (formData) {
|
||||
const until = formData.length > 0 ? (
|
||||
Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))
|
||||
@@ -36,6 +37,7 @@ define('forum/account/moderate', [
|
||||
throwModal({
|
||||
tpl: 'modals/unban',
|
||||
title: '[[user:unban-account]]',
|
||||
type: 'ban',
|
||||
onSubmit: function (formData) {
|
||||
api.del('/users/' + encodeURIComponent(theirid) + '/ban', {
|
||||
reason: formData.reason || '',
|
||||
@@ -51,6 +53,7 @@ define('forum/account/moderate', [
|
||||
throwModal({
|
||||
tpl: 'modals/temporary-mute',
|
||||
title: '[[user:mute-account]]',
|
||||
type: 'mute',
|
||||
onSubmit: function (formData) {
|
||||
const until = formData.length > 0 ? (
|
||||
Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1))
|
||||
@@ -84,7 +87,7 @@ define('forum/account/moderate', [
|
||||
};
|
||||
|
||||
async function throwModal(options) {
|
||||
const reasons = await socket.emit('user.getBanReasons');
|
||||
const reasons = await socket.emit('user.getCustomReasons', { type: options.type || '' });
|
||||
const html = await app.parseAndTranslate(options.tpl, { reasons });
|
||||
const modal = bootbox.dialog({
|
||||
title: options.title,
|
||||
|
||||
@@ -592,7 +592,10 @@ postsAPI.removeQueuedPost = async (caller, data) => {
|
||||
await canEditQueue(caller.uid, data, 'reject');
|
||||
const result = await posts.removeFromQueue(data.id);
|
||||
if (result && caller.uid !== parseInt(result.uid, 10)) {
|
||||
await sendQueueNotification('post-queue-rejected', result.uid, '/');
|
||||
const msg = validator.escape(String(data.message ? data.message : ''));
|
||||
await sendQueueNotification(
|
||||
msg ? 'post-queue-rejected-for-reason' : 'post-queue-rejected', result.uid, '/', msg
|
||||
);
|
||||
}
|
||||
await logQueueEvent(caller, result, 'reject');
|
||||
};
|
||||
@@ -612,7 +615,7 @@ postsAPI.notifyQueuedPostOwner = async (caller, data) => {
|
||||
await canEditQueue(caller.uid, data, 'notify');
|
||||
const result = await posts.getFromQueue(data.id);
|
||||
if (result) {
|
||||
await sendQueueNotification('post-queue-notify', result.uid, `/post-queue/${data.id}`, validator.escape(String(data.message)));
|
||||
await sendQueueNotification('post-queue-notify', result.uid, `/post-queue/${data.id}`, validator.escape(String(data.message || '')));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -316,6 +316,6 @@ usersController.customFields = async function (req, res) {
|
||||
};
|
||||
|
||||
usersController.banReasons = async function (req, res) {
|
||||
const reasons = await user.bans.getBanReasons();
|
||||
res.render('admin/manage/users/ban-reasons', { reasons });
|
||||
const reasons = await user.bans.getCustomReasons();
|
||||
res.render('admin/manage/users/custom-reasons', { reasons });
|
||||
};
|
||||
@@ -196,7 +196,7 @@ Posts.acceptQueuedPost = async (req, res) => {
|
||||
};
|
||||
|
||||
Posts.removeQueuedPost = async (req, res) => {
|
||||
await api.posts.removeQueuedPost(req, { id: req.params.id });
|
||||
await api.posts.removeQueuedPost(req, { id: req.params.id, message: req.body.message });
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ module.exports = function (app, name, middleware, controllers) {
|
||||
|
||||
helpers.setupAdminPageRoute(app, `/${name}/manage/users`, middlewares, controllers.admin.users.index);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/manage/users/custom-fields`, middlewares, controllers.admin.users.customFields);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/manage/users/ban-reasons`, middlewares, controllers.admin.users.banReasons);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/manage/users/custom-reasons`, middlewares, controllers.admin.users.banReasons);
|
||||
helpers.setupAdminPageRoute(app, `/${name}/manage/registration`, middlewares, controllers.admin.users.registrationQueue);
|
||||
|
||||
helpers.setupAdminPageRoute(app, `/${name}/manage/admins-mods`, middlewares, controllers.admin.adminsMods.get);
|
||||
|
||||
@@ -219,11 +219,11 @@ User.saveCustomFields = async function (socket, fields) {
|
||||
await user.reloadCustomFieldWhitelist();
|
||||
};
|
||||
|
||||
User.saveBanReasons = async function (socket, reasons) {
|
||||
const keys = await db.getSortedSetRange('ban-reasons', 0, -1);
|
||||
await db.delete('ban-reasons');
|
||||
await db.deleteAll(keys.map(k => `ban-reason:${k}`));
|
||||
User.saveCustomReasons = async function (socket, reasons) {
|
||||
const keys = await db.getSortedSetRange('custom-reasons', 0, -1);
|
||||
await db.delete('custom-reasons');
|
||||
await db.deleteAll(keys.map(k => `custom-reason:${k}`));
|
||||
const ids = reasons.map((f, i) => i);
|
||||
await db.sortedSetAdd(`ban-reasons`, ids, ids);
|
||||
await db.setObjectBulk(reasons.map((reason, i) => [`ban-reason:${i}`, reason]));
|
||||
await db.sortedSetAdd(`custom-reasons`, ids, ids);
|
||||
await db.setObjectBulk(reasons.map((reason, i) => [`custom-reason:${i}`, reason]));
|
||||
};
|
||||
|
||||
@@ -174,12 +174,12 @@ SocketUser.editModerationNote = async function (socket, data) {
|
||||
return await user.getModerationNotesByIds(data.uid, [data.id]);
|
||||
};
|
||||
|
||||
SocketUser.getBanReasons = async function (socket) {
|
||||
SocketUser.getCustomReasons = async function (socket, { type }) {
|
||||
const canBan = await privileges.users.hasBanPrivilege(socket.uid);
|
||||
if (!canBan) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
return await user.bans.getBanReasons();
|
||||
return await user.bans.getCustomReasons({ type });
|
||||
};
|
||||
|
||||
SocketUser.deleteUpload = async function (socket, data) {
|
||||
|
||||
@@ -165,14 +165,18 @@ module.exports = function (User) {
|
||||
return banObj && banObj.reason ? banObj.reason : '';
|
||||
};
|
||||
|
||||
User.bans.getBanReasons = async function () {
|
||||
const keys = await db.getSortedSetRange('ban-reasons', 0, -1);
|
||||
const reasons = (await db.getObjects(keys.map(k => `ban-reason:${k}`))).filter(Boolean);
|
||||
User.bans.getCustomReasons = async function ({ type = '' } = {}) {
|
||||
const keys = await db.getSortedSetRange('custom-reasons', 0, -1);
|
||||
type = type || '';
|
||||
const reasons = (await db.getObjects(keys.map(k => `custom-reason:${k}`))).filter(Boolean);
|
||||
await Promise.all(reasons.map(async (reason, i) => {
|
||||
reason.key = i;
|
||||
reason.parsedBody = translator.escape(await plugins.hooks.fire('filter:parse.raw', reason.body || ''));
|
||||
reason.body = translator.escape(reason.body);
|
||||
}));
|
||||
if (type !== '') {
|
||||
return reasons.filter(reason => reason.type === type || reason.type === '');
|
||||
}
|
||||
return reasons;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<li><a target="_blank" href="#" class="dropdown-item rounded-1 export-csv" role="menuitem">[[admin/manage/users:download-csv]]</a></li>
|
||||
<li><a class="dropdown-item rounded-1" href="{relative_path}/admin/manage/users/custom-fields">[[admin/manage/users:custom-user-fields]]</a>
|
||||
</li>
|
||||
<li><a class="dropdown-item rounded-1" href="{relative_path}/admin/manage/users/ban-reasons">[[admin/manage/users:ban-reasons]]</a>
|
||||
<li><a class="dropdown-item rounded-1" href="{relative_path}/admin/manage/users/custom-reasons">[[admin/manage/users:custom-reasons]]</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<div class="manage-users d-flex flex-column gap-2 px-lg-4 h-100">
|
||||
<div class="d-flex border-bottom py-2 m-0 sticky-top acp-page-main-header align-items-center justify-content-between flex-wrap gap-2">
|
||||
<div class="">
|
||||
<h4 class="fw-bold tracking-tight mb-0">[[admin/manage/ban-reasons:title]]</h4>
|
||||
<h4 class="fw-bold tracking-tight mb-0">[[admin/manage/custom-reasons:title]]</h4>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-1">
|
||||
<button id="new" class="btn btn-light btn-sm text-nowrap" type="button">
|
||||
<i class="fa fa-fw fa-plus"></i> [[admin/manage/ban-reasons:create-reason]]
|
||||
<i class="fa fa-fw fa-plus"></i> [[admin/manage/custom-reasons:create-reason]]
|
||||
</button>
|
||||
<button id="save" class="btn btn-primary btn-sm fw-semibold ff-secondary w-100 text-center text-nowrap">[[admin/admin:save-changes]]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-secondary">[[admin/manage/custom-reasons:reasons-help]]</p>
|
||||
|
||||
<div class="row flex-grow-1">
|
||||
<div class="col-lg-12 d-flex flex-column gap-2">
|
||||
<div class="table-responsive flex-grow-1">
|
||||
@@ -18,18 +20,20 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-muted">[[admin/manage/ban-reasons:reason-title]]</th>
|
||||
<th class="text-muted">[[admin/manage/ban-reasons:reason-body]]</th>
|
||||
<th class="text-muted">[[admin/manage/custom-reasons:reason-title]]</th>
|
||||
<th class="text-muted">[[admin/manage/custom-reasons:reason-type]]</th>
|
||||
<th class="text-muted">[[admin/manage/custom-reasons:reason-body]]</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{{ each reasons }}}
|
||||
<tr data-key="{./key}" data-title="{./title}" data-body="{./body}">
|
||||
<tr data-key="{./key}" data-title="{./title}" data-type="{./type}" data-body="{./body}">
|
||||
<td class="" style="width: 32px;">
|
||||
<a href="#" component="sort/handle" class="btn btn-light btn-sm d-none d-md-block ui-sortable-handle" style="cursor:grab;"><i class="fa fa-arrows-up-down text-muted"></i></a>
|
||||
</td>
|
||||
<td class="text-nowrap ">{./title}</td>
|
||||
<td class="text-nowrap">{./title}</td>
|
||||
<td class="text-nowrap">{{{ if ./type }}}[[admin/manage/custom-reasons:reason-{{./type}}]]{{{ else }}}[[admin/manage/custom-reasons:reason-all]]{{{ end }}}</td>
|
||||
<td class="">{./parsedBody}</td>
|
||||
<td class="">
|
||||
<div class="d-flex justify-content-end gap-1">
|
||||
@@ -1,11 +0,0 @@
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">[[admin/manage/ban-reasons:reason-title]]</label>
|
||||
<input class="form-control" type="text" name="title" value="{./title}">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">[[admin/manage/ban-reasons:reason-body]]</label>
|
||||
<textarea rows="8" class="form-control" type="text" name="body">{./body}</textarea>
|
||||
</div>
|
||||
</form>
|
||||
22
src/views/admin/partials/manage-custom-reasons-modal.tpl
Normal file
22
src/views/admin/partials/manage-custom-reasons-modal.tpl
Normal file
@@ -0,0 +1,22 @@
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">[[admin/manage/custom-reasons:reason-title]]</label>
|
||||
<input class="form-control" type="text" name="title" value="{./title}">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">[[admin/manage/custom-reasons:reason-type]]</label>
|
||||
<select class="form-select" name="type">
|
||||
<option value="" {{{ if (type == "") }}}selected{{{ end }}} >[[admin/manage/custom-reasons:reason-all]]</option>
|
||||
<option value="ban" {{{ if (type == "ban") }}}selected{{{ end }}}>[[admin/manage/custom-reasons:reason-ban]]</option>
|
||||
<option value="mute" {{{ if (type == "mute") }}}selected{{{ end }}}>[[admin/manage/custom-reasons:reason-mute]]</option>
|
||||
<option value="post-queue" {{{ if (type == "post-queue") }}}selected{{{ end }}}>[[admin/manage/custom-reasons:reason-post-queue]]</option>
|
||||
</select>
|
||||
<p class="form-text">[[admin/manage/custom-reasons:reason-type-help]]</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">[[admin/manage/custom-reasons:reason-body]]</label>
|
||||
<textarea rows="8" class="form-control" type="text" name="body">{./body}</textarea>
|
||||
</div>
|
||||
</form>
|
||||
@@ -23,24 +23,7 @@
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||
<label class="form-label mb-0" for="reason">[[admin/manage/users:temp-ban.reason]]</label>
|
||||
{{{ if reasons.length }}}
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-light btn-sm dropdown-toggle" type="button" id="reasonDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
[[admin/manage/users:temp-ban.select-reason]]
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end p-1" aria-labelledby="reasonDropdown">
|
||||
{{{ each reasons }}}
|
||||
<li><a class="dropdown-item rounded-1" href="#" data-key="{./key}">{./title}</a></li>
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
|
||||
<textarea rows="8" type="text" class="form-control" id="reason" name="reason"></textarea>
|
||||
<!-- IMPORT partials/custom-reason.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,24 +24,7 @@
|
||||
|
||||
<div class="col-12">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||
<label class="form-label mb-0" for="reason">[[admin/manage/users:temp-ban.reason]]</label>
|
||||
{{{ if reasons.length }}}
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-light btn-sm dropdown-toggle" type="button" id="reasonDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
[[admin/manage/users:temp-ban.select-reason]]
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end p-1" aria-labelledby="reasonDropdown">
|
||||
{{{ each reasons }}}
|
||||
<li><a class="dropdown-item rounded-1" href="#" data-key="{./key}">{./title}</a></li>
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
|
||||
<textarea rows="8" type="text" class="form-control" id="reason" name="reason"></textarea>
|
||||
<!-- IMPORT partials/custom-reason.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
20
src/views/partials/custom-reason.tpl
Normal file
20
src/views/partials/custom-reason.tpl
Normal file
@@ -0,0 +1,20 @@
|
||||
<div>
|
||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||
<label class="form-label mb-0" for="reason">[[admin/manage/users:temp-ban.reason]]</label>
|
||||
{{{ if reasons.length }}}
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-light btn-sm dropdown-toggle" type="button" id="reasonDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
[[admin/manage/users:temp-ban.select-reason]]
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end p-1" aria-labelledby="reasonDropdown">
|
||||
{{{ each reasons }}}
|
||||
<li><a class="dropdown-item rounded-1" href="#" data-key="{./key}">{./title}</a></li>
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
|
||||
<textarea rows="8" type="text" class="form-control" id="reason" name="reason"></textarea>
|
||||
</div>
|
||||
Reference in New Issue
Block a user