Add per-guild moderation settings and records

This commit is contained in:
2026-01-27 11:46:43 +01:00
parent b6a7d35ce3
commit f743262991
10 changed files with 298 additions and 19 deletions
+48
View File
@@ -0,0 +1,48 @@
const { connectToDatabase } = require('../db');
const DEFAULT_GUILD_SETTINGS = {
moderation: {
strikeThresholds: {
mute: 2,
kick: 3,
ban: 5,
},
muteDurationMinutes: 30,
banDurationMs: 0,
},
};
const normalizeGuildSettings = (settings = {}) => {
const moderation = settings.moderation ?? {};
const strikeThresholds = moderation.strikeThresholds ?? {};
return {
...DEFAULT_GUILD_SETTINGS,
...settings,
moderation: {
...DEFAULT_GUILD_SETTINGS.moderation,
...moderation,
strikeThresholds: {
...DEFAULT_GUILD_SETTINGS.moderation.strikeThresholds,
...strikeThresholds,
},
},
};
};
const getGuildSettings = async (guildId) => {
if (!guildId) {
return normalizeGuildSettings();
}
const dbClient = await connectToDatabase();
const db = dbClient.db('discord');
const collection = db.collection('guild_settings');
const settings = await collection.findOne({ guildId });
return normalizeGuildSettings(settings);
};
module.exports = {
getGuildSettings,
};
+91
View File
@@ -0,0 +1,91 @@
const { connectToDatabase } = require('../db');
const MODERATION_COLLECTION = 'moderation_records';
const getModerationCollection = async () => {
const client = await connectToDatabase();
return client.db('discord').collection(MODERATION_COLLECTION);
};
const updateStrikes = async ({ guildId, userId, strikes }) => {
const collection = await getModerationCollection();
const now = new Date();
return collection.findOneAndUpdate(
{ guildId, userId },
{
$set: {
strikes,
lastWarnedAt: now,
updatedAt: now,
},
$setOnInsert: {
guildId,
userId,
actions: [],
createdAt: now,
},
},
{ upsert: true, returnDocument: 'after' },
);
};
const recordModerationAction = async ({
guildId,
userId,
action,
moderatorId,
reason,
metadata = {},
stateUpdates = {},
}) => {
const collection = await getModerationCollection();
const now = new Date();
const actionEntry = {
action,
moderatorId,
reason,
metadata,
createdAt: now,
};
return collection.findOneAndUpdate(
{ guildId, userId },
{
$push: { actions: actionEntry },
$set: {
lastAction: action,
lastActionAt: now,
updatedAt: now,
...stateUpdates,
},
$setOnInsert: {
guildId,
userId,
strikes: 0,
createdAt: now,
},
},
{ upsert: true, returnDocument: 'after' },
);
};
const clearBanStatus = async ({ guildId, userId }) =>
recordModerationAction({
guildId,
userId,
action: 'unban',
moderatorId: null,
reason: 'Temporary ban expired',
metadata: {},
stateUpdates: {
isBanned: false,
bannedUntil: null,
},
});
module.exports = {
updateStrikes,
recordModerationAction,
clearBanStatus,
};
+1 -1
View File
@@ -40,7 +40,7 @@ const isCommandAllowed = async ({
permissions.adminUserIds.includes(userId) ||
(member && memberHasRole(member, permissions.adminRoleIds));
if (permissionGroup && isAdmin) {
if (isAdmin) {
return true;
}
+5 -1
View File
@@ -1,4 +1,5 @@
const { connectToDatabase } = require('../db');
const { updateStrikes } = require('./moderationRecords');
const WARNING_COLLECTION = 'warnings';
@@ -25,8 +26,11 @@ const addWarning = async ({ guildId, userId, moderatorId, reason }) => {
);
const warnings = result.value?.warnings ?? [];
const strikeCount = warnings.length;
return { warnings, warningEntry };
await updateStrikes({ guildId, userId, strikes: strikeCount });
return { warnings, warningEntry, strikeCount };
};
const getWarnings = async ({ guildId, userId }) => {