3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-07-07 19:17:19 +00:00
This commit is contained in:
iamshoXy 2024-02-27 15:57:17 +01:00
commit ee382e0907
255 changed files with 3862 additions and 5155 deletions

View file

@ -6,7 +6,7 @@ import { onGuildEvent } from "../../data/GuildEvents";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildMutes } from "../../data/GuildMutes";
import { GuildTempbans } from "../../data/GuildTempbans";
import { makeIoTsConfigParser, mapToPublicFn } from "../../pluginUtils";
import { mapToPublicFn } from "../../pluginUtils";
import { MINUTES, trimPluginDescription } from "../../utils";
import { CasesPlugin } from "../Cases/CasesPlugin";
import { LogsPlugin } from "../Logs/LogsPlugin";
@ -52,7 +52,7 @@ import { offModActionsEvent } from "./functions/offModActionsEvent";
import { onModActionsEvent } from "./functions/onModActionsEvent";
import { updateCase } from "./functions/updateCase";
import { warnMember } from "./functions/warnMember";
import { BanOptions, ConfigSchema, KickOptions, ModActionsPluginType, WarnOptions } from "./types";
import { BanOptions, KickOptions, ModActionsPluginType, WarnOptions, zModActionsConfig } from "./types";
const defaultOptions = {
config: {
@ -128,11 +128,11 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
description: trimPluginDescription(`
This plugin contains the 'typical' mod actions such as warning, muting, kicking, banning, etc.
`),
configSchema: ConfigSchema,
configSchema: zModActionsConfig,
},
dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
configParser: makeIoTsConfigParser(ConfigSchema),
configParser: (input) => zModActionsConfig.parse(input),
defaultOptions,
events: [CreateBanCaseOnManualBanEvt, CreateUnbanCaseOnManualUnbanEvt, PostAlertOnMemberJoinEvt, AuditLogEvents],

View file

@ -3,7 +3,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
import { Case } from "../../../data/entities/Case";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername, resolveMember, resolveUser } from "../../../utils";
import { renderUsername, resolveMember, resolveUser } from "../../../utils";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
import { modActionsCmd } from "../types";
@ -75,7 +75,7 @@ export const AddCaseCmd = modActionsCmd({
sendSuccessMessage(
pluginData,
msg.channel,
`Case #${theCase.case_number} created for **${renderUserUsername(user)}**`,
`Case #${theCase.case_number} created for **${renderUsername(user)}**`,
);
} else {
sendSuccessMessage(pluginData, msg.channel, `Case #${theCase.case_number} created`);

View file

@ -5,7 +5,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
import { clearExpiringTempban, registerExpiringTempban } from "../../../data/loops/expiringTempbansLoop";
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { renderUserUsername, resolveMember, resolveUser } from "../../../utils";
import { renderUsername, resolveMember, resolveUser } from "../../../utils";
import { banLock } from "../../../utils/lockNameHelpers";
import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
import { LogsPlugin } from "../../Logs/LogsPlugin";
@ -195,7 +195,7 @@ export const BanCmd = modActionsCmd({
// Confirm the action to the moderator
let response = "";
if (!forceban) {
response = `Banned **${renderUserUsername(user)}** ${forTime}(Case #${banResult.case.case_number})`;
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})`;

View file

@ -1,10 +1,9 @@
import { APIEmbed, User } from "discord.js";
import { APIEmbed } from "discord.js";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { sendErrorMessage } from "../../../pluginUtils";
import { emptyEmbedValue, resolveUser, trimLines } from "../../../utils";
import { UnknownUser, emptyEmbedValue, renderUsername, resolveMember, resolveUser, trimLines } from "../../../utils";
import { asyncMap } from "../../../utils/async";
import { createPaginatedMessage } from "../../../utils/createPaginatedMessage";
import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
import { getGuildPrefix } from "../../../utils/getGuildPrefix";
import { CasesPlugin } from "../../Cases/CasesPlugin";
import { modActionsCmd } from "../types";
@ -28,8 +27,10 @@ export const CasesModCmd = modActionsCmd({
async run({ pluginData, message: msg, args }) {
const modId = args.mod || msg.author.id;
const mod = await resolveUser(pluginData.client, modId);
const modName = mod instanceof User ? mod.tag : modId;
const mod =
(await resolveMember(pluginData.client, pluginData.guild, modId)) ||
(await resolveUser(pluginData.client, modId));
const modName = mod instanceof UnknownUser ? modId : renderUsername(mod);
const casesPlugin = pluginData.getPlugin(CasesPlugin);
const totalCases = await casesPlugin.getTotalCasesByMod(modId);
@ -50,17 +51,18 @@ export const CasesModCmd = modActionsCmd({
const cases = await casesPlugin.getRecentCasesByMod(modId, casesPerPage, (page - 1) * casesPerPage);
const lines = await asyncMap(cases, (c) => casesPlugin.getCaseSummary(c, true, msg.author.id));
const isLastPage = page === totalPages;
const firstCaseNum = (page - 1) * casesPerPage + 1;
const lastCaseNum = page * casesPerPage;
const lastCaseNum = isLastPage ? totalCases : page * casesPerPage;
const title = `Most recent cases ${firstCaseNum}-${lastCaseNum} of ${totalCases} by ${modName}`;
const embed = {
author: {
name: title,
icon_url: mod instanceof User ? mod.displayAvatarURL() : undefined,
icon_url: mod instanceof UnknownUser ? undefined : mod.displayAvatarURL(),
},
description: lines.join("\n"),
fields: [
...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")),
{
name: emptyEmbedValue,
value: trimLines(`

View file

@ -3,9 +3,9 @@ import { commandTypeHelpers as ct } from "../../../commandTypes";
import { CaseTypes } from "../../../data/CaseTypes";
import { sendErrorMessage } from "../../../pluginUtils";
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
import { UnknownUser, chunkArray, emptyEmbedValue, renderUserUsername, resolveUser, trimLines } from "../../../utils";
import { UnknownUser, chunkArray, emptyEmbedValue, renderUsername, resolveMember, resolveUser } from "../../../utils";
import { asyncMap } from "../../../utils/async";
import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
import { createPaginatedMessage } from "../../../utils/createPaginatedMessage.js";
import { getGuildPrefix } from "../../../utils/getGuildPrefix";
import { modActionsCmd } from "../types";
@ -21,6 +21,8 @@ const opts = {
unbans: ct.switchOption({ def: false, shortcut: "ub" }),
};
const casesPerPage = 5;
export const CasesUserCmd = modActionsCmd({
trigger: ["cases", "modlogs"],
permission: "can_view",
@ -35,8 +37,10 @@ export const CasesUserCmd = modActionsCmd({
],
async run({ pluginData, message: msg, args }) {
const user = await resolveUser(pluginData.client, args.user);
if (!user.id) {
const user =
(await resolveMember(pluginData.client, pluginData.guild, args.user)) ||
(await resolveUser(pluginData.client, args.user));
if (user instanceof UnknownUser) {
sendErrorMessage(pluginData, msg.channel, `User not found`);
return;
}
@ -62,7 +66,7 @@ export const CasesUserCmd = modActionsCmd({
const hiddenCases = cases.filter((c) => c.is_hidden);
const userName =
user instanceof UnknownUser && cases.length ? cases[cases.length - 1].user_name : renderUserUsername(user);
user instanceof UnknownUser && cases.length ? cases[cases.length - 1].user_name : renderUsername(user);
if (cases.length === 0) {
msg.channel.send(`No cases found for **${userName}**`);
@ -90,49 +94,55 @@ export const CasesUserCmd = modActionsCmd({
} else {
// Compact view (= regular message with a preview of each case)
const casesPlugin = pluginData.getPlugin(CasesPlugin);
const lines = await asyncMap(casesToDisplay, (c) => casesPlugin.getCaseSummary(c, true, msg.author.id));
const totalPages = Math.max(Math.ceil(cases.length / casesPerPage), 1);
const prefix = getGuildPrefix(pluginData);
const linesPerChunk = 10;
const lineChunks = chunkArray(lines, linesPerChunk);
const footerField = {
name: emptyEmbedValue,
value: trimLines(`
Use \`${prefix}case <num>\` to see more information about an individual case
`),
};
createPaginatedMessage(
pluginData.client,
msg.channel,
totalPages,
async (page) => {
const chunkedCases = chunkArray(cases, casesPerPage)[page - 1];
const lines = await asyncMap(chunkedCases, (c) => casesPlugin.getCaseSummary(c, true, msg.author.id));
for (const [i, linesInChunk] of lineChunks.entries()) {
const isLastChunk = i === lineChunks.length - 1;
const isLastPage = page === totalPages;
const firstCaseNum = (page - 1) * casesPerPage + 1;
const lastCaseNum = isLastPage ? cases.length : page * casesPerPage;
const title =
totalPages === 1
? `Cases for ${userName} (${lines.length} total)`
: `Most recent cases ${firstCaseNum}-${lastCaseNum} of ${cases.length} for ${userName}`;
if (isLastChunk && !args.hidden && hiddenCases.length) {
if (hiddenCases.length === 1) {
linesInChunk.push(`*+${hiddenCases.length} hidden case, use "-hidden" to show it*`);
} else {
linesInChunk.push(`*+${hiddenCases.length} hidden cases, use "-hidden" to show them*`);
}
}
const embed = {
author: {
name: title,
icon_url: user instanceof User ? user.displayAvatarURL() : undefined,
},
description: lines.join("\n"),
fields: [
{
name: emptyEmbedValue,
value: `Use \`${prefix}case <num>\` to see more information about an individual case`,
},
],
} satisfies APIEmbed;
const chunkStart = i * linesPerChunk + 1;
const chunkEnd = Math.min((i + 1) * linesPerChunk, lines.length);
if (isLastPage && !args.hidden && hiddenCases.length)
embed.fields.push({
name: emptyEmbedValue,
value:
hiddenCases.length === 1
? `*+${hiddenCases.length} hidden case, use "-hidden" to show it*`
: `*+${hiddenCases.length} hidden cases, use "-hidden" to show them*`,
});
const embed = {
author: {
name:
lineChunks.length === 1
? `Cases for ${userName} (${lines.length} total)`
: `Cases ${chunkStart}${chunkEnd} of ${lines.length} for ${userName}`,
icon_url: user instanceof User ? user.displayAvatarURL() : undefined,
},
fields: [
...getChunkedEmbedFields(emptyEmbedValue, linesInChunk.join("\n")),
...(isLastChunk ? [footerField] : []),
],
} satisfies APIEmbed;
msg.channel.send({ embeds: [embed] });
}
return { embeds: [embed] };
},
{
limitToUserId: msg.author.id,
},
);
}
}
},

View file

@ -2,7 +2,7 @@ import { helpers } from "knub";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { Case } from "../../../data/entities/Case";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { SECONDS, trimLines } from "../../../utils";
import { SECONDS, renderUsername, trimLines } from "../../../utils";
import { CasesPlugin } from "../../Cases/CasesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
@ -60,7 +60,7 @@ export const DeleteCaseCmd = modActionsCmd({
}
}
const deletedByName = message.author.tag;
const deletedByName = renderUsername(message.author);
const timeAndDate = pluginData.getPlugin(TimeAndDatePlugin);
const deletedAt = timeAndDate.inGuildTz().format(timeAndDate.getDateFormat("pretty_datetime"));

View file

@ -1,7 +1,7 @@
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { CaseTypes } from "../../../data/CaseTypes";
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { renderUserUsername, resolveUser } from "../../../utils";
import { renderUsername, resolveUser } from "../../../utils";
import { CasesPlugin } from "../../Cases/CasesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
@ -29,7 +29,7 @@ export const NoteCmd = modActionsCmd({
return;
}
const userName = renderUserUsername(user);
const userName = renderUsername(user);
const reason = formatReasonWithAttachments(args.note, [...msg.attachments.values()]);
const casesPlugin = pluginData.getPlugin(CasesPlugin);

View file

@ -1,7 +1,7 @@
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { CaseTypes } from "../../../data/CaseTypes";
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { errorMessage, renderUserUsername, resolveMember, resolveUser } from "../../../utils";
import { errorMessage, renderUsername, resolveMember, resolveUser } from "../../../utils";
import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
import { CasesPlugin } from "../../Cases/CasesPlugin";
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
@ -106,7 +106,7 @@ export const WarnCmd = modActionsCmd({
sendSuccessMessage(
pluginData,
msg.channel,
`Warned **${renderUserUsername(memberToWarn.user)}** (Case #${warnResult.case.case_number})${messageResultText}`,
`Warned **${renderUsername(memberToWarn)}** (Case #${warnResult.case.case_number})${messageResultText}`,
);
},
});

View file

@ -42,7 +42,9 @@ export const AuditLogEvents = modActionsEvt({
caseId: existingCaseId,
modId: auditLogEntry.executor?.id || "0",
body: auditLogEntry.reason || "",
noteDetails: [`Timeout set to expire on <t:${moment.utc(muteChange.new as string).valueOf()}>`],
noteDetails: [
`Timeout set to expire on <t:${Math.ceil(moment.utc(muteChange.new as string).valueOf() / 1_000)}>`,
],
});
} else {
await casesPlugin.createCase({

View file

@ -1,5 +1,5 @@
import { PermissionsBitField, Snowflake, TextChannel } from "discord.js";
import { renderUserUsername, resolveMember } from "../../../utils";
import { renderUsername, resolveMember } from "../../../utils";
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
import { LogsPlugin } from "../../Logs/LogsPlugin";
import { modActionsEvt } from "../types";
@ -46,9 +46,7 @@ export const PostAlertOnMemberJoinEvt = modActionsEvt({
}
await alertChannel.send(
`<@!${member.id}> (${renderUserUsername(member.user)} \`${member.id}\`) joined with ${
actions.length
} prior record(s)`,
`<@!${member.id}> (${renderUsername(member)} \`${member.id}\`) joined with ${actions.length} prior record(s)`,
);
}
},

View file

@ -3,7 +3,7 @@ import { GuildPluginData } from "knub";
import { hasPermission } from "knub/helpers";
import { LogType } from "../../../data/LogType";
import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { DAYS, SECONDS, errorMessage, renderUserUsername, resolveMember, resolveUser } from "../../../utils";
import { DAYS, SECONDS, errorMessage, renderUsername, resolveMember, resolveUser } from "../../../utils";
import { IgnoredEventType, ModActionsPluginType } from "../types";
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
import { ignoreEvent } from "./ignoreEvent";
@ -103,7 +103,7 @@ export async function actualKickMemberCmd(
}
// Confirm the action to the moderator
let response = `Kicked **${renderUserUsername(memberToKick.user)}** (Case #${kickResult.case.case_number})`;
let response = `Kicked **${renderUsername(memberToKick)}** (Case #${kickResult.case.case_number})`;
if (kickResult.notifyResult.text) response += ` (${kickResult.notifyResult.text})`;
sendSuccessMessage(pluginData, msg.channel, response);

View file

@ -4,7 +4,7 @@ import { GuildPluginData } from "knub";
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
import { logger } from "../../../logger";
import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { UnknownUser, asSingleLine, isDiscordAPIError, renderUserUsername } from "../../../utils";
import { UnknownUser, asSingleLine, isDiscordAPIError, renderUsername } from "../../../utils";
import { MutesPlugin } from "../../Mutes/MutesPlugin";
import { MuteResult } from "../../Mutes/types";
import { ModActionsPluginType } from "../types";
@ -86,24 +86,24 @@ export async function actualMuteUserCmd(
if (args.time) {
if (muteResult.updatedExistingMute) {
response = asSingleLine(`
Updated **${renderUserUsername(user)}**'s
Updated **${renderUsername(user)}**'s
mute to ${timeUntilUnmute} (Case #${muteResult.case.case_number})
`);
} else {
response = asSingleLine(`
Muted **${renderUserUsername(user)}**
Muted **${renderUsername(user)}**
for ${timeUntilUnmute} (Case #${muteResult.case.case_number})
`);
}
} else {
if (muteResult.updatedExistingMute) {
response = asSingleLine(`
Updated **${renderUserUsername(user)}**'s
Updated **${renderUsername(user)}**'s
mute to indefinite (Case #${muteResult.case.case_number})
`);
} else {
response = asSingleLine(`
Muted **${renderUserUsername(user)}**
Muted **${renderUsername(user)}**
indefinitely (Case #${muteResult.case.case_number})
`);
}

View file

@ -3,7 +3,7 @@ import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub";
import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
import { UnknownUser, asSingleLine, renderUserUsername } from "../../../utils";
import { UnknownUser, asSingleLine, renderUsername } from "../../../utils";
import { ModActionsPluginType } from "../types";
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
@ -48,7 +48,7 @@ export async function actualUnmuteCmd(
pluginData,
msg.channel,
asSingleLine(`
Unmuting **${renderUserUsername(user)}**
Unmuting **${renderUsername(user)}**
in ${timeUntilUnmute} (Case #${result.case.case_number})
`),
);
@ -57,7 +57,7 @@ export async function actualUnmuteCmd(
pluginData,
msg.channel,
asSingleLine(`
Unmuted **${renderUserUsername(user)}**
Unmuted **${renderUsername(user)}**
(Case #${result.case.case_number})
`),
);

View file

@ -5,7 +5,7 @@ import { CaseTypes } from "../../../data/CaseTypes";
import { LogType } from "../../../data/LogType";
import { registerExpiringTempban } from "../../../data/loops/expiringTempbansLoop";
import { logger } from "../../../logger";
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
import { TemplateParseError, TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
import {
DAYS,
SECONDS,
@ -54,30 +54,52 @@ export async function banUserId(
if (contactMethods.length) {
if (!banTime && config.ban_message) {
const banMessage = await renderTemplate(
config.ban_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: banOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, banOptions.caseArgs.modId))
: null,
}),
);
let banMessage: string;
try {
banMessage = await renderTemplate(
config.ban_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: banOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, banOptions.caseArgs.modId))
: null,
}),
);
} catch (err) {
if (err instanceof TemplateParseError) {
return {
status: "failed",
error: `Invalid ban_message format: ${err.message}`,
};
}
throw err;
}
notifyResult = await notifyUser(member.user, banMessage, contactMethods);
} else if (banTime && config.tempban_message) {
const banMessage = await renderTemplate(
config.tempban_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: banOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, banOptions.caseArgs.modId))
: null,
banTime: humanizeDuration(banTime),
}),
);
let banMessage: string;
try {
banMessage = await renderTemplate(
config.tempban_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: banOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, banOptions.caseArgs.modId))
: null,
banTime: humanizeDuration(banTime),
}),
);
} catch (err) {
if (err instanceof TemplateParseError) {
return {
status: "failed",
error: `Invalid tempban_message format: ${err.message}`,
};
}
throw err;
}
notifyResult = await notifyUser(member.user, banMessage, contactMethods);
} else {

View file

@ -2,10 +2,10 @@ import { Snowflake } from "discord.js";
import humanizeDuration from "humanize-duration";
import { GuildPluginData } from "knub";
import moment from "moment-timezone";
import { LogType } from "src/data/LogType";
import { logger } from "src/logger";
import { CaseTypes } from "../../../data/CaseTypes";
import { LogType } from "../../../data/LogType";
import { Tempban } from "../../../data/entities/Tempban";
import { logger } from "../../../logger";
import { resolveUser } from "../../../utils";
import { CasesPlugin } from "../../Cases/CasesPlugin";
import { LogsPlugin } from "../../Logs/LogsPlugin";

View file

@ -3,33 +3,33 @@ import { GuildPluginData } from "knub";
import { ModActionsPluginType } from "../types";
export async function hasNotePermission(
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
) {
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_note;
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_note;
}
export async function hasWarnPermission(
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
) {
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_warn;
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_warn;
}
export async function hasMutePermission(
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
) {
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_mute;
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_mute;
}
export async function hasBanPermission(
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
pluginData: GuildPluginData<ModActionsPluginType>,
member: GuildMember,
channelId: Snowflake,
) {
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_ban;
}
return (await pluginData.config.getMatchingConfig({ member, channelId })).can_ban;
}

View file

@ -2,7 +2,7 @@ import { GuildMember } from "discord.js";
import { GuildPluginData } from "knub";
import { CaseTypes } from "../../../data/CaseTypes";
import { LogType } from "../../../data/LogType";
import { renderTemplate, TemplateSafeValueContainer } from "../../../templateFormatter";
import { renderTemplate, TemplateParseError, TemplateSafeValueContainer } from "../../../templateFormatter";
import { createUserNotificationError, notifyUser, resolveUser, ucfirst, UserNotificationResult } from "../../../utils";
import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
import { CasesPlugin } from "../../Cases/CasesPlugin";
@ -31,16 +31,27 @@ export async function kickMember(
if (contactMethods.length) {
if (config.kick_message) {
const kickMessage = await renderTemplate(
config.kick_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: kickOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, kickOptions.caseArgs.modId))
: null,
}),
);
let kickMessage: string;
try {
kickMessage = await renderTemplate(
config.kick_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: kickOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, kickOptions.caseArgs.modId))
: null,
}),
);
} catch (err) {
if (err instanceof TemplateParseError) {
return {
status: "failed",
error: `Invalid kick_message format: ${err.message}`,
};
}
throw err;
}
notifyResult = await notifyUser(member.user, kickMessage, contactMethods);
} else {

View file

@ -1,7 +1,7 @@
import { GuildMember, Snowflake } from "discord.js";
import { GuildPluginData } from "knub";
import { CaseTypes } from "../../../data/CaseTypes";
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
import { TemplateParseError, TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
import { UserNotificationResult, createUserNotificationError, notifyUser, resolveUser, ucfirst } from "../../../utils";
import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
import { waitForButtonConfirm } from "../../../utils/waitForInteraction";
@ -20,16 +20,27 @@ export async function warnMember(
let notifyResult: UserNotificationResult;
if (config.warn_message) {
const warnMessage = await renderTemplate(
config.warn_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: warnOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, warnOptions.caseArgs.modId))
: null,
}),
);
let warnMessage: string;
try {
warnMessage = await renderTemplate(
config.warn_message,
new TemplateSafeValueContainer({
guildName: pluginData.guild.name,
reason,
moderator: warnOptions.caseArgs?.modId
? userToTemplateSafeUser(await resolveUser(pluginData.client, warnOptions.caseArgs.modId))
: null,
}),
);
} catch (err) {
if (err instanceof TemplateParseError) {
return {
status: "failed",
error: `Invalid warn_message format: ${err.message}`,
};
}
throw err;
}
const contactMethods = warnOptions?.contactMethods
? warnOptions.contactMethods
: getDefaultContactMethods(pluginData, "warn");

View file

@ -1,53 +1,52 @@
import { GuildTextBasedChannel } from "discord.js";
import { EventEmitter } from "events";
import * as t from "io-ts";
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
import z from "zod";
import { Queue } from "../../Queue";
import { GuildCases } from "../../data/GuildCases";
import { GuildLogs } from "../../data/GuildLogs";
import { GuildMutes } from "../../data/GuildMutes";
import { GuildTempbans } from "../../data/GuildTempbans";
import { Case } from "../../data/entities/Case";
import { UserNotificationMethod, UserNotificationResult, tNullable } from "../../utils";
import { UserNotificationMethod, UserNotificationResult } from "../../utils";
import { CaseArgs } from "../Cases/types";
export const ConfigSchema = t.type({
export const zModActionsConfig = z.strictObject({
main_guild: tNullable(t.string),
dm_on_warn: t.boolean,
dm_on_kick: t.boolean,
dm_on_ban: t.boolean,
message_on_warn: t.boolean,
message_on_kick: t.boolean,
message_on_ban: t.boolean,
message_channel: tNullable(t.string),
warn_message: tNullable(t.string),
kick_message: tNullable(t.string),
ban_message: tNullable(t.string),
tempban_message: tNullable(t.string),
dm_on_warn: z.boolean(),
dm_on_kick: z.boolean(),
dm_on_ban: z.boolean(),
message_on_warn: z.boolean(),
message_on_kick: z.boolean(),
message_on_ban: z.boolean(),
message_channel: z.nullable(z.string()),
warn_message: z.nullable(z.string()),
kick_message: z.nullable(z.string()),
ban_message: z.nullable(z.string()),
tempban_message: z.nullable(z.string()),
default_ban_reason: tNullable(t.string),
alert_on_rejoin: t.boolean,
alert_channel: tNullable(t.string),
warn_notify_enabled: t.boolean,
warn_notify_threshold: t.number,
warn_notify_message: t.string,
ban_delete_message_days: t.number,
can_note: t.boolean,
can_warn: t.boolean,
can_mute: t.boolean,
can_kick: t.boolean,
can_ban: t.boolean,
can_unban: t.boolean,
can_view: t.boolean,
can_addcase: t.boolean,
can_massunban: t.boolean,
can_massban: t.boolean,
can_massmute: t.boolean,
can_hidecase: t.boolean,
can_deletecase: t.boolean,
can_act_as_other: t.boolean,
create_cases_for_manual_actions: t.boolean,
alert_on_rejoin: z.boolean(),
alert_channel: z.nullable(z.string()),
warn_notify_enabled: z.boolean(),
warn_notify_threshold: z.number(),
warn_notify_message: z.string(),
ban_delete_message_days: z.number(),
can_note: z.boolean(),
can_warn: z.boolean(),
can_mute: z.boolean(),
can_kick: z.boolean(),
can_ban: z.boolean(),
can_unban: z.boolean(),
can_view: z.boolean(),
can_addcase: z.boolean(),
can_massunban: z.boolean(),
can_massban: z.boolean(),
can_massmute: z.boolean(),
can_hidecase: z.boolean(),
can_deletecase: z.boolean(),
can_act_as_other: z.boolean(),
create_cases_for_manual_actions: z.boolean(),
});
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
export interface ModActionsEvents {
note: (userId: string, reason?: string) => void;
@ -64,7 +63,7 @@ export interface ModActionsEventEmitter extends EventEmitter {
}
export interface ModActionsPluginType extends BasePluginType {
config: TConfigSchema;
config: z.infer<typeof zModActionsConfig>;
state: {
mutes: GuildMutes;
cases: GuildCases;