diff --git a/backend/src/data/GuildArchives.ts b/backend/src/data/GuildArchives.ts index 0451dfe0..4d74ccef 100644 --- a/backend/src/data/GuildArchives.ts +++ b/backend/src/data/GuildArchives.ts @@ -4,12 +4,12 @@ import { Repository } from "typeorm"; import { TemplateSafeValueContainer, renderTemplate } from "../templateFormatter"; import { renderUsername, trimLines } from "../utils"; import { decrypt, encrypt } from "../utils/crypt"; +import { isDefaultSticker } from "../utils/isDefaultSticker"; import { channelToTemplateSafeChannel, guildToTemplateSafeGuild } from "../utils/templateSafeObjects"; import { BaseGuildRepository } from "./BaseGuildRepository"; import { dataSource } from "./dataSource"; import { ArchiveEntry } from "./entities/ArchiveEntry"; import { SavedMessage } from "./entities/SavedMessage"; -import { isDefaultSticker } from "../utils/isDefaultSticker"; const DEFAULT_EXPIRY_DAYS = 30; diff --git a/backend/src/exportSchemas.ts b/backend/src/exportSchemas.ts index 9fa5c3a5..54f55291 100644 --- a/backend/src/exportSchemas.ts +++ b/backend/src/exportSchemas.ts @@ -1,21 +1,21 @@ import { z } from "zod"; -import { guildPlugins } from "./plugins/availablePlugins"; import zodToJsonSchema from "zod-to-json-schema"; +import { guildPlugins } from "./plugins/availablePlugins"; import { zZeppelinGuildConfig } from "./types"; const pluginSchemaMap = guildPlugins.reduce((map, plugin) => { - if (! plugin.info) { + if (!plugin.info) { return map; } map[plugin.name] = plugin.info.configSchema; return map; }, {}); -const fullSchema = zZeppelinGuildConfig - .omit({ plugins: true }) - .merge(z.strictObject({ +const fullSchema = zZeppelinGuildConfig.omit({ plugins: true }).merge( + z.strictObject({ plugins: z.strictObject(pluginSchemaMap).partial(), - })); + }), +); const jsonSchema = zodToJsonSchema(fullSchema); diff --git a/backend/src/pluginUtils.ts b/backend/src/pluginUtils.ts index a2f744d9..31cbd77c 100644 --- a/backend/src/pluginUtils.ts +++ b/backend/src/pluginUtils.ts @@ -10,13 +10,7 @@ import { PermissionsBitField, TextBasedChannel, } from "discord.js"; -import { - AnyPluginData, - CommandContext, - ExtendedMatchParams, - GuildPluginData, - helpers -} from "knub"; +import { AnyPluginData, CommandContext, ExtendedMatchParams, GuildPluginData, helpers } from "knub"; import { logger } from "./logger"; import { isStaff } from "./staff"; import { TZeppelinKnub } from "./types"; diff --git a/backend/src/plugins/AutoDelete/types.ts b/backend/src/plugins/AutoDelete/types.ts index 69100438..be6ff7ee 100644 --- a/backend/src/plugins/AutoDelete/types.ts +++ b/backend/src/plugins/AutoDelete/types.ts @@ -1,10 +1,10 @@ import { BasePluginType } from "knub"; +import z from "zod"; import { GuildLogs } from "../../data/GuildLogs"; import { GuildSavedMessages } from "../../data/GuildSavedMessages"; import { SavedMessage } from "../../data/entities/SavedMessage"; import { MINUTES, zDelayString } from "../../utils"; import Timeout = NodeJS.Timeout; -import z from "zod"; export const MAX_DELAY = 5 * MINUTES; diff --git a/backend/src/plugins/Automod/AutomodPlugin.ts b/backend/src/plugins/Automod/AutomodPlugin.ts index 9634c25d..29fcf9e6 100644 --- a/backend/src/plugins/Automod/AutomodPlugin.ts +++ b/backend/src/plugins/Automod/AutomodPlugin.ts @@ -1,9 +1,9 @@ import { CooldownManager } from "knub"; +import { Queue } from "../../Queue"; import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels"; import { GuildArchives } from "../../data/GuildArchives"; import { GuildLogs } from "../../data/GuildLogs"; import { GuildSavedMessages } from "../../data/GuildSavedMessages"; -import { Queue } from "../../Queue"; import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners"; import { MINUTES, SECONDS } from "../../utils"; import { registerEventListenersFromMap } from "../../utils/registerEventListenersFromMap"; @@ -19,9 +19,9 @@ import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint"; import { AntiraidClearCmd } from "./commands/AntiraidClearCmd"; import { SetAntiraidCmd } from "./commands/SetAntiraidCmd"; import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd"; -import { runAutomodOnCounterTrigger } from "./events/runAutomodOnCounterTrigger"; import { RunAutomodOnJoinEvt, RunAutomodOnLeaveEvt } from "./events/RunAutomodOnJoinLeaveEvt"; import { RunAutomodOnMemberUpdate } from "./events/RunAutomodOnMemberUpdate"; +import { runAutomodOnCounterTrigger } from "./events/runAutomodOnCounterTrigger"; import { runAutomodOnMessage } from "./events/runAutomodOnMessage"; import { runAutomodOnModAction } from "./events/runAutomodOnModAction"; import { diff --git a/backend/src/plugins/Automod/actions/alert.ts b/backend/src/plugins/Automod/actions/alert.ts index 65456218..d21fb4d5 100644 --- a/backend/src/plugins/Automod/actions/alert.ts +++ b/backend/src/plugins/Automod/actions/alert.ts @@ -16,7 +16,7 @@ import { zAllowedMentions, zBoundedCharacters, zNullishToUndefined, - zSnowflake + zSnowflake, } from "../../../utils"; import { erisAllowedMentionsToDjsMentionOptions } from "../../../utils/erisAllowedMentionsToDjsMentionOptions"; import { messageIsEmpty } from "../../../utils/messageIsEmpty"; diff --git a/backend/src/plugins/Automod/actions/ban.ts b/backend/src/plugins/Automod/actions/ban.ts index 22cc8167..5bf5b3a2 100644 --- a/backend/src/plugins/Automod/actions/ban.ts +++ b/backend/src/plugins/Automod/actions/ban.ts @@ -1,10 +1,17 @@ import z from "zod"; -import { convertDelayStringToMS, nonNullish, unique, zBoundedCharacters, zDelayString, zSnowflake } from "../../../utils"; +import { + convertDelayStringToMS, + nonNullish, + unique, + zBoundedCharacters, + zDelayString, + zSnowflake, +} from "../../../utils"; import { CaseArgs } from "../../Cases/types"; import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin"; +import { zNotify } from "../constants"; import { resolveActionContactMethods } from "../functions/resolveActionContactMethods"; import { automodAction } from "../helpers"; -import { zNotify } from "../constants"; const configSchema = z.strictObject({ reason: zBoundedCharacters(0, 4000).nullable().default(null), diff --git a/backend/src/plugins/Automod/actions/changePerms.ts b/backend/src/plugins/Automod/actions/changePerms.ts index 92fdbb84..7b7eba37 100644 --- a/backend/src/plugins/Automod/actions/changePerms.ts +++ b/backend/src/plugins/Automod/actions/changePerms.ts @@ -68,10 +68,7 @@ export const ChangePermsAction = automodAction({ configSchema: z.strictObject({ target: zBoundedCharacters(1, 2000), channel: zBoundedCharacters(1, 2000).nullable().default(null), - perms: z.record( - z.enum(allPermissionNames), - z.boolean().nullable(), - ), + perms: z.record(z.enum(allPermissionNames), z.boolean().nullable()), }), async apply({ pluginData, contexts, actionConfig }) { diff --git a/backend/src/plugins/Automod/actions/kick.ts b/backend/src/plugins/Automod/actions/kick.ts index 412309cd..2161e2c0 100644 --- a/backend/src/plugins/Automod/actions/kick.ts +++ b/backend/src/plugins/Automod/actions/kick.ts @@ -2,9 +2,9 @@ import z from "zod"; import { asyncMap, nonNullish, resolveMember, unique, zBoundedCharacters, zSnowflake } from "../../../utils"; import { CaseArgs } from "../../Cases/types"; import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin"; +import { zNotify } from "../constants"; import { resolveActionContactMethods } from "../functions/resolveActionContactMethods"; import { automodAction } from "../helpers"; -import { zNotify } from "../constants"; export const KickAction = automodAction({ configSchema: z.strictObject({ diff --git a/backend/src/plugins/Automod/actions/mute.ts b/backend/src/plugins/Automod/actions/mute.ts index c2f8e186..ba932b7f 100644 --- a/backend/src/plugins/Automod/actions/mute.ts +++ b/backend/src/plugins/Automod/actions/mute.ts @@ -1,12 +1,19 @@ import z from "zod"; import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError"; -import { convertDelayStringToMS, nonNullish, unique, zBoundedCharacters, zDelayString, zSnowflake } from "../../../utils"; +import { + convertDelayStringToMS, + nonNullish, + unique, + zBoundedCharacters, + zDelayString, + zSnowflake, +} from "../../../utils"; import { CaseArgs } from "../../Cases/types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { MutesPlugin } from "../../Mutes/MutesPlugin"; +import { zNotify } from "../constants"; import { resolveActionContactMethods } from "../functions/resolveActionContactMethods"; import { automodAction } from "../helpers"; -import { zNotify } from "../constants"; export const MuteAction = automodAction({ configSchema: z.strictObject({ @@ -14,8 +21,14 @@ export const MuteAction = automodAction({ duration: zDelayString.nullable().default(null), notify: zNotify.nullable().default(null), notifyChannel: zSnowflake.nullable().default(null), - remove_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).nullable().default(null), - restore_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).nullable().default(null), + remove_roles_on_mute: z + .union([z.boolean(), z.array(zSnowflake)]) + .nullable() + .default(null), + restore_roles_on_mute: z + .union([z.boolean(), z.array(zSnowflake)]) + .nullable() + .default(null), postInCaseLog: z.boolean().nullable().default(null), hide_case: z.boolean().nullable().default(false), }), diff --git a/backend/src/plugins/Automod/actions/reply.ts b/backend/src/plugins/Automod/actions/reply.ts index 02ff9545..e8b1fdf8 100644 --- a/backend/src/plugins/Automod/actions/reply.ts +++ b/backend/src/plugins/Automod/actions/reply.ts @@ -10,7 +10,7 @@ import { verboseChannelMention, zBoundedCharacters, zDelayString, - zMessageContent + zMessageContent, } from "../../../utils"; import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions"; import { messageIsEmpty } from "../../../utils/messageIsEmpty"; diff --git a/backend/src/plugins/Automod/actions/warn.ts b/backend/src/plugins/Automod/actions/warn.ts index 7ccb3898..d8a7805b 100644 --- a/backend/src/plugins/Automod/actions/warn.ts +++ b/backend/src/plugins/Automod/actions/warn.ts @@ -2,9 +2,9 @@ import z from "zod"; import { asyncMap, nonNullish, resolveMember, unique, zBoundedCharacters, zSnowflake } from "../../../utils"; import { CaseArgs } from "../../Cases/types"; import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin"; +import { zNotify } from "../constants"; import { resolveActionContactMethods } from "../functions/resolveActionContactMethods"; import { automodAction } from "../helpers"; -import { zNotify } from "../constants"; export const WarnAction = automodAction({ configSchema: z.strictObject({ diff --git a/backend/src/plugins/Automod/constants.ts b/backend/src/plugins/Automod/constants.ts index cc37f402..c2baae77 100644 --- a/backend/src/plugins/Automod/constants.ts +++ b/backend/src/plugins/Automod/constants.ts @@ -20,7 +20,4 @@ export enum RecentActionType { ThreadCreate, } -export const zNotify = z.union([ - z.literal("dm"), - z.literal("channel"), -]); +export const zNotify = z.union([z.literal("dm"), z.literal("channel")]); diff --git a/backend/src/plugins/Automod/functions/createMessageSpamTrigger.ts b/backend/src/plugins/Automod/functions/createMessageSpamTrigger.ts index 562ade6b..cb7eb288 100644 --- a/backend/src/plugins/Automod/functions/createMessageSpamTrigger.ts +++ b/backend/src/plugins/Automod/functions/createMessageSpamTrigger.ts @@ -1,3 +1,4 @@ +import z from "zod"; import { SavedMessage } from "../../../data/entities/SavedMessage"; import { humanizeDurationShort } from "../../../humanizeDurationShort"; import { getBaseUrl } from "../../../pluginUtils"; @@ -7,7 +8,6 @@ import { automodTrigger } from "../helpers"; import { findRecentSpam } from "./findRecentSpam"; import { getMatchingMessageRecentActions } from "./getMatchingMessageRecentActions"; import { getMessageSpamIdentifier } from "./getSpamIdentifier"; -import z from "zod"; interface TMessageSpamMatchResultType { archiveId: string; diff --git a/backend/src/plugins/Automod/helpers.ts b/backend/src/plugins/Automod/helpers.ts index d1c04d61..b4b9f764 100644 --- a/backend/src/plugins/Automod/helpers.ts +++ b/backend/src/plugins/Automod/helpers.ts @@ -1,7 +1,7 @@ import { GuildPluginData } from "knub"; +import z, { ZodTypeAny } from "zod"; import { Awaitable } from "../../utils/typeUtils"; import { AutomodContext, AutomodPluginType } from "./types"; -import z, { ZodTypeAny } from "zod"; interface BaseAutomodTriggerMatchResult { extraContexts?: AutomodContext[]; diff --git a/backend/src/plugins/Automod/triggers/antiraidLevel.ts b/backend/src/plugins/Automod/triggers/antiraidLevel.ts index 1c5f7458..c1467bf8 100644 --- a/backend/src/plugins/Automod/triggers/antiraidLevel.ts +++ b/backend/src/plugins/Automod/triggers/antiraidLevel.ts @@ -1,5 +1,5 @@ -import { automodTrigger } from "../helpers"; import z from "zod"; +import { automodTrigger } from "../helpers"; interface AntiraidLevelTriggerResult {} diff --git a/backend/src/plugins/Automod/triggers/anyMessage.ts b/backend/src/plugins/Automod/triggers/anyMessage.ts index 93ce0abc..71c92019 100644 --- a/backend/src/plugins/Automod/triggers/anyMessage.ts +++ b/backend/src/plugins/Automod/triggers/anyMessage.ts @@ -1,7 +1,7 @@ import { Snowflake } from "discord.js"; +import z from "zod"; import { verboseChannelMention } from "../../../utils"; import { automodTrigger } from "../helpers"; -import z from "zod"; interface AnyMessageResultType {} diff --git a/backend/src/plugins/Automod/triggers/matchAttachmentType.ts b/backend/src/plugins/Automod/triggers/matchAttachmentType.ts index 6dd49580..8c562eb1 100644 --- a/backend/src/plugins/Automod/triggers/matchAttachmentType.ts +++ b/backend/src/plugins/Automod/triggers/matchAttachmentType.ts @@ -1,6 +1,6 @@ import { escapeInlineCode, Snowflake } from "discord.js"; -import z from "zod"; import { extname } from "path"; +import z from "zod"; import { asSingleLine, messageSummary, verboseChannelMention } from "../../../utils"; import { automodTrigger } from "../helpers"; @@ -9,28 +9,30 @@ interface MatchResultType { mode: "blacklist" | "whitelist"; } -const configSchema = z.strictObject({ - filetype_blacklist: z.array(z.string().max(32)).max(255).default([]), - blacklist_enabled: z.boolean().default(false), - filetype_whitelist: z.array(z.string().max(32)).max(255).default([]), - whitelist_enabled: z.boolean().default(false), -}).transform((parsed, ctx) => { - if (parsed.blacklist_enabled && parsed.whitelist_enabled) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Cannot have both blacklist and whitelist enabled", - }); - return z.NEVER; - } - if (! parsed.blacklist_enabled && ! parsed.whitelist_enabled) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Must have either blacklist or whitelist enabled", - }); - return z.NEVER; - } - return parsed; -}); +const configSchema = z + .strictObject({ + filetype_blacklist: z.array(z.string().max(32)).max(255).default([]), + blacklist_enabled: z.boolean().default(false), + filetype_whitelist: z.array(z.string().max(32)).max(255).default([]), + whitelist_enabled: z.boolean().default(false), + }) + .transform((parsed, ctx) => { + if (parsed.blacklist_enabled && parsed.whitelist_enabled) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Cannot have both blacklist and whitelist enabled", + }); + return z.NEVER; + } + if (!parsed.blacklist_enabled && !parsed.whitelist_enabled) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Must have either blacklist or whitelist enabled", + }); + return z.NEVER; + } + return parsed; + }); export const MatchAttachmentTypeTrigger = automodTrigger()({ configSchema, diff --git a/backend/src/plugins/Automod/triggers/matchLinks.ts b/backend/src/plugins/Automod/triggers/matchLinks.ts index fe3280fc..c43d8320 100644 --- a/backend/src/plugins/Automod/triggers/matchLinks.ts +++ b/backend/src/plugins/Automod/triggers/matchLinks.ts @@ -26,12 +26,20 @@ const configSchema = z.strictObject({ include_subdomains: z.boolean().default(true), include_words: z.array(z.string().max(2000)).max(700).optional(), exclude_words: z.array(z.string().max(2000)).max(700).optional(), - include_regex: z.array(zRegex(z.string().max(2000))).max(512).optional(), - exclude_regex: z.array(zRegex(z.string().max(2000))).max(512).optional(), - phisherman: z.strictObject({ - include_suspected: z.boolean().optional(), - include_verified: z.boolean().optional(), - }).optional(), + include_regex: z + .array(zRegex(z.string().max(2000))) + .max(512) + .optional(), + exclude_regex: z + .array(zRegex(z.string().max(2000))) + .max(512) + .optional(), + phisherman: z + .strictObject({ + include_suspected: z.boolean().optional(), + include_verified: z.boolean().optional(), + }) + .optional(), only_real_links: z.boolean().default(true), match_messages: z.boolean().default(true), match_embeds: z.boolean().default(true), diff --git a/backend/src/plugins/Automod/triggers/matchMimeType.ts b/backend/src/plugins/Automod/triggers/matchMimeType.ts index 8da9b2e3..86232916 100644 --- a/backend/src/plugins/Automod/triggers/matchMimeType.ts +++ b/backend/src/plugins/Automod/triggers/matchMimeType.ts @@ -8,28 +8,30 @@ interface MatchResultType { mode: "blacklist" | "whitelist"; } -const configSchema = z.strictObject({ - mime_type_blacklist: z.array(z.string().max(255)).max(255).default([]), - blacklist_enabled: z.boolean().default(false), - mime_type_whitelist: z.array(z.string().max(255)).max(255).default([]), - whitelist_enabled: z.boolean().default(false), -}).transform((parsed, ctx) => { - if (parsed.blacklist_enabled && parsed.whitelist_enabled) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Cannot have both blacklist and whitelist enabled", - }); - return z.NEVER; - } - if (! parsed.blacklist_enabled && ! parsed.whitelist_enabled) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Must have either blacklist or whitelist enabled", - }); - return z.NEVER; - } - return parsed; -}); +const configSchema = z + .strictObject({ + mime_type_blacklist: z.array(z.string().max(255)).max(255).default([]), + blacklist_enabled: z.boolean().default(false), + mime_type_whitelist: z.array(z.string().max(255)).max(255).default([]), + whitelist_enabled: z.boolean().default(false), + }) + .transform((parsed, ctx) => { + if (parsed.blacklist_enabled && parsed.whitelist_enabled) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Cannot have both blacklist and whitelist enabled", + }); + return z.NEVER; + } + if (!parsed.blacklist_enabled && !parsed.whitelist_enabled) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Must have either blacklist or whitelist enabled", + }); + return z.NEVER; + } + return parsed; + }); export const MatchMimeTypeTrigger = automodTrigger()({ configSchema, diff --git a/backend/src/plugins/Automod/triggers/roleAdded.ts b/backend/src/plugins/Automod/triggers/roleAdded.ts index 47027b6b..ce1e0ab5 100644 --- a/backend/src/plugins/Automod/triggers/roleAdded.ts +++ b/backend/src/plugins/Automod/triggers/roleAdded.ts @@ -8,10 +8,7 @@ interface RoleAddedMatchResult { matchedRoleId: string; } -const configSchema = z.union([ - zSnowflake, - z.array(zSnowflake).max(255), -]).default([]); +const configSchema = z.union([zSnowflake, z.array(zSnowflake).max(255)]).default([]); export const RoleAddedTrigger = automodTrigger()({ configSchema, diff --git a/backend/src/plugins/Automod/triggers/roleRemoved.ts b/backend/src/plugins/Automod/triggers/roleRemoved.ts index 26caf227..f11dafeb 100644 --- a/backend/src/plugins/Automod/triggers/roleRemoved.ts +++ b/backend/src/plugins/Automod/triggers/roleRemoved.ts @@ -8,10 +8,7 @@ interface RoleAddedMatchResult { matchedRoleId: string; } -const configSchema = z.union([ - zSnowflake, - z.array(zSnowflake).max(255), -]).default([]); +const configSchema = z.union([zSnowflake, z.array(zSnowflake).max(255)]).default([]); export const RoleRemovedTrigger = automodTrigger()({ configSchema, diff --git a/backend/src/plugins/Automod/types.ts b/backend/src/plugins/Automod/types.ts index 2cf2df2f..6cf88ad6 100644 --- a/backend/src/plugins/Automod/types.ts +++ b/backend/src/plugins/Automod/types.ts @@ -19,58 +19,62 @@ import { availableTriggers } from "./triggers/availableTriggers"; import Timeout = NodeJS.Timeout; export type ZTriggersMapHelper = { - [TriggerName in keyof typeof availableTriggers]: typeof availableTriggers[TriggerName]["configSchema"]; + [TriggerName in keyof typeof availableTriggers]: (typeof availableTriggers)[TriggerName]["configSchema"]; }; -const zTriggersMap = z.strictObject(entries(availableTriggers).reduce((map, [triggerName, trigger]) => { - map[triggerName] = trigger.configSchema; - return map; -}, {} as ZTriggersMapHelper)).partial(); +const zTriggersMap = z + .strictObject( + entries(availableTriggers).reduce((map, [triggerName, trigger]) => { + map[triggerName] = trigger.configSchema; + return map; + }, {} as ZTriggersMapHelper), + ) + .partial(); type ZActionsMapHelper = { - [ActionName in keyof typeof availableActions]: typeof availableActions[ActionName]["configSchema"]; + [ActionName in keyof typeof availableActions]: (typeof availableActions)[ActionName]["configSchema"]; }; -const zActionsMap = z.strictObject(entries(availableActions).reduce((map, [actionName, action]) => { - // @ts-expect-error TS can't infer this properly but it works fine thanks to our helper - map[actionName] = action.configSchema; - return map; -}, {} as ZActionsMapHelper)).partial(); +const zActionsMap = z + .strictObject( + entries(availableActions).reduce((map, [actionName, action]) => { + // @ts-expect-error TS can't infer this properly but it works fine thanks to our helper + map[actionName] = action.configSchema; + return map; + }, {} as ZActionsMapHelper), + ) + .partial(); const zRule = z.strictObject({ enabled: z.boolean().default(true), // Typed as "never" because you are not expected to supply this directly. // The transform instead picks it up from the property key and the output type is a string. - name: z.never().optional().transform((_, ctx) => { - const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); - if (! ruleName) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Automod rules must have names", - }); - return z.NEVER; - } - return ruleName; - }), + name: z + .never() + .optional() + .transform((_, ctx) => { + const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); + if (!ruleName) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Automod rules must have names", + }); + return z.NEVER; + } + return ruleName; + }), presets: z.array(z.string().max(100)).max(25).default([]), affects_bots: z.boolean().default(false), affects_self: z.boolean().default(false), cooldown: zDelayString.nullable().default(null), allow_further_rules: z.boolean().default(false), triggers: z.array(zTriggersMap), - actions: zActionsMap.refine( - (v) => ! (v.clean && v.start_thread), - { - message: "Cannot have both clean and start_thread active at the same time", - } - ), + actions: zActionsMap.refine((v) => !(v.clean && v.start_thread), { + message: "Cannot have both clean and start_thread active at the same time", + }), }); export type TRule = z.infer; export const zAutomodConfig = z.strictObject({ - rules: zBoundedRecord( - z.record(z.string().max(100), zRule), - 0, - 255, - ), + rules: zBoundedRecord(z.record(z.string().max(100), zRule), 0, 255), antiraid_levels: z.array(z.string().max(100)).max(10), can_set_antiraid: z.boolean(), can_view_antiraid: z.boolean(), diff --git a/backend/src/plugins/ContextMenus/actions/mute.ts b/backend/src/plugins/ContextMenus/actions/mute.ts index c6eedbc6..16b48a4a 100644 --- a/backend/src/plugins/ContextMenus/actions/mute.ts +++ b/backend/src/plugins/ContextMenus/actions/mute.ts @@ -2,13 +2,13 @@ import { ContextMenuCommandInteraction } from "discord.js"; import humanizeDuration from "humanize-duration"; import { GuildPluginData } from "knub"; import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError"; +import { canActOn } from "../../../pluginUtils"; import { convertDelayStringToMS } from "../../../utils"; import { CaseArgs } from "../../Cases/types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin"; import { MutesPlugin } from "../../Mutes/MutesPlugin"; import { ContextMenuPluginType } from "../types"; -import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin"; -import { canActOn } from "../../../pluginUtils"; export async function muteAction( pluginData: GuildPluginData, diff --git a/backend/src/plugins/Counters/CountersPlugin.ts b/backend/src/plugins/Counters/CountersPlugin.ts index 85be2cf5..1cc1ec25 100644 --- a/backend/src/plugins/Counters/CountersPlugin.ts +++ b/backend/src/plugins/Counters/CountersPlugin.ts @@ -1,10 +1,7 @@ import { EventEmitter } from "events"; import { PluginOptions } from "knub"; import { GuildCounters } from "../../data/GuildCounters"; -import { - CounterTrigger, - parseCounterConditionString -} from "../../data/entities/CounterTrigger"; +import { CounterTrigger, parseCounterConditionString } from "../../data/entities/CounterTrigger"; import { mapToPublicFn } from "../../pluginUtils"; import { MINUTES, convertDelayStringToMS, values } from "../../utils"; import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint"; diff --git a/backend/src/plugins/Counters/types.ts b/backend/src/plugins/Counters/types.ts index 783ec666..8e70c4ab 100644 --- a/backend/src/plugins/Counters/types.ts +++ b/backend/src/plugins/Counters/types.ts @@ -2,33 +2,45 @@ import { EventEmitter } from "events"; import { BasePluginType } from "knub"; import z from "zod"; import { GuildCounters } from "../../data/GuildCounters"; -import { CounterTrigger, buildCounterConditionString, getReverseCounterComparisonOp, parseCounterConditionString } from "../../data/entities/CounterTrigger"; +import { + CounterTrigger, + buildCounterConditionString, + getReverseCounterComparisonOp, + parseCounterConditionString, +} from "../../data/entities/CounterTrigger"; import { zBoundedCharacters, zBoundedRecord, zDelayString } from "../../utils"; import Timeout = NodeJS.Timeout; const MAX_COUNTERS = 5; const MAX_TRIGGERS_PER_COUNTER = 5; -export const zTrigger = z.strictObject({ - // Dummy type because name gets replaced by the property key in transform() - name: z.never().optional().transform(() => ""), - pretty_name: zBoundedCharacters(0, 100).nullable().default(null), - condition: zBoundedCharacters(1, 64).refine( - (str) => parseCounterConditionString(str) !== null, - { message: "Invalid counter trigger condition" }, - ), - reverse_condition: zBoundedCharacters(1, 64).refine( - (str) => parseCounterConditionString(str) !== null, - { message: "Invalid counter trigger reverse condition" }, - ).optional(), -}) +export const zTrigger = z + .strictObject({ + // Dummy type because name gets replaced by the property key in transform() + name: z + .never() + .optional() + .transform(() => ""), + pretty_name: zBoundedCharacters(0, 100).nullable().default(null), + condition: zBoundedCharacters(1, 64).refine((str) => parseCounterConditionString(str) !== null, { + message: "Invalid counter trigger condition", + }), + reverse_condition: zBoundedCharacters(1, 64) + .refine((str) => parseCounterConditionString(str) !== null, { + message: "Invalid counter trigger reverse condition", + }) + .optional(), + }) .transform((val, ctx) => { const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); let reverseCondition = val.reverse_condition; - if (! reverseCondition) { + if (!reverseCondition) { const parsedCondition = parseCounterConditionString(val.condition)!; - reverseCondition = buildCounterConditionString(getReverseCounterComparisonOp(parsedCondition[0]), parsedCondition[1]); + reverseCondition = buildCounterConditionString( + getReverseCounterComparisonOp(parsedCondition[0]), + parsedCondition[1], + ); } return { @@ -38,68 +50,65 @@ export const zTrigger = z.strictObject({ }; }); -const zTriggerFromString = zBoundedCharacters(0, 100) - .transform((val, ctx) => { - const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); - const parsedCondition = parseCounterConditionString(val); - if (!parsedCondition) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Invalid counter trigger condition", - }); - return z.NEVER; - } - return { - name: ruleName, - pretty_name: null, - condition: buildCounterConditionString(parsedCondition[0], parsedCondition[1]), - reverse_condition: buildCounterConditionString(getReverseCounterComparisonOp(parsedCondition[0]), parsedCondition[1]), - }; - }); +const zTriggerFromString = zBoundedCharacters(0, 100).transform((val, ctx) => { + const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); + const parsedCondition = parseCounterConditionString(val); + if (!parsedCondition) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Invalid counter trigger condition", + }); + return z.NEVER; + } + return { + name: ruleName, + pretty_name: null, + condition: buildCounterConditionString(parsedCondition[0], parsedCondition[1]), + reverse_condition: buildCounterConditionString( + getReverseCounterComparisonOp(parsedCondition[0]), + parsedCondition[1], + ), + }; +}); const zTriggerInput = z.union([zTrigger, zTriggerFromString]); export const zCounter = z.strictObject({ // Typed as "never" because you are not expected to supply this directly. // The transform instead picks it up from the property key and the output type is a string. - name: z.never().optional().transform((_, ctx) => { - const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); - if (! ruleName) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Counters must have names", - }); - return z.NEVER; - } - return ruleName; - }), + name: z + .never() + .optional() + .transform((_, ctx) => { + const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); + if (!ruleName) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Counters must have names", + }); + return z.NEVER; + } + return ruleName; + }), pretty_name: zBoundedCharacters(0, 100).nullable().default(null), per_channel: z.boolean().default(false), per_user: z.boolean().default(false), initial_value: z.number().default(0), - triggers: zBoundedRecord( - z.record( - zBoundedCharacters(0, 100), - zTriggerInput, - ), - 1, - MAX_TRIGGERS_PER_COUNTER, - ), - decay: z.strictObject({ - amount: z.number(), - every: zDelayString, - }).nullable().default(null), + triggers: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zTriggerInput), 1, MAX_TRIGGERS_PER_COUNTER), + decay: z + .strictObject({ + amount: z.number(), + every: zDelayString, + }) + .nullable() + .default(null), can_view: z.boolean().default(false), can_edit: z.boolean().default(false), can_reset_all: z.boolean().default(false), }); export const zCountersConfig = z.strictObject({ - counters: zBoundedRecord( - z.record(zBoundedCharacters(0, 100), zCounter), - 0, - MAX_COUNTERS, - ), + counters: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zCounter), 0, MAX_COUNTERS), can_view: z.boolean(), can_edit: z.boolean(), can_reset_all: z.boolean(), diff --git a/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts b/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts index dbd7b932..b2e44d93 100644 --- a/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts +++ b/backend/src/plugins/CustomEvents/actions/setChannelPermissionOverrides.ts @@ -9,14 +9,16 @@ import { CustomEventsPluginType, TCustomEvent } from "../types"; export const zSetChannelPermissionOverridesAction = z.strictObject({ type: z.literal("set_channel_permission_overrides"), channel: zSnowflake, - overrides: z.array( - z.strictObject({ - type: z.union([z.literal("member"), z.literal("role")]), - id: zSnowflake, - allow: z.number(), - deny: z.number(), - }), - ).max(15), + overrides: z + .array( + z.strictObject({ + type: z.union([z.literal("member"), z.literal("role")]), + id: zSnowflake, + allow: z.number(), + deny: z.number(), + }), + ) + .max(15), }); export type TSetChannelPermissionOverridesAction = z.infer; diff --git a/backend/src/plugins/CustomEvents/types.ts b/backend/src/plugins/CustomEvents/types.ts index 4572b1cf..6433b6d0 100644 --- a/backend/src/plugins/CustomEvents/types.ts +++ b/backend/src/plugins/CustomEvents/types.ts @@ -36,11 +36,7 @@ export const zCustomEvent = z.strictObject({ export type TCustomEvent = z.infer; export const zCustomEventsConfig = z.strictObject({ - events: zBoundedRecord( - z.record(zBoundedCharacters(0, 100), zCustomEvent), - 0, - 100, - ), + events: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zCustomEvent), 0, 100), }); export interface CustomEventsPluginType extends BasePluginType { diff --git a/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts b/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts index b8639134..3c267aab 100644 --- a/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts +++ b/backend/src/plugins/GuildAccessMonitor/GuildAccessMonitorPlugin.ts @@ -1,10 +1,10 @@ import { Guild } from "discord.js"; import { BasePluginType, GlobalPluginData, globalPluginEventListener } from "knub"; +import z from "zod"; import { AllowedGuilds } from "../../data/AllowedGuilds"; import { Configs } from "../../data/Configs"; import { env } from "../../env"; import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint"; -import z from "zod"; interface GuildAccessMonitorPluginType extends BasePluginType { state: { diff --git a/backend/src/plugins/GuildInfoSaver/GuildInfoSaverPlugin.ts b/backend/src/plugins/GuildInfoSaver/GuildInfoSaverPlugin.ts index a8d71e06..873711b3 100644 --- a/backend/src/plugins/GuildInfoSaver/GuildInfoSaverPlugin.ts +++ b/backend/src/plugins/GuildInfoSaver/GuildInfoSaverPlugin.ts @@ -1,11 +1,11 @@ import { Guild } from "discord.js"; import { guildPluginEventListener } from "knub"; +import z from "zod"; import { AllowedGuilds } from "../../data/AllowedGuilds"; import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments"; import { MINUTES } from "../../utils"; import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint"; import { GuildInfoSaverPluginType } from "./types"; -import z from "zod"; export const GuildInfoSaverPlugin = zeppelinGuildPlugin()({ name: "guild_info_saver", diff --git a/backend/src/plugins/Logs/LogsPlugin.ts b/backend/src/plugins/Logs/LogsPlugin.ts index 923ac623..c989c682 100644 --- a/backend/src/plugins/Logs/LogsPlugin.ts +++ b/backend/src/plugins/Logs/LogsPlugin.ts @@ -123,7 +123,7 @@ const defaultOptions: PluginOptions = { timestamp: FORMAT_NO_TIMESTAMP, ...DefaultLogMessages, }, - ping_user: true, + ping_user: true, allow_user_mentions: false, timestamp_format: "[]", include_embed_timestamp: true, diff --git a/backend/src/plugins/Logs/logFunctions/logMessageDelete.ts b/backend/src/plugins/Logs/logFunctions/logMessageDelete.ts index 25c8c340..b56f7410 100644 --- a/backend/src/plugins/Logs/logFunctions/logMessageDelete.ts +++ b/backend/src/plugins/Logs/logFunctions/logMessageDelete.ts @@ -32,7 +32,9 @@ export function logMessageDelete(pluginData: GuildPluginData, da // See comment on FORMAT_NO_TIMESTAMP in types.ts const config = pluginData.config.get(); const timestampFormat = - (config.format.timestamp !== FORMAT_NO_TIMESTAMP ? config.format.timestamp : null) ?? config.timestamp_format ?? undefined; + (config.format.timestamp !== FORMAT_NO_TIMESTAMP ? config.format.timestamp : null) ?? + config.timestamp_format ?? + undefined; return log( pluginData, diff --git a/backend/src/plugins/Logs/types.ts b/backend/src/plugins/Logs/types.ts index 6b214c99..47557514 100644 --- a/backend/src/plugins/Logs/types.ts +++ b/backend/src/plugins/Logs/types.ts @@ -29,10 +29,12 @@ const MAX_BATCH_TIME = 5000; type ZLogFormatsHelper = { -readonly [K in keyof typeof LogType]: typeof zMessageContent; }; -export const zLogFormats = z.strictObject(keys(LogType).reduce((map, logType) => { - map[logType] = zMessageContent; - return map; -}, {} as ZLogFormatsHelper)); +export const zLogFormats = z.strictObject( + keys(LogType).reduce((map, logType) => { + map[logType] = zMessageContent; + return map; + }, {} as ZLogFormatsHelper), +); export type TLogFormats = z.infer; const zLogChannel = z.strictObject({ @@ -58,10 +60,12 @@ export type TLogChannelMap = z.infer; export const zLogsConfig = z.strictObject({ channels: zLogChannelMap, - format: zLogFormats.merge(z.strictObject({ - // Legacy/deprecated, use timestamp_format below instead - timestamp: zBoundedCharacters(0, 64).nullable(), - })), + format: zLogFormats.merge( + z.strictObject({ + // Legacy/deprecated, use timestamp_format below instead + timestamp: zBoundedCharacters(0, 64).nullable(), + }), + ), // Legacy/deprecated, if below is false mentions wont actually ping. In case you really want the old behavior, set below to true ping_user: z.boolean(), allow_user_mentions: z.boolean(), diff --git a/backend/src/plugins/Logs/util/isLogIgnored.ts b/backend/src/plugins/Logs/util/isLogIgnored.ts index 71255f50..8d3e15c1 100644 --- a/backend/src/plugins/Logs/util/isLogIgnored.ts +++ b/backend/src/plugins/Logs/util/isLogIgnored.ts @@ -2,6 +2,10 @@ import { GuildPluginData } from "knub"; import { LogType } from "../../../data/LogType"; import { LogsPluginType } from "../types"; -export function isLogIgnored(pluginData: GuildPluginData, type: keyof typeof LogType, ignoreId: string) { +export function isLogIgnored( + pluginData: GuildPluginData, + type: keyof typeof LogType, + ignoreId: string, +) { return pluginData.state.guildLogs.isLogIgnored(type, ignoreId); } diff --git a/backend/src/plugins/ModActions/functions/clearTempban.ts b/backend/src/plugins/ModActions/functions/clearTempban.ts index 5173ca7e..1133d651 100644 --- a/backend/src/plugins/ModActions/functions/clearTempban.ts +++ b/backend/src/plugins/ModActions/functions/clearTempban.ts @@ -3,7 +3,9 @@ import humanizeDuration from "humanize-duration"; import { GuildPluginData } from "knub"; import moment from "moment-timezone"; 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"; @@ -11,8 +13,6 @@ import { IgnoredEventType, ModActionsPluginType } from "../types"; import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; import { ignoreEvent } from "./ignoreEvent"; import { isBanned } from "./isBanned"; -import { LogType } from "../../../data/LogType"; -import { logger } from "../../../logger"; export async function clearTempban(pluginData: GuildPluginData, tempban: Tempban) { if (!(await isBanned(pluginData, tempban.user_id))) { diff --git a/backend/src/plugins/ReactionRoles/types.ts b/backend/src/plugins/ReactionRoles/types.ts index a1c09f00..b955c6fa 100644 --- a/backend/src/plugins/ReactionRoles/types.ts +++ b/backend/src/plugins/ReactionRoles/types.ts @@ -22,10 +22,7 @@ export type PendingMemberRoleChanges = { }>; }; -const zReactionRolePair = z.union([ - z.tuple([z.string(), z.string(), z.string()]), - z.tuple([z.string(), z.string()]), -]); +const zReactionRolePair = z.union([z.tuple([z.string(), z.string(), z.string()]), z.tuple([z.string(), z.string()])]); export type TReactionRolePair = z.infer; export interface ReactionRolesPluginType extends BasePluginType { diff --git a/backend/src/plugins/RoleButtons/types.ts b/backend/src/plugins/RoleButtons/types.ts index 3c94f8a8..95e46f79 100644 --- a/backend/src/plugins/RoleButtons/types.ts +++ b/backend/src/plugins/RoleButtons/types.ts @@ -11,89 +11,99 @@ const zRoleButtonOption = z.strictObject({ label: z.string().nullable().default(null), emoji: z.string().nullable().default(null), // https://discord.js.org/#/docs/discord.js/v13/typedef/MessageButtonStyle - style: z.union([ - z.literal(ButtonStyle.Primary), - z.literal(ButtonStyle.Secondary), - z.literal(ButtonStyle.Success), - z.literal(ButtonStyle.Danger), + style: z + .union([ + z.literal(ButtonStyle.Primary), + z.literal(ButtonStyle.Secondary), + z.literal(ButtonStyle.Success), + z.literal(ButtonStyle.Danger), - // The following are deprecated - z.literal("PRIMARY"), - z.literal("SECONDARY"), - z.literal("SUCCESS"), - z.literal("DANGER"), - // z.literal("LINK"), // Role buttons don't use link buttons, but adding this here so it's documented why it's not available - ]).nullable().default(null), + // The following are deprecated + z.literal("PRIMARY"), + z.literal("SECONDARY"), + z.literal("SUCCESS"), + z.literal("DANGER"), + // z.literal("LINK"), // Role buttons don't use link buttons, but adding this here so it's documented why it's not available + ]) + .nullable() + .default(null), start_new_row: z.boolean().default(false), }); export type TRoleButtonOption = z.infer; -const zRoleButtonsConfigItem = z.strictObject({ - // Typed as "never" because you are not expected to supply this directly. - // The transform instead picks it up from the property key and the output type is a string. - name: z.never().optional().transform((_, ctx) => { - const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); - if (! ruleName) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: "Role buttons must have names", - }); - return z.NEVER; - } - return ruleName; - }), - message: z.union([ - z.strictObject({ - channel_id: zSnowflake, - message_id: zSnowflake, - }), - z.strictObject({ - channel_id: zSnowflake, - content: zMessageContent, - }), - ]), - options: z.array(zRoleButtonOption).max(25), - exclusive: z.boolean().default(false), -}) - .refine((parsed) => { - try { - createButtonComponents(parsed); - } catch (err) { - if (err instanceof TooManyComponentsError) { - return false; +const zRoleButtonsConfigItem = z + .strictObject({ + // Typed as "never" because you are not expected to supply this directly. + // The transform instead picks it up from the property key and the output type is a string. + name: z + .never() + .optional() + .transform((_, ctx) => { + const ruleName = String(ctx.path[ctx.path.length - 2]).trim(); + if (!ruleName) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Role buttons must have names", + }); + return z.NEVER; + } + return ruleName; + }), + message: z.union([ + z.strictObject({ + channel_id: zSnowflake, + message_id: zSnowflake, + }), + z.strictObject({ + channel_id: zSnowflake, + content: zMessageContent, + }), + ]), + options: z.array(zRoleButtonOption).max(25), + exclusive: z.boolean().default(false), + }) + .refine( + (parsed) => { + try { + createButtonComponents(parsed); + } catch (err) { + if (err instanceof TooManyComponentsError) { + return false; + } + throw err; } - throw err; - } - return true; - }, { - message: "Too many options; can only have max 5 buttons per row on max 5 rows." - }); + return true; + }, + { + message: "Too many options; can only have max 5 buttons per row on max 5 rows.", + }, + ); export type TRoleButtonsConfigItem = z.infer; -export const zRoleButtonsConfig = z.strictObject({ - buttons: zBoundedRecord( - z.record(zBoundedCharacters(1, 16), zRoleButtonsConfigItem), - 0, - 100, - ), - can_reset: z.boolean(), -}) - .refine((parsed) => { - const seenMessages = new Set(); - for (const button of Object.values(parsed.buttons)) { - if (button.message) { - if ("message_id" in button.message) { - if (seenMessages.has(button.message.message_id)) { - return false; +export const zRoleButtonsConfig = z + .strictObject({ + buttons: zBoundedRecord(z.record(zBoundedCharacters(1, 16), zRoleButtonsConfigItem), 0, 100), + can_reset: z.boolean(), + }) + .refine( + (parsed) => { + const seenMessages = new Set(); + for (const button of Object.values(parsed.buttons)) { + if (button.message) { + if ("message_id" in button.message) { + if (seenMessages.has(button.message.message_id)) { + return false; + } + seenMessages.add(button.message.message_id); } - seenMessages.add(button.message.message_id); } } - } - return true; - }, { - message: "Can't target the same message with two sets of role buttons", - }); + return true; + }, + { + message: "Can't target the same message with two sets of role buttons", + }, + ); export interface RoleButtonsPluginType extends BasePluginType { config: z.infer; diff --git a/backend/src/plugins/SelfGrantableRoles/types.ts b/backend/src/plugins/SelfGrantableRoles/types.ts index a1aed241..e3c7a786 100644 --- a/backend/src/plugins/SelfGrantableRoles/types.ts +++ b/backend/src/plugins/SelfGrantableRoles/types.ts @@ -4,9 +4,10 @@ import { zBoundedCharacters, zBoundedRecord } from "../../utils"; const zRoleMap = z.record( zBoundedCharacters(1, 100), - z.array(zBoundedCharacters(1, 2000)) + z + .array(zBoundedCharacters(1, 2000)) .max(100) - .transform((parsed) => parsed.map(v => v.toLowerCase())), + .transform((parsed) => parsed.map((v) => v.toLowerCase())), ); const zSelfGrantableRoleEntry = z.strictObject({ diff --git a/backend/src/plugins/Slowmode/types.ts b/backend/src/plugins/Slowmode/types.ts index c4fe44d5..7c8d5b56 100644 --- a/backend/src/plugins/Slowmode/types.ts +++ b/backend/src/plugins/Slowmode/types.ts @@ -7,7 +7,7 @@ import { SlowmodeChannel } from "../../data/entities/SlowmodeChannel"; export const zSlowmodeConfig = z.strictObject({ use_native_slowmode: z.boolean(), - + can_manage: z.boolean(), is_affected: z.boolean(), }); diff --git a/backend/src/plugins/Spam/types.ts b/backend/src/plugins/Spam/types.ts index 74ea872f..f71e4180 100644 --- a/backend/src/plugins/Spam/types.ts +++ b/backend/src/plugins/Spam/types.ts @@ -11,14 +11,8 @@ const zBaseSingleSpamConfig = z.strictObject({ count: z.number(), mute: z.boolean().default(false), mute_time: z.number().nullable().default(null), - remove_roles_on_mute: z.union([ - z.boolean(), - z.array(zSnowflake), - ]).default(false), - restore_roles_on_mute: z.union([ - z.boolean(), - z.array(zSnowflake), - ]).default(false), + remove_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).default(false), + restore_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).default(false), clean: z.boolean().default(false), }); export type TBaseSingleSpamConfig = z.infer; diff --git a/backend/src/plugins/Starboard/types.ts b/backend/src/plugins/Starboard/types.ts index 7dc2d8f5..bb8845fe 100644 --- a/backend/src/plugins/Starboard/types.ts +++ b/backend/src/plugins/Starboard/types.ts @@ -18,11 +18,7 @@ const zStarboardOpts = z.strictObject({ export type TStarboardOpts = z.infer; export const zStarboardConfig = z.strictObject({ - boards: zBoundedRecord( - z.record(z.string(), zStarboardOpts), - 0, - 100, - ), + boards: zBoundedRecord(z.record(z.string(), zStarboardOpts), 0, 100), can_migrate: z.boolean(), }); diff --git a/backend/src/plugins/Tags/commands/TagEvalCmd.ts b/backend/src/plugins/Tags/commands/TagEvalCmd.ts index 27cbe4f3..3515ef74 100644 --- a/backend/src/plugins/Tags/commands/TagEvalCmd.ts +++ b/backend/src/plugins/Tags/commands/TagEvalCmd.ts @@ -1,11 +1,11 @@ import { MessageCreateOptions } from "discord.js"; import { commandTypeHelpers as ct } from "../../../commandTypes"; +import { logger } from "../../../logger"; import { sendErrorMessage } from "../../../pluginUtils"; import { TemplateParseError } from "../../../templateFormatter"; import { memberToTemplateSafeMember, userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; import { tagsCmd } from "../types"; import { renderTagBody } from "../util/renderTagBody"; -import { logger } from "../../../logger"; export const TagEvalCmd = tagsCmd({ trigger: "tag eval", @@ -35,13 +35,11 @@ export const TagEvalCmd = tagsCmd({ msg.channel.send(rendered); } catch (e) { - const errorMessage = e instanceof TemplateParseError - ? e.message - : "Internal error"; + const errorMessage = e instanceof TemplateParseError ? e.message : "Internal error"; sendErrorMessage(pluginData, msg.channel, `Failed to render tag: ${errorMessage}`); - if (! (e instanceof TemplateParseError)) { + if (!(e instanceof TemplateParseError)) { logger.warn(`Internal error evaluating tag in ${pluginData.guild.id}: ${e}`); } diff --git a/backend/src/plugins/Tags/types.ts b/backend/src/plugins/Tags/types.ts index 441906fe..5ff7e9c7 100644 --- a/backend/src/plugins/Tags/types.ts +++ b/backend/src/plugins/Tags/types.ts @@ -9,52 +9,48 @@ import { zEmbedInput } from "../../utils"; export const zTag = z.union([z.string(), zEmbedInput]); export type TTag = z.infer; -export const zTagCategory = z.strictObject({ - prefix: z.string().nullable().default(null), - delete_with_command: z.boolean().default(false), +export const zTagCategory = z + .strictObject({ + prefix: z.string().nullable().default(null), + delete_with_command: z.boolean().default(false), - user_tag_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Per user, per tag - user_category_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Per user, per tag category - global_tag_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Any user, per tag - allow_mentions: z.boolean().nullable().default(null), - global_category_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Any user, per category - auto_delete_command: z.boolean().nullable().default(null), + user_tag_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Per user, per tag + user_category_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Per user, per tag category + global_tag_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Any user, per tag + allow_mentions: z.boolean().nullable().default(null), + global_category_cooldown: z.union([z.string(), z.number()]).nullable().default(null), // Any user, per category + auto_delete_command: z.boolean().nullable().default(null), - tags: z.record(z.string(), zTag), + tags: z.record(z.string(), zTag), - can_use: z.boolean().nullable().default(null), -}) - .refine( - (parsed) => ! (parsed.auto_delete_command && parsed.delete_with_command), - { - message: "Cannot have both (category specific) delete_with_command and auto_delete_command enabled", - }, - ); + can_use: z.boolean().nullable().default(null), + }) + .refine((parsed) => !(parsed.auto_delete_command && parsed.delete_with_command), { + message: "Cannot have both (category specific) delete_with_command and auto_delete_command enabled", + }); export type TTagCategory = z.infer; -export const zTagsConfig = z.strictObject({ - prefix: z.string(), - delete_with_command: z.boolean(), +export const zTagsConfig = z + .strictObject({ + prefix: z.string(), + delete_with_command: z.boolean(), - user_tag_cooldown: z.union([z.string(), z.number()]).nullable(), // Per user, per tag - global_tag_cooldown: z.union([z.string(), z.number()]).nullable(), // Any user, per tag - user_cooldown: z.union([z.string(), z.number()]).nullable(), // Per user - allow_mentions: z.boolean(), // Per user - global_cooldown: z.union([z.string(), z.number()]).nullable(), // Any tag use - auto_delete_command: z.boolean(), // Any tag + user_tag_cooldown: z.union([z.string(), z.number()]).nullable(), // Per user, per tag + global_tag_cooldown: z.union([z.string(), z.number()]).nullable(), // Any user, per tag + user_cooldown: z.union([z.string(), z.number()]).nullable(), // Per user + allow_mentions: z.boolean(), // Per user + global_cooldown: z.union([z.string(), z.number()]).nullable(), // Any tag use + auto_delete_command: z.boolean(), // Any tag - categories: z.record(z.string(), zTagCategory), + categories: z.record(z.string(), zTagCategory), - can_create: z.boolean(), - can_use: z.boolean(), - can_list: z.boolean(), -}) -.refine( - (parsed) => ! (parsed.auto_delete_command && parsed.delete_with_command), - { + can_create: z.boolean(), + can_use: z.boolean(), + can_list: z.boolean(), + }) + .refine((parsed) => !(parsed.auto_delete_command && parsed.delete_with_command), { message: "Cannot have both (category specific) delete_with_command and auto_delete_command enabled", - }, -); + }); export interface TagsPluginType extends BasePluginType { config: z.infer; diff --git a/backend/src/plugins/Tags/util/onMessageCreate.ts b/backend/src/plugins/Tags/util/onMessageCreate.ts index aa7c8490..f06d3282 100644 --- a/backend/src/plugins/Tags/util/onMessageCreate.ts +++ b/backend/src/plugins/Tags/util/onMessageCreate.ts @@ -2,11 +2,11 @@ import { Snowflake, TextChannel } from "discord.js"; import { GuildPluginData } from "knub"; import { SavedMessage } from "../../../data/entities/SavedMessage"; import { convertDelayStringToMS, resolveMember, zStrictMessageContent } from "../../../utils"; +import { erisAllowedMentionsToDjsMentionOptions } from "../../../utils/erisAllowedMentionsToDjsMentionOptions"; import { messageIsEmpty } from "../../../utils/messageIsEmpty"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { TagsPluginType } from "../types"; import { matchAndRenderTagFromString } from "./matchAndRenderTagFromString"; -import { erisAllowedMentionsToDjsMentionOptions } from "../../../utils/erisAllowedMentionsToDjsMentionOptions"; export async function onMessageCreate(pluginData: GuildPluginData, msg: SavedMessage) { if (msg.is_bot) return; @@ -85,7 +85,7 @@ export async function onMessageCreate(pluginData: GuildPluginData, @@ -36,14 +36,12 @@ export async function renderTagFromString( return validateAndParseMessageContent(rendered); } catch (e) { const logs = pluginData.getPlugin(LogsPlugin); - const errorMessage = e instanceof TemplateParseError - ? e.message - : "Internal error"; + const errorMessage = e instanceof TemplateParseError ? e.message : "Internal error"; logs.logBotAlert({ body: `Failed to render tag \`${prefix}${tagName}\`: ${errorMessage}`, }); - if (! (e instanceof TemplateParseError)) { + if (!(e instanceof TemplateParseError)) { logger.warn(`Internal error rendering tag ${tagName} in ${pluginData.guild.id}: ${e}`); } diff --git a/backend/src/plugins/Utility/commands/InfoCmd.ts b/backend/src/plugins/Utility/commands/InfoCmd.ts index a430898e..62f89bd6 100644 --- a/backend/src/plugins/Utility/commands/InfoCmd.ts +++ b/backend/src/plugins/Utility/commands/InfoCmd.ts @@ -79,11 +79,7 @@ export const InfoCmd = utilityCmd({ const messageTarget = await resolveMessageTarget(pluginData, value); if (messageTarget) { if (canReadChannel(messageTarget.channel, message.member)) { - const embed = await getMessageInfoEmbed( - pluginData, - messageTarget.channel.id, - messageTarget.messageId, - ); + const embed = await getMessageInfoEmbed(pluginData, messageTarget.channel.id, messageTarget.messageId); if (embed) { message.channel.send({ embeds: [embed] }); return; diff --git a/backend/src/plugins/Utility/commands/MessageInfoCmd.ts b/backend/src/plugins/Utility/commands/MessageInfoCmd.ts index 72df1f6c..19164ca4 100644 --- a/backend/src/plugins/Utility/commands/MessageInfoCmd.ts +++ b/backend/src/plugins/Utility/commands/MessageInfoCmd.ts @@ -20,11 +20,7 @@ export const MessageInfoCmd = utilityCmd({ return; } - const embed = await getMessageInfoEmbed( - pluginData, - args.message.channel.id, - args.message.messageId, - ); + const embed = await getMessageInfoEmbed(pluginData, args.message.channel.id, args.message.messageId); if (!embed) { sendErrorMessage(pluginData, message.channel, "Unknown message"); return; diff --git a/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts b/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts index 700546ca..dd19d9b2 100644 --- a/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getRoleInfoEmbed.ts @@ -6,10 +6,7 @@ import { UtilityPluginType } from "../types"; const MENTION_ICON = "https://cdn.discordapp.com/attachments/705009450855039042/839284872152481792/mention.png"; -export async function getRoleInfoEmbed( - pluginData: GuildPluginData, - role: Role, -): Promise { +export async function getRoleInfoEmbed(pluginData: GuildPluginData, role: Role): Promise { const embed: EmbedWith<"fields" | "author" | "color"> = { fields: [], author: { diff --git a/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts b/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts index 7009241c..8449ba74 100644 --- a/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts +++ b/backend/src/plugins/Utility/functions/getSnowflakeInfoEmbed.ts @@ -4,10 +4,7 @@ import { snowflakeToTimestamp } from "../../../utils/snowflakeToTimestamp"; const SNOWFLAKE_ICON = "https://cdn.discordapp.com/attachments/740650744830623756/742020790471491668/snowflake.png"; -export async function getSnowflakeInfoEmbed( - snowflake: string, - showUnknownWarning = false, -): Promise { +export async function getSnowflakeInfoEmbed(snowflake: string, showUnknownWarning = false): Promise { const embed: EmbedWith<"fields" | "author"> = { fields: [], author: { diff --git a/backend/src/plugins/Utility/search.ts b/backend/src/plugins/Utility/search.ts index dbaacf27..92b5b75f 100644 --- a/backend/src/plugins/Utility/search.ts +++ b/backend/src/plugins/Utility/search.ts @@ -14,7 +14,15 @@ import { ArgsFromSignatureOrArray, GuildPluginData } from "knub"; import moment from "moment-timezone"; import { RegExpRunner, allowTimeout } from "../../RegExpRunner"; import { getBaseUrl, sendErrorMessage } from "../../pluginUtils"; -import { InvalidRegexError, MINUTES, inputPatternToRegExp, multiSorter, renderUserUsername, sorter, trimLines } from "../../utils"; +import { + InvalidRegexError, + MINUTES, + inputPatternToRegExp, + multiSorter, + renderUserUsername, + sorter, + trimLines, +} from "../../utils"; import { asyncFilter } from "../../utils/async"; import { hasDiscordPermissions } from "../../utils/hasDiscordPermissions"; import { banSearchSignature } from "./commands/BanSearchCmd"; diff --git a/backend/src/plugins/ZeppelinPluginBlueprint.ts b/backend/src/plugins/ZeppelinPluginBlueprint.ts index aa266abc..338182df 100644 --- a/backend/src/plugins/ZeppelinPluginBlueprint.ts +++ b/backend/src/plugins/ZeppelinPluginBlueprint.ts @@ -7,8 +7,8 @@ import { GuildPluginBlueprint, GuildPluginData, } from "knub"; -import { TMarkdown } from "../types"; import { ZodTypeAny } from "zod"; +import { TMarkdown } from "../types"; /** * GUILD PLUGINS diff --git a/backend/src/utils.ts b/backend/src/utils.ts index 97f51301..8790ab50 100644 --- a/backend/src/utils.ts +++ b/backend/src/utils.ts @@ -87,8 +87,10 @@ export function isDiscordAPIError(err: Error | string): err is DiscordAPIError { } // null | undefined -> undefined -export function zNullishToUndefined(type: T): ZodEffects> | undefined> { - return type.transform(v => v ?? undefined); +export function zNullishToUndefined( + type: T, +): ZodEffects> | undefined> { + return type.transform((v) => v ?? undefined); } export function getScalarDifference( @@ -151,15 +153,18 @@ export type GroupDMInvite = Invite & { }; export function zBoundedCharacters(min: number, max: number) { - return z.string().refine(str => { - const len = [...str].length; // Unicode aware character split - return (len >= min && len <= max); - }, { - message: `String must be between ${min} and ${max} characters long`, - }); + return z.string().refine( + (str) => { + const len = [...str].length; // Unicode aware character split + return len >= min && len <= max; + }, + { + message: `String must be between ${min} and ${max} characters long`, + }, + ); } -export const zSnowflake = z.string().refine(str => isSnowflake(str), { +export const zSnowflake = z.string().refine((str) => isSnowflake(str), { message: "Invalid snowflake ID", }); @@ -188,7 +193,7 @@ export function zRegex(zStr: T) { if (err instanceof InvalidRegexError) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: "Invalid regex" + message: "Invalid regex", }); return z.NEVER; } @@ -343,8 +348,18 @@ function dropNullValuesRecursively(obj: any) { */ export const zAllowedMentions = z.strictObject({ everyone: zNullishToUndefined(z.boolean().nullable().optional()), - users: zNullishToUndefined(z.union([z.boolean(), z.array(z.string())]).nullable().optional()), - roles: zNullishToUndefined(z.union([z.boolean(), z.array(z.string())]).nullable().optional()), + users: zNullishToUndefined( + z + .union([z.boolean(), z.array(z.string())]) + .nullable() + .optional(), + ), + roles: zNullishToUndefined( + z + .union([z.boolean(), z.array(z.string())]) + .nullable() + .optional(), + ), replied_user: zNullishToUndefined(z.boolean().nullable().optional()), }); @@ -359,18 +374,28 @@ export function dropPropertiesByName(obj, propName) { } } -export function zBoundedRecord>(record: TRecord, minKeys: number, maxKeys: number): ZodEffects { - return record.refine(data => { - const len = Object.keys(data).length; - return (len >= minKeys && len <= maxKeys); - }, { - message: `Object must have ${minKeys}-${maxKeys} keys`, - }); +export function zBoundedRecord>( + record: TRecord, + minKeys: number, + maxKeys: number, +): ZodEffects { + return record.refine( + (data) => { + const len = Object.keys(data).length; + return len >= minKeys && len <= maxKeys; + }, + { + message: `Object must have ${minKeys}-${maxKeys} keys`, + }, + ); } -export const zDelayString = z.string().max(32).refine(str => convertDelayStringToMS(str) !== null, { - message: "Invalid delay string", -}); +export const zDelayString = z + .string() + .max(32) + .refine((str) => convertDelayStringToMS(str) !== null, { + message: "Invalid delay string", + }); // To avoid running into issues with the JS max date vaLue, we cap maximum delay strings *far* below that. // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#The_ECMAScript_epoch_and_timestamps @@ -1487,9 +1512,11 @@ export function renderUserUsername(user: User | UnknownUser): string { return renderUsername(user.username, user.discriminator); } -type Entries = Array<{ - [Key in keyof T]-?: [Key, T[Key]]; -}[keyof T]>; +type Entries = Array< + { + [Key in keyof T]-?: [Key, T[Key]]; + }[keyof T] +>; export function entries(object: T) { return Object.entries(object) as Entries; diff --git a/backend/src/utils/formatZodIssue.ts b/backend/src/utils/formatZodIssue.ts index 2b5c3d8e..93932f66 100644 --- a/backend/src/utils/formatZodIssue.ts +++ b/backend/src/utils/formatZodIssue.ts @@ -1,6 +1,6 @@ import { ZodIssue } from "zod"; export function formatZodIssue(issue: ZodIssue): string { - const path = issue.path.join("/"); - return `${path}: ${issue.message}`; + const path = issue.path.join("/"); + return `${path}: ${issue.message}`; } diff --git a/backend/src/validateActiveConfigs.ts b/backend/src/validateActiveConfigs.ts index c9e3414b..f985fd14 100644 --- a/backend/src/validateActiveConfigs.ts +++ b/backend/src/validateActiveConfigs.ts @@ -6,7 +6,10 @@ import { loadYamlSafely } from "./utils/loadYamlSafely"; import { ObjectAliasError } from "./utils/validateNoObjectAliases"; function writeError(key: string, error: string) { - const indented = error.split("\n").map(s => " ".repeat(64) + s).join("\n"); + const indented = error + .split("\n") + .map((s) => " ".repeat(64) + s) + .join("\n"); const prefix = `Invalid config ${key}:`; const prefixed = prefix + indented.slice(prefix.length); console.log(prefixed + "\n\n");