diff --git a/backend/src/api/guilds/importExport.ts b/backend/src/api/guilds/importExport.ts index 019c5369..8bb46748 100644 --- a/backend/src/api/guilds/importExport.ts +++ b/backend/src/api/guilds/importExport.ts @@ -75,7 +75,10 @@ export function initGuildsImportExportAPI(guildRouter: express.Router) { try { data = importExportData.parse(req.body.data); } catch (err) { - return clientError(res, "Invalid import data format"); + const prettyMessage = `${err.issues[0].code}: expected ${err.issues[0].expected}, received ${ + err.issues[0].received + } at /${err.issues[0].path.join("/")}`; + return clientError(res, `Invalid import data format: ${prettyMessage}`); return; } @@ -87,6 +90,14 @@ export function initGuildsImportExportAPI(guildRouter: express.Router) { return; } + const seenCaseNumbers = new Set(); + for (const theCase of data.cases) { + if (seenCaseNumbers.has(theCase.case_number)) { + return clientError(res, `Duplicate case number: ${theCase.case_number}`); + } + seenCaseNumbers.add(theCase.case_number); + } + const guildCases = GuildCases.getGuildInstance(req.params.guildId); // Prepare cases diff --git a/backend/src/data/GuildNicknameHistory.ts b/backend/src/data/GuildNicknameHistory.ts index 9f75d24e..e0cf7cfb 100644 --- a/backend/src/data/GuildNicknameHistory.ts +++ b/backend/src/data/GuildNicknameHistory.ts @@ -17,7 +17,7 @@ if (!isAPI()) { setTimeout(cleanup, 30 * SECONDS); } -export const MAX_NICKNAME_ENTRIES_PER_USER = 10; +export const MAX_NICKNAME_ENTRIES_PER_USER = 20; export class GuildNicknameHistory extends BaseGuildRepository { private nicknameHistory: Repository; diff --git a/backend/src/data/UsernameHistory.ts b/backend/src/data/UsernameHistory.ts index 7aa4331a..bcd3ba9d 100644 --- a/backend/src/data/UsernameHistory.ts +++ b/backend/src/data/UsernameHistory.ts @@ -17,7 +17,7 @@ if (!isAPI()) { setTimeout(cleanup, 30 * SECONDS); } -export const MAX_USERNAME_ENTRIES_PER_USER = 5; +export const MAX_USERNAME_ENTRIES_PER_USER = 20; export class UsernameHistory extends BaseRepository { private usernameHistory: Repository; diff --git a/backend/src/plugins/Automod/actions/ban.ts b/backend/src/plugins/Automod/actions/ban.ts index e32279a7..9cd0fd86 100644 --- a/backend/src/plugins/Automod/actions/ban.ts +++ b/backend/src/plugins/Automod/actions/ban.ts @@ -25,7 +25,7 @@ export const BanAction = automodAction({ const reason = actionConfig.reason || "Kicked automatically"; const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : undefined; const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined; - const deleteMessageDays = actionConfig.deleteMessageDays || undefined; + const deleteMessageDays = actionConfig.deleteMessageDays ?? undefined; const caseArgs: Partial = { modId: pluginData.client.user!.id, diff --git a/backend/src/plugins/Automod/actions/clean.ts b/backend/src/plugins/Automod/actions/clean.ts index 27ee1cb6..56452d79 100644 --- a/backend/src/plugins/Automod/actions/clean.ts +++ b/backend/src/plugins/Automod/actions/clean.ts @@ -4,6 +4,8 @@ import { LogType } from "../../../data/LogType"; import { noop } from "../../../utils"; import { automodAction } from "../helpers"; +const cleanDebugServer = process.env.TEMP_CLEAN_DEBUG_SERVER; + export const CleanAction = automodAction({ configType: t.boolean, defaultConfig: false, @@ -27,13 +29,26 @@ export const CleanAction = automodAction({ } } + if (pluginData.guild.id === cleanDebugServer) { + const toDeleteFormatted = Array.from(messageIdsToDeleteByChannelId.entries()) + .map(([channelId, messageIds]) => `- ${channelId}: ${messageIds.join(", ")}`) + .join("\n"); + // tslint:disable-next-line:no-console + console.log(`[DEBUG] Cleaning messages (${ruleName}):\n${toDeleteFormatted}`); + } + for (const [channelId, messageIds] of messageIdsToDeleteByChannelId.entries()) { for (const id of messageIds) { pluginData.state.logs.ignoreLog(LogType.MESSAGE_DELETE, id); } const channel = pluginData.guild.channels.cache.get(channelId as Snowflake) as TextChannel; - await channel.bulkDelete(messageIds as Snowflake[]).catch(noop); + await channel.bulkDelete(messageIds as Snowflake[]).catch((err) => { + if (pluginData.guild.id === cleanDebugServer) { + // tslint:disable-next-line:no-console + console.error(`[DEBUG] Failed to bulk delete messages (${ruleName}): ${err}`); + } + }); } }, }); diff --git a/backend/src/plugins/Automod/actions/reply.ts b/backend/src/plugins/Automod/actions/reply.ts index efe833cb..52aa491d 100644 --- a/backend/src/plugins/Automod/actions/reply.ts +++ b/backend/src/plugins/Automod/actions/reply.ts @@ -17,6 +17,7 @@ import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions"; import { automodAction } from "../helpers"; import { AutomodContext } from "../types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { messageIsEmpty } from "../../../utils/messageIsEmpty"; export const ReplyAction = automodAction({ configType: t.union([ @@ -109,6 +110,10 @@ export const ReplyAction = automodAction({ }; } + if (messageIsEmpty(messageOpts)) { + return; + } + const replyMsg = await channel.send(messageOpts); if (typeof actionConfig === "object" && actionConfig.auto_delete) { diff --git a/backend/src/plugins/Cases/caseIcons.ts b/backend/src/plugins/Cases/caseIcons.ts index 3c685804..342c25a7 100644 --- a/backend/src/plugins/Cases/caseIcons.ts +++ b/backend/src/plugins/Cases/caseIcons.ts @@ -1,13 +1,13 @@ import { CaseTypes } from "../../data/CaseTypes"; export const caseIcons: Record = { - [CaseTypes.Ban]: "<:case_ban:742540201443721317>", - [CaseTypes.Unban]: "<:case_unban:742540201670475846>", - [CaseTypes.Note]: "<:case_note:742540201368485950>", - [CaseTypes.Warn]: "<:case_warn:742540201624338454>", - [CaseTypes.Kick]: "<:case_kick:742540201661825165>", - [CaseTypes.Mute]: "<:case_mute:742540201817145364>", - [CaseTypes.Unmute]: "<:case_unmute:742540201489858643>", - [CaseTypes.Deleted]: "<:case_deleted:742540201473343529>", - [CaseTypes.Softban]: "<:case_softban:742540201766813747>", + [CaseTypes.Ban]: "<:case_ban:906897178176393246>", + [CaseTypes.Unban]: "<:case_unban:906897177824067665>", + [CaseTypes.Note]: "<:case_note:906897177832476743>", + [CaseTypes.Warn]: "<:case_warn:906897177840844832>", + [CaseTypes.Kick]: "<:case_kick:906897178310639646>", + [CaseTypes.Mute]: "<:case_mute:906897178147057664>", + [CaseTypes.Unmute]: "<:case_unmute:906897177819881523>", + [CaseTypes.Deleted]: "<:case_deleted:906897178209968148>", + [CaseTypes.Softban]: "<:case_softban:906897177828278274>", }; diff --git a/backend/src/plugins/ModActions/functions/banUserId.ts b/backend/src/plugins/ModActions/functions/banUserId.ts index bb7f691e..8253b3b3 100644 --- a/backend/src/plugins/ModActions/functions/banUserId.ts +++ b/backend/src/plugins/ModActions/functions/banUserId.ts @@ -87,7 +87,7 @@ export async function banUserId( pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId); ignoreEvent(pluginData, IgnoredEventType.Ban, userId); try { - const deleteMessageDays = Math.min(30, Math.max(0, banOptions.deleteMessageDays ?? 1)); + const deleteMessageDays = Math.min(7, Math.max(0, banOptions.deleteMessageDays ?? 1)); await pluginData.guild.bans.create(userId as Snowflake, { days: deleteMessageDays, reason: reason ?? undefined, diff --git a/backend/src/plugins/NameHistory/NameHistoryPlugin.ts b/backend/src/plugins/NameHistory/NameHistoryPlugin.ts index 0efb5fe3..733c9306 100644 --- a/backend/src/plugins/NameHistory/NameHistoryPlugin.ts +++ b/backend/src/plugins/NameHistory/NameHistoryPlugin.ts @@ -23,7 +23,7 @@ const defaultOptions: PluginOptions = { export const NameHistoryPlugin = zeppelinGuildPlugin()({ name: "name_history", - showInDocs: false, + showInDocs: true, configSchema: ConfigSchema, defaultOptions, @@ -35,9 +35,8 @@ export const NameHistoryPlugin = zeppelinGuildPlugin()({ // prettier-ignore events: [ - // FIXME: Temporary - // ChannelJoinEvt, - // MessageCreateEvt, + ChannelJoinEvt, + MessageCreateEvt, ], beforeLoad(pluginData) { diff --git a/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts b/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts index a217c1e5..8ccbd01a 100644 --- a/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts +++ b/backend/src/plugins/ReactionRoles/ReactionRolesPlugin.ts @@ -117,13 +117,13 @@ export const ReactionRolesPlugin = zeppelinGuildPlugin( RefreshReactionRolesCmd, ClearReactionRolesCmd, InitReactionRolesCmd, - // PostButtonRolesCmd, + PostButtonRolesCmd, ], // prettier-ignore events: [ AddReactionRoleEvt, - // ButtonInteractionEvt, + ButtonInteractionEvt, MessageDeletedEvt, ], configPreprocessor, diff --git a/backend/src/plugins/Utility/commands/HelpCmd.ts b/backend/src/plugins/Utility/commands/HelpCmd.ts index b03d3aa4..1f571592 100644 --- a/backend/src/plugins/Utility/commands/HelpCmd.ts +++ b/backend/src/plugins/Utility/commands/HelpCmd.ts @@ -63,7 +63,7 @@ export const HelpCmd = utilityCmd({ let snippet = `**${prefix}${trigger}**`; if (description) snippet += `\n${description}`; if (usage) snippet += `\nBasic usage: \`${usage}\``; - snippet += `\n`; + snippet += `\n`; return snippet; }); diff --git a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts index 17e2c63f..9d3c6d68 100644 --- a/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getMessageInfoEmbed.ts @@ -130,9 +130,10 @@ export async function getMessageInfoEmbed( } if (message.attachments.size) { + const attachmentUrls = message.attachments.map((att) => att.url); embed.fields.push({ name: preEmbedPadding + "Attachments", - value: message.attachments[0].url, + value: attachmentUrls.join("\n"), }); } diff --git a/backend/src/utils.ts b/backend/src/utils.ts index 9a37511e..24d46255 100644 --- a/backend/src/utils.ts +++ b/backend/src/utils.ts @@ -571,7 +571,7 @@ export function convertMSToDelayString(ms: number): string { return result; } -export function successMessage(str, emoji = "<:zep_check:650361014180904971>") { +export function successMessage(str, emoji = "<:zep_check:906897402101891093>") { return emoji ? `${emoji} ${str}` : str; }