mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-05-24 01:55:03 +00:00
initial - tempbans & mutes
This commit is contained in:
parent
c84d1a0be1
commit
744b9273bb
14 changed files with 322 additions and 109 deletions
|
@ -4,67 +4,123 @@ import { GuildPluginData } from "knub";
|
|||
import moment from "moment-timezone";
|
||||
import { LogType } from "src/data/LogType";
|
||||
import { logger } from "src/logger";
|
||||
import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
|
||||
import { CaseTypes } from "../../../data/CaseTypes";
|
||||
import { resolveUser, SECONDS } from "../../../utils";
|
||||
import { MINUTES, resolveUser } from "../../../utils";
|
||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||
import { IgnoredEventType, ModActionsPluginType } from "../types";
|
||||
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
|
||||
import { ignoreEvent } from "./ignoreEvent";
|
||||
import { isBanned } from "./isBanned";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { Tempban } from "src/data/entities/Tempban";
|
||||
import { ExpiringTimer } from "src/utils/timers";
|
||||
|
||||
const TEMPBAN_LOOP_TIME = 60 * SECONDS;
|
||||
const LOAD_LESS_THAN_MIN_COUNT = 60 * MINUTES;
|
||||
|
||||
export async function outdatedTempbansLoop(pluginData: GuildPluginData<ModActionsPluginType>) {
|
||||
const outdatedTempbans = await pluginData.state.tempbans.getExpiredTempbans();
|
||||
|
||||
for (const tempban of outdatedTempbans) {
|
||||
if (!(await isBanned(pluginData, tempban.user_id))) {
|
||||
pluginData.state.tempbans.clear(tempban.user_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, tempban.user_id);
|
||||
const reason = formatReasonWithAttachments(
|
||||
`Tempban timed out.
|
||||
Tempbanned at: \`${tempban.created_at} UTC\``,
|
||||
[],
|
||||
);
|
||||
try {
|
||||
ignoreEvent(pluginData, IgnoredEventType.Unban, tempban.user_id);
|
||||
await pluginData.guild.bans.remove(tempban.user_id as Snowflake, reason ?? undefined);
|
||||
} catch (e) {
|
||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||
body: `Encountered an error trying to automatically unban ${tempban.user_id} after tempban timeout`,
|
||||
});
|
||||
logger.warn(`Error automatically unbanning ${tempban.user_id} (tempban timeout): ${e}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create case and delete tempban
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
const createdCase = await casesPlugin.createCase({
|
||||
userId: tempban.user_id,
|
||||
modId: tempban.mod_id,
|
||||
type: CaseTypes.Unban,
|
||||
reason,
|
||||
ppId: undefined,
|
||||
export function addTimer(pluginData: GuildPluginData<ModActionsPluginType>, tempban: Tempban) {
|
||||
const existingMute = pluginData.state.timers.find(
|
||||
(tm) => tm.options.key === tempban.user_id && tm.options.guildId === tempban.guild_id && !tm.done,
|
||||
); // for future-proof when you do global events
|
||||
if (!existingMute && tempban.expires_at) {
|
||||
const exp = moment(tempban.expires_at!).toDate().getTime() - moment.utc().toDate().getTime();
|
||||
const newTimer = new ExpiringTimer({
|
||||
key: tempban.user_id,
|
||||
guildId: tempban.guild_id,
|
||||
plugin: "tempban",
|
||||
expiry: exp,
|
||||
callback: async () => {
|
||||
await clearTempBan(pluginData, tempban);
|
||||
},
|
||||
});
|
||||
pluginData.state.tempbans.clear(tempban.user_id);
|
||||
|
||||
// Log the unban
|
||||
const banTime = moment(tempban.created_at).diff(moment(tempban.expires_at));
|
||||
pluginData.getPlugin(LogsPlugin).logMemberTimedUnban({
|
||||
mod: await resolveUser(pluginData.client, tempban.mod_id),
|
||||
userId: tempban.user_id,
|
||||
caseNumber: createdCase.case_number,
|
||||
reason,
|
||||
banTime: humanizeDuration(banTime),
|
||||
});
|
||||
}
|
||||
|
||||
if (!pluginData.state.unloaded) {
|
||||
pluginData.state.outdatedTempbansTimeout = setTimeout(() => outdatedTempbansLoop(pluginData), TEMPBAN_LOOP_TIME);
|
||||
pluginData.state.timers.push(newTimer);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeTimer(pluginData: GuildPluginData<ModActionsPluginType>, tempban: Tempban) {
|
||||
const existingMute = pluginData.state.timers.findIndex(
|
||||
(tm) => tm.options.key === tempban.user_id && tm.options.guildId === tempban.guild_id && !tm.done,
|
||||
);
|
||||
if (existingMute) {
|
||||
const tm = pluginData.state.timers[existingMute];
|
||||
tm.clear();
|
||||
tm.done = true;
|
||||
pluginData.state.timers.splice(existingMute, 1);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeTimerByUserId(pluginData: GuildPluginData<ModActionsPluginType>, user_id: Snowflake) {
|
||||
const existingMute = pluginData.state.timers.findIndex((tm) => tm.options.key === user_id && !tm.done);
|
||||
if (existingMute) {
|
||||
const tm = pluginData.state.timers[existingMute];
|
||||
tm.clear();
|
||||
tm.done = true;
|
||||
pluginData.state.timers.splice(existingMute, 1);
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadExpiringTimers(pluginData: GuildPluginData<ModActionsPluginType>) {
|
||||
const now = moment.utc().toDate().getTime();
|
||||
pluginData.state.timers = pluginData.state.timers.filter((tm) => !tm.done || !tm.timeout);
|
||||
const tempbans = (await pluginData.state.tempbans.getAllTempbans()).filter((m) => m.expires_at);
|
||||
const expiredBans = tempbans.filter((m) => now >= moment(m.expires_at!).toDate().getTime());
|
||||
const expiringBans = tempbans.filter(
|
||||
(m) => !expiredBans.find((exp) => exp.user_id === m.user_id && exp.guild_id === m.guild_id),
|
||||
);
|
||||
|
||||
for (const tempban of expiringBans) {
|
||||
const expires = moment(tempban.expires_at!).toDate().getTime();
|
||||
if (expires <= now) continue; // exclude expired mutes, just in case
|
||||
if (expires > now + LOAD_LESS_THAN_MIN_COUNT) continue; // exclude timers that are expiring in over 180 mins
|
||||
|
||||
addTimer(pluginData, tempban);
|
||||
}
|
||||
|
||||
for (const tempban of expiredBans) {
|
||||
await clearTempBan(pluginData, tempban);
|
||||
}
|
||||
}
|
||||
|
||||
export async function clearTempBan(pluginData: GuildPluginData<ModActionsPluginType>, tempban: Tempban) {
|
||||
if (!(await isBanned(pluginData, tempban.user_id))) {
|
||||
pluginData.state.tempbans.clear(tempban.user_id);
|
||||
return;
|
||||
}
|
||||
|
||||
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, tempban.user_id);
|
||||
const reason = formatReasonWithAttachments(
|
||||
`Tempban timed out.
|
||||
Tempbanned at: \`${tempban.created_at} UTC\``,
|
||||
[],
|
||||
);
|
||||
try {
|
||||
ignoreEvent(pluginData, IgnoredEventType.Unban, tempban.user_id);
|
||||
await pluginData.guild.bans.remove(tempban.user_id as Snowflake, reason ?? undefined);
|
||||
} catch (e) {
|
||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||
body: `Encountered an error trying to automatically unban ${tempban.user_id} after tempban timeout`,
|
||||
});
|
||||
logger.warn(`Error automatically unbanning ${tempban.user_id} (tempban timeout): ${e}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create case and delete tempban
|
||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||
const createdCase = await casesPlugin.createCase({
|
||||
userId: tempban.user_id,
|
||||
modId: tempban.mod_id,
|
||||
type: CaseTypes.Unban,
|
||||
reason,
|
||||
ppId: undefined,
|
||||
});
|
||||
pluginData.state.tempbans.clear(tempban.user_id);
|
||||
|
||||
// Log the unban
|
||||
const banTime = moment(tempban.created_at).diff(moment(tempban.expires_at));
|
||||
pluginData.getPlugin(LogsPlugin).logMemberTimedUnban({
|
||||
mod: await resolveUser(pluginData.client, tempban.mod_id),
|
||||
userId: tempban.user_id,
|
||||
caseNumber: createdCase.case_number,
|
||||
reason,
|
||||
banTime: humanizeDuration(banTime),
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue