3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-05-13 21:35:02 +00:00
zeppelin/backend/src/plugins/ModActions/commands/ban/actualBanCmd.ts
2024-05-12 21:34:17 +02:00

190 lines
6.9 KiB
TypeScript

import { Attachment, ChatInputCommandInteraction, GuildMember, Message, User } from "discord.js";
import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub";
import { getMemberLevel } from "knub/helpers";
import { CaseTypes } from "../../../../data/CaseTypes";
import { clearExpiringTempban, registerExpiringTempban } from "../../../../data/loops/expiringTempbansLoop";
import { canActOn, getContextChannel } from "../../../../pluginUtils";
import { UnknownUser, UserNotificationMethod, renderUsername, resolveMember } from "../../../../utils";
import { banLock } from "../../../../utils/lockNameHelpers";
import { waitForButtonConfirm } from "../../../../utils/waitForInteraction";
import { CasesPlugin } from "../../../Cases/CasesPlugin";
import { LogsPlugin } from "../../../Logs/LogsPlugin";
import { handleAttachmentLinkDetectionAndGetRestriction } from "../../functions/attachmentLinkReaction";
import { banUserId } from "../../functions/banUserId";
import {
formatReasonWithAttachments,
formatReasonWithMessageLinkForAttachments,
} from "../../functions/formatReasonForAttachments";
import { isBanned } from "../../functions/isBanned";
import { ModActionsPluginType } from "../../types";
export async function actualBanCmd(
pluginData: GuildPluginData<ModActionsPluginType>,
context: Message | ChatInputCommandInteraction,
user: User | UnknownUser,
time: number | null,
reason: string,
attachments: Attachment[],
author: GuildMember,
mod: GuildMember,
contactMethods?: UserNotificationMethod[],
deleteDays?: number,
) {
if (await handleAttachmentLinkDetectionAndGetRestriction(pluginData, context, reason)) {
return;
}
const memberToBan = await resolveMember(pluginData.client, pluginData.guild, user.id);
const formattedReason = await formatReasonWithMessageLinkForAttachments(pluginData, reason, context, attachments);
const formattedReasonWithAttachments = formatReasonWithAttachments(reason, attachments);
// acquire a lock because of the needed user-inputs below (if banned/not on server)
const lock = await pluginData.locks.acquire(banLock(user));
let forceban = false;
const existingTempban = await pluginData.state.tempbans.findExistingTempbanForUserId(user.id);
if (!memberToBan) {
const banned = await isBanned(pluginData, user.id);
if (!banned) {
// Ask the mod if we should upgrade to a forceban as the user is not on the server
const reply = await waitForButtonConfirm(
context,
{ content: "User not on server, forceban instead?" },
{ confirmText: "Yes", cancelText: "No", restrictToId: author.id },
);
if (!reply) {
pluginData.state.common.sendErrorMessage(context, "User not on server, ban cancelled by moderator");
lock.unlock();
return;
} else {
forceban = true;
}
} else {
// Abort if trying to ban user indefinitely if they are already banned indefinitely
if (!existingTempban && !time) {
pluginData.state.common.sendErrorMessage(context, `User is already banned indefinitely.`);
return;
}
// Ask the mod if we should update the existing ban
const reply = await waitForButtonConfirm(
context,
{ content: "Failed to message the user. Log the warning anyway?" },
{ confirmText: "Yes", cancelText: "No", restrictToId: author.id },
);
if (!reply) {
pluginData.state.common.sendErrorMessage(context, "User already banned, update cancelled by moderator");
lock.unlock();
return;
}
// Update or add new tempban / remove old tempban
if (time && time > 0) {
if (existingTempban) {
await pluginData.state.tempbans.updateExpiryTime(user.id, time, mod.id);
} else {
await pluginData.state.tempbans.addTempban(user.id, time, mod.id);
}
const tempban = (await pluginData.state.tempbans.findExistingTempbanForUserId(user.id))!;
registerExpiringTempban(tempban);
} else if (existingTempban) {
clearExpiringTempban(existingTempban);
pluginData.state.tempbans.clear(user.id);
}
// Create a new case for the updated ban since we never stored the old case id and log the action
const casesPlugin = pluginData.getPlugin(CasesPlugin);
const createdCase = await casesPlugin.createCase({
modId: mod.id,
type: CaseTypes.Ban,
userId: user.id,
reason: formattedReason,
noteDetails: [`Ban updated to ${time ? humanizeDuration(time) : "indefinite"}`],
});
if (time) {
pluginData.getPlugin(LogsPlugin).logMemberTimedBan({
mod: mod.user,
user,
caseNumber: createdCase.case_number,
reason: formattedReason,
banTime: humanizeDuration(time),
});
} else {
pluginData.getPlugin(LogsPlugin).logMemberBan({
mod: mod.user,
user,
caseNumber: createdCase.case_number,
reason: formattedReason,
});
}
pluginData.state.common.sendSuccessMessage(
context,
`Ban updated to ${time ? "expire in " + humanizeDuration(time) + " from now" : "indefinite"}`,
);
lock.unlock();
return;
}
}
// Make sure we're allowed to ban this member if they are on the server
if (!forceban && !canActOn(pluginData, author, memberToBan!)) {
const ourLevel = getMemberLevel(pluginData, author);
const targetLevel = getMemberLevel(pluginData, memberToBan!);
pluginData.state.common.sendErrorMessage(
context,
`Cannot ban: target permission level is equal or higher to yours, ${targetLevel} >= ${ourLevel}`,
);
lock.unlock();
return;
}
const matchingConfig = await pluginData.config.getMatchingConfig({
member: author,
channel: await getContextChannel(context),
});
const deleteMessageDays = deleteDays ?? matchingConfig.ban_delete_message_days;
const banResult = await banUserId(
pluginData,
user.id,
formattedReason,
formattedReasonWithAttachments,
{
contactMethods,
caseArgs: {
modId: mod.id,
ppId: mod.id !== author.id ? author.id : undefined,
},
deleteMessageDays,
modId: mod.id,
},
time ?? undefined,
);
if (banResult.status === "failed") {
pluginData.state.common.sendErrorMessage(context, `Failed to ban member: ${banResult.error}`);
lock.unlock();
return;
}
let forTime = "";
if (time && time > 0) {
forTime = `for ${humanizeDuration(time)} `;
}
// Confirm the action to the moderator
let response = "";
if (!forceban) {
response = `Banned **${renderUsername(user)}** ${forTime}(Case #${banResult.case.case_number})`;
if (banResult.notifyResult.text) response += ` (${banResult.notifyResult.text})`;
} else {
response = `Member forcebanned ${forTime}(Case #${banResult.case.case_number})`;
}
lock.unlock();
pluginData.state.common.sendSuccessMessage(context, response);
}