feat: add mute history, closes #10596

isekai-main
Barış Soner Uşaklı 3 years ago
parent 9acdc6808c
commit c926358d73

@ -1,5 +1,6 @@
{ {
"banned": "Banned", "banned": "Banned",
"muted": "Muted",
"offline": "Offline", "offline": "Offline",
"deleted": "Deleted", "deleted": "Deleted",
"username": "User Name", "username": "User Name",
@ -173,6 +174,10 @@
"info.banned-permanently": "Banned permanently", "info.banned-permanently": "Banned permanently",
"info.banned-reason-label": "Reason", "info.banned-reason-label": "Reason",
"info.banned-no-reason": "No reason given.", "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.muted-no-reason": "No reason given.",
"info.username-history": "Username History", "info.username-history": "Username History",
"info.email-history": "Email History", "info.email-history": "Email History",

@ -231,11 +231,24 @@ usersAPI.mute = async function (caller, data) {
} else if (await user.isAdministrator(data.uid)) { } else if (await user.isAdministrator(data.uid)) {
throw new Error('[[error:cant-mute-other-admins]]'); throw new Error('[[error:cant-mute-other-admins]]');
} }
const reason = data.reason || '[[user:info.muted-no-reason]]';
await db.setObject(`user:${data.uid}`, { await db.setObject(`user:${data.uid}`, {
mutedUntil: data.until, 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({ await events.log({
type: 'user-mute', type: 'user-mute',
uid: caller.uid, uid: caller.uid,

@ -757,6 +757,7 @@ Flags.getHistory = async function (flagId) {
// Append ban history and username change data // Append ban history and username change data
history = await mergeBanHistory(history, targetUid, uids); history = await mergeBanHistory(history, targetUid, uids);
history = await mergeMuteHistory(history, targetUid, uids);
history = await mergeUsernameEmailChanges(history, targetUid, uids); history = await mergeUsernameEmailChanges(history, targetUid, uids);
const userData = await user.getUsersFields(uids, ['username', 'userslug', 'picture']); 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) { async function mergeBanHistory(history, targetUid, uids) {
let recentBans = await db.getSortedSetRevRange(`uid:${targetUid}:bans:timestamp`, 0, 19); return await mergeBanMuteHistory(history, uids, {
recentBans = await db.getObjects(recentBans); set: `uid:${targetUid}:bans:timestamp`,
label: '[[user:banned]]',
reasonDefault: '[[user:info.banned-no-reason]]',
expiryKey: '[[user:info.banned-expiry]]',
});
}
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(recentBans.reduce((memo, cur) => { return history.concat(recentObjs.reduce((memo, cur) => {
uids.push(cur.fromUid); uids.push(cur.fromUid);
memo.push({ memo.push({
uid: cur.fromUid, uid: cur.fromUid,
meta: [ meta: [
{ {
key: '[[user:banned]]', key: params.label,
value: validator.escape(String(cur.reason)), value: validator.escape(String(cur.reason || params.reasonDefault)),
labelClass: 'danger', labelClass: 'danger',
}, },
{ {
key: '[[user:info.banned-expiry]]', key: params.expiryKey,
value: new Date(parseInt(cur.expire, 10)).toISOString(), value: new Date(parseInt(cur.expire, 10)).toISOString(),
labelClass: 'default', labelClass: 'default',
}, },

@ -30,9 +30,10 @@ module.exports = function (User) {
}; };
User.getModerationHistory = async function (uid) { 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.getSortedSetRevRangeWithScores(`flags:byTargetUid:${uid}`, 0, 19),
db.getSortedSetRevRange(`uid:${uid}:bans:timestamp`, 0, 19), db.getSortedSetRevRange(`uid:${uid}:bans:timestamp`, 0, 19),
db.getSortedSetRevRange(`uid:${uid}:mutes:timestamp`, 0, 19),
]); ]);
// Get pids from flag objects // Get pids from flag objects
@ -51,14 +52,16 @@ module.exports = function (User) {
return memo; return memo;
}, []); }, []);
[flags, bans] = await Promise.all([ [flags, bans, mutes] = await Promise.all([
getFlagMetadata(flags), getFlagMetadata(flags),
formatBanData(bans), formatBanMuteData(bans, '[[user:info.banned-no-reason]]'),
formatBanMuteData(mutes, '[[user:info.muted-no-reason]]'),
]); ]);
return { return {
flags: flags, flags: flags,
bans: bans, bans: bans,
mutes: mutes,
}; };
}; };
@ -95,17 +98,17 @@ module.exports = function (User) {
return flags; return flags;
} }
async function formatBanData(bans) { async function formatBanMuteData(keys, noReasonLangKey) {
const banData = await db.getObjects(bans); const data = await db.getObjects(keys);
const uids = banData.map(banData => banData.fromUid); const uids = data.map(d => d.fromUid);
const usersData = await User.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture']); 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.user = usersData[index];
banObj.until = parseInt(banObj.expire, 10); banObj.until = parseInt(banObj.expire, 10);
banObj.untilReadable = new Date(banObj.until).toString(); banObj.untilReadable = new Date(banObj.until).toString();
banObj.timestampReadable = new Date(parseInt(banObj.timestamp, 10)).toString(); banObj.timestampReadable = new Date(parseInt(banObj.timestamp, 10)).toString();
banObj.timestampISO = utils.toISOString(banObj.timestamp); 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; return banObj;
}); });
} }

Loading…
Cancel
Save