chore: run prettier
This commit is contained in:
parent
77ab2718e7
commit
873bf7eb99
54 changed files with 462 additions and 416 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
zAllowedMentions,
|
||||
zBoundedCharacters,
|
||||
zNullishToUndefined,
|
||||
zSnowflake
|
||||
zSnowflake,
|
||||
} from "../../../utils";
|
||||
import { erisAllowedMentionsToDjsMentionOptions } from "../../../utils/erisAllowedMentionsToDjsMentionOptions";
|
||||
import { messageIsEmpty } from "../../../utils/messageIsEmpty";
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 }) {
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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),
|
||||
}),
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
verboseChannelMention,
|
||||
zBoundedCharacters,
|
||||
zDelayString,
|
||||
zMessageContent
|
||||
zMessageContent,
|
||||
} from "../../../utils";
|
||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||
import { messageIsEmpty } from "../../../utils/messageIsEmpty";
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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")]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { automodTrigger } from "../helpers";
|
||||
import z from "zod";
|
||||
import { automodTrigger } from "../helpers";
|
||||
|
||||
interface AntiraidLevelTriggerResult {}
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
|
||||
|
|
|
@ -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,12 +9,14 @@ interface MatchResultType {
|
|||
mode: "blacklist" | "whitelist";
|
||||
}
|
||||
|
||||
const configSchema = z.strictObject({
|
||||
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) => {
|
||||
})
|
||||
.transform((parsed, ctx) => {
|
||||
if (parsed.blacklist_enabled && parsed.whitelist_enabled) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
|
@ -22,7 +24,7 @@ const configSchema = z.strictObject({
|
|||
});
|
||||
return z.NEVER;
|
||||
}
|
||||
if (! parsed.blacklist_enabled && ! parsed.whitelist_enabled) {
|
||||
if (!parsed.blacklist_enabled && !parsed.whitelist_enabled) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Must have either blacklist or whitelist enabled",
|
||||
|
@ -30,7 +32,7 @@ const configSchema = z.strictObject({
|
|||
return z.NEVER;
|
||||
}
|
||||
return parsed;
|
||||
});
|
||||
});
|
||||
|
||||
export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
|
||||
configSchema,
|
||||
|
|
|
@ -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_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(),
|
||||
})
|
||||
.optional(),
|
||||
only_real_links: z.boolean().default(true),
|
||||
match_messages: z.boolean().default(true),
|
||||
match_embeds: z.boolean().default(true),
|
||||
|
|
|
@ -8,12 +8,14 @@ interface MatchResultType {
|
|||
mode: "blacklist" | "whitelist";
|
||||
}
|
||||
|
||||
const configSchema = z.strictObject({
|
||||
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) => {
|
||||
})
|
||||
.transform((parsed, ctx) => {
|
||||
if (parsed.blacklist_enabled && parsed.whitelist_enabled) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
|
@ -21,7 +23,7 @@ const configSchema = z.strictObject({
|
|||
});
|
||||
return z.NEVER;
|
||||
}
|
||||
if (! parsed.blacklist_enabled && ! parsed.whitelist_enabled) {
|
||||
if (!parsed.blacklist_enabled && !parsed.whitelist_enabled) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Must have either blacklist or whitelist enabled",
|
||||
|
@ -29,7 +31,7 @@ const configSchema = z.strictObject({
|
|||
return z.NEVER;
|
||||
}
|
||||
return parsed;
|
||||
});
|
||||
});
|
||||
|
||||
export const MatchMimeTypeTrigger = automodTrigger<MatchResultType>()({
|
||||
configSchema,
|
||||
|
|
|
@ -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<RoleAddedMatchResult>()({
|
||||
configSchema,
|
||||
|
|
|
@ -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<RoleAddedMatchResult>()({
|
||||
configSchema,
|
||||
|
|
|
@ -19,29 +19,40 @@ 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]) => {
|
||||
const zTriggersMap = z
|
||||
.strictObject(
|
||||
entries(availableTriggers).reduce((map, [triggerName, trigger]) => {
|
||||
map[triggerName] = trigger.configSchema;
|
||||
return map;
|
||||
}, {} as ZTriggersMapHelper)).partial();
|
||||
}, {} 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]) => {
|
||||
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();
|
||||
}, {} 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) => {
|
||||
name: z
|
||||
.never()
|
||||
.optional()
|
||||
.transform((_, ctx) => {
|
||||
const ruleName = String(ctx.path[ctx.path.length - 2]).trim();
|
||||
if (! ruleName) {
|
||||
if (!ruleName) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Automod rules must have names",
|
||||
|
@ -56,21 +67,14 @@ const zRule = z.strictObject({
|
|||
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),
|
||||
{
|
||||
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<typeof zRule>;
|
||||
|
||||
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(),
|
||||
|
|
|
@ -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<ContextMenuPluginType>,
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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({
|
||||
export const zTrigger = z
|
||||
.strictObject({
|
||||
// Dummy type because name gets replaced by the property key in transform()
|
||||
name: z.never().optional().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(),
|
||||
})
|
||||
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,8 +50,7 @@ export const zTrigger = z.strictObject({
|
|||
};
|
||||
});
|
||||
|
||||
const zTriggerFromString = zBoundedCharacters(0, 100)
|
||||
.transform((val, ctx) => {
|
||||
const zTriggerFromString = zBoundedCharacters(0, 100).transform((val, ctx) => {
|
||||
const ruleName = String(ctx.path[ctx.path.length - 2]).trim();
|
||||
const parsedCondition = parseCounterConditionString(val);
|
||||
if (!parsedCondition) {
|
||||
|
@ -53,18 +64,24 @@ const zTriggerFromString = zBoundedCharacters(0, 100)
|
|||
name: ruleName,
|
||||
pretty_name: null,
|
||||
condition: buildCounterConditionString(parsedCondition[0], parsedCondition[1]),
|
||||
reverse_condition: buildCounterConditionString(getReverseCounterComparisonOp(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) => {
|
||||
name: z
|
||||
.never()
|
||||
.optional()
|
||||
.transform((_, ctx) => {
|
||||
const ruleName = String(ctx.path[ctx.path.length - 2]).trim();
|
||||
if (! ruleName) {
|
||||
if (!ruleName) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Counters must have names",
|
||||
|
@ -77,29 +94,21 @@ export const zCounter = z.strictObject({
|
|||
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({
|
||||
triggers: zBoundedRecord(z.record(zBoundedCharacters(0, 100), zTriggerInput), 1, MAX_TRIGGERS_PER_COUNTER),
|
||||
decay: z
|
||||
.strictObject({
|
||||
amount: z.number(),
|
||||
every: zDelayString,
|
||||
}).nullable().default(null),
|
||||
})
|
||||
.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(),
|
||||
|
|
|
@ -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(
|
||||
overrides: z
|
||||
.array(
|
||||
z.strictObject({
|
||||
type: z.union([z.literal("member"), z.literal("role")]),
|
||||
id: zSnowflake,
|
||||
allow: z.number(),
|
||||
deny: z.number(),
|
||||
}),
|
||||
).max(15),
|
||||
)
|
||||
.max(15),
|
||||
});
|
||||
export type TSetChannelPermissionOverridesAction = z.infer<typeof zSetChannelPermissionOverridesAction>;
|
||||
|
||||
|
|
|
@ -36,11 +36,7 @@ export const zCustomEvent = z.strictObject({
|
|||
export type TCustomEvent = z.infer<typeof zCustomEvent>;
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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<GuildInfoSaverPluginType>()({
|
||||
name: "guild_info_saver",
|
||||
|
|
|
@ -32,7 +32,9 @@ export function logMessageDelete(pluginData: GuildPluginData<LogsPluginType>, 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,
|
||||
|
|
|
@ -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) => {
|
||||
export const zLogFormats = z.strictObject(
|
||||
keys(LogType).reduce((map, logType) => {
|
||||
map[logType] = zMessageContent;
|
||||
return map;
|
||||
}, {} as ZLogFormatsHelper));
|
||||
}, {} as ZLogFormatsHelper),
|
||||
);
|
||||
export type TLogFormats = z.infer<typeof zLogFormats>;
|
||||
|
||||
const zLogChannel = z.strictObject({
|
||||
|
@ -58,10 +60,12 @@ export type TLogChannelMap = z.infer<typeof zLogChannelMap>;
|
|||
|
||||
export const zLogsConfig = z.strictObject({
|
||||
channels: zLogChannelMap,
|
||||
format: zLogFormats.merge(z.strictObject({
|
||||
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(),
|
||||
|
|
|
@ -2,6 +2,10 @@ import { GuildPluginData } from "knub";
|
|||
import { LogType } from "../../../data/LogType";
|
||||
import { LogsPluginType } from "../types";
|
||||
|
||||
export function isLogIgnored(pluginData: GuildPluginData<LogsPluginType>, type: keyof typeof LogType, ignoreId: string) {
|
||||
export function isLogIgnored(
|
||||
pluginData: GuildPluginData<LogsPluginType>,
|
||||
type: keyof typeof LogType,
|
||||
ignoreId: string,
|
||||
) {
|
||||
return pluginData.state.guildLogs.isLogIgnored(type, ignoreId);
|
||||
}
|
||||
|
|
|
@ -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<ModActionsPluginType>, tempban: Tempban) {
|
||||
if (!(await isBanned(pluginData, tempban.user_id))) {
|
||||
|
|
|
@ -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<typeof zReactionRolePair>;
|
||||
|
||||
export interface ReactionRolesPluginType extends BasePluginType {
|
||||
|
|
|
@ -11,7 +11,8 @@ 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([
|
||||
style: z
|
||||
.union([
|
||||
z.literal(ButtonStyle.Primary),
|
||||
z.literal(ButtonStyle.Secondary),
|
||||
z.literal(ButtonStyle.Success),
|
||||
|
@ -23,17 +24,23 @@ const zRoleButtonOption = z.strictObject({
|
|||
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),
|
||||
])
|
||||
.nullable()
|
||||
.default(null),
|
||||
start_new_row: z.boolean().default(false),
|
||||
});
|
||||
export type TRoleButtonOption = z.infer<typeof zRoleButtonOption>;
|
||||
|
||||
const zRoleButtonsConfigItem = z.strictObject({
|
||||
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) => {
|
||||
name: z
|
||||
.never()
|
||||
.optional()
|
||||
.transform((_, ctx) => {
|
||||
const ruleName = String(ctx.path[ctx.path.length - 2]).trim();
|
||||
if (! ruleName) {
|
||||
if (!ruleName) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Role buttons must have names",
|
||||
|
@ -54,8 +61,9 @@ const zRoleButtonsConfigItem = z.strictObject({
|
|||
]),
|
||||
options: z.array(zRoleButtonOption).max(25),
|
||||
exclusive: z.boolean().default(false),
|
||||
})
|
||||
.refine((parsed) => {
|
||||
})
|
||||
.refine(
|
||||
(parsed) => {
|
||||
try {
|
||||
createButtonComponents(parsed);
|
||||
} catch (err) {
|
||||
|
@ -65,20 +73,20 @@ const zRoleButtonsConfigItem = z.strictObject({
|
|||
throw err;
|
||||
}
|
||||
return true;
|
||||
}, {
|
||||
message: "Too many options; can only have max 5 buttons per row on max 5 rows."
|
||||
});
|
||||
},
|
||||
{
|
||||
message: "Too many options; can only have max 5 buttons per row on max 5 rows.",
|
||||
},
|
||||
);
|
||||
export type TRoleButtonsConfigItem = z.infer<typeof zRoleButtonsConfigItem>;
|
||||
|
||||
export const zRoleButtonsConfig = z.strictObject({
|
||||
buttons: zBoundedRecord(
|
||||
z.record(zBoundedCharacters(1, 16), zRoleButtonsConfigItem),
|
||||
0,
|
||||
100,
|
||||
),
|
||||
export const zRoleButtonsConfig = z
|
||||
.strictObject({
|
||||
buttons: zBoundedRecord(z.record(zBoundedCharacters(1, 16), zRoleButtonsConfigItem), 0, 100),
|
||||
can_reset: z.boolean(),
|
||||
})
|
||||
.refine((parsed) => {
|
||||
})
|
||||
.refine(
|
||||
(parsed) => {
|
||||
const seenMessages = new Set();
|
||||
for (const button of Object.values(parsed.buttons)) {
|
||||
if (button.message) {
|
||||
|
@ -91,9 +99,11 @@ export const zRoleButtonsConfig = z.strictObject({
|
|||
}
|
||||
}
|
||||
return true;
|
||||
}, {
|
||||
},
|
||||
{
|
||||
message: "Can't target the same message with two sets of role buttons",
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export interface RoleButtonsPluginType extends BasePluginType {
|
||||
config: z.infer<typeof zRoleButtonsConfig>;
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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<typeof zBaseSingleSpamConfig>;
|
||||
|
|
|
@ -18,11 +18,7 @@ const zStarboardOpts = z.strictObject({
|
|||
export type TStarboardOpts = z.infer<typeof zStarboardOpts>;
|
||||
|
||||
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(),
|
||||
});
|
||||
|
||||
|
|
|
@ -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}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ import { zEmbedInput } from "../../utils";
|
|||
export const zTag = z.union([z.string(), zEmbedInput]);
|
||||
export type TTag = z.infer<typeof zTag>;
|
||||
|
||||
export const zTagCategory = z.strictObject({
|
||||
export const zTagCategory = z
|
||||
.strictObject({
|
||||
prefix: z.string().nullable().default(null),
|
||||
delete_with_command: z.boolean().default(false),
|
||||
|
||||
|
@ -23,16 +24,14 @@ export const zTagCategory = z.strictObject({
|
|||
tags: z.record(z.string(), zTag),
|
||||
|
||||
can_use: z.boolean().nullable().default(null),
|
||||
})
|
||||
.refine(
|
||||
(parsed) => ! (parsed.auto_delete_command && parsed.delete_with_command),
|
||||
{
|
||||
})
|
||||
.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<typeof zTagCategory>;
|
||||
|
||||
export const zTagsConfig = z.strictObject({
|
||||
export const zTagsConfig = z
|
||||
.strictObject({
|
||||
prefix: z.string(),
|
||||
delete_with_command: z.boolean(),
|
||||
|
||||
|
@ -48,13 +47,10 @@ export const zTagsConfig = z.strictObject({
|
|||
can_create: z.boolean(),
|
||||
can_use: z.boolean(),
|
||||
can_list: z.boolean(),
|
||||
})
|
||||
.refine(
|
||||
(parsed) => ! (parsed.auto_delete_command && parsed.delete_with_command),
|
||||
{
|
||||
})
|
||||
.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<typeof zTagsConfig>;
|
||||
|
|
|
@ -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<TagsPluginType>, msg: SavedMessage) {
|
||||
if (msg.is_bot) return;
|
||||
|
@ -85,7 +85,7 @@ export async function onMessageCreate(pluginData: GuildPluginData<TagsPluginType
|
|||
}
|
||||
|
||||
const validated = zStrictMessageContent.safeParse(tagResult.renderedContent);
|
||||
if (! validated.success) {
|
||||
if (!validated.success) {
|
||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||
body: `Rendering tag ${tagResult.tagName} resulted in an invalid message: ${validated.error.message}`,
|
||||
});
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { GuildMember } from "discord.js";
|
||||
import { GuildPluginData } from "knub";
|
||||
import { parseArguments } from "knub-command-manager";
|
||||
import { logger } from "../../../logger";
|
||||
import { TemplateParseError } from "../../../templateFormatter";
|
||||
import { StrictMessageContent, validateAndParseMessageContent } from "../../../utils";
|
||||
import { memberToTemplateSafeMember, userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { TTag, TagsPluginType } from "../types";
|
||||
import { renderTagBody } from "./renderTagBody";
|
||||
import { logger } from "../../../logger";
|
||||
|
||||
export async function renderTagFromString(
|
||||
pluginData: GuildPluginData<TagsPluginType>,
|
||||
|
@ -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}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<UtilityPluginType>,
|
||||
role: Role,
|
||||
): Promise<APIEmbed> {
|
||||
export async function getRoleInfoEmbed(pluginData: GuildPluginData<UtilityPluginType>, role: Role): Promise<APIEmbed> {
|
||||
const embed: EmbedWith<"fields" | "author" | "color"> = {
|
||||
fields: [],
|
||||
author: {
|
||||
|
|
|
@ -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<APIEmbed> {
|
||||
export async function getSnowflakeInfoEmbed(snowflake: string, showUnknownWarning = false): Promise<APIEmbed> {
|
||||
const embed: EmbedWith<"fields" | "author"> = {
|
||||
fields: [],
|
||||
author: {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -7,8 +7,8 @@ import {
|
|||
GuildPluginBlueprint,
|
||||
GuildPluginData,
|
||||
} from "knub";
|
||||
import { TMarkdown } from "../types";
|
||||
import { ZodTypeAny } from "zod";
|
||||
import { TMarkdown } from "../types";
|
||||
|
||||
/**
|
||||
* GUILD PLUGINS
|
||||
|
|
|
@ -87,8 +87,10 @@ export function isDiscordAPIError(err: Error | string): err is DiscordAPIError {
|
|||
}
|
||||
|
||||
// null | undefined -> undefined
|
||||
export function zNullishToUndefined<T extends z.ZodTypeAny>(type: T): ZodEffects<T, NonNullable<z.output<T>> | undefined> {
|
||||
return type.transform(v => v ?? undefined);
|
||||
export function zNullishToUndefined<T extends z.ZodTypeAny>(
|
||||
type: T,
|
||||
): ZodEffects<T, NonNullable<z.output<T>> | undefined> {
|
||||
return type.transform((v) => v ?? undefined);
|
||||
}
|
||||
|
||||
export function getScalarDifference<T extends object>(
|
||||
|
@ -151,15 +153,18 @@ export type GroupDMInvite = Invite & {
|
|||
};
|
||||
|
||||
export function zBoundedCharacters(min: number, max: number) {
|
||||
return z.string().refine(str => {
|
||||
return z.string().refine(
|
||||
(str) => {
|
||||
const len = [...str].length; // Unicode aware character split
|
||||
return (len >= min && len <= max);
|
||||
}, {
|
||||
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<T extends ZodString>(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<TRecord extends ZodRecord<any, any>>(record: TRecord, minKeys: number, maxKeys: number): ZodEffects<TRecord> {
|
||||
return record.refine(data => {
|
||||
export function zBoundedRecord<TRecord extends ZodRecord<any, any>>(
|
||||
record: TRecord,
|
||||
minKeys: number,
|
||||
maxKeys: number,
|
||||
): ZodEffects<TRecord> {
|
||||
return record.refine(
|
||||
(data) => {
|
||||
const len = Object.keys(data).length;
|
||||
return (len >= minKeys && len <= maxKeys);
|
||||
}, {
|
||||
return len >= minKeys && len <= maxKeys;
|
||||
},
|
||||
{
|
||||
message: `Object must have ${minKeys}-${maxKeys} keys`,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export const zDelayString = z.string().max(32).refine(str => convertDelayStringToMS(str) !== null, {
|
||||
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<T> = Array<{
|
||||
type Entries<T> = Array<
|
||||
{
|
||||
[Key in keyof T]-?: [Key, T[Key]];
|
||||
}[keyof T]>;
|
||||
}[keyof T]
|
||||
>;
|
||||
|
||||
export function entries<T extends object>(object: T) {
|
||||
return Object.entries(object) as Entries<T>;
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Add table
Reference in a new issue