mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 08:36:12 +01:00
feat: add mute history, closes #10596
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"banned": "Banned",
|
||||
"muted": "Muted",
|
||||
"offline": "Offline",
|
||||
"deleted": "Deleted",
|
||||
"username": "User Name",
|
||||
@@ -173,6 +174,10 @@
|
||||
"info.banned-permanently": "Banned permanently",
|
||||
"info.banned-reason-label": "Reason",
|
||||
"info.banned-no-reason": "No reason given.",
|
||||
"info.mute-history": "Recent Mute History",
|
||||
"info.no-mute-history": "This user has never been muted",
|
||||
"info.muted-until": "Muted until %1",
|
||||
"info.muted-expiry": "Expiry",
|
||||
"info.muted-no-reason": "No reason given.",
|
||||
"info.username-history": "Username History",
|
||||
"info.email-history": "Email History",
|
||||
|
||||
@@ -231,11 +231,24 @@ usersAPI.mute = async function (caller, data) {
|
||||
} else if (await user.isAdministrator(data.uid)) {
|
||||
throw new Error('[[error:cant-mute-other-admins]]');
|
||||
}
|
||||
const reason = data.reason || '[[user:info.muted-no-reason]]';
|
||||
await db.setObject(`user:${data.uid}`, {
|
||||
mutedUntil: data.until,
|
||||
mutedReason: data.reason || '[[user:info.muted-no-reason]]',
|
||||
mutedReason: reason,
|
||||
});
|
||||
|
||||
const now = Date.now();
|
||||
const muteKey = `uid:${data.uid}:mute:${now}`;
|
||||
const muteData = {
|
||||
fromUid: caller.uid,
|
||||
uid: data.uid,
|
||||
timestamp: now,
|
||||
expire: data.until,
|
||||
};
|
||||
if (data.reason) {
|
||||
muteData.reason = reason;
|
||||
}
|
||||
await db.sortedSetAdd(`uid:${data.uid}:mutes:timestamp`, now, muteKey);
|
||||
await db.setObject(muteKey, muteData);
|
||||
await events.log({
|
||||
type: 'user-mute',
|
||||
uid: caller.uid,
|
||||
|
||||
31
src/flags.js
31
src/flags.js
@@ -757,6 +757,7 @@ Flags.getHistory = async function (flagId) {
|
||||
|
||||
// Append ban history and username change data
|
||||
history = await mergeBanHistory(history, targetUid, uids);
|
||||
history = await mergeMuteHistory(history, targetUid, uids);
|
||||
history = await mergeUsernameEmailChanges(history, targetUid, uids);
|
||||
|
||||
const userData = await user.getUsersFields(uids, ['username', 'userslug', 'picture']);
|
||||
@@ -854,21 +855,39 @@ Flags.notify = async function (flagObj, uid, notifySelf = false) {
|
||||
};
|
||||
|
||||
async function mergeBanHistory(history, targetUid, uids) {
|
||||
let recentBans = await db.getSortedSetRevRange(`uid:${targetUid}:bans:timestamp`, 0, 19);
|
||||
recentBans = await db.getObjects(recentBans);
|
||||
return await mergeBanMuteHistory(history, uids, {
|
||||
set: `uid:${targetUid}:bans:timestamp`,
|
||||
label: '[[user:banned]]',
|
||||
reasonDefault: '[[user:info.banned-no-reason]]',
|
||||
expiryKey: '[[user:info.banned-expiry]]',
|
||||
});
|
||||
}
|
||||
|
||||
return history.concat(recentBans.reduce((memo, cur) => {
|
||||
async function mergeMuteHistory(history, targetUid, uids) {
|
||||
return await mergeBanMuteHistory(history, uids, {
|
||||
set: `uid:${targetUid}:mutes:timestamp`,
|
||||
label: '[[user:muted]]',
|
||||
reasonDefault: '[[user:info.muted-no-reason]]',
|
||||
expiryKey: '[[user:info.muted-expiry]]',
|
||||
});
|
||||
}
|
||||
|
||||
async function mergeBanMuteHistory(history, uids, params) {
|
||||
let recentObjs = await db.getSortedSetRevRange(params.set, 0, 19);
|
||||
recentObjs = await db.getObjects(recentObjs);
|
||||
|
||||
return history.concat(recentObjs.reduce((memo, cur) => {
|
||||
uids.push(cur.fromUid);
|
||||
memo.push({
|
||||
uid: cur.fromUid,
|
||||
meta: [
|
||||
{
|
||||
key: '[[user:banned]]',
|
||||
value: validator.escape(String(cur.reason)),
|
||||
key: params.label,
|
||||
value: validator.escape(String(cur.reason || params.reasonDefault)),
|
||||
labelClass: 'danger',
|
||||
},
|
||||
{
|
||||
key: '[[user:info.banned-expiry]]',
|
||||
key: params.expiryKey,
|
||||
value: new Date(parseInt(cur.expire, 10)).toISOString(),
|
||||
labelClass: 'default',
|
||||
},
|
||||
|
||||
@@ -30,9 +30,10 @@ module.exports = function (User) {
|
||||
};
|
||||
|
||||
User.getModerationHistory = async function (uid) {
|
||||
let [flags, bans] = await Promise.all([
|
||||
let [flags, bans, mutes] = await Promise.all([
|
||||
db.getSortedSetRevRangeWithScores(`flags:byTargetUid:${uid}`, 0, 19),
|
||||
db.getSortedSetRevRange(`uid:${uid}:bans:timestamp`, 0, 19),
|
||||
db.getSortedSetRevRange(`uid:${uid}:mutes:timestamp`, 0, 19),
|
||||
]);
|
||||
|
||||
// Get pids from flag objects
|
||||
@@ -51,14 +52,16 @@ module.exports = function (User) {
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
[flags, bans] = await Promise.all([
|
||||
[flags, bans, mutes] = await Promise.all([
|
||||
getFlagMetadata(flags),
|
||||
formatBanData(bans),
|
||||
formatBanMuteData(bans, '[[user:info.banned-no-reason]]'),
|
||||
formatBanMuteData(mutes, '[[user:info.muted-no-reason]]'),
|
||||
]);
|
||||
|
||||
return {
|
||||
flags: flags,
|
||||
bans: bans,
|
||||
mutes: mutes,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -95,17 +98,17 @@ module.exports = function (User) {
|
||||
return flags;
|
||||
}
|
||||
|
||||
async function formatBanData(bans) {
|
||||
const banData = await db.getObjects(bans);
|
||||
const uids = banData.map(banData => banData.fromUid);
|
||||
async function formatBanMuteData(keys, noReasonLangKey) {
|
||||
const data = await db.getObjects(keys);
|
||||
const uids = data.map(d => d.fromUid);
|
||||
const usersData = await User.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture']);
|
||||
return banData.map((banObj, index) => {
|
||||
return data.map((banObj, index) => {
|
||||
banObj.user = usersData[index];
|
||||
banObj.until = parseInt(banObj.expire, 10);
|
||||
banObj.untilReadable = new Date(banObj.until).toString();
|
||||
banObj.timestampReadable = new Date(parseInt(banObj.timestamp, 10)).toString();
|
||||
banObj.timestampISO = utils.toISOString(banObj.timestamp);
|
||||
banObj.reason = validator.escape(String(banObj.reason || '')) || '[[user:info.banned-no-reason]]';
|
||||
banObj.reason = validator.escape(String(banObj.reason || '')) || noReasonLangKey;
|
||||
return banObj;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user