refactor: replace io-ts with zod
This commit is contained in:
parent
fafaefa1fb
commit
28692962bc
161 changed files with 1450 additions and 2105 deletions
9
backend/package-lock.json
generated
9
backend/package-lock.json
generated
|
@ -22,7 +22,6 @@
|
||||||
"express": "^4.17.0",
|
"express": "^4.17.0",
|
||||||
"fp-ts": "^2.0.1",
|
"fp-ts": "^2.0.1",
|
||||||
"humanize-duration": "^3.15.0",
|
"humanize-duration": "^3.15.0",
|
||||||
"io-ts": "^2.0.0",
|
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"knub": "^32.0.0-next.16",
|
"knub": "^32.0.0-next.16",
|
||||||
"knub-command-manager": "^9.1.0",
|
"knub-command-manager": "^9.1.0",
|
||||||
|
@ -4975,14 +4974,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||||
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||||
},
|
},
|
||||||
"node_modules/io-ts": {
|
|
||||||
"version": "2.2.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
|
||||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"fp-ts": "^2.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/iota-array": {
|
"node_modules/iota-array": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
"express": "^4.17.0",
|
"express": "^4.17.0",
|
||||||
"fp-ts": "^2.0.1",
|
"fp-ts": "^2.0.1",
|
||||||
"humanize-duration": "^3.15.0",
|
"humanize-duration": "^3.15.0",
|
||||||
"io-ts": "^2.0.0",
|
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"knub": "^32.0.0-next.16",
|
"knub": "^32.0.0-next.16",
|
||||||
"knub-command-manager": "^9.1.0",
|
"knub-command-manager": "^9.1.0",
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { createTypeHelper } from "knub-command-manager";
|
||||||
import {
|
import {
|
||||||
channelMentionRegex,
|
channelMentionRegex,
|
||||||
convertDelayStringToMS,
|
convertDelayStringToMS,
|
||||||
|
inputPatternToRegExp,
|
||||||
isValidSnowflake,
|
isValidSnowflake,
|
||||||
resolveMember,
|
resolveMember,
|
||||||
resolveUser,
|
resolveUser,
|
||||||
|
@ -26,7 +27,6 @@ import {
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import { isValidTimezone } from "./utils/isValidTimezone";
|
import { isValidTimezone } from "./utils/isValidTimezone";
|
||||||
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
|
import { MessageTarget, resolveMessageTarget } from "./utils/resolveMessageTarget";
|
||||||
import { inputPatternToRegExp } from "./validatorUtils";
|
|
||||||
|
|
||||||
export const commandTypes = {
|
export const commandTypes = {
|
||||||
...messageCommandBaseTypeConverters,
|
...messageCommandBaseTypeConverters,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { ConfigValidationError, PluginConfigManager } from "knub";
|
import { PluginConfigManager } from "knub";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
import { ZodError } from "zod";
|
||||||
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
import { ZeppelinPlugin } from "./plugins/ZeppelinPlugin";
|
||||||
import { guildPlugins } from "./plugins/availablePlugins";
|
import { guildPlugins } from "./plugins/availablePlugins";
|
||||||
import { PartialZeppelinGuildConfigSchema, ZeppelinGuildConfig } from "./types";
|
import { ZeppelinGuildConfig, zZeppelinGuildConfig } from "./types";
|
||||||
import { StrictValidationError, decodeAndValidateStrict } from "./validatorUtils";
|
|
||||||
|
|
||||||
const pluginNameToPlugin = new Map<string, ZeppelinPlugin>();
|
const pluginNameToPlugin = new Map<string, ZeppelinPlugin>();
|
||||||
for (const plugin of guildPlugins) {
|
for (const plugin of guildPlugins) {
|
||||||
|
@ -11,8 +11,10 @@ for (const plugin of guildPlugins) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function validateGuildConfig(config: any): Promise<string | null> {
|
export async function validateGuildConfig(config: any): Promise<string | null> {
|
||||||
const validationResult = decodeAndValidateStrict(PartialZeppelinGuildConfigSchema, config);
|
const validationResult = zZeppelinGuildConfig.safeParse(config);
|
||||||
if (validationResult instanceof StrictValidationError) return validationResult.getErrors();
|
if (!validationResult.success) {
|
||||||
|
return validationResult.error.issues.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
const guildConfig = config as ZeppelinGuildConfig;
|
const guildConfig = config as ZeppelinGuildConfig;
|
||||||
|
|
||||||
|
@ -41,8 +43,8 @@ export async function validateGuildConfig(config: any): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
await configManager.init();
|
await configManager.init();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof ConfigValidationError || err instanceof StrictValidationError) {
|
if (err instanceof ZodError) {
|
||||||
return `${pluginName}: ${err.message}`;
|
return `${pluginName}: ${err.issues.join("\n")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
|
|
|
@ -10,22 +10,18 @@ import {
|
||||||
PermissionsBitField,
|
PermissionsBitField,
|
||||||
TextBasedChannel,
|
TextBasedChannel,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import {
|
import {
|
||||||
AnyPluginData,
|
AnyPluginData,
|
||||||
CommandContext,
|
CommandContext,
|
||||||
ConfigValidationError,
|
|
||||||
ExtendedMatchParams,
|
ExtendedMatchParams,
|
||||||
GuildPluginData,
|
GuildPluginData,
|
||||||
PluginOverrideCriteria,
|
helpers
|
||||||
helpers,
|
|
||||||
} from "knub";
|
} from "knub";
|
||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
import { isStaff } from "./staff";
|
import { isStaff } from "./staff";
|
||||||
import { TZeppelinKnub } from "./types";
|
import { TZeppelinKnub } from "./types";
|
||||||
import { errorMessage, successMessage, tNullable } from "./utils";
|
import { errorMessage, successMessage } from "./utils";
|
||||||
import { Tail } from "./utils/typeUtils";
|
import { Tail } from "./utils/typeUtils";
|
||||||
import { StrictValidationError, parseIoTsSchema } from "./validatorUtils";
|
|
||||||
|
|
||||||
const { getMemberLevel } = helpers;
|
const { getMemberLevel } = helpers;
|
||||||
|
|
||||||
|
@ -59,46 +55,6 @@ export async function hasPermission(
|
||||||
return helpers.hasPermission(config, permission);
|
return helpers.hasPermission(config, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PluginOverrideCriteriaType: t.Type<PluginOverrideCriteria<unknown>> = t.recursion(
|
|
||||||
"PluginOverrideCriteriaType",
|
|
||||||
() =>
|
|
||||||
t.partial({
|
|
||||||
channel: tNullable(t.union([t.string, t.array(t.string)])),
|
|
||||||
category: tNullable(t.union([t.string, t.array(t.string)])),
|
|
||||||
level: tNullable(t.union([t.string, t.array(t.string)])),
|
|
||||||
user: tNullable(t.union([t.string, t.array(t.string)])),
|
|
||||||
role: tNullable(t.union([t.string, t.array(t.string)])),
|
|
||||||
|
|
||||||
all: tNullable(t.array(PluginOverrideCriteriaType)),
|
|
||||||
any: tNullable(t.array(PluginOverrideCriteriaType)),
|
|
||||||
not: tNullable(PluginOverrideCriteriaType),
|
|
||||||
|
|
||||||
extra: t.unknown,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export function strictValidationErrorToConfigValidationError(err: StrictValidationError) {
|
|
||||||
return new ConfigValidationError(
|
|
||||||
err
|
|
||||||
.getErrors()
|
|
||||||
.map((e) => e.toString())
|
|
||||||
.join("\n"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeIoTsConfigParser<Schema extends t.Type<any>>(schema: Schema): (input: unknown) => t.TypeOf<Schema> {
|
|
||||||
return (input: unknown) => {
|
|
||||||
try {
|
|
||||||
return parseIoTsSchema(schema, input);
|
|
||||||
} catch (err) {
|
|
||||||
if (err instanceof StrictValidationError) {
|
|
||||||
throw strictValidationErrorToConfigValidationError(err);
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function sendSuccessMessage(
|
export async function sendSuccessMessage(
|
||||||
pluginData: AnyPluginData<any>,
|
pluginData: AnyPluginData<any>,
|
||||||
channel: TextBasedChannel,
|
channel: TextBasedChannel,
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { AutoDeletePluginType, ConfigSchema } from "./types";
|
import { AutoDeletePluginType, zAutoDeleteConfig } from "./types";
|
||||||
import { onMessageCreate } from "./util/onMessageCreate";
|
import { onMessageCreate } from "./util/onMessageCreate";
|
||||||
import { onMessageDelete } from "./util/onMessageDelete";
|
import { onMessageDelete } from "./util/onMessageDelete";
|
||||||
import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk";
|
import { onMessageDeleteBulk } from "./util/onMessageDeleteBulk";
|
||||||
|
@ -24,11 +23,11 @@ export const AutoDeletePlugin = zeppelinGuildPlugin<AutoDeletePluginType>()({
|
||||||
prettyName: "Auto-delete",
|
prettyName: "Auto-delete",
|
||||||
description: "Allows Zeppelin to auto-delete messages from a channel after a delay",
|
description: "Allows Zeppelin to auto-delete messages from a channel after a delay",
|
||||||
configurationGuide: "Maximum deletion delay is currently 5 minutes",
|
configurationGuide: "Maximum deletion delay is currently 5 minutes",
|
||||||
configSchema: ConfigSchema,
|
configSchema: zAutoDeleteConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
dependencies: () => [TimeAndDatePlugin, LogsPlugin],
|
dependencies: () => [TimeAndDatePlugin, LogsPlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zAutoDeleteConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
beforeLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType } from "knub";
|
import { BasePluginType } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { SavedMessage } from "../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../data/entities/SavedMessage";
|
||||||
import { MINUTES, tDelayString } from "../../utils";
|
import { MINUTES, zDelayString } from "../../utils";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
export const MAX_DELAY = 5 * MINUTES;
|
export const MAX_DELAY = 5 * MINUTES;
|
||||||
|
|
||||||
|
@ -13,14 +13,13 @@ export interface IDeletionQueueItem {
|
||||||
message: SavedMessage;
|
message: SavedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zAutoDeleteConfig = z.strictObject({
|
||||||
enabled: t.boolean,
|
enabled: z.boolean(),
|
||||||
delay: tDelayString,
|
delay: zDelayString,
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface AutoDeletePluginType extends BasePluginType {
|
export interface AutoDeletePluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.output<typeof zAutoDeleteConfig>;
|
||||||
state: {
|
state: {
|
||||||
guildSavedMessages: GuildSavedMessages;
|
guildSavedMessages: GuildSavedMessages;
|
||||||
guildLogs: GuildLogs;
|
guildLogs: GuildLogs;
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { trimPluginDescription } from "../../utils";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd";
|
import { DisableAutoReactionsCmd } from "./commands/DisableAutoReactionsCmd";
|
||||||
import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd";
|
import { NewAutoReactionsCmd } from "./commands/NewAutoReactionsCmd";
|
||||||
import { AddReactionsEvt } from "./events/AddReactionsEvt";
|
import { AddReactionsEvt } from "./events/AddReactionsEvt";
|
||||||
import { AutoReactionsPluginType, ConfigSchema } from "./types";
|
import { AutoReactionsPluginType, zAutoReactionsConfig } from "./types";
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
|
const defaultOptions: PluginOptions<AutoReactionsPluginType> = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -32,7 +31,7 @@ export const AutoReactionsPlugin = zeppelinGuildPlugin<AutoReactionsPluginType>(
|
||||||
description: trimPluginDescription(`
|
description: trimPluginDescription(`
|
||||||
Allows setting up automatic reactions to all new messages on a channel
|
Allows setting up automatic reactions to all new messages on a channel
|
||||||
`),
|
`),
|
||||||
configSchema: ConfigSchema,
|
configSchema: zAutoReactionsConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
@ -40,7 +39,7 @@ export const AutoReactionsPlugin = zeppelinGuildPlugin<AutoReactionsPluginType>(
|
||||||
LogsPlugin,
|
LogsPlugin,
|
||||||
],
|
],
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zAutoReactionsConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
|
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
import { GuildAutoReactions } from "../../data/GuildAutoReactions";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { AutoReaction } from "../../data/entities/AutoReaction";
|
import { AutoReaction } from "../../data/entities/AutoReaction";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zAutoReactionsConfig = z.strictObject({
|
||||||
can_manage: t.boolean,
|
can_manage: z.boolean(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface AutoReactionsPluginType extends BasePluginType {
|
export interface AutoReactionsPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.output<typeof zAutoReactionsConfig>;
|
||||||
state: {
|
state: {
|
||||||
logs: GuildLogs;
|
logs: GuildLogs;
|
||||||
savedMessages: GuildSavedMessages;
|
savedMessages: GuildSavedMessages;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { configUtils, CooldownManager } from "knub";
|
import { CooldownManager } from "knub";
|
||||||
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
|
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
|
@ -8,7 +8,6 @@ import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
||||||
import { MINUTES, SECONDS } from "../../utils";
|
import { MINUTES, SECONDS } from "../../utils";
|
||||||
import { registerEventListenersFromMap } from "../../utils/registerEventListenersFromMap";
|
import { registerEventListenersFromMap } from "../../utils/registerEventListenersFromMap";
|
||||||
import { unregisterEventListenersFromMap } from "../../utils/unregisterEventListenersFromMap";
|
import { unregisterEventListenersFromMap } from "../../utils/unregisterEventListenersFromMap";
|
||||||
import { parseIoTsSchema, StrictValidationError } from "../../validatorUtils";
|
|
||||||
import { CountersPlugin } from "../Counters/CountersPlugin";
|
import { CountersPlugin } from "../Counters/CountersPlugin";
|
||||||
import { InternalPosterPlugin } from "../InternalPoster/InternalPosterPlugin";
|
import { InternalPosterPlugin } from "../InternalPoster/InternalPosterPlugin";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
|
@ -17,7 +16,6 @@ import { MutesPlugin } from "../Mutes/MutesPlugin";
|
||||||
import { PhishermanPlugin } from "../Phisherman/PhishermanPlugin";
|
import { PhishermanPlugin } from "../Phisherman/PhishermanPlugin";
|
||||||
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
|
import { RoleManagerPlugin } from "../RoleManager/RoleManagerPlugin";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { availableActions } from "./actions/availableActions";
|
|
||||||
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
|
import { AntiraidClearCmd } from "./commands/AntiraidClearCmd";
|
||||||
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
|
import { SetAntiraidCmd } from "./commands/SetAntiraidCmd";
|
||||||
import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd";
|
import { ViewAntiraidCmd } from "./commands/ViewAntiraidCmd";
|
||||||
|
@ -35,8 +33,7 @@ import { clearOldRecentNicknameChanges } from "./functions/clearOldNicknameChang
|
||||||
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
|
import { clearOldRecentActions } from "./functions/clearOldRecentActions";
|
||||||
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
|
import { clearOldRecentSpam } from "./functions/clearOldRecentSpam";
|
||||||
import { pluginInfo } from "./info";
|
import { pluginInfo } from "./info";
|
||||||
import { availableTriggers } from "./triggers/availableTriggers";
|
import { AutomodPluginType, zAutomodConfig } from "./types";
|
||||||
import { AutomodPluginType, ConfigSchema } from "./types";
|
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -61,129 +58,6 @@ const defaultOptions = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Config preprocessor to set default values for triggers and perform extra validation
|
|
||||||
* TODO: Separate input and output types
|
|
||||||
*/
|
|
||||||
const configParser = (input: unknown) => {
|
|
||||||
const rules = (input as any).rules;
|
|
||||||
if (rules) {
|
|
||||||
// Loop through each rule
|
|
||||||
for (const [name, rule] of Object.entries(rules)) {
|
|
||||||
if (rule == null) {
|
|
||||||
delete rules[name];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
rule["name"] = name;
|
|
||||||
|
|
||||||
// If the rule doesn't have an explicitly set "enabled" property, set it to true
|
|
||||||
if (rule["enabled"] == null) {
|
|
||||||
rule["enabled"] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule["allow_further_rules"] == null) {
|
|
||||||
rule["allow_further_rules"] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule["affects_bots"] == null) {
|
|
||||||
rule["affects_bots"] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule["affects_self"] == null) {
|
|
||||||
rule["affects_self"] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through the rule's triggers
|
|
||||||
if (rule["triggers"]) {
|
|
||||||
for (const triggerObj of rule["triggers"]) {
|
|
||||||
for (const triggerName in triggerObj) {
|
|
||||||
if (!availableTriggers[triggerName]) {
|
|
||||||
throw new StrictValidationError([`Unknown trigger '${triggerName}' in rule '${rule["name"]}'`]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const triggerBlueprint = availableTriggers[triggerName];
|
|
||||||
|
|
||||||
if (typeof triggerBlueprint.defaultConfig === "object" && triggerBlueprint.defaultConfig != null) {
|
|
||||||
triggerObj[triggerName] = configUtils.mergeConfig(
|
|
||||||
triggerBlueprint.defaultConfig,
|
|
||||||
triggerObj[triggerName] || {},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
triggerObj[triggerName] = triggerObj[triggerName] || triggerBlueprint.defaultConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (triggerObj[triggerName].match_attachment_type) {
|
|
||||||
const white = triggerObj[triggerName].match_attachment_type.whitelist_enabled;
|
|
||||||
const black = triggerObj[triggerName].match_attachment_type.blacklist_enabled;
|
|
||||||
|
|
||||||
if (white && black) {
|
|
||||||
throw new StrictValidationError([
|
|
||||||
`Cannot have both blacklist and whitelist enabled at rule <${rule["name"]}/match_attachment_type>`,
|
|
||||||
]);
|
|
||||||
} else if (!white && !black) {
|
|
||||||
throw new StrictValidationError([
|
|
||||||
`Must have either blacklist or whitelist enabled at rule <${rule["name"]}/match_attachment_type>`,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (triggerObj[triggerName].match_mime_type) {
|
|
||||||
const white = triggerObj[triggerName].match_mime_type.whitelist_enabled;
|
|
||||||
const black = triggerObj[triggerName].match_mime_type.blacklist_enabled;
|
|
||||||
|
|
||||||
if (white && black) {
|
|
||||||
throw new StrictValidationError([
|
|
||||||
`Cannot have both blacklist and whitelist enabled at rule <${rule["name"]}/match_mime_type>`,
|
|
||||||
]);
|
|
||||||
} else if (!white && !black) {
|
|
||||||
throw new StrictValidationError([
|
|
||||||
`Must have either blacklist or whitelist enabled at rule <${rule["name"]}/match_mime_type>`,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule["actions"]) {
|
|
||||||
for (const actionName in rule["actions"]) {
|
|
||||||
if (!availableActions[actionName]) {
|
|
||||||
throw new StrictValidationError([`Unknown action '${actionName}' in rule '${rule["name"]}'`]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const actionBlueprint = availableActions[actionName];
|
|
||||||
const actionConfig = rule["actions"][actionName];
|
|
||||||
|
|
||||||
if (typeof actionConfig !== "object" || Array.isArray(actionConfig) || actionConfig == null) {
|
|
||||||
rule["actions"][actionName] = actionConfig;
|
|
||||||
} else {
|
|
||||||
rule["actions"][actionName] = configUtils.mergeConfig(actionBlueprint.defaultConfig, actionConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable logging of automod actions by default
|
|
||||||
if (rule["actions"]) {
|
|
||||||
for (const actionName in rule["actions"]) {
|
|
||||||
if (!availableActions[actionName]) {
|
|
||||||
throw new StrictValidationError([`Unknown action '${actionName}' in rule '${rule["name"]}'`]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule["actions"]["log"] == null) {
|
|
||||||
rule["actions"]["log"] = true;
|
|
||||||
}
|
|
||||||
if (rule["actions"]["clean"] && rule["actions"]["start_thread"]) {
|
|
||||||
throw new StrictValidationError([`Cannot have both clean and start_thread at rule '${rule["name"]}'`]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseIoTsSchema(ConfigSchema, input);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
|
export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
|
||||||
name: "automod",
|
name: "automod",
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
|
@ -201,7 +75,7 @@ export const AutomodPlugin = zeppelinGuildPlugin<AutomodPluginType>()({
|
||||||
],
|
],
|
||||||
|
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
configParser,
|
configParser: (input) => zAutomodConfig.parse(input),
|
||||||
|
|
||||||
customOverrideCriteriaFunctions: {
|
customOverrideCriteriaFunctions: {
|
||||||
antiraid_level: (pluginData, matchParams, value) => {
|
antiraid_level: (pluginData, matchParams, value) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { PermissionFlagsBits, Snowflake } from "discord.js";
|
import { PermissionFlagsBits, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { nonNullish, unique } from "../../../utils";
|
import { nonNullish, unique, zSnowflake } from "../../../utils";
|
||||||
import { canAssignRole } from "../../../utils/canAssignRole";
|
import { canAssignRole } from "../../../utils/canAssignRole";
|
||||||
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
||||||
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
||||||
|
@ -11,9 +11,10 @@ import { automodAction } from "../helpers";
|
||||||
|
|
||||||
const p = PermissionFlagsBits;
|
const p = PermissionFlagsBits;
|
||||||
|
|
||||||
|
const configSchema = z.array(zSnowflake);
|
||||||
|
|
||||||
export const AddRolesAction = automodAction({
|
export const AddRolesAction = automodAction({
|
||||||
configType: t.array(t.string),
|
configSchema,
|
||||||
defaultConfig: [],
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const members = unique(contexts.map((c) => c.member).filter(nonNullish));
|
const members = unique(contexts.map((c) => c.member).filter(nonNullish));
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
|
import { zBoundedCharacters } from "../../../utils";
|
||||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const AddToCounterAction = automodAction({
|
const configSchema = z.object({
|
||||||
configType: t.type({
|
counter: zBoundedCharacters(0, 100),
|
||||||
counter: t.string,
|
amount: z.number(),
|
||||||
amount: t.number,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const AddToCounterAction = automodAction({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Snowflake } from "discord.js";
|
import { Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { erisAllowedMentionsToDjsMentionOptions } from "src/utils/erisAllowedMentionsToDjsMentionOptions";
|
import { erisAllowedMentionsToDjsMentionOptions } from "src/utils/erisAllowedMentionsToDjsMentionOptions";
|
||||||
|
import z from "zod";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import {
|
import {
|
||||||
createTypedTemplateSafeValueContainer,
|
createTypedTemplateSafeValueContainer,
|
||||||
|
@ -12,10 +12,12 @@ import {
|
||||||
chunkMessageLines,
|
chunkMessageLines,
|
||||||
isTruthy,
|
isTruthy,
|
||||||
messageLink,
|
messageLink,
|
||||||
tAllowedMentions,
|
|
||||||
tNormalizedNullOptional,
|
|
||||||
validateAndParseMessageContent,
|
validateAndParseMessageContent,
|
||||||
verboseChannelMention,
|
verboseChannelMention,
|
||||||
|
zAllowedMentions,
|
||||||
|
zBoundedCharacters,
|
||||||
|
zNullishToUndefined,
|
||||||
|
zSnowflake
|
||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
import { messageIsEmpty } from "../../../utils/messageIsEmpty";
|
import { messageIsEmpty } from "../../../utils/messageIsEmpty";
|
||||||
import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
|
import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
|
||||||
|
@ -23,14 +25,14 @@ import { InternalPosterPlugin } from "../../InternalPoster/InternalPosterPlugin"
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const AlertAction = automodAction({
|
const configSchema = z.object({
|
||||||
configType: t.type({
|
channel: zSnowflake,
|
||||||
channel: t.string,
|
text: zBoundedCharacters(1, 4000),
|
||||||
text: t.string,
|
allowed_mentions: zNullishToUndefined(zAllowedMentions.nullable().default(null)),
|
||||||
allowed_mentions: tNormalizedNullOptional(tAllowedMentions),
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const AlertAction = automodAction({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
|
||||||
const channel = pluginData.guild.channels.cache.get(actionConfig.channel as Snowflake);
|
const channel = pluginData.guild.channels.cache.get(actionConfig.channel as Snowflake);
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { AnyThreadChannel } from "discord.js";
|
import { AnyThreadChannel } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { noop } from "../../../utils";
|
import { noop } from "../../../utils";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({});
|
||||||
|
|
||||||
export const ArchiveThreadAction = automodAction({
|
export const ArchiveThreadAction = automodAction({
|
||||||
configType: t.type({}),
|
configSchema,
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts }) {
|
async apply({ pluginData, contexts }) {
|
||||||
const threads = contexts
|
const threads = contexts
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { AutomodActionBlueprint } from "../helpers";
|
import { AutomodActionBlueprint } from "../helpers";
|
||||||
import { AddRolesAction } from "./addRoles";
|
import { AddRolesAction } from "./addRoles";
|
||||||
import { AddToCounterAction } from "./addToCounter";
|
import { AddToCounterAction } from "./addToCounter";
|
||||||
|
@ -19,7 +18,7 @@ import { SetSlowmodeAction } from "./setSlowmode";
|
||||||
import { StartThreadAction } from "./startThread";
|
import { StartThreadAction } from "./startThread";
|
||||||
import { WarnAction } from "./warn";
|
import { WarnAction } from "./warn";
|
||||||
|
|
||||||
export const availableActions: Record<string, AutomodActionBlueprint<any>> = {
|
export const availableActions = {
|
||||||
clean: CleanAction,
|
clean: CleanAction,
|
||||||
warn: WarnAction,
|
warn: WarnAction,
|
||||||
mute: MuteAction,
|
mute: MuteAction,
|
||||||
|
@ -38,25 +37,4 @@ export const availableActions: Record<string, AutomodActionBlueprint<any>> = {
|
||||||
start_thread: StartThreadAction,
|
start_thread: StartThreadAction,
|
||||||
archive_thread: ArchiveThreadAction,
|
archive_thread: ArchiveThreadAction,
|
||||||
change_perms: ChangePermsAction,
|
change_perms: ChangePermsAction,
|
||||||
};
|
} satisfies Record<string, AutomodActionBlueprint<any>>;
|
||||||
|
|
||||||
export const AvailableActions = t.type({
|
|
||||||
clean: CleanAction.configType,
|
|
||||||
warn: WarnAction.configType,
|
|
||||||
mute: MuteAction.configType,
|
|
||||||
kick: KickAction.configType,
|
|
||||||
ban: BanAction.configType,
|
|
||||||
alert: AlertAction.configType,
|
|
||||||
change_nickname: ChangeNicknameAction.configType,
|
|
||||||
log: LogAction.configType,
|
|
||||||
add_roles: AddRolesAction.configType,
|
|
||||||
remove_roles: RemoveRolesAction.configType,
|
|
||||||
set_antiraid_level: SetAntiraidLevelAction.configType,
|
|
||||||
reply: ReplyAction.configType,
|
|
||||||
add_to_counter: AddToCounterAction.configType,
|
|
||||||
set_counter: SetCounterAction.configType,
|
|
||||||
set_slowmode: SetSlowmodeAction.configType,
|
|
||||||
start_thread: StartThreadAction.configType,
|
|
||||||
archive_thread: ArchiveThreadAction.configType,
|
|
||||||
change_perms: ChangePermsAction.configType,
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,25 +1,23 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { convertDelayStringToMS, nonNullish, tDelayString, tNullable, unique } from "../../../utils";
|
import { convertDelayStringToMS, nonNullish, unique, zBoundedCharacters, zDelayString, zSnowflake } from "../../../utils";
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
import { zNotify } from "../types";
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({
|
||||||
|
reason: zBoundedCharacters(0, 4000).nullable().default(null),
|
||||||
|
duration: zDelayString.nullable().default(null),
|
||||||
|
notify: zNotify.nullable().default(null),
|
||||||
|
notifyChannel: zSnowflake.nullable().default(null),
|
||||||
|
deleteMessageDays: z.number().nullable().default(null),
|
||||||
|
postInCaseLog: z.boolean().nullable().default(null),
|
||||||
|
hide_case: z.boolean().nullable().default(false),
|
||||||
|
});
|
||||||
|
|
||||||
export const BanAction = automodAction({
|
export const BanAction = automodAction({
|
||||||
configType: t.type({
|
configSchema,
|
||||||
reason: tNullable(t.string),
|
|
||||||
duration: tNullable(tDelayString),
|
|
||||||
notify: tNullable(t.string),
|
|
||||||
notifyChannel: tNullable(t.string),
|
|
||||||
deleteMessageDays: tNullable(t.number),
|
|
||||||
postInCaseLog: tNullable(t.boolean),
|
|
||||||
hide_case: tNullable(t.boolean),
|
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
|
||||||
notify: null, // Use defaults from ModActions
|
|
||||||
hide_case: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, matchResult }) {
|
async apply({ pluginData, contexts, actionConfig, matchResult }) {
|
||||||
const reason = actionConfig.reason || "Kicked automatically";
|
const reason = actionConfig.reason || "Kicked automatically";
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { nonNullish, unique } from "../../../utils";
|
import { nonNullish, unique, zBoundedCharacters } from "../../../utils";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const ChangeNicknameAction = automodAction({
|
export const ChangeNicknameAction = automodAction({
|
||||||
configType: t.union([
|
configSchema: z.union([
|
||||||
t.string,
|
zBoundedCharacters(0, 32),
|
||||||
t.type({
|
z.strictObject({
|
||||||
name: t.string,
|
name: zBoundedCharacters(0, 32),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig }) {
|
async apply({ pluginData, contexts, actionConfig }) {
|
||||||
const members = unique(contexts.map((c) => c.member).filter(nonNullish));
|
const members = unique(contexts.map((c) => c.member).filter(nonNullish));
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { PermissionsBitField, PermissionsString } from "discord.js";
|
import { PermissionsBitField, PermissionsString } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import { U } from "ts-toolbelt";
|
||||||
|
import z from "zod";
|
||||||
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
||||||
import { isValidSnowflake, noop, tNullable, tPartialDictionary } from "../../../utils";
|
import { isValidSnowflake, keys, noop, zSnowflake } from "../../../utils";
|
||||||
import {
|
import {
|
||||||
guildToTemplateSafeGuild,
|
guildToTemplateSafeGuild,
|
||||||
savedMessageToTemplateSafeSavedMessage,
|
savedMessageToTemplateSafeSavedMessage,
|
||||||
|
@ -59,16 +60,19 @@ const realToLegacyMap = Object.entries(legacyPermMap).reduce((map, pair) => {
|
||||||
return map;
|
return map;
|
||||||
}, {}) as Record<keyof typeof PermissionsBitField.Flags, keyof typeof legacyPermMap>;
|
}, {}) as Record<keyof typeof PermissionsBitField.Flags, keyof typeof legacyPermMap>;
|
||||||
|
|
||||||
|
const permissionNames = keys(PermissionsBitField.Flags) as U.ListOf<keyof typeof PermissionsBitField.Flags>;
|
||||||
|
const legacyPermissionNames = keys(legacyPermMap) as U.ListOf<keyof typeof legacyPermMap>;
|
||||||
|
const allPermissionNames = [...permissionNames, ...legacyPermissionNames] as const;
|
||||||
|
|
||||||
export const ChangePermsAction = automodAction({
|
export const ChangePermsAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
target: t.string,
|
target: zSnowflake,
|
||||||
channel: tNullable(t.string),
|
channel: zSnowflake.nullable().default(null),
|
||||||
perms: tPartialDictionary(
|
perms: z.record(
|
||||||
t.union([t.keyof(PermissionsBitField.Flags), t.keyof(legacyPermMap)]),
|
z.enum(allPermissionNames),
|
||||||
tNullable(t.boolean),
|
z.boolean().nullable(),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig }) {
|
async apply({ pluginData, contexts, actionConfig }) {
|
||||||
const user = contexts.find((c) => c.user)?.user;
|
const user = contexts.find((c) => c.user)?.user;
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import { GuildTextBasedChannel, Snowflake } from "discord.js";
|
import { GuildTextBasedChannel, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { noop } from "../../../utils";
|
import { noop } from "../../../utils";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const CleanAction = automodAction({
|
export const CleanAction = automodAction({
|
||||||
configType: t.boolean,
|
configSchema: z.boolean().default(false),
|
||||||
defaultConfig: false,
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, ruleName }) {
|
async apply({ pluginData, contexts, ruleName }) {
|
||||||
const messageIdsToDeleteByChannelId: Map<string, string[]> = new Map();
|
const messageIdsToDeleteByChannelId: Map<string, string[]> = new Map();
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
|
import { zBoundedCharacters } from "../../../utils";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const ExampleAction = automodAction({
|
export const ExampleAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
someValue: t.string,
|
someValue: zBoundedCharacters(0, 1000),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
async apply({ pluginData, contexts, actionConfig }) {
|
async apply({ pluginData, contexts, actionConfig }) {
|
||||||
// TODO: Everything
|
// TODO: Everything
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
import { asyncMap, nonNullish, resolveMember, unique, zBoundedCharacters, zSnowflake } from "../../../utils";
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
import { zNotify } from "../types";
|
||||||
|
|
||||||
export const KickAction = automodAction({
|
export const KickAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
reason: tNullable(t.string),
|
reason: zBoundedCharacters(0, 4000).nullable().default(null),
|
||||||
notify: tNullable(t.string),
|
notify: zNotify.nullable().default(null),
|
||||||
notifyChannel: tNullable(t.string),
|
notifyChannel: zSnowflake.nullable().default(null),
|
||||||
postInCaseLog: tNullable(t.boolean),
|
postInCaseLog: z.boolean().nullable().default(null),
|
||||||
hide_case: tNullable(t.boolean),
|
hide_case: z.boolean().nullable().default(false),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultConfig: {
|
|
||||||
notify: null, // Use defaults from ModActions
|
|
||||||
hide_case: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, matchResult }) {
|
async apply({ pluginData, contexts, actionConfig, matchResult }) {
|
||||||
const reason = actionConfig.reason || "Kicked automatically";
|
const reason = actionConfig.reason || "Kicked automatically";
|
||||||
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { isTruthy, unique } from "../../../utils";
|
import { isTruthy, unique } from "../../../utils";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const LogAction = automodAction({
|
export const LogAction = automodAction({
|
||||||
configType: t.boolean,
|
configSchema: z.boolean().default(true),
|
||||||
defaultConfig: true,
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, ruleName, matchResult }) {
|
async apply({ pluginData, contexts, ruleName, matchResult }) {
|
||||||
const users = unique(contexts.map((c) => c.user)).filter(isTruthy);
|
const users = unique(contexts.map((c) => c.user)).filter(isTruthy);
|
||||||
|
|
|
@ -1,29 +1,25 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
||||||
import { convertDelayStringToMS, nonNullish, tDelayString, tNullable, unique } from "../../../utils";
|
import { convertDelayStringToMS, nonNullish, unique, zBoundedCharacters, zDelayString, zSnowflake } from "../../../utils";
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
import { zNotify } from "../types";
|
||||||
|
|
||||||
export const MuteAction = automodAction({
|
export const MuteAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
reason: tNullable(t.string),
|
reason: zBoundedCharacters(0, 4000).nullable().default(null),
|
||||||
duration: tNullable(tDelayString),
|
duration: zDelayString.nullable().default(null),
|
||||||
notify: tNullable(t.string),
|
notify: zNotify.nullable().default(null),
|
||||||
notifyChannel: tNullable(t.string),
|
notifyChannel: zSnowflake.nullable().default(null),
|
||||||
remove_roles_on_mute: tNullable(t.union([t.boolean, t.array(t.string)])),
|
remove_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).nullable().default(null),
|
||||||
restore_roles_on_mute: tNullable(t.union([t.boolean, t.array(t.string)])),
|
restore_roles_on_mute: z.union([z.boolean(), z.array(zSnowflake)]).nullable().default(null),
|
||||||
postInCaseLog: tNullable(t.boolean),
|
postInCaseLog: z.boolean().nullable().default(null),
|
||||||
hide_case: tNullable(t.boolean),
|
hide_case: z.boolean().nullable().default(false),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultConfig: {
|
|
||||||
notify: null, // Use defaults from ModActions
|
|
||||||
hide_case: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) {
|
||||||
const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : undefined;
|
const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : undefined;
|
||||||
const reason = actionConfig.reason || "Muted automatically";
|
const reason = actionConfig.reason || "Muted automatically";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { PermissionFlagsBits, Snowflake } from "discord.js";
|
import { PermissionFlagsBits, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { nonNullish, unique } from "../../../utils";
|
import { nonNullish, unique, zSnowflake } from "../../../utils";
|
||||||
import { canAssignRole } from "../../../utils/canAssignRole";
|
import { canAssignRole } from "../../../utils/canAssignRole";
|
||||||
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
import { getMissingPermissions } from "../../../utils/getMissingPermissions";
|
||||||
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
||||||
|
@ -12,9 +12,7 @@ import { automodAction } from "../helpers";
|
||||||
const p = PermissionFlagsBits;
|
const p = PermissionFlagsBits;
|
||||||
|
|
||||||
export const RemoveRolesAction = automodAction({
|
export const RemoveRolesAction = automodAction({
|
||||||
configType: t.array(t.string),
|
configSchema: z.array(zSnowflake).default([]),
|
||||||
|
|
||||||
defaultConfig: [],
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const members = unique(contexts.map((c) => c.member).filter(nonNullish));
|
const members = unique(contexts.map((c) => c.member).filter(nonNullish));
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { GuildTextBasedChannel, MessageCreateOptions, PermissionsBitField, Snowflake, User } from "discord.js";
|
import { GuildTextBasedChannel, MessageCreateOptions, PermissionsBitField, Snowflake, User } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
||||||
import {
|
import {
|
||||||
convertDelayStringToMS,
|
convertDelayStringToMS,
|
||||||
noop,
|
noop,
|
||||||
renderRecursively,
|
renderRecursively,
|
||||||
tDelayString,
|
|
||||||
tMessageContent,
|
|
||||||
tNullable,
|
|
||||||
unique,
|
unique,
|
||||||
validateAndParseMessageContent,
|
validateAndParseMessageContent,
|
||||||
verboseChannelMention,
|
verboseChannelMention,
|
||||||
|
zBoundedCharacters,
|
||||||
|
zDelayString,
|
||||||
|
zMessageContent
|
||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||||
import { messageIsEmpty } from "../../../utils/messageIsEmpty";
|
import { messageIsEmpty } from "../../../utils/messageIsEmpty";
|
||||||
|
@ -20,17 +20,15 @@ import { automodAction } from "../helpers";
|
||||||
import { AutomodContext } from "../types";
|
import { AutomodContext } from "../types";
|
||||||
|
|
||||||
export const ReplyAction = automodAction({
|
export const ReplyAction = automodAction({
|
||||||
configType: t.union([
|
configSchema: z.union([
|
||||||
t.string,
|
zBoundedCharacters(0, 4000),
|
||||||
t.type({
|
z.strictObject({
|
||||||
text: tMessageContent,
|
text: zMessageContent,
|
||||||
auto_delete: tNullable(t.union([tDelayString, t.number])),
|
auto_delete: z.union([zDelayString, z.number()]).nullable().default(null),
|
||||||
inline: tNullable(t.boolean),
|
inline: z.boolean().default(false),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const contextsWithTextChannels = contexts
|
const contextsWithTextChannels = contexts
|
||||||
.filter((c) => c.message?.channel_id)
|
.filter((c) => c.message?.channel_id)
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import * as t from "io-ts";
|
import { zBoundedCharacters } from "../../../utils";
|
||||||
import { tNullable } from "../../../utils";
|
|
||||||
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
import { setAntiraidLevel } from "../functions/setAntiraidLevel";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const SetAntiraidLevelAction = automodAction({
|
export const SetAntiraidLevelAction = automodAction({
|
||||||
configType: tNullable(t.string),
|
configSchema: zBoundedCharacters(0, 100).nullable(),
|
||||||
defaultConfig: "",
|
|
||||||
|
|
||||||
async apply({ pluginData, actionConfig }) {
|
async apply({ pluginData, actionConfig }) {
|
||||||
setAntiraidLevel(pluginData, actionConfig ?? null);
|
setAntiraidLevel(pluginData, actionConfig ?? null);
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
|
import { zBoundedCharacters } from "../../../utils";
|
||||||
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
import { CountersPlugin } from "../../Counters/CountersPlugin";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const SetCounterAction = automodAction({
|
export const SetCounterAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
counter: t.string,
|
counter: zBoundedCharacters(0, 100),
|
||||||
value: t.number,
|
value: z.number(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
async apply({ pluginData, contexts, actionConfig, ruleName }) {
|
||||||
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
const countersPlugin = pluginData.getPlugin(CountersPlugin);
|
||||||
if (!countersPlugin.counterExists(actionConfig.counter)) {
|
if (!countersPlugin.counterExists(actionConfig.counter)) {
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
import { ChannelType, GuildTextBasedChannel, Snowflake } from "discord.js";
|
import { ChannelType, GuildTextBasedChannel, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { convertDelayStringToMS, isDiscordAPIError, tDelayString, tNullable } from "../../../utils";
|
import { convertDelayStringToMS, isDiscordAPIError, zDelayString, zSnowflake } from "../../../utils";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
export const SetSlowmodeAction = automodAction({
|
export const SetSlowmodeAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
channels: t.array(t.string),
|
channels: z.array(zSnowflake),
|
||||||
duration: tNullable(tDelayString),
|
duration: zDelayString.nullable().default("10s"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultConfig: {
|
|
||||||
duration: "10s",
|
|
||||||
},
|
|
||||||
|
|
||||||
async apply({ pluginData, actionConfig }) {
|
async apply({ pluginData, actionConfig }) {
|
||||||
const slowmodeMs = Math.max(actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : 0, 0);
|
const slowmodeMs = Math.max(actionConfig.duration ? convertDelayStringToMS(actionConfig.duration)! : 0, 0);
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ import {
|
||||||
ThreadAutoArchiveDuration,
|
ThreadAutoArchiveDuration,
|
||||||
ThreadChannel,
|
ThreadChannel,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
||||||
import { MINUTES, convertDelayStringToMS, noop, tDelayString, tNullable } from "../../../utils";
|
import { MINUTES, convertDelayStringToMS, noop, zBoundedCharacters, zDelayString } from "../../../utils";
|
||||||
import { savedMessageToTemplateSafeSavedMessage, userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
|
import { savedMessageToTemplateSafeSavedMessage, userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
|
||||||
|
@ -19,18 +19,14 @@ const validThreadAutoArchiveDurations: ThreadAutoArchiveDuration[] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export const StartThreadAction = automodAction({
|
export const StartThreadAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
name: tNullable(t.string),
|
name: zBoundedCharacters(1, 100).nullable(),
|
||||||
auto_archive: tDelayString,
|
auto_archive: zDelayString,
|
||||||
private: tNullable(t.boolean),
|
private: z.boolean().default(false),
|
||||||
slowmode: tNullable(tDelayString),
|
slowmode: zDelayString.nullable().default(null),
|
||||||
limit_per_channel: tNullable(t.number),
|
limit_per_channel: z.number().nullable().default(5),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultConfig: {
|
|
||||||
limit_per_channel: 5,
|
|
||||||
},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig }) {
|
async apply({ pluginData, contexts, actionConfig }) {
|
||||||
// check if the message still exists, we don't want to create threads for deleted messages
|
// check if the message still exists, we don't want to create threads for deleted messages
|
||||||
const threads = contexts.filter((c) => {
|
const threads = contexts.filter((c) => {
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { asyncMap, nonNullish, resolveMember, tNullable, unique } from "../../../utils";
|
import { asyncMap, nonNullish, resolveMember, unique, zBoundedCharacters, zSnowflake } from "../../../utils";
|
||||||
import { CaseArgs } from "../../Cases/types";
|
import { CaseArgs } from "../../Cases/types";
|
||||||
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin";
|
||||||
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
import { resolveActionContactMethods } from "../functions/resolveActionContactMethods";
|
||||||
import { automodAction } from "../helpers";
|
import { automodAction } from "../helpers";
|
||||||
|
import { zNotify } from "../types";
|
||||||
|
|
||||||
export const WarnAction = automodAction({
|
export const WarnAction = automodAction({
|
||||||
configType: t.type({
|
configSchema: z.strictObject({
|
||||||
reason: tNullable(t.string),
|
reason: zBoundedCharacters(0, 4000).nullable().default(null),
|
||||||
notify: tNullable(t.string),
|
notify: zNotify.nullable().default(null),
|
||||||
notifyChannel: tNullable(t.string),
|
notifyChannel: zSnowflake.nullable().default(null),
|
||||||
postInCaseLog: tNullable(t.boolean),
|
postInCaseLog: z.boolean().nullable().default(null),
|
||||||
hide_case: tNullable(t.boolean),
|
hide_case: z.boolean().nullable().default(false),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultConfig: {
|
|
||||||
notify: null, // Use defaults from ModActions
|
|
||||||
hide_case: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async apply({ pluginData, contexts, actionConfig, matchResult }) {
|
async apply({ pluginData, contexts, actionConfig, matchResult }) {
|
||||||
const reason = actionConfig.reason || "Warned automatically";
|
const reason = actionConfig.reason || "Warned automatically";
|
||||||
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
const contactMethods = actionConfig.notify ? resolveActionContactMethods(pluginData, actionConfig) : undefined;
|
||||||
|
|
|
@ -1,28 +1,27 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../../data/entities/SavedMessage";
|
||||||
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
||||||
import { getBaseUrl } from "../../../pluginUtils";
|
import { getBaseUrl } from "../../../pluginUtils";
|
||||||
import { convertDelayStringToMS, sorter, tDelayString, tNullable } from "../../../utils";
|
import { convertDelayStringToMS, sorter, zDelayString } from "../../../utils";
|
||||||
import { RecentActionType } from "../constants";
|
import { RecentActionType } from "../constants";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
import { findRecentSpam } from "./findRecentSpam";
|
import { findRecentSpam } from "./findRecentSpam";
|
||||||
import { getMatchingMessageRecentActions } from "./getMatchingMessageRecentActions";
|
import { getMatchingMessageRecentActions } from "./getMatchingMessageRecentActions";
|
||||||
import { getMessageSpamIdentifier } from "./getSpamIdentifier";
|
import { getMessageSpamIdentifier } from "./getSpamIdentifier";
|
||||||
|
import z from "zod";
|
||||||
const MessageSpamTriggerConfig = t.type({
|
|
||||||
amount: t.number,
|
|
||||||
within: tDelayString,
|
|
||||||
per_channel: tNullable(t.boolean),
|
|
||||||
});
|
|
||||||
|
|
||||||
interface TMessageSpamMatchResultType {
|
interface TMessageSpamMatchResultType {
|
||||||
archiveId: string;
|
archiveId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({
|
||||||
|
amount: z.number().int(),
|
||||||
|
within: zDelayString,
|
||||||
|
per_channel: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
export function createMessageSpamTrigger(spamType: RecentActionType, prettyName: string) {
|
export function createMessageSpamTrigger(spamType: RecentActionType, prettyName: string) {
|
||||||
return automodTrigger<TMessageSpamMatchResultType>()({
|
return automodTrigger<TMessageSpamMatchResultType>()({
|
||||||
configType: MessageSpamTriggerConfig,
|
configSchema,
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async match({ pluginData, context, triggerConfig }) {
|
async match({ pluginData, context, triggerConfig }) {
|
||||||
if (!context.message) {
|
if (!context.message) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { Awaitable } from "../../utils/typeUtils";
|
import { Awaitable } from "../../utils/typeUtils";
|
||||||
import { AutomodContext, AutomodPluginType } from "./types";
|
import { AutomodContext, AutomodPluginType } from "./types";
|
||||||
|
import z, { ZodTypeAny } from "zod";
|
||||||
|
|
||||||
interface BaseAutomodTriggerMatchResult {
|
interface BaseAutomodTriggerMatchResult {
|
||||||
extraContexts?: AutomodContext[];
|
extraContexts?: AutomodContext[];
|
||||||
|
@ -31,21 +31,19 @@ type AutomodTriggerRenderMatchInformationFn<TConfigType, TMatchResultExtra> = (m
|
||||||
matchResult: AutomodTriggerMatchResult<TMatchResultExtra>;
|
matchResult: AutomodTriggerMatchResult<TMatchResultExtra>;
|
||||||
}) => Awaitable<string>;
|
}) => Awaitable<string>;
|
||||||
|
|
||||||
export interface AutomodTriggerBlueprint<TConfigType extends t.Any, TMatchResultExtra> {
|
export interface AutomodTriggerBlueprint<TConfigSchema extends ZodTypeAny, TMatchResultExtra> {
|
||||||
configType: TConfigType;
|
configSchema: TConfigSchema;
|
||||||
defaultConfig: Partial<t.TypeOf<TConfigType>>;
|
match: AutomodTriggerMatchFn<z.output<TConfigSchema>, TMatchResultExtra>;
|
||||||
|
renderMatchInformation: AutomodTriggerRenderMatchInformationFn<z.output<TConfigSchema>, TMatchResultExtra>;
|
||||||
match: AutomodTriggerMatchFn<t.TypeOf<TConfigType>, TMatchResultExtra>;
|
|
||||||
renderMatchInformation: AutomodTriggerRenderMatchInformationFn<t.TypeOf<TConfigType>, TMatchResultExtra>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function automodTrigger<TMatchResultExtra>(): <TConfigType extends t.Any>(
|
export function automodTrigger<TMatchResultExtra>(): <TConfigSchema extends ZodTypeAny>(
|
||||||
blueprint: AutomodTriggerBlueprint<TConfigType, TMatchResultExtra>,
|
blueprint: AutomodTriggerBlueprint<TConfigSchema, TMatchResultExtra>,
|
||||||
) => AutomodTriggerBlueprint<TConfigType, TMatchResultExtra>;
|
) => AutomodTriggerBlueprint<TConfigSchema, TMatchResultExtra>;
|
||||||
|
|
||||||
export function automodTrigger<TConfigType extends t.Any>(
|
export function automodTrigger<TConfigSchema extends ZodTypeAny>(
|
||||||
blueprint: AutomodTriggerBlueprint<TConfigType, unknown>,
|
blueprint: AutomodTriggerBlueprint<TConfigSchema, unknown>,
|
||||||
): AutomodTriggerBlueprint<TConfigType, unknown>;
|
): AutomodTriggerBlueprint<TConfigSchema, unknown>;
|
||||||
|
|
||||||
export function automodTrigger(...args) {
|
export function automodTrigger(...args) {
|
||||||
if (args.length) {
|
if (args.length) {
|
||||||
|
@ -63,15 +61,13 @@ type AutomodActionApplyFn<TConfigType> = (meta: {
|
||||||
matchResult: AutomodTriggerMatchResult;
|
matchResult: AutomodTriggerMatchResult;
|
||||||
}) => Awaitable<void>;
|
}) => Awaitable<void>;
|
||||||
|
|
||||||
export interface AutomodActionBlueprint<TConfigType extends t.Any> {
|
export interface AutomodActionBlueprint<TConfigSchema extends ZodTypeAny> {
|
||||||
configType: TConfigType;
|
configSchema: TConfigSchema;
|
||||||
defaultConfig: Partial<t.TypeOf<TConfigType>>;
|
apply: AutomodActionApplyFn<z.output<TConfigSchema>>;
|
||||||
|
|
||||||
apply: AutomodActionApplyFn<t.TypeOf<TConfigType>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function automodAction<TConfigType extends t.Any>(
|
export function automodAction<TConfigSchema extends ZodTypeAny>(
|
||||||
blueprint: AutomodActionBlueprint<TConfigType>,
|
blueprint: AutomodActionBlueprint<TConfigSchema>,
|
||||||
): AutomodActionBlueprint<TConfigType> {
|
): AutomodActionBlueprint<TConfigSchema> {
|
||||||
return blueprint;
|
return blueprint;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { trimPluginDescription } from "../../utils";
|
||||||
import { ZeppelinGuildPluginBlueprint } from "../ZeppelinPluginBlueprint";
|
import { ZeppelinGuildPluginBlueprint } from "../ZeppelinPluginBlueprint";
|
||||||
import { ConfigSchema } from "./types";
|
import { zAutomodConfig } from "./types";
|
||||||
|
|
||||||
export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
|
export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
|
||||||
prettyName: "Automod",
|
prettyName: "Automod",
|
||||||
|
@ -100,5 +100,5 @@ export const pluginInfo: ZeppelinGuildPluginBlueprint["info"] = {
|
||||||
{matchSummary}
|
{matchSummary}
|
||||||
~~~
|
~~~
|
||||||
`),
|
`),
|
||||||
configSchema: ConfigSchema,
|
configSchema: zAutomodConfig,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { tNullable } from "../../../utils";
|
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
interface AntiraidLevelTriggerResult {}
|
interface AntiraidLevelTriggerResult {}
|
||||||
|
|
||||||
export const AntiraidLevelTrigger = automodTrigger<AntiraidLevelTriggerResult>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
level: z.nullable(z.string().max(100)),
|
||||||
level: tNullable(t.string),
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const AntiraidLevelTrigger = automodTrigger<AntiraidLevelTriggerResult>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ triggerConfig, context }) {
|
async match({ triggerConfig, context }) {
|
||||||
if (!context.antiraid) {
|
if (!context.antiraid) {
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { Snowflake } from "discord.js";
|
import { Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { verboseChannelMention } from "../../../utils";
|
import { verboseChannelMention } from "../../../utils";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
interface AnyMessageResultType {}
|
interface AnyMessageResultType {}
|
||||||
|
|
||||||
export const AnyMessageTrigger = automodTrigger<AnyMessageResultType>()({
|
const configSchema = z.strictObject({});
|
||||||
configType: t.type({}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const AnyMessageTrigger = automodTrigger<AnyMessageResultType>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ context }) {
|
async match({ context }) {
|
||||||
if (!context.message) {
|
if (!context.message) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { AutomodTriggerBlueprint } from "../helpers";
|
import { AutomodTriggerBlueprint } from "../helpers";
|
||||||
import { AntiraidLevelTrigger } from "./antiraidLevel";
|
import { AntiraidLevelTrigger } from "./antiraidLevel";
|
||||||
import { AnyMessageTrigger } from "./anyMessage";
|
import { AnyMessageTrigger } from "./anyMessage";
|
||||||
|
@ -45,6 +44,7 @@ export const availableTriggers: Record<string, AutomodTriggerBlueprint<any, any>
|
||||||
match_attachment_type: MatchAttachmentTypeTrigger,
|
match_attachment_type: MatchAttachmentTypeTrigger,
|
||||||
match_mime_type: MatchMimeTypeTrigger,
|
match_mime_type: MatchMimeTypeTrigger,
|
||||||
member_join: MemberJoinTrigger,
|
member_join: MemberJoinTrigger,
|
||||||
|
member_leave: MemberLeaveTrigger,
|
||||||
role_added: RoleAddedTrigger,
|
role_added: RoleAddedTrigger,
|
||||||
role_removed: RoleRemovedTrigger,
|
role_removed: RoleRemovedTrigger,
|
||||||
|
|
||||||
|
@ -76,46 +76,3 @@ export const availableTriggers: Record<string, AutomodTriggerBlueprint<any, any>
|
||||||
thread_archive: ThreadArchiveTrigger,
|
thread_archive: ThreadArchiveTrigger,
|
||||||
thread_unarchive: ThreadUnarchiveTrigger,
|
thread_unarchive: ThreadUnarchiveTrigger,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AvailableTriggers = t.type({
|
|
||||||
any_message: AnyMessageTrigger.configType,
|
|
||||||
|
|
||||||
match_words: MatchWordsTrigger.configType,
|
|
||||||
match_regex: MatchRegexTrigger.configType,
|
|
||||||
match_invites: MatchInvitesTrigger.configType,
|
|
||||||
match_links: MatchLinksTrigger.configType,
|
|
||||||
match_attachment_type: MatchAttachmentTypeTrigger.configType,
|
|
||||||
match_mime_type: MatchMimeTypeTrigger.configType,
|
|
||||||
member_join: MemberJoinTrigger.configType,
|
|
||||||
member_leave: MemberLeaveTrigger.configType,
|
|
||||||
role_added: RoleAddedTrigger.configType,
|
|
||||||
role_removed: RoleRemovedTrigger.configType,
|
|
||||||
|
|
||||||
message_spam: MessageSpamTrigger.configType,
|
|
||||||
mention_spam: MentionSpamTrigger.configType,
|
|
||||||
link_spam: LinkSpamTrigger.configType,
|
|
||||||
attachment_spam: AttachmentSpamTrigger.configType,
|
|
||||||
emoji_spam: EmojiSpamTrigger.configType,
|
|
||||||
line_spam: LineSpamTrigger.configType,
|
|
||||||
character_spam: CharacterSpamTrigger.configType,
|
|
||||||
member_join_spam: MemberJoinSpamTrigger.configType,
|
|
||||||
sticker_spam: StickerSpamTrigger.configType,
|
|
||||||
thread_create_spam: ThreadCreateSpamTrigger.configType,
|
|
||||||
|
|
||||||
counter_trigger: CounterTrigger.configType,
|
|
||||||
|
|
||||||
note: NoteTrigger.configType,
|
|
||||||
warn: WarnTrigger.configType,
|
|
||||||
mute: MuteTrigger.configType,
|
|
||||||
unmute: UnmuteTrigger.configType,
|
|
||||||
kick: KickTrigger.configType,
|
|
||||||
ban: BanTrigger.configType,
|
|
||||||
unban: UnbanTrigger.configType,
|
|
||||||
|
|
||||||
antiraid_level: AntiraidLevelTrigger.configType,
|
|
||||||
|
|
||||||
thread_create: ThreadCreateTrigger.configType,
|
|
||||||
thread_delete: ThreadDeleteTrigger.configType,
|
|
||||||
thread_archive: ThreadArchiveTrigger.configType,
|
|
||||||
thread_unarchive: ThreadUnarchiveTrigger.configType,
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface BanTriggerResultType {}
|
interface BanTriggerResultType {}
|
||||||
|
|
||||||
export const BanTrigger = automodTrigger<BanTriggerResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
manual: z.boolean().default(true),
|
||||||
manual: t.boolean,
|
automatic: z.boolean().default(true),
|
||||||
automatic: t.boolean,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const BanTrigger = automodTrigger<BanTriggerResultType>()({
|
||||||
manual: true,
|
configSchema,
|
||||||
automatic: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ context, triggerConfig }) {
|
async match({ context, triggerConfig }) {
|
||||||
if (context.modAction?.type !== "ban") {
|
if (context.modAction?.type !== "ban") {
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { tNullable } from "../../../utils";
|
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
interface CounterTriggerResult {}
|
interface CounterTriggerResult {}
|
||||||
|
|
||||||
export const CounterTrigger = automodTrigger<CounterTriggerResult>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
counter: z.string().max(100),
|
||||||
counter: t.string,
|
trigger: z.string().max(100),
|
||||||
trigger: t.string,
|
reverse: z.boolean().optional(),
|
||||||
reverse: tNullable(t.boolean),
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const CounterTrigger = automodTrigger<CounterTriggerResult>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ triggerConfig, context }) {
|
async match({ triggerConfig, context }) {
|
||||||
if (!context.counterTrigger) {
|
if (!context.counterTrigger) {
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
interface ExampleMatchResultType {
|
interface ExampleMatchResultType {
|
||||||
isBanana: boolean;
|
isBanana: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExampleTrigger = automodTrigger<ExampleMatchResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
allowedFruits: z.array(z.string().max(100)).max(50).default(["peach", "banana"]),
|
||||||
allowedFruits: t.array(t.string),
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const ExampleTrigger = automodTrigger<ExampleMatchResultType>()({
|
||||||
allowedFruits: ["peach", "banana"],
|
configSchema,
|
||||||
},
|
|
||||||
|
|
||||||
async match({ triggerConfig, context }) {
|
async match({ triggerConfig, context }) {
|
||||||
const foundFruit = triggerConfig.allowedFruits.find((fruit) => context.message?.data.content === fruit);
|
const foundFruit = triggerConfig.allowedFruits.find((fruit) => context.message?.data.content === fruit);
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface KickTriggerResultType {}
|
interface KickTriggerResultType {}
|
||||||
|
|
||||||
export const KickTrigger = automodTrigger<KickTriggerResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
manual: z.boolean().default(true),
|
||||||
manual: t.boolean,
|
automatic: z.boolean().default(true),
|
||||||
automatic: t.boolean,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const KickTrigger = automodTrigger<KickTriggerResultType>()({
|
||||||
manual: true,
|
configSchema,
|
||||||
automatic: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ context, triggerConfig }) {
|
async match({ context, triggerConfig }) {
|
||||||
if (context.modAction?.type !== "kick") {
|
if (context.modAction?.type !== "kick") {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { escapeInlineCode, Snowflake } from "discord.js";
|
import { escapeInlineCode, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { asSingleLine, messageSummary, verboseChannelMention } from "../../../utils";
|
import { asSingleLine, messageSummary, verboseChannelMention } from "../../../utils";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
|
@ -8,20 +8,31 @@ interface MatchResultType {
|
||||||
mode: "blacklist" | "whitelist";
|
mode: "blacklist" | "whitelist";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
filetype_blacklist: z.array(z.string().max(32)).max(255).default([]),
|
||||||
filetype_blacklist: t.array(t.string),
|
blacklist_enabled: z.boolean().default(false),
|
||||||
blacklist_enabled: t.boolean,
|
filetype_whitelist: z.array(z.string().max(32)).max(255).default([]),
|
||||||
filetype_whitelist: t.array(t.string),
|
whitelist_enabled: z.boolean().default(false),
|
||||||
whitelist_enabled: t.boolean,
|
}).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;
|
||||||
|
});
|
||||||
|
|
||||||
defaultConfig: {
|
export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
|
||||||
filetype_blacklist: [],
|
configSchema,
|
||||||
blacklist_enabled: false,
|
|
||||||
filetype_whitelist: [],
|
|
||||||
whitelist_enabled: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ context, triggerConfig: trigger }) {
|
async match({ context, triggerConfig: trigger }) {
|
||||||
if (!context.message) {
|
if (!context.message) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { getInviteCodesInString, GuildInvite, isGuildInvite, resolveInvite, tNullable } from "../../../utils";
|
import { getInviteCodesInString, GuildInvite, isGuildInvite, resolveInvite, zSnowflake } from "../../../utils";
|
||||||
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
||||||
import { MatchableTextType, matchMultipleTextTypesOnMessage } from "../functions/matchMultipleTextTypesOnMessage";
|
import { MatchableTextType, matchMultipleTextTypesOnMessage } from "../functions/matchMultipleTextTypesOnMessage";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
@ -10,30 +10,22 @@ interface MatchResultType {
|
||||||
invite?: GuildInvite;
|
invite?: GuildInvite;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MatchInvitesTrigger = automodTrigger<MatchResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
include_guilds: z.array(zSnowflake).max(255).optional(),
|
||||||
include_guilds: tNullable(t.array(t.string)),
|
exclude_guilds: z.array(zSnowflake).max(255).optional(),
|
||||||
exclude_guilds: tNullable(t.array(t.string)),
|
include_invite_codes: z.array(z.string().max(32)).max(255).optional(),
|
||||||
include_invite_codes: tNullable(t.array(t.string)),
|
exclude_invite_codes: z.array(z.string().max(32)).max(255).optional(),
|
||||||
exclude_invite_codes: tNullable(t.array(t.string)),
|
allow_group_dm_invites: z.boolean().default(false),
|
||||||
allow_group_dm_invites: t.boolean,
|
match_messages: z.boolean().default(true),
|
||||||
match_messages: t.boolean,
|
match_embeds: z.boolean().default(false),
|
||||||
match_embeds: t.boolean,
|
match_visible_names: z.boolean().default(false),
|
||||||
match_visible_names: t.boolean,
|
match_usernames: z.boolean().default(false),
|
||||||
match_usernames: t.boolean,
|
match_nicknames: z.boolean().default(false),
|
||||||
match_nicknames: t.boolean,
|
match_custom_status: z.boolean().default(false),
|
||||||
match_custom_status: t.boolean,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const MatchInvitesTrigger = automodTrigger<MatchResultType>()({
|
||||||
allow_group_dm_invites: false,
|
configSchema,
|
||||||
match_messages: true,
|
|
||||||
match_embeds: false,
|
|
||||||
match_visible_names: false,
|
|
||||||
match_usernames: false,
|
|
||||||
match_nicknames: false,
|
|
||||||
match_custom_status: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ pluginData, context, triggerConfig: trigger }) {
|
async match({ pluginData, context, triggerConfig: trigger }) {
|
||||||
if (!context.message) {
|
if (!context.message) {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { escapeInlineCode } from "discord.js";
|
import { escapeInlineCode } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { allowTimeout } from "../../../RegExpRunner";
|
import { allowTimeout } from "../../../RegExpRunner";
|
||||||
import { phishermanDomainIsSafe } from "../../../data/Phisherman";
|
import { phishermanDomainIsSafe } from "../../../data/Phisherman";
|
||||||
import { getUrlsInString, tNullable } from "../../../utils";
|
import { getUrlsInString, zRegex } from "../../../utils";
|
||||||
import { mergeRegexes } from "../../../utils/mergeRegexes";
|
import { mergeRegexes } from "../../../utils/mergeRegexes";
|
||||||
import { mergeWordsIntoRegex } from "../../../utils/mergeWordsIntoRegex";
|
import { mergeWordsIntoRegex } from "../../../utils/mergeWordsIntoRegex";
|
||||||
import { TRegex } from "../../../validatorUtils";
|
|
||||||
import { PhishermanPlugin } from "../../Phisherman/PhishermanPlugin";
|
import { PhishermanPlugin } from "../../Phisherman/PhishermanPlugin";
|
||||||
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
||||||
import { MatchableTextType, matchMultipleTextTypesOnMessage } from "../functions/matchMultipleTextTypesOnMessage";
|
import { MatchableTextType, matchMultipleTextTypesOnMessage } from "../functions/matchMultipleTextTypesOnMessage";
|
||||||
|
@ -21,40 +20,29 @@ const regexCache = new WeakMap<any, RegExp[]>();
|
||||||
|
|
||||||
const quickLinkCheck = /^https?:\/\//i;
|
const quickLinkCheck = /^https?:\/\//i;
|
||||||
|
|
||||||
export const MatchLinksTrigger = automodTrigger<MatchResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
include_domains: z.array(z.string().max(255)).max(255).optional(),
|
||||||
include_domains: tNullable(t.array(t.string)),
|
exclude_domains: z.array(z.string().max(255)).max(255).optional(),
|
||||||
exclude_domains: tNullable(t.array(t.string)),
|
include_subdomains: z.boolean().default(true),
|
||||||
include_subdomains: t.boolean,
|
include_words: z.array(z.string().max(2000)).max(512).optional(),
|
||||||
include_words: tNullable(t.array(t.string)),
|
exclude_words: z.array(z.string().max(2000)).max(512).optional(),
|
||||||
exclude_words: tNullable(t.array(t.string)),
|
include_regex: z.array(zRegex(z.string().max(2000))).max(512).optional(),
|
||||||
include_regex: tNullable(t.array(TRegex)),
|
exclude_regex: z.array(zRegex(z.string().max(2000))).max(512).optional(),
|
||||||
exclude_regex: tNullable(t.array(TRegex)),
|
phisherman: z.strictObject({
|
||||||
phisherman: tNullable(
|
include_suspected: z.boolean().optional(),
|
||||||
t.type({
|
include_verified: z.boolean().optional(),
|
||||||
include_suspected: tNullable(t.boolean),
|
}).optional(),
|
||||||
include_verified: tNullable(t.boolean),
|
only_real_links: z.boolean(),
|
||||||
}),
|
match_messages: z.boolean().default(true),
|
||||||
),
|
match_embeds: z.boolean().default(true),
|
||||||
only_real_links: t.boolean,
|
match_visible_names: z.boolean().default(false),
|
||||||
match_messages: t.boolean,
|
match_usernames: z.boolean().default(false),
|
||||||
match_embeds: t.boolean,
|
match_nicknames: z.boolean().default(false),
|
||||||
match_visible_names: t.boolean,
|
match_custom_status: z.boolean().default(false),
|
||||||
match_usernames: t.boolean,
|
});
|
||||||
match_nicknames: t.boolean,
|
|
||||||
match_custom_status: t.boolean,
|
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const MatchLinksTrigger = automodTrigger<MatchResultType>()({
|
||||||
include_subdomains: true,
|
configSchema,
|
||||||
match_messages: true,
|
|
||||||
match_embeds: false,
|
|
||||||
match_visible_names: false,
|
|
||||||
match_usernames: false,
|
|
||||||
match_nicknames: false,
|
|
||||||
match_custom_status: false,
|
|
||||||
only_real_links: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ pluginData, context, triggerConfig: trigger }) {
|
async match({ pluginData, context, triggerConfig: trigger }) {
|
||||||
if (!context.message) {
|
if (!context.message) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { escapeInlineCode } from "discord.js";
|
import { escapeInlineCode } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { asSingleLine, messageSummary, verboseChannelMention } from "../../../utils";
|
import { asSingleLine, messageSummary, verboseChannelMention } from "../../../utils";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
|
@ -8,20 +8,31 @@ interface MatchResultType {
|
||||||
mode: "blacklist" | "whitelist";
|
mode: "blacklist" | "whitelist";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MatchMimeTypeTrigger = automodTrigger<MatchResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
mime_type_blacklist: z.array(z.string().max(255)).max(255).default([]),
|
||||||
mime_type_blacklist: t.array(t.string),
|
blacklist_enabled: z.boolean().default(false),
|
||||||
blacklist_enabled: t.boolean,
|
mime_type_whitelist: z.array(z.string().max(255)).max(255).default([]),
|
||||||
mime_type_whitelist: t.array(t.string),
|
whitelist_enabled: z.boolean().default(false),
|
||||||
whitelist_enabled: t.boolean,
|
}).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;
|
||||||
|
});
|
||||||
|
|
||||||
defaultConfig: {
|
export const MatchMimeTypeTrigger = automodTrigger<MatchResultType>()({
|
||||||
mime_type_blacklist: [],
|
configSchema,
|
||||||
blacklist_enabled: false,
|
|
||||||
mime_type_whitelist: [],
|
|
||||||
whitelist_enabled: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ context, triggerConfig: trigger }) {
|
async match({ context, triggerConfig: trigger }) {
|
||||||
if (!context.message) return;
|
if (!context.message) return;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { allowTimeout } from "../../../RegExpRunner";
|
import { allowTimeout } from "../../../RegExpRunner";
|
||||||
|
import { zRegex } from "../../../utils";
|
||||||
import { mergeRegexes } from "../../../utils/mergeRegexes";
|
import { mergeRegexes } from "../../../utils/mergeRegexes";
|
||||||
import { normalizeText } from "../../../utils/normalizeText";
|
import { normalizeText } from "../../../utils/normalizeText";
|
||||||
import { stripMarkdown } from "../../../utils/stripMarkdown";
|
import { stripMarkdown } from "../../../utils/stripMarkdown";
|
||||||
import { TRegex } from "../../../validatorUtils";
|
|
||||||
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
||||||
import { MatchableTextType, matchMultipleTextTypesOnMessage } from "../functions/matchMultipleTextTypesOnMessage";
|
import { MatchableTextType, matchMultipleTextTypesOnMessage } from "../functions/matchMultipleTextTypesOnMessage";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
@ -13,33 +13,23 @@ interface MatchResultType {
|
||||||
type: MatchableTextType;
|
type: MatchableTextType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({
|
||||||
|
patterns: z.array(zRegex(z.string().max(2000))).max(512),
|
||||||
|
case_sensitive: z.boolean().default(false),
|
||||||
|
normalize: z.boolean().default(false),
|
||||||
|
strip_markdown: z.boolean().default(false),
|
||||||
|
match_messages: z.boolean().default(true),
|
||||||
|
match_embeds: z.boolean().default(false),
|
||||||
|
match_visible_names: z.boolean().default(false),
|
||||||
|
match_usernames: z.boolean().default(false),
|
||||||
|
match_nicknames: z.boolean().default(false),
|
||||||
|
match_custom_status: z.boolean().default(false),
|
||||||
|
});
|
||||||
|
|
||||||
const regexCache = new WeakMap<any, RegExp[]>();
|
const regexCache = new WeakMap<any, RegExp[]>();
|
||||||
|
|
||||||
export const MatchRegexTrigger = automodTrigger<MatchResultType>()({
|
export const MatchRegexTrigger = automodTrigger<MatchResultType>()({
|
||||||
configType: t.type({
|
configSchema,
|
||||||
patterns: t.array(TRegex),
|
|
||||||
case_sensitive: t.boolean,
|
|
||||||
normalize: t.boolean,
|
|
||||||
strip_markdown: t.boolean,
|
|
||||||
match_messages: t.boolean,
|
|
||||||
match_embeds: t.boolean,
|
|
||||||
match_visible_names: t.boolean,
|
|
||||||
match_usernames: t.boolean,
|
|
||||||
match_nicknames: t.boolean,
|
|
||||||
match_custom_status: t.boolean,
|
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
|
||||||
case_sensitive: false,
|
|
||||||
normalize: false,
|
|
||||||
strip_markdown: false,
|
|
||||||
match_messages: true,
|
|
||||||
match_embeds: false,
|
|
||||||
match_visible_names: false,
|
|
||||||
match_usernames: false,
|
|
||||||
match_nicknames: false,
|
|
||||||
match_custom_status: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ pluginData, context, triggerConfig: trigger }) {
|
async match({ pluginData, context, triggerConfig: trigger }) {
|
||||||
if (!context.message) {
|
if (!context.message) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import escapeStringRegexp from "escape-string-regexp";
|
import escapeStringRegexp from "escape-string-regexp";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { normalizeText } from "../../../utils/normalizeText";
|
import { normalizeText } from "../../../utils/normalizeText";
|
||||||
import { stripMarkdown } from "../../../utils/stripMarkdown";
|
import { stripMarkdown } from "../../../utils/stripMarkdown";
|
||||||
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary";
|
||||||
|
@ -13,37 +13,24 @@ interface MatchResultType {
|
||||||
|
|
||||||
const regexCache = new WeakMap<any, RegExp[]>();
|
const regexCache = new WeakMap<any, RegExp[]>();
|
||||||
|
|
||||||
export const MatchWordsTrigger = automodTrigger<MatchResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
words: z.array(z.string().max(2000)).max(512),
|
||||||
words: t.array(t.string),
|
case_sensitive: z.boolean().default(false),
|
||||||
case_sensitive: t.boolean,
|
only_full_words: z.boolean().default(true),
|
||||||
only_full_words: t.boolean,
|
normalize: z.boolean().default(false),
|
||||||
normalize: t.boolean,
|
loose_matching: z.boolean().default(false),
|
||||||
loose_matching: t.boolean,
|
loose_matching_threshold: z.number().int().default(4),
|
||||||
loose_matching_threshold: t.number,
|
strip_markdown: z.boolean().default(false),
|
||||||
strip_markdown: t.boolean,
|
match_messages: z.boolean().default(true),
|
||||||
match_messages: t.boolean,
|
match_embeds: z.boolean().default(false),
|
||||||
match_embeds: t.boolean,
|
match_visible_names: z.boolean().default(false),
|
||||||
match_visible_names: t.boolean,
|
match_usernames: z.boolean().default(false),
|
||||||
match_usernames: t.boolean,
|
match_nicknames: z.boolean().default(false),
|
||||||
match_nicknames: t.boolean,
|
match_custom_status: z.boolean().default(false),
|
||||||
match_custom_status: t.boolean,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const MatchWordsTrigger = automodTrigger<MatchResultType>()({
|
||||||
case_sensitive: false,
|
configSchema,
|
||||||
only_full_words: true,
|
|
||||||
normalize: false,
|
|
||||||
loose_matching: false,
|
|
||||||
loose_matching_threshold: 4,
|
|
||||||
strip_markdown: false,
|
|
||||||
match_messages: true,
|
|
||||||
match_embeds: false,
|
|
||||||
match_visible_names: false,
|
|
||||||
match_usernames: false,
|
|
||||||
match_nicknames: false,
|
|
||||||
match_custom_status: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ pluginData, context, triggerConfig: trigger }) {
|
async match({ pluginData, context, triggerConfig: trigger }) {
|
||||||
if (!context.message) {
|
if (!context.message) {
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { convertDelayStringToMS, tDelayString } from "../../../utils";
|
import { convertDelayStringToMS, zDelayString } from "../../../utils";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
export const MemberJoinTrigger = automodTrigger<unknown>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
only_new: z.boolean().default(false),
|
||||||
only_new: t.boolean,
|
new_threshold: zDelayString.default("1h"),
|
||||||
new_threshold: tDelayString,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const MemberJoinTrigger = automodTrigger<unknown>()({
|
||||||
only_new: false,
|
configSchema,
|
||||||
new_threshold: "1h",
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ context, triggerConfig }) {
|
async match({ context, triggerConfig }) {
|
||||||
if (!context.joined || !context.member) {
|
if (!context.joined || !context.member) {
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { convertDelayStringToMS, tDelayString } from "../../../utils";
|
import { convertDelayStringToMS, zDelayString } from "../../../utils";
|
||||||
import { RecentActionType } from "../constants";
|
import { RecentActionType } from "../constants";
|
||||||
import { findRecentSpam } from "../functions/findRecentSpam";
|
import { findRecentSpam } from "../functions/findRecentSpam";
|
||||||
import { getMatchingRecentActions } from "../functions/getMatchingRecentActions";
|
import { getMatchingRecentActions } from "../functions/getMatchingRecentActions";
|
||||||
import { sumRecentActionCounts } from "../functions/sumRecentActionCounts";
|
import { sumRecentActionCounts } from "../functions/sumRecentActionCounts";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
export const MemberJoinSpamTrigger = automodTrigger<unknown>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
amount: z.number().int(),
|
||||||
amount: t.number,
|
within: zDelayString,
|
||||||
within: tDelayString,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const MemberJoinSpamTrigger = automodTrigger<unknown>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ pluginData, context, triggerConfig }) {
|
async match({ pluginData, context, triggerConfig }) {
|
||||||
if (!context.joined || !context.member) {
|
if (!context.joined || !context.member) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
export const MemberLeaveTrigger = automodTrigger<unknown>()({
|
const configSchema = z.strictObject({});
|
||||||
configType: t.type({}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const MemberLeaveTrigger = automodTrigger<unknown>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ context }) {
|
async match({ context }) {
|
||||||
if (!context.joined || !context.member) {
|
if (!context.joined || !context.member) {
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface MuteTriggerResultType {}
|
interface MuteTriggerResultType {}
|
||||||
|
|
||||||
export const MuteTrigger = automodTrigger<MuteTriggerResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
manual: z.boolean().default(true),
|
||||||
manual: t.boolean,
|
automatic: z.boolean().default(true),
|
||||||
automatic: t.boolean,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const MuteTrigger = automodTrigger<MuteTriggerResultType>()({
|
||||||
manual: true,
|
configSchema,
|
||||||
automatic: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ context, triggerConfig }) {
|
async match({ context, triggerConfig }) {
|
||||||
if (context.modAction?.type !== "mute") {
|
if (context.modAction?.type !== "mute") {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface NoteTriggerResultType {}
|
interface NoteTriggerResultType {}
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({});
|
||||||
|
|
||||||
export const NoteTrigger = automodTrigger<NoteTriggerResultType>()({
|
export const NoteTrigger = automodTrigger<NoteTriggerResultType>()({
|
||||||
configType: t.type({}),
|
configSchema,
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async match({ context }) {
|
async match({ context }) {
|
||||||
if (context.modAction?.type !== "note") {
|
if (context.modAction?.type !== "note") {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Snowflake } from "discord.js";
|
import { Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { renderUserUsername } from "../../../utils";
|
import { renderUserUsername, zSnowflake } from "../../../utils";
|
||||||
import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
|
import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
|
@ -8,10 +8,13 @@ interface RoleAddedMatchResult {
|
||||||
matchedRoleId: string;
|
matchedRoleId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RoleAddedTrigger = automodTrigger<RoleAddedMatchResult>()({
|
const configSchema = z.union([
|
||||||
configType: t.union([t.string, t.array(t.string)]),
|
zSnowflake,
|
||||||
|
z.array(zSnowflake).max(255),
|
||||||
|
]).default([]);
|
||||||
|
|
||||||
defaultConfig: "",
|
export const RoleAddedTrigger = automodTrigger<RoleAddedMatchResult>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ triggerConfig, context, pluginData }) {
|
async match({ triggerConfig, context, pluginData }) {
|
||||||
if (!context.member || !context.rolesChanged || context.rolesChanged.added!.length === 0) {
|
if (!context.member || !context.rolesChanged || context.rolesChanged.added!.length === 0) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Snowflake } from "discord.js";
|
import { Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { renderUserUsername } from "../../../utils";
|
import { renderUserUsername, zSnowflake } from "../../../utils";
|
||||||
import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
|
import { consumeIgnoredRoleChange } from "../functions/ignoredRoleChanges";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
|
@ -8,10 +8,13 @@ interface RoleAddedMatchResult {
|
||||||
matchedRoleId: string;
|
matchedRoleId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RoleRemovedTrigger = automodTrigger<RoleAddedMatchResult>()({
|
const configSchema = z.union([
|
||||||
configType: t.union([t.string, t.array(t.string)]),
|
zSnowflake,
|
||||||
|
z.array(zSnowflake).max(255),
|
||||||
|
]).default([]);
|
||||||
|
|
||||||
defaultConfig: "",
|
export const RoleRemovedTrigger = automodTrigger<RoleAddedMatchResult>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ triggerConfig, context, pluginData }) {
|
async match({ triggerConfig, context, pluginData }) {
|
||||||
if (!context.member || !context.rolesChanged || context.rolesChanged.removed!.length === 0) {
|
if (!context.member || !context.rolesChanged || context.rolesChanged.removed!.length === 0) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { User, escapeBold, type Snowflake } from "discord.js";
|
import { User, escapeBold, type Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { tNullable } from "../../../utils";
|
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
interface ThreadArchiveResult {
|
interface ThreadArchiveResult {
|
||||||
|
@ -11,12 +10,12 @@ interface ThreadArchiveResult {
|
||||||
matchedThreadOwner: User | undefined;
|
matchedThreadOwner: User | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ThreadArchiveTrigger = automodTrigger<ThreadArchiveResult>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
locked: z.boolean().optional(),
|
||||||
locked: tNullable(t.boolean),
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const ThreadArchiveTrigger = automodTrigger<ThreadArchiveResult>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ context, triggerConfig }) {
|
async match({ context, triggerConfig }) {
|
||||||
if (!context.threadChange?.archived) {
|
if (!context.threadChange?.archived) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { User, escapeBold, type Snowflake } from "discord.js";
|
import { User, escapeBold, type Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
interface ThreadCreateResult {
|
interface ThreadCreateResult {
|
||||||
|
@ -10,9 +10,10 @@ interface ThreadCreateResult {
|
||||||
matchedThreadOwner: User | undefined;
|
matchedThreadOwner: User | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({});
|
||||||
|
|
||||||
export const ThreadCreateTrigger = automodTrigger<ThreadCreateResult>()({
|
export const ThreadCreateTrigger = automodTrigger<ThreadCreateResult>()({
|
||||||
configType: t.type({}),
|
configSchema,
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async match({ context }) {
|
async match({ context }) {
|
||||||
if (!context.threadChange?.created) {
|
if (!context.threadChange?.created) {
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { convertDelayStringToMS, tDelayString } from "../../../utils";
|
import { convertDelayStringToMS, zDelayString } from "../../../utils";
|
||||||
import { RecentActionType } from "../constants";
|
import { RecentActionType } from "../constants";
|
||||||
import { findRecentSpam } from "../functions/findRecentSpam";
|
import { findRecentSpam } from "../functions/findRecentSpam";
|
||||||
import { getMatchingRecentActions } from "../functions/getMatchingRecentActions";
|
import { getMatchingRecentActions } from "../functions/getMatchingRecentActions";
|
||||||
import { sumRecentActionCounts } from "../functions/sumRecentActionCounts";
|
import { sumRecentActionCounts } from "../functions/sumRecentActionCounts";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
export const ThreadCreateSpamTrigger = automodTrigger<unknown>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
amount: z.number().int(),
|
||||||
amount: t.number,
|
within: zDelayString,
|
||||||
within: tDelayString,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const ThreadCreateSpamTrigger = automodTrigger<unknown>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ pluginData, context, triggerConfig }) {
|
async match({ pluginData, context, triggerConfig }) {
|
||||||
if (!context.threadChange?.created) {
|
if (!context.threadChange?.created) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { User, escapeBold, type Snowflake } from "discord.js";
|
import { User, escapeBold, type Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
interface ThreadDeleteResult {
|
interface ThreadDeleteResult {
|
||||||
|
@ -10,9 +10,10 @@ interface ThreadDeleteResult {
|
||||||
matchedThreadOwner: User | undefined;
|
matchedThreadOwner: User | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({});
|
||||||
|
|
||||||
export const ThreadDeleteTrigger = automodTrigger<ThreadDeleteResult>()({
|
export const ThreadDeleteTrigger = automodTrigger<ThreadDeleteResult>()({
|
||||||
configType: t.type({}),
|
configSchema,
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async match({ context }) {
|
async match({ context }) {
|
||||||
if (!context.threadChange?.deleted) {
|
if (!context.threadChange?.deleted) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { User, escapeBold, type Snowflake } from "discord.js";
|
import { User, escapeBold, type Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { tNullable } from "../../../utils";
|
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
interface ThreadUnarchiveResult {
|
interface ThreadUnarchiveResult {
|
||||||
|
@ -11,12 +10,12 @@ interface ThreadUnarchiveResult {
|
||||||
matchedThreadOwner: User | undefined;
|
matchedThreadOwner: User | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ThreadUnarchiveTrigger = automodTrigger<ThreadUnarchiveResult>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
locked: z.boolean().optional(),
|
||||||
locked: tNullable(t.boolean),
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {},
|
export const ThreadUnarchiveTrigger = automodTrigger<ThreadUnarchiveResult>()({
|
||||||
|
configSchema,
|
||||||
|
|
||||||
async match({ context, triggerConfig }) {
|
async match({ context, triggerConfig }) {
|
||||||
if (!context.threadChange?.unarchived) {
|
if (!context.threadChange?.unarchived) {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface UnbanTriggerResultType {}
|
interface UnbanTriggerResultType {}
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({});
|
||||||
|
|
||||||
export const UnbanTrigger = automodTrigger<UnbanTriggerResultType>()({
|
export const UnbanTrigger = automodTrigger<UnbanTriggerResultType>()({
|
||||||
configType: t.type({}),
|
configSchema,
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async match({ context }) {
|
async match({ context }) {
|
||||||
if (context.modAction?.type !== "unban") {
|
if (context.modAction?.type !== "unban") {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface UnmuteTriggerResultType {}
|
interface UnmuteTriggerResultType {}
|
||||||
|
|
||||||
|
const configSchema = z.strictObject({});
|
||||||
|
|
||||||
export const UnmuteTrigger = automodTrigger<UnmuteTriggerResultType>()({
|
export const UnmuteTrigger = automodTrigger<UnmuteTriggerResultType>()({
|
||||||
configType: t.type({}),
|
configSchema,
|
||||||
defaultConfig: {},
|
|
||||||
|
|
||||||
async match({ context }) {
|
async match({ context }) {
|
||||||
if (context.modAction?.type !== "unmute") {
|
if (context.modAction?.type !== "unmute") {
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { automodTrigger } from "../helpers";
|
import { automodTrigger } from "../helpers";
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface WarnTriggerResultType {}
|
interface WarnTriggerResultType {}
|
||||||
|
|
||||||
export const WarnTrigger = automodTrigger<WarnTriggerResultType>()({
|
const configSchema = z.strictObject({
|
||||||
configType: t.type({
|
manual: z.boolean().default(true),
|
||||||
manual: t.boolean,
|
automatic: z.boolean().default(true),
|
||||||
automatic: t.boolean,
|
});
|
||||||
}),
|
|
||||||
|
|
||||||
defaultConfig: {
|
export const WarnTrigger = automodTrigger<WarnTriggerResultType>()({
|
||||||
manual: true,
|
configSchema,
|
||||||
automatic: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
async match({ context, triggerConfig }) {
|
async match({ context, triggerConfig }) {
|
||||||
if (context.modAction?.type !== "warn") {
|
if (context.modAction?.type !== "warn") {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { GuildMember, GuildTextBasedChannel, PartialGuildMember, ThreadChannel, User } from "discord.js";
|
import { GuildMember, GuildTextBasedChannel, PartialGuildMember, ThreadChannel, User } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, CooldownManager } from "knub";
|
import { BasePluginType, CooldownManager } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
import { RegExpRunner } from "../../RegExpRunner";
|
import { RegExpRunner } from "../../RegExpRunner";
|
||||||
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
|
import { GuildAntiraidLevels } from "../../data/GuildAntiraidLevels";
|
||||||
|
@ -8,39 +8,81 @@ import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { SavedMessage } from "../../data/entities/SavedMessage";
|
import { SavedMessage } from "../../data/entities/SavedMessage";
|
||||||
import { tNullable } from "../../utils";
|
import { entries, zBoundedRecord, zDelayString } from "../../utils";
|
||||||
import { CounterEvents } from "../Counters/types";
|
import { CounterEvents } from "../Counters/types";
|
||||||
import { ModActionType, ModActionsEvents } from "../ModActions/types";
|
import { ModActionType, ModActionsEvents } from "../ModActions/types";
|
||||||
import { MutesEvents } from "../Mutes/types";
|
import { MutesEvents } from "../Mutes/types";
|
||||||
import { AvailableActions } from "./actions/availableActions";
|
import { availableActions } from "./actions/availableActions";
|
||||||
import { RecentActionType } from "./constants";
|
import { RecentActionType } from "./constants";
|
||||||
import { AvailableTriggers } from "./triggers/availableTriggers";
|
import { availableTriggers } from "./triggers/availableTriggers";
|
||||||
|
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
export const Rule = t.type({
|
export type ZTriggersMapHelper = {
|
||||||
enabled: t.boolean,
|
[TriggerName in keyof typeof availableTriggers]: typeof availableTriggers[TriggerName]["configSchema"];
|
||||||
name: t.string,
|
};
|
||||||
presets: tNullable(t.array(t.string)),
|
const zTriggersMap = z.strictObject(entries(availableTriggers).reduce((map, [triggerName, trigger]) => {
|
||||||
affects_bots: t.boolean,
|
map[triggerName] = trigger.configSchema;
|
||||||
affects_self: t.boolean,
|
return map;
|
||||||
triggers: t.array(t.partial(AvailableTriggers.props)),
|
}, {} as ZTriggersMapHelper)).partial();
|
||||||
actions: t.partial(AvailableActions.props),
|
|
||||||
cooldown: tNullable(t.string),
|
|
||||||
allow_further_rules: t.boolean,
|
|
||||||
});
|
|
||||||
export type TRule = t.TypeOf<typeof Rule>;
|
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
type ZActionsMapHelper = {
|
||||||
rules: t.record(t.string, Rule),
|
[ActionName in keyof typeof availableActions]: typeof availableActions[ActionName]["configSchema"];
|
||||||
antiraid_levels: t.array(t.string),
|
};
|
||||||
can_set_antiraid: t.boolean,
|
const zActionsMap = z.strictObject(entries(availableActions).reduce((map, [actionName, action]) => {
|
||||||
can_view_antiraid: t.boolean,
|
// @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;
|
||||||
|
}),
|
||||||
|
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",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
});
|
||||||
|
export type TRule = z.infer<typeof zRule>;
|
||||||
|
|
||||||
|
export const zNotify = z.union([
|
||||||
|
z.literal("dm"),
|
||||||
|
z.literal("channel"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const zAutomodConfig = z.strictObject({
|
||||||
|
rules: zBoundedRecord(
|
||||||
|
z.record(z.string().max(100), zRule),
|
||||||
|
0,
|
||||||
|
100,
|
||||||
|
),
|
||||||
|
antiraid_levels: z.array(z.string().max(100)).max(10),
|
||||||
|
can_set_antiraid: z.boolean(),
|
||||||
|
can_view_antiraid: z.boolean(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface AutomodPluginType extends BasePluginType {
|
export interface AutomodPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.output<typeof zAutomodConfig>;
|
||||||
|
|
||||||
customOverrideCriteria: {
|
customOverrideCriteria: {
|
||||||
antiraid_level?: string;
|
antiraid_level?: string;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { AllowedGuilds } from "../../data/AllowedGuilds";
|
||||||
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
||||||
import { Configs } from "../../data/Configs";
|
import { Configs } from "../../data/Configs";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { makeIoTsConfigParser, sendSuccessMessage } from "../../pluginUtils";
|
import { sendSuccessMessage } from "../../pluginUtils";
|
||||||
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { getActiveReload, resetActiveReload } from "./activeReload";
|
import { getActiveReload, resetActiveReload } from "./activeReload";
|
||||||
import { AddDashboardUserCmd } from "./commands/AddDashboardUserCmd";
|
import { AddDashboardUserCmd } from "./commands/AddDashboardUserCmd";
|
||||||
|
@ -22,7 +22,7 @@ import { ReloadServerCmd } from "./commands/ReloadServerCmd";
|
||||||
import { RemoveDashboardUserCmd } from "./commands/RemoveDashboardUserCmd";
|
import { RemoveDashboardUserCmd } from "./commands/RemoveDashboardUserCmd";
|
||||||
import { RestPerformanceCmd } from "./commands/RestPerformanceCmd";
|
import { RestPerformanceCmd } from "./commands/RestPerformanceCmd";
|
||||||
import { ServersCmd } from "./commands/ServersCmd";
|
import { ServersCmd } from "./commands/ServersCmd";
|
||||||
import { BotControlPluginType, ConfigSchema } from "./types";
|
import { BotControlPluginType, zBotControlConfig } from "./types";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -37,7 +37,7 @@ const defaultOptions = {
|
||||||
|
|
||||||
export const BotControlPlugin = zeppelinGlobalPlugin<BotControlPluginType>()({
|
export const BotControlPlugin = zeppelinGlobalPlugin<BotControlPluginType>()({
|
||||||
name: "bot_control",
|
name: "bot_control",
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zBotControlConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, globalPluginEventListener, globalPluginMessageCommand } from "knub";
|
import { BasePluginType, globalPluginEventListener, globalPluginMessageCommand } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
||||||
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
||||||
import { Configs } from "../../data/Configs";
|
import { Configs } from "../../data/Configs";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { tNullable } from "../../utils";
|
import { zBoundedCharacters } from "../../utils";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zBotControlConfig = z.strictObject({
|
||||||
can_use: t.boolean,
|
can_use: z.boolean(),
|
||||||
can_eligible: t.boolean,
|
can_eligible: z.boolean(),
|
||||||
can_performance: t.boolean,
|
can_performance: z.boolean(),
|
||||||
can_add_server_from_invite: t.boolean,
|
can_add_server_from_invite: z.boolean(),
|
||||||
can_list_dashboard_perms: t.boolean,
|
can_list_dashboard_perms: z.boolean(),
|
||||||
update_cmd: tNullable(t.string),
|
update_cmd: zBoundedCharacters(0, 2000).nullable(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface BotControlPluginType extends BasePluginType {
|
export interface BotControlPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.output<typeof zBotControlConfig>;
|
||||||
state: {
|
state: {
|
||||||
archives: GuildArchives;
|
archives: GuildArchives;
|
||||||
allowedGuilds: AllowedGuilds;
|
allowedGuilds: AllowedGuilds;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Case } from "../../data/entities/Case";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { GuildCases } from "../../data/GuildCases";
|
import { GuildCases } from "../../data/GuildCases";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { makeIoTsConfigParser, mapToPublicFn } from "../../pluginUtils";
|
import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { trimPluginDescription } from "../../utils";
|
||||||
import { InternalPosterPlugin } from "../InternalPoster/InternalPosterPlugin";
|
import { InternalPosterPlugin } from "../InternalPoster/InternalPosterPlugin";
|
||||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||||
|
@ -16,7 +16,7 @@ import { getCaseTypeAmountForUserId } from "./functions/getCaseTypeAmountForUser
|
||||||
import { getRecentCasesByMod } from "./functions/getRecentCasesByMod";
|
import { getRecentCasesByMod } from "./functions/getRecentCasesByMod";
|
||||||
import { getTotalCasesByMod } from "./functions/getTotalCasesByMod";
|
import { getTotalCasesByMod } from "./functions/getTotalCasesByMod";
|
||||||
import { postCaseToCaseLogChannel } from "./functions/postToCaseLogChannel";
|
import { postCaseToCaseLogChannel } from "./functions/postToCaseLogChannel";
|
||||||
import { CaseArgs, CaseNoteArgs, CasesPluginType, ConfigSchema } from "./types";
|
import { CaseArgs, CaseNoteArgs, CasesPluginType, zCasesConfig } from "./types";
|
||||||
|
|
||||||
// The `any` cast here is to prevent TypeScript from locking up from the circular dependency
|
// The `any` cast here is to prevent TypeScript from locking up from the circular dependency
|
||||||
function getLogsPlugin(): Promise<any> {
|
function getLogsPlugin(): Promise<any> {
|
||||||
|
@ -42,11 +42,11 @@ export const CasesPlugin = zeppelinGuildPlugin<CasesPluginType>()({
|
||||||
description: trimPluginDescription(`
|
description: trimPluginDescription(`
|
||||||
This plugin contains basic configuration for cases created by other plugins
|
This plugin contains basic configuration for cases created by other plugins
|
||||||
`),
|
`),
|
||||||
configSchema: ConfigSchema,
|
configSchema: zCasesConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getLogsPlugin()).LogsPlugin],
|
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getLogsPlugin()).LogsPlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zCasesConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
public: {
|
public: {
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType } from "knub";
|
import { BasePluginType } from "knub";
|
||||||
|
import { U } from "ts-toolbelt";
|
||||||
|
import z from "zod";
|
||||||
import { CaseNameToType, CaseTypes } from "../../data/CaseTypes";
|
import { CaseNameToType, CaseTypes } from "../../data/CaseTypes";
|
||||||
import { GuildArchives } from "../../data/GuildArchives";
|
import { GuildArchives } from "../../data/GuildArchives";
|
||||||
import { GuildCases } from "../../data/GuildCases";
|
import { GuildCases } from "../../data/GuildCases";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { tDelayString, tNullable, tPartialDictionary } from "../../utils";
|
import { keys, zBoundedCharacters, zDelayString, zSnowflake } from "../../utils";
|
||||||
import { tColor } from "../../utils/tColor";
|
import { zColor } from "../../utils/zColor";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
const caseKeys = keys(CaseNameToType) as U.ListOf<keyof typeof CaseNameToType>;
|
||||||
log_automatic_actions: t.boolean,
|
|
||||||
case_log_channel: tNullable(t.string),
|
export const zCasesConfig = z.strictObject({
|
||||||
show_relative_times: t.boolean,
|
log_automatic_actions: z.boolean(),
|
||||||
relative_time_cutoff: tDelayString,
|
case_log_channel: zSnowflake.nullable(),
|
||||||
case_colors: tNullable(tPartialDictionary(t.keyof(CaseNameToType), tColor)),
|
show_relative_times: z.boolean(),
|
||||||
case_icons: tNullable(tPartialDictionary(t.keyof(CaseNameToType), t.string)),
|
relative_time_cutoff: zDelayString.default("1w"),
|
||||||
|
case_colors: z.record(z.enum(caseKeys), zColor).nullable(),
|
||||||
|
case_icons: z.record(z.enum(caseKeys), zBoundedCharacters(0, 32)).nullable(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface CasesPluginType extends BasePluginType {
|
export interface CasesPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zCasesConfig>;
|
||||||
state: {
|
state: {
|
||||||
logs: GuildLogs;
|
logs: GuildLogs;
|
||||||
cases: GuildCases;
|
cases: GuildCases;
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { trimPluginDescription } from "../../utils";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { CensorPluginType, ConfigSchema } from "./types";
|
import { CensorPluginType, zCensorConfig } from "./types";
|
||||||
import { onMessageCreate } from "./util/onMessageCreate";
|
import { onMessageCreate } from "./util/onMessageCreate";
|
||||||
import { onMessageUpdate } from "./util/onMessageUpdate";
|
import { onMessageUpdate } from "./util/onMessageUpdate";
|
||||||
|
|
||||||
|
@ -54,11 +53,11 @@ export const CensorPlugin = zeppelinGuildPlugin<CensorPluginType>()({
|
||||||
For more advanced filtering, check out the Automod plugin!
|
For more advanced filtering, check out the Automod plugin!
|
||||||
`),
|
`),
|
||||||
legacy: true,
|
legacy: true,
|
||||||
configSchema: ConfigSchema,
|
configSchema: zCensorConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
dependencies: () => [LogsPlugin],
|
dependencies: () => [LogsPlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zCensorConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
beforeLoad(pluginData) {
|
beforeLoad(pluginData) {
|
||||||
|
|
|
@ -1,30 +1,28 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType } from "knub";
|
import { BasePluginType } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { RegExpRunner } from "../../RegExpRunner";
|
import { RegExpRunner } from "../../RegExpRunner";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { tNullable } from "../../utils";
|
import { zBoundedCharacters, zRegex, zSnowflake } from "../../utils";
|
||||||
import { TRegex } from "../../validatorUtils";
|
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zCensorConfig = z.strictObject({
|
||||||
filter_zalgo: t.boolean,
|
filter_zalgo: z.boolean(),
|
||||||
filter_invites: t.boolean,
|
filter_invites: z.boolean(),
|
||||||
invite_guild_whitelist: tNullable(t.array(t.string)),
|
invite_guild_whitelist: z.array(zSnowflake).nullable(),
|
||||||
invite_guild_blacklist: tNullable(t.array(t.string)),
|
invite_guild_blacklist: z.array(zSnowflake).nullable(),
|
||||||
invite_code_whitelist: tNullable(t.array(t.string)),
|
invite_code_whitelist: z.array(zBoundedCharacters(0, 16)).nullable(),
|
||||||
invite_code_blacklist: tNullable(t.array(t.string)),
|
invite_code_blacklist: z.array(zBoundedCharacters(0, 16)).nullable(),
|
||||||
allow_group_dm_invites: t.boolean,
|
allow_group_dm_invites: z.boolean(),
|
||||||
filter_domains: t.boolean,
|
filter_domains: z.boolean(),
|
||||||
domain_whitelist: tNullable(t.array(t.string)),
|
domain_whitelist: z.array(zBoundedCharacters(0, 255)).nullable(),
|
||||||
domain_blacklist: tNullable(t.array(t.string)),
|
domain_blacklist: z.array(zBoundedCharacters(0, 255)).nullable(),
|
||||||
blocked_tokens: tNullable(t.array(t.string)),
|
blocked_tokens: z.array(zBoundedCharacters(0, 2000)).nullable(),
|
||||||
blocked_words: tNullable(t.array(t.string)),
|
blocked_words: z.array(zBoundedCharacters(0, 2000)).nullable(),
|
||||||
blocked_regex: tNullable(t.array(TRegex)),
|
blocked_regex: z.array(zRegex(z.string().max(1000))).nullable(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface CensorPluginType extends BasePluginType {
|
export interface CensorPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zCensorConfig>;
|
||||||
state: {
|
state: {
|
||||||
serverLogs: GuildLogs;
|
serverLogs: GuildLogs;
|
||||||
savedMessages: GuildSavedMessages;
|
savedMessages: GuildSavedMessages;
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { ArchiveChannelCmd } from "./commands/ArchiveChannelCmd";
|
import { ArchiveChannelCmd } from "./commands/ArchiveChannelCmd";
|
||||||
import { ChannelArchiverPluginType } from "./types";
|
import { ChannelArchiverPluginType } from "./types";
|
||||||
|
|
||||||
const ConfigSchema = t.type({});
|
|
||||||
|
|
||||||
export const ChannelArchiverPlugin = zeppelinGuildPlugin<ChannelArchiverPluginType>()({
|
export const ChannelArchiverPlugin = zeppelinGuildPlugin<ChannelArchiverPluginType>()({
|
||||||
name: "channel_archiver",
|
name: "channel_archiver",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
dependencies: () => [TimeAndDatePlugin],
|
dependencies: () => [TimeAndDatePlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => z.strictObject({}).parse(input),
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
messageCommands: [
|
messageCommands: [
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { CooldownManager } from "knub";
|
import { CooldownManager } from "knub";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { trimPluginDescription } from "../../utils";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { VoiceStateUpdateEvt } from "./events/VoiceStateUpdateEvt";
|
import { VoiceStateUpdateEvt } from "./events/VoiceStateUpdateEvt";
|
||||||
import { CompanionChannelsPluginType, ConfigSchema } from "./types";
|
import { CompanionChannelsPluginType, zCompanionChannelsConfig } from "./types";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -23,11 +22,11 @@ export const CompanionChannelsPlugin = zeppelinGuildPlugin<CompanionChannelsPlug
|
||||||
Once set up, any time a user joins one of the specified voice channels,
|
Once set up, any time a user joins one of the specified voice channels,
|
||||||
they'll get channel permissions applied to them for the text channels.
|
they'll get channel permissions applied to them for the text channels.
|
||||||
`),
|
`),
|
||||||
configSchema: ConfigSchema,
|
configSchema: zCompanionChannelsConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
dependencies: () => [LogsPlugin],
|
dependencies: () => [LogsPlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zCompanionChannelsConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
events: [VoiceStateUpdateEvt],
|
events: [VoiceStateUpdateEvt],
|
||||||
|
|
|
@ -1,28 +1,23 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, CooldownManager, guildPluginEventListener } from "knub";
|
import { BasePluginType, CooldownManager, guildPluginEventListener } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { tNullable } from "../../utils";
|
import { zBoundedCharacters, zSnowflake } from "../../utils";
|
||||||
|
|
||||||
// Permissions using these numbers: https://abal.moe/Eris/docs/reference (add all allowed/denied ones up)
|
export const zCompanionChannelOpts = z.strictObject({
|
||||||
export const CompanionChannelOpts = t.type({
|
voice_channel_ids: z.array(zSnowflake),
|
||||||
voice_channel_ids: t.array(t.string),
|
text_channel_ids: z.array(zSnowflake),
|
||||||
text_channel_ids: t.array(t.string),
|
// See https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags
|
||||||
permissions: t.number,
|
permissions: z.number(),
|
||||||
enabled: tNullable(t.boolean),
|
enabled: z.boolean().nullable().default(true),
|
||||||
});
|
});
|
||||||
export type TCompanionChannelOpts = t.TypeOf<typeof CompanionChannelOpts>;
|
export type TCompanionChannelOpts = z.infer<typeof zCompanionChannelOpts>;
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zCompanionChannelsConfig = z.strictObject({
|
||||||
entries: t.record(t.string, CompanionChannelOpts),
|
entries: z.record(zBoundedCharacters(0, 100), zCompanionChannelOpts),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface ICompanionChannelMap {
|
|
||||||
[channelId: string]: TCompanionChannelOpts;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CompanionChannelsPluginType extends BasePluginType {
|
export interface CompanionChannelsPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zCompanionChannelsConfig>;
|
||||||
state: {
|
state: {
|
||||||
errorCooldownManager: CooldownManager;
|
errorCooldownManager: CooldownManager;
|
||||||
serverLogs: GuildLogs;
|
serverLogs: GuildLogs;
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { GuildContextMenuLinks } from "../../data/GuildContextMenuLinks";
|
import { GuildContextMenuLinks } from "../../data/GuildContextMenuLinks";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
import { MutesPlugin } from "../Mutes/MutesPlugin";
|
import { MutesPlugin } from "../Mutes/MutesPlugin";
|
||||||
import { UtilityPlugin } from "../Utility/UtilityPlugin";
|
import { UtilityPlugin } from "../Utility/UtilityPlugin";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { ContextClickedEvt } from "./events/ContextClickedEvt";
|
import { ContextClickedEvt } from "./events/ContextClickedEvt";
|
||||||
import { ConfigSchema, ContextMenuPluginType } from "./types";
|
import { ContextMenuPluginType, zContextMenusConfig } from "./types";
|
||||||
import { loadAllCommands } from "./utils/loadAllCommands";
|
import { loadAllCommands } from "./utils/loadAllCommands";
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<ContextMenuPluginType> = {
|
const defaultOptions: PluginOptions<ContextMenuPluginType> = {
|
||||||
|
@ -37,7 +36,7 @@ export const ContextMenuPlugin = zeppelinGuildPlugin<ContextMenuPluginType>()({
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
dependencies: () => [MutesPlugin, LogsPlugin, UtilityPlugin],
|
dependencies: () => [MutesPlugin, LogsPlugin, UtilityPlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zContextMenusConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
@ -45,9 +45,9 @@ export async function muteAction(
|
||||||
try {
|
try {
|
||||||
const result = await mutes.muteUser(userId, durationMs, "Context Menu Action", { caseArgs });
|
const result = await mutes.muteUser(userId, durationMs, "Context Menu Action", { caseArgs });
|
||||||
|
|
||||||
const muteMessage = `Muted **${result.case.user_name}** ${
|
const muteMessage = `Muted **${result.case!.user_name}** ${
|
||||||
durationMs ? `for ${humanizeDuration(durationMs)}` : "indefinitely"
|
durationMs ? `for ${humanizeDuration(durationMs)}` : "indefinitely"
|
||||||
} (Case #${result.case.case_number}) (user notified via ${
|
} (Case #${result.case!.case_number}) (user notified via ${
|
||||||
result.notifyResult.method ?? "dm"
|
result.notifyResult.method ?? "dm"
|
||||||
})\nPlease update the new case with the \`update\` command`;
|
})\nPlease update the new case with the \`update\` command`;
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, guildPluginEventListener } from "knub";
|
import { BasePluginType, guildPluginEventListener } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { GuildContextMenuLinks } from "../../data/GuildContextMenuLinks";
|
import { GuildContextMenuLinks } from "../../data/GuildContextMenuLinks";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zContextMenusConfig = z.strictObject({
|
||||||
can_use: t.boolean,
|
can_use: z.boolean(),
|
||||||
|
user_muteindef: z.boolean(),
|
||||||
user_muteindef: t.boolean,
|
user_mute1d: z.boolean(),
|
||||||
user_mute1d: t.boolean,
|
user_mute1h: z.boolean(),
|
||||||
user_mute1h: t.boolean,
|
user_info: z.boolean(),
|
||||||
user_info: t.boolean,
|
message_clean10: z.boolean(),
|
||||||
message_clean10: t.boolean,
|
message_clean25: z.boolean(),
|
||||||
message_clean25: t.boolean,
|
message_clean50: z.boolean(),
|
||||||
message_clean50: t.boolean,
|
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface ContextMenuPluginType extends BasePluginType {
|
export interface ContextMenuPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zContextMenusConfig>;
|
||||||
state: {
|
state: {
|
||||||
contextMenuLinks: GuildContextMenuLinks;
|
contextMenuLinks: GuildContextMenuLinks;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import {
|
|
||||||
buildCounterConditionString,
|
|
||||||
CounterTrigger,
|
|
||||||
getReverseCounterComparisonOp,
|
|
||||||
parseCounterConditionString,
|
|
||||||
} from "../../data/entities/CounterTrigger";
|
|
||||||
import { GuildCounters } from "../../data/GuildCounters";
|
import { GuildCounters } from "../../data/GuildCounters";
|
||||||
|
import {
|
||||||
|
CounterTrigger,
|
||||||
|
parseCounterConditionString
|
||||||
|
} from "../../data/entities/CounterTrigger";
|
||||||
import { mapToPublicFn } from "../../pluginUtils";
|
import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { convertDelayStringToMS, MINUTES } from "../../utils";
|
import { MINUTES, convertDelayStringToMS, values } from "../../utils";
|
||||||
import { parseIoTsSchema, StrictValidationError } from "../../validatorUtils";
|
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { AddCounterCmd } from "./commands/AddCounterCmd";
|
import { AddCounterCmd } from "./commands/AddCounterCmd";
|
||||||
import { CountersListCmd } from "./commands/CountersListCmd";
|
import { CountersListCmd } from "./commands/CountersListCmd";
|
||||||
|
@ -25,10 +22,8 @@ import { getPrettyNameForCounterTrigger } from "./functions/getPrettyNameForCoun
|
||||||
import { offCounterEvent } from "./functions/offCounterEvent";
|
import { offCounterEvent } from "./functions/offCounterEvent";
|
||||||
import { onCounterEvent } from "./functions/onCounterEvent";
|
import { onCounterEvent } from "./functions/onCounterEvent";
|
||||||
import { setCounterValue } from "./functions/setCounterValue";
|
import { setCounterValue } from "./functions/setCounterValue";
|
||||||
import { ConfigSchema, CountersPluginType, TTrigger } from "./types";
|
import { CountersPluginType, zCountersConfig } from "./types";
|
||||||
|
|
||||||
const MAX_COUNTERS = 5;
|
|
||||||
const MAX_TRIGGERS_PER_COUNTER = 5;
|
|
||||||
const DECAY_APPLY_INTERVAL = 5 * MINUTES;
|
const DECAY_APPLY_INTERVAL = 5 * MINUTES;
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<CountersPluginType> = {
|
const defaultOptions: PluginOptions<CountersPluginType> = {
|
||||||
|
@ -72,50 +67,12 @@ export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()({
|
||||||
description:
|
description:
|
||||||
"Keep track of per-user, per-channel, or global numbers and trigger specific actions based on this number",
|
"Keep track of per-user, per-channel, or global numbers and trigger specific actions based on this number",
|
||||||
configurationGuide: "See <a href='/docs/setup-guides/counters'>Counters setup guide</a>",
|
configurationGuide: "See <a href='/docs/setup-guides/counters'>Counters setup guide</a>",
|
||||||
configSchema: ConfigSchema,
|
configSchema: zCountersConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
// TODO: Separate input and output types
|
// TODO: Separate input and output types
|
||||||
configParser: (input) => {
|
configParser: (input) => zCountersConfig.parse(input),
|
||||||
for (const [counterName, counter] of Object.entries<any>((input as any).counters || {})) {
|
|
||||||
counter.name = counterName;
|
|
||||||
counter.per_user = counter.per_user ?? false;
|
|
||||||
counter.per_channel = counter.per_channel ?? false;
|
|
||||||
counter.initial_value = counter.initial_value ?? 0;
|
|
||||||
counter.triggers = counter.triggers || {};
|
|
||||||
|
|
||||||
if (Object.values(counter.triggers).length > MAX_TRIGGERS_PER_COUNTER) {
|
|
||||||
throw new StrictValidationError([`You can only have at most ${MAX_TRIGGERS_PER_COUNTER} triggers per counter`]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize triggers
|
|
||||||
for (const [triggerName, trigger] of Object.entries(counter.triggers)) {
|
|
||||||
const triggerObj = (typeof trigger === "string" ? { condition: trigger } : trigger) as Partial<TTrigger>;
|
|
||||||
|
|
||||||
triggerObj.name = triggerName;
|
|
||||||
const parsedCondition = parseCounterConditionString(triggerObj.condition || "");
|
|
||||||
if (!parsedCondition) {
|
|
||||||
throw new StrictValidationError([
|
|
||||||
`Invalid comparison in counter trigger ${counterName}/${triggerName}: "${triggerObj.condition}"`,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
triggerObj.condition = buildCounterConditionString(parsedCondition[0], parsedCondition[1]);
|
|
||||||
triggerObj.reverse_condition =
|
|
||||||
triggerObj.reverse_condition ||
|
|
||||||
buildCounterConditionString(getReverseCounterComparisonOp(parsedCondition[0]), parsedCondition[1]);
|
|
||||||
|
|
||||||
counter.triggers[triggerName] = triggerObj as TTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.values((input as any).counters || {}).length > MAX_COUNTERS) {
|
|
||||||
throw new StrictValidationError([`You can only have at most ${MAX_COUNTERS} counters`]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseIoTsSchema(ConfigSchema, input);
|
|
||||||
},
|
|
||||||
|
|
||||||
public: {
|
public: {
|
||||||
counterExists: mapToPublicFn(counterExists),
|
counterExists: mapToPublicFn(counterExists),
|
||||||
|
@ -163,13 +120,12 @@ export const CountersPlugin = zeppelinGuildPlugin<CountersPluginType>()({
|
||||||
state.counterTriggersByCounterId.set(dbCounter.id, thisCounterTriggers);
|
state.counterTriggersByCounterId.set(dbCounter.id, thisCounterTriggers);
|
||||||
|
|
||||||
// Initialize triggers
|
// Initialize triggers
|
||||||
for (const trigger of Object.values(counter.triggers)) {
|
for (const trigger of values(counter.triggers)) {
|
||||||
const theTrigger = trigger as TTrigger;
|
const parsedCondition = parseCounterConditionString(trigger.condition)!;
|
||||||
const parsedCondition = parseCounterConditionString(theTrigger.condition)!;
|
const parsedReverseCondition = parseCounterConditionString(trigger.reverse_condition)!;
|
||||||
const parsedReverseCondition = parseCounterConditionString(theTrigger.reverse_condition)!;
|
|
||||||
const counterTrigger = await state.counters.initCounterTrigger(
|
const counterTrigger = await state.counters.initCounterTrigger(
|
||||||
dbCounter.id,
|
dbCounter.id,
|
||||||
theTrigger.name,
|
trigger.name,
|
||||||
parsedCondition[0],
|
parsedCondition[0],
|
||||||
parsedCondition[1],
|
parsedCondition[1],
|
||||||
parsedReverseCondition[0],
|
parsedReverseCondition[0],
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { CountersPluginType, TTrigger } from "../types";
|
import { CountersPluginType } from "../types";
|
||||||
|
|
||||||
export function getPrettyNameForCounterTrigger(
|
export function getPrettyNameForCounterTrigger(
|
||||||
pluginData: GuildPluginData<CountersPluginType>,
|
pluginData: GuildPluginData<CountersPluginType>,
|
||||||
|
@ -12,6 +12,6 @@ export function getPrettyNameForCounterTrigger(
|
||||||
return "Unknown Counter Trigger";
|
return "Unknown Counter Trigger";
|
||||||
}
|
}
|
||||||
|
|
||||||
const trigger = counter.triggers[triggerName] as TTrigger | undefined;
|
const trigger = counter.triggers[triggerName];
|
||||||
return trigger ? trigger.pretty_name || trigger.name : "Unknown Counter Trigger";
|
return trigger ? trigger.pretty_name || trigger.name : "Unknown Counter Trigger";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,98 @@
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType } from "knub";
|
import { BasePluginType } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { GuildCounters } from "../../data/GuildCounters";
|
import { GuildCounters } from "../../data/GuildCounters";
|
||||||
import { CounterTrigger } from "../../data/entities/CounterTrigger";
|
import { CounterTrigger, buildCounterConditionString, getReverseCounterComparisonOp, parseCounterConditionString } from "../../data/entities/CounterTrigger";
|
||||||
import { tDelayString, tNullable } from "../../utils";
|
import { zBoundedCharacters, zBoundedRecord, zDelayString } from "../../utils";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
export const Trigger = t.type({
|
const MAX_COUNTERS = 5;
|
||||||
name: t.string,
|
const MAX_TRIGGERS_PER_COUNTER = 5;
|
||||||
pretty_name: tNullable(t.string),
|
|
||||||
condition: t.string,
|
|
||||||
reverse_condition: t.string,
|
|
||||||
});
|
|
||||||
export type TTrigger = t.TypeOf<typeof Trigger>;
|
|
||||||
|
|
||||||
export const Counter = t.type({
|
export const zTrigger = z.strictObject({
|
||||||
name: t.string,
|
// Dummy type because name gets replaced by the property key in zTriggerInput
|
||||||
pretty_name: tNullable(t.string),
|
name: z.never().optional().transform(() => ""),
|
||||||
per_channel: t.boolean,
|
pretty_name: zBoundedCharacters(0, 100).nullable().default(null),
|
||||||
per_user: t.boolean,
|
condition: zBoundedCharacters(1, 64).refine(
|
||||||
initial_value: t.number,
|
(str) => parseCounterConditionString(str) !== null,
|
||||||
triggers: t.record(t.string, t.union([t.string, Trigger])),
|
{ message: "Invalid counter trigger condition" },
|
||||||
decay: tNullable(
|
),
|
||||||
t.type({
|
reverse_condition: zBoundedCharacters(1, 64).refine(
|
||||||
amount: t.number,
|
(str) => parseCounterConditionString(str) !== null,
|
||||||
every: tDelayString,
|
{ message: "Invalid counter trigger reverse condition" },
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
can_view: tNullable(t.boolean),
|
|
||||||
can_edit: tNullable(t.boolean),
|
|
||||||
can_reset_all: tNullable(t.boolean),
|
|
||||||
});
|
});
|
||||||
export type TCounter = t.TypeOf<typeof Counter>;
|
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
const zTriggerInput = z.union([zBoundedCharacters(0, 100), zTrigger])
|
||||||
counters: t.record(t.string, Counter),
|
.transform((val, ctx) => {
|
||||||
can_view: t.boolean,
|
const ruleName = String(ctx.path[ctx.path.length - 2]).trim();
|
||||||
can_edit: t.boolean,
|
if (typeof val === "string") {
|
||||||
can_reset_all: t.boolean,
|
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]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...val,
|
||||||
|
name: ruleName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
}),
|
||||||
|
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),
|
||||||
|
can_view: z.boolean(),
|
||||||
|
can_edit: z.boolean(),
|
||||||
|
can_reset_all: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const zCountersConfig = z.strictObject({
|
||||||
|
counters: zBoundedRecord(
|
||||||
|
z.record(zBoundedCharacters(0, 100), zCounter),
|
||||||
|
0,
|
||||||
|
MAX_COUNTERS,
|
||||||
|
),
|
||||||
|
can_view: z.boolean(),
|
||||||
|
can_edit: z.boolean(),
|
||||||
|
can_reset_all: z.boolean(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface CounterEvents {
|
export interface CounterEvents {
|
||||||
trigger: (counterName: string, triggerName: string, channelId: string | null, userId: string | null) => void;
|
trigger: (counterName: string, triggerName: string, channelId: string | null, userId: string | null) => void;
|
||||||
|
@ -52,7 +105,7 @@ export interface CounterEventEmitter extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CountersPluginType extends BasePluginType {
|
export interface CountersPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zCountersConfig>;
|
||||||
state: {
|
state: {
|
||||||
counters: GuildCounters;
|
counters: GuildCounters;
|
||||||
counterIds: Record<string, number>;
|
counterIds: Record<string, number>;
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { GuildChannel, GuildMember, User } from "discord.js";
|
||||||
import { guildPluginMessageCommand, parseSignature } from "knub";
|
import { guildPluginMessageCommand, parseSignature } from "knub";
|
||||||
import { TSignature } from "knub-command-manager";
|
import { TSignature } from "knub-command-manager";
|
||||||
import { commandTypes } from "../../commandTypes";
|
import { commandTypes } from "../../commandTypes";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { TemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter";
|
import { TemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter";
|
||||||
import { UnknownUser } from "../../utils";
|
import { UnknownUser } from "../../utils";
|
||||||
import { isScalar } from "../../utils/isScalar";
|
import { isScalar } from "../../utils/isScalar";
|
||||||
|
@ -14,7 +13,7 @@ import {
|
||||||
} from "../../utils/templateSafeObjects";
|
} from "../../utils/templateSafeObjects";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { runEvent } from "./functions/runEvent";
|
import { runEvent } from "./functions/runEvent";
|
||||||
import { ConfigSchema, CustomEventsPluginType } from "./types";
|
import { CustomEventsPluginType, zCustomEventsConfig } from "./types";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -26,7 +25,7 @@ export const CustomEventsPlugin = zeppelinGuildPlugin<CustomEventsPluginType>()(
|
||||||
name: "custom_events",
|
name: "custom_events",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zCustomEventsConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
afterLoad(pluginData) {
|
afterLoad(pluginData) {
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { canActOn } from "../../../pluginUtils";
|
import { canActOn } from "../../../pluginUtils";
|
||||||
import { renderTemplate, TemplateSafeValueContainer } from "../../../templateFormatter";
|
import { renderTemplate, TemplateSafeValueContainer } from "../../../templateFormatter";
|
||||||
import { resolveMember } from "../../../utils";
|
import { resolveMember, zSnowflake } from "../../../utils";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
||||||
|
|
||||||
export const AddRoleAction = t.type({
|
export const zAddRoleAction = z.strictObject({
|
||||||
type: t.literal("add_role"),
|
type: z.literal("add_role"),
|
||||||
target: t.string,
|
target: zSnowflake,
|
||||||
role: t.union([t.string, t.array(t.string)]),
|
role: z.union([zSnowflake, z.array(zSnowflake)]),
|
||||||
});
|
});
|
||||||
export type TAddRoleAction = t.TypeOf<typeof AddRoleAction>;
|
export type TAddRoleAction = z.infer<typeof zAddRoleAction>;
|
||||||
|
|
||||||
export async function addRoleAction(
|
export async function addRoleAction(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
import { renderTemplate, TemplateSafeValueContainer } from "../../../templateFormatter";
|
import { renderTemplate, TemplateSafeValueContainer } from "../../../templateFormatter";
|
||||||
|
import { zBoundedCharacters, zSnowflake } from "../../../utils";
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
||||||
|
|
||||||
export const CreateCaseAction = t.type({
|
export const zCreateCaseAction = z.strictObject({
|
||||||
type: t.literal("create_case"),
|
type: z.literal("create_case"),
|
||||||
case_type: t.string,
|
case_type: zBoundedCharacters(0, 32),
|
||||||
mod: t.string,
|
mod: zSnowflake,
|
||||||
target: t.string,
|
target: zSnowflake,
|
||||||
reason: t.string,
|
reason: zBoundedCharacters(0, 4000),
|
||||||
});
|
});
|
||||||
export type TCreateCaseAction = t.TypeOf<typeof CreateCaseAction>;
|
export type TCreateCaseAction = z.infer<typeof zCreateCaseAction>;
|
||||||
|
|
||||||
export async function createCaseAction(
|
export async function createCaseAction(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
@ -32,7 +33,7 @@ export async function createCaseAction(
|
||||||
}
|
}
|
||||||
|
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
await casesPlugin.createCase({
|
await casesPlugin!.createCase({
|
||||||
userId: targetId,
|
userId: targetId,
|
||||||
modId,
|
modId,
|
||||||
type: CaseTypes[action.case_type],
|
type: CaseTypes[action.case_type],
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { Snowflake } from "discord.js";
|
import { Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { TemplateSafeValueContainer } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer } from "../../../templateFormatter";
|
||||||
import { convertDelayStringToMS, noop, tDelayString } from "../../../utils";
|
import { convertDelayStringToMS, noop, zDelayString, zSnowflake } from "../../../utils";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
||||||
|
|
||||||
export const MakeRoleMentionableAction = t.type({
|
export const zMakeRoleMentionableAction = z.strictObject({
|
||||||
type: t.literal("make_role_mentionable"),
|
type: z.literal("make_role_mentionable"),
|
||||||
role: t.string,
|
role: zSnowflake,
|
||||||
timeout: tDelayString,
|
timeout: zDelayString,
|
||||||
});
|
});
|
||||||
export type TMakeRoleMentionableAction = t.TypeOf<typeof MakeRoleMentionableAction>;
|
export type TMakeRoleMentionableAction = z.infer<typeof zMakeRoleMentionableAction>;
|
||||||
|
|
||||||
export async function makeRoleMentionableAction(
|
export async function makeRoleMentionableAction(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { Snowflake } from "discord.js";
|
import { Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { TemplateSafeValueContainer } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer } from "../../../templateFormatter";
|
||||||
|
import { zSnowflake } from "../../../utils";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
||||||
|
|
||||||
export const MakeRoleUnmentionableAction = t.type({
|
export const zMakeRoleUnmentionableAction = z.strictObject({
|
||||||
type: t.literal("make_role_unmentionable"),
|
type: z.literal("make_role_unmentionable"),
|
||||||
role: t.string,
|
role: zSnowflake,
|
||||||
});
|
});
|
||||||
export type TMakeRoleUnmentionableAction = t.TypeOf<typeof MakeRoleUnmentionableAction>;
|
export type TMakeRoleUnmentionableAction = z.infer<typeof zMakeRoleUnmentionableAction>;
|
||||||
|
|
||||||
export async function makeRoleUnmentionableAction(
|
export async function makeRoleUnmentionableAction(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import { Snowflake, TextChannel } from "discord.js";
|
import { Snowflake, TextChannel } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
||||||
|
import { zBoundedCharacters, zSnowflake } from "../../../utils";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { CustomEventsPluginType } from "../types";
|
import { CustomEventsPluginType } from "../types";
|
||||||
|
|
||||||
export const MessageAction = t.type({
|
export const zMessageAction = z.strictObject({
|
||||||
type: t.literal("message"),
|
type: z.literal("message"),
|
||||||
channel: t.string,
|
channel: zSnowflake,
|
||||||
content: t.string,
|
content: zBoundedCharacters(0, 4000),
|
||||||
});
|
});
|
||||||
export type TMessageAction = t.TypeOf<typeof MessageAction>;
|
export type TMessageAction = z.infer<typeof zMessageAction>;
|
||||||
|
|
||||||
export async function messageAction(
|
export async function messageAction(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { Snowflake, VoiceChannel } from "discord.js";
|
import { Snowflake, VoiceChannel } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { canActOn } from "../../../pluginUtils";
|
import { canActOn } from "../../../pluginUtils";
|
||||||
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
||||||
import { resolveMember } from "../../../utils";
|
import { resolveMember, zSnowflake } from "../../../utils";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
||||||
|
|
||||||
export const MoveToVoiceChannelAction = t.type({
|
export const zMoveToVoiceChannelAction = z.strictObject({
|
||||||
type: t.literal("move_to_vc"),
|
type: z.literal("move_to_vc"),
|
||||||
target: t.string,
|
target: zSnowflake,
|
||||||
channel: t.string,
|
channel: zSnowflake,
|
||||||
});
|
});
|
||||||
export type TMoveToVoiceChannelAction = t.TypeOf<typeof MoveToVoiceChannelAction>;
|
export type TMoveToVoiceChannelAction = z.infer<typeof zMoveToVoiceChannelAction>;
|
||||||
|
|
||||||
export async function moveToVoiceChannelAction(
|
export async function moveToVoiceChannelAction(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
import { PermissionsBitField, PermissionsString, Snowflake } from "discord.js";
|
import { PermissionsBitField, PermissionsString, Snowflake } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { TemplateSafeValueContainer } from "../../../templateFormatter";
|
import { TemplateSafeValueContainer } from "../../../templateFormatter";
|
||||||
|
import { zSnowflake } from "../../../utils";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
import { CustomEventsPluginType, TCustomEvent } from "../types";
|
||||||
|
|
||||||
export const SetChannelPermissionOverridesAction = t.type({
|
export const zSetChannelPermissionOverridesAction = z.strictObject({
|
||||||
type: t.literal("set_channel_permission_overrides"),
|
type: z.literal("set_channel_permission_overrides"),
|
||||||
channel: t.string,
|
channel: zSnowflake,
|
||||||
overrides: t.array(
|
overrides: z.array(
|
||||||
t.type({
|
z.strictObject({
|
||||||
type: t.union([t.literal("member"), t.literal("role")]),
|
type: z.union([z.literal("member"), z.literal("role")]),
|
||||||
id: t.string,
|
id: zSnowflake,
|
||||||
allow: t.number,
|
allow: z.number(),
|
||||||
deny: t.number,
|
deny: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
).max(15),
|
||||||
});
|
});
|
||||||
export type TSetChannelPermissionOverridesAction = t.TypeOf<typeof SetChannelPermissionOverridesAction>;
|
export type TSetChannelPermissionOverridesAction = z.infer<typeof zSetChannelPermissionOverridesAction>;
|
||||||
|
|
||||||
export async function setChannelPermissionOverridesAction(
|
export async function setChannelPermissionOverridesAction(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
|
|
@ -1,47 +1,50 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType } from "knub";
|
import { BasePluginType } from "knub";
|
||||||
import { AddRoleAction } from "./actions/addRoleAction";
|
import z from "zod";
|
||||||
import { CreateCaseAction } from "./actions/createCaseAction";
|
import { zBoundedCharacters, zBoundedRecord } from "../../utils";
|
||||||
import { MakeRoleMentionableAction } from "./actions/makeRoleMentionableAction";
|
import { zAddRoleAction } from "./actions/addRoleAction";
|
||||||
import { MakeRoleUnmentionableAction } from "./actions/makeRoleUnmentionableAction";
|
import { zCreateCaseAction } from "./actions/createCaseAction";
|
||||||
import { MessageAction } from "./actions/messageAction";
|
import { zMakeRoleMentionableAction } from "./actions/makeRoleMentionableAction";
|
||||||
import { MoveToVoiceChannelAction } from "./actions/moveToVoiceChannelAction";
|
import { zMakeRoleUnmentionableAction } from "./actions/makeRoleUnmentionableAction";
|
||||||
import { SetChannelPermissionOverridesAction } from "./actions/setChannelPermissionOverrides";
|
import { zMessageAction } from "./actions/messageAction";
|
||||||
|
import { zMoveToVoiceChannelAction } from "./actions/moveToVoiceChannelAction";
|
||||||
|
import { zSetChannelPermissionOverridesAction } from "./actions/setChannelPermissionOverrides";
|
||||||
|
|
||||||
// Triggers
|
const zCommandTrigger = z.strictObject({
|
||||||
const CommandTrigger = t.type({
|
type: z.literal("command"),
|
||||||
type: t.literal("command"),
|
name: zBoundedCharacters(0, 100),
|
||||||
name: t.string,
|
params: zBoundedCharacters(0, 255),
|
||||||
params: t.string,
|
can_use: z.boolean(),
|
||||||
can_use: t.boolean,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const AnyTrigger = CommandTrigger; // TODO: Make into a union once we have more triggers
|
const zAnyTrigger = zCommandTrigger; // TODO: Make into a union once we have more triggers
|
||||||
|
|
||||||
const AnyAction = t.union([
|
const zAnyAction = z.union([
|
||||||
AddRoleAction,
|
zAddRoleAction,
|
||||||
CreateCaseAction,
|
zCreateCaseAction,
|
||||||
MoveToVoiceChannelAction,
|
zMoveToVoiceChannelAction,
|
||||||
MessageAction,
|
zMessageAction,
|
||||||
MakeRoleMentionableAction,
|
zMakeRoleMentionableAction,
|
||||||
MakeRoleUnmentionableAction,
|
zMakeRoleUnmentionableAction,
|
||||||
SetChannelPermissionOverridesAction,
|
zSetChannelPermissionOverridesAction,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const CustomEvent = t.type({
|
export const zCustomEvent = z.strictObject({
|
||||||
name: t.string,
|
name: zBoundedCharacters(0, 100),
|
||||||
trigger: AnyTrigger,
|
trigger: zAnyTrigger,
|
||||||
actions: t.array(AnyAction),
|
actions: z.array(zAnyAction).max(10),
|
||||||
});
|
});
|
||||||
export type TCustomEvent = t.TypeOf<typeof CustomEvent>;
|
export type TCustomEvent = z.infer<typeof zCustomEvent>;
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zCustomEventsConfig = z.strictObject({
|
||||||
events: t.record(t.string, CustomEvent),
|
events: zBoundedRecord(
|
||||||
|
z.record(zBoundedCharacters(0, 100), zCustomEvent),
|
||||||
|
0,
|
||||||
|
100,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface CustomEventsPluginType extends BasePluginType {
|
export interface CustomEventsPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zCustomEventsConfig>;
|
||||||
state: {
|
state: {
|
||||||
clearTriggers: () => void;
|
clearTriggers: () => void;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { Guild } from "discord.js";
|
import { Guild } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, GlobalPluginData, globalPluginEventListener } from "knub";
|
import { BasePluginType, GlobalPluginData, globalPluginEventListener } from "knub";
|
||||||
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
||||||
import { Configs } from "../../data/Configs";
|
import { Configs } from "../../data/Configs";
|
||||||
import { env } from "../../env";
|
import { env } from "../../env";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
interface GuildAccessMonitorPluginType extends BasePluginType {
|
interface GuildAccessMonitorPluginType extends BasePluginType {
|
||||||
state: {
|
state: {
|
||||||
|
@ -26,7 +25,7 @@ async function checkGuild(pluginData: GlobalPluginData<GuildAccessMonitorPluginT
|
||||||
*/
|
*/
|
||||||
export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin<GuildAccessMonitorPluginType>()({
|
export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin<GuildAccessMonitorPluginType>()({
|
||||||
name: "guild_access_monitor",
|
name: "guild_access_monitor",
|
||||||
configParser: makeIoTsConfigParser(t.type({})),
|
configParser: (input) => z.strictObject({}).parse(input),
|
||||||
|
|
||||||
events: [
|
events: [
|
||||||
globalPluginEventListener<GuildAccessMonitorPluginType>()({
|
globalPluginEventListener<GuildAccessMonitorPluginType>()({
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { Configs } from "../../data/Configs";
|
import { Configs } from "../../data/Configs";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { reloadChangedGuilds } from "./functions/reloadChangedGuilds";
|
import { reloadChangedGuilds } from "./functions/reloadChangedGuilds";
|
||||||
import { GuildConfigReloaderPluginType } from "./types";
|
import { GuildConfigReloaderPluginType } from "./types";
|
||||||
|
@ -9,7 +8,7 @@ export const GuildConfigReloaderPlugin = zeppelinGlobalPlugin<GuildConfigReloade
|
||||||
name: "guild_config_reloader",
|
name: "guild_config_reloader",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(t.type({})),
|
configParser: (input) => z.strictObject({}).parse(input),
|
||||||
|
|
||||||
async beforeLoad(pluginData) {
|
async beforeLoad(pluginData) {
|
||||||
const { state } = pluginData;
|
const { state } = pluginData;
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
import { Guild } from "discord.js";
|
import { Guild } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { guildPluginEventListener } from "knub";
|
import { guildPluginEventListener } from "knub";
|
||||||
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
||||||
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
import { ApiPermissionAssignments } from "../../data/ApiPermissionAssignments";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { MINUTES } from "../../utils";
|
import { MINUTES } from "../../utils";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { GuildInfoSaverPluginType } from "./types";
|
import { GuildInfoSaverPluginType } from "./types";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
export const GuildInfoSaverPlugin = zeppelinGuildPlugin<GuildInfoSaverPluginType>()({
|
export const GuildInfoSaverPlugin = zeppelinGuildPlugin<GuildInfoSaverPluginType>()({
|
||||||
name: "guild_info_saver",
|
name: "guild_info_saver",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(t.type({})),
|
configParser: (input) => z.strictObject({}).parse(input),
|
||||||
|
|
||||||
events: [
|
events: [
|
||||||
guildPluginEventListener({
|
guildPluginEventListener({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as t from "io-ts";
|
import z from "zod";
|
||||||
import { GuildMemberCache } from "../../data/GuildMemberCache";
|
import { GuildMemberCache } from "../../data/GuildMemberCache";
|
||||||
import { makeIoTsConfigParser, mapToPublicFn } from "../../pluginUtils";
|
import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { SECONDS } from "../../utils";
|
import { SECONDS } from "../../utils";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { cancelDeletionOnMemberJoin } from "./events/cancelDeletionOnMemberJoin";
|
import { cancelDeletionOnMemberJoin } from "./events/cancelDeletionOnMemberJoin";
|
||||||
|
@ -18,7 +18,7 @@ export const GuildMemberCachePlugin = zeppelinGuildPlugin<GuildMemberCachePlugin
|
||||||
name: "guild_member_cache",
|
name: "guild_member_cache",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(t.type({})),
|
configParser: (input) => z.strictObject({}).parse(input),
|
||||||
|
|
||||||
events: [
|
events: [
|
||||||
updateMemberCacheOnMemberUpdate,
|
updateMemberCacheOnMemberUpdate,
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
import { Webhooks } from "../../data/Webhooks";
|
import { Webhooks } from "../../data/Webhooks";
|
||||||
import { makeIoTsConfigParser, mapToPublicFn } from "../../pluginUtils";
|
import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { editMessage } from "./functions/editMessage";
|
import { editMessage } from "./functions/editMessage";
|
||||||
import { sendMessage } from "./functions/sendMessage";
|
import { sendMessage } from "./functions/sendMessage";
|
||||||
import { ConfigSchema, InternalPosterPluginType } from "./types";
|
import { InternalPosterPluginType } from "./types";
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<InternalPosterPluginType> = {
|
const defaultOptions: PluginOptions<InternalPosterPluginType> = {
|
||||||
config: {},
|
config: {},
|
||||||
|
@ -16,7 +17,7 @@ export const InternalPosterPlugin = zeppelinGuildPlugin<InternalPosterPluginType
|
||||||
name: "internal_poster",
|
name: "internal_poster",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => z.strictObject({}).parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
import { WebhookClient } from "discord.js";
|
import { WebhookClient } from "discord.js";
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType } from "knub";
|
import { BasePluginType } from "knub";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
import { Webhooks } from "../../data/Webhooks";
|
import { Webhooks } from "../../data/Webhooks";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({});
|
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface InternalPosterPluginType extends BasePluginType {
|
export interface InternalPosterPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
queue: Queue;
|
queue: Queue;
|
||||||
webhooks: Webhooks;
|
webhooks: Webhooks;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { onGuildEvent } from "../../data/GuildEvents";
|
import { onGuildEvent } from "../../data/GuildEvents";
|
||||||
import { GuildVCAlerts } from "../../data/GuildVCAlerts";
|
import { GuildVCAlerts } from "../../data/GuildVCAlerts";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { trimPluginDescription } from "../../utils";
|
import { trimPluginDescription } from "../../utils";
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { FollowCmd } from "./commands/FollowCmd";
|
import { FollowCmd } from "./commands/FollowCmd";
|
||||||
|
@ -9,7 +8,7 @@ import { DeleteFollowCmd, ListFollowCmd } from "./commands/ListFollowCmd";
|
||||||
import { WhereCmd } from "./commands/WhereCmd";
|
import { WhereCmd } from "./commands/WhereCmd";
|
||||||
import { GuildBanRemoveAlertsEvt } from "./events/BanRemoveAlertsEvt";
|
import { GuildBanRemoveAlertsEvt } from "./events/BanRemoveAlertsEvt";
|
||||||
import { VoiceStateUpdateAlertEvt } from "./events/SendAlertsEvts";
|
import { VoiceStateUpdateAlertEvt } from "./events/SendAlertsEvts";
|
||||||
import { ConfigSchema, LocateUserPluginType } from "./types";
|
import { LocateUserPluginType, zLocateUserConfig } from "./types";
|
||||||
import { clearExpiredAlert } from "./utils/clearExpiredAlert";
|
import { clearExpiredAlert } from "./utils/clearExpiredAlert";
|
||||||
import { fillActiveAlertsList } from "./utils/fillAlertsList";
|
import { fillActiveAlertsList } from "./utils/fillAlertsList";
|
||||||
|
|
||||||
|
@ -39,10 +38,10 @@ export const LocateUserPlugin = zeppelinGuildPlugin<LocateUserPluginType>()({
|
||||||
* Instantly receive an invite to the voice channel of a user
|
* Instantly receive an invite to the voice channel of a user
|
||||||
* Be notified as soon as a user switches or joins a voice channel
|
* Be notified as soon as a user switches or joins a voice channel
|
||||||
`),
|
`),
|
||||||
configSchema: ConfigSchema,
|
configSchema: zLocateUserConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zLocateUserConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
|
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { GuildVCAlerts } from "../../data/GuildVCAlerts";
|
import { GuildVCAlerts } from "../../data/GuildVCAlerts";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zLocateUserConfig = z.strictObject({
|
||||||
can_where: t.boolean,
|
can_where: z.boolean(),
|
||||||
can_alert: t.boolean,
|
can_alert: z.boolean(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface LocateUserPluginType extends BasePluginType {
|
export interface LocateUserPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zLocateUserConfig>;
|
||||||
state: {
|
state: {
|
||||||
alerts: GuildVCAlerts;
|
alerts: GuildVCAlerts;
|
||||||
usersWithAlerts: string[];
|
usersWithAlerts: string[];
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { LogType } from "../../data/LogType";
|
import { LogType } from "../../data/LogType";
|
||||||
import { logger } from "../../logger";
|
import { logger } from "../../logger";
|
||||||
import { makeIoTsConfigParser, mapToPublicFn } from "../../pluginUtils";
|
import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
import { discardRegExpRunner, getRegExpRunner } from "../../regExpRunners";
|
||||||
import { TypedTemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter";
|
import { TypedTemplateSafeValueContainer, createTypedTemplateSafeValueContainer } from "../../templateFormatter";
|
||||||
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
|
||||||
|
@ -31,7 +31,7 @@ import {
|
||||||
import { LogsThreadCreateEvt, LogsThreadDeleteEvt, LogsThreadUpdateEvt } from "./events/LogsThreadModifyEvts";
|
import { LogsThreadCreateEvt, LogsThreadDeleteEvt, LogsThreadUpdateEvt } from "./events/LogsThreadModifyEvts";
|
||||||
import { LogsGuildMemberUpdateEvt } from "./events/LogsUserUpdateEvts";
|
import { LogsGuildMemberUpdateEvt } from "./events/LogsUserUpdateEvts";
|
||||||
import { LogsVoiceStateUpdateEvt } from "./events/LogsVoiceChannelEvts";
|
import { LogsVoiceStateUpdateEvt } from "./events/LogsVoiceChannelEvts";
|
||||||
import { ConfigSchema, FORMAT_NO_TIMESTAMP, ILogTypeData, LogsPluginType, TLogChannel } from "./types";
|
import { FORMAT_NO_TIMESTAMP, ILogTypeData, LogsPluginType, TLogChannel, zLogsConfig } from "./types";
|
||||||
import { getLogMessage } from "./util/getLogMessage";
|
import { getLogMessage } from "./util/getLogMessage";
|
||||||
import { log } from "./util/log";
|
import { log } from "./util/log";
|
||||||
import { onMessageDelete } from "./util/onMessageDelete";
|
import { onMessageDelete } from "./util/onMessageDelete";
|
||||||
|
@ -110,7 +110,6 @@ import { logVoiceChannelForceMove } from "./logFunctions/logVoiceChannelForceMov
|
||||||
import { logVoiceChannelJoin } from "./logFunctions/logVoiceChannelJoin";
|
import { logVoiceChannelJoin } from "./logFunctions/logVoiceChannelJoin";
|
||||||
import { logVoiceChannelLeave } from "./logFunctions/logVoiceChannelLeave";
|
import { logVoiceChannelLeave } from "./logFunctions/logVoiceChannelLeave";
|
||||||
import { logVoiceChannelMove } from "./logFunctions/logVoiceChannelMove";
|
import { logVoiceChannelMove } from "./logFunctions/logVoiceChannelMove";
|
||||||
import { asBoundedString } from "../../utils/iotsUtils";
|
|
||||||
|
|
||||||
// The `any` cast here is to prevent TypeScript from locking up from the circular dependency
|
// The `any` cast here is to prevent TypeScript from locking up from the circular dependency
|
||||||
function getCasesPlugin(): Promise<any> {
|
function getCasesPlugin(): Promise<any> {
|
||||||
|
@ -121,12 +120,12 @@ const defaultOptions: PluginOptions<LogsPluginType> = {
|
||||||
config: {
|
config: {
|
||||||
channels: {},
|
channels: {},
|
||||||
format: {
|
format: {
|
||||||
timestamp: asBoundedString(FORMAT_NO_TIMESTAMP), // Legacy/deprecated, use timestamp_format below instead
|
timestamp: FORMAT_NO_TIMESTAMP,
|
||||||
...DefaultLogMessages,
|
...DefaultLogMessages,
|
||||||
},
|
},
|
||||||
ping_user: true, // Legacy/deprecated, if below is false mentions wont actually ping. In case you really want the old behavior, set below to true
|
ping_user: true,
|
||||||
allow_user_mentions: false,
|
allow_user_mentions: false,
|
||||||
timestamp_format: asBoundedString("[<t:]X[>]"),
|
timestamp_format: "[<t:]X[>]",
|
||||||
include_embed_timestamp: true,
|
include_embed_timestamp: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -134,7 +133,8 @@ const defaultOptions: PluginOptions<LogsPluginType> = {
|
||||||
{
|
{
|
||||||
level: ">=50",
|
level: ">=50",
|
||||||
config: {
|
config: {
|
||||||
ping_user: false, // Legacy/deprecated, read comment on global ping_user option
|
// Legacy/deprecated, read comment on global ping_user option
|
||||||
|
ping_user: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -145,11 +145,11 @@ export const LogsPlugin = zeppelinGuildPlugin<LogsPluginType>()({
|
||||||
showInDocs: true,
|
showInDocs: true,
|
||||||
info: {
|
info: {
|
||||||
prettyName: "Logs",
|
prettyName: "Logs",
|
||||||
configSchema: ConfigSchema,
|
configSchema: zLogsConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin],
|
dependencies: async () => [TimeAndDatePlugin, InternalPosterPlugin, (await getCasesPlugin()).CasesPlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zLogsConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
events: [
|
events: [
|
||||||
|
|
|
@ -32,7 +32,7 @@ export function logMessageDelete(pluginData: GuildPluginData<LogsPluginType>, da
|
||||||
// See comment on FORMAT_NO_TIMESTAMP in types.ts
|
// See comment on FORMAT_NO_TIMESTAMP in types.ts
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
const timestampFormat =
|
const timestampFormat =
|
||||||
(config.format.timestamp !== FORMAT_NO_TIMESTAMP ? config.format.timestamp : null) ?? config.timestamp_format;
|
(config.format.timestamp !== FORMAT_NO_TIMESTAMP ? config.format.timestamp : null) ?? config.timestamp_format ?? undefined;
|
||||||
|
|
||||||
return log(
|
return log(
|
||||||
pluginData,
|
pluginData,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, CooldownManager, guildPluginEventListener } from "knub";
|
import { BasePluginType, CooldownManager, guildPluginEventListener } from "knub";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { RegExpRunner } from "../../RegExpRunner";
|
import { RegExpRunner } from "../../RegExpRunner";
|
||||||
|
@ -7,7 +6,7 @@ import { GuildCases } from "../../data/GuildCases";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { LogType } from "../../data/LogType";
|
import { LogType } from "../../data/LogType";
|
||||||
import { tMessageContent, tNullable } from "../../utils";
|
import { zBoundedCharacters, zMessageContent, zRegex, zSnowflake } from "../../utils";
|
||||||
import { MessageBuffer } from "../../utils/MessageBuffer";
|
import { MessageBuffer } from "../../utils/MessageBuffer";
|
||||||
import {
|
import {
|
||||||
TemplateSafeCase,
|
TemplateSafeCase,
|
||||||
|
@ -22,55 +21,56 @@ import {
|
||||||
TemplateSafeUnknownUser,
|
TemplateSafeUnknownUser,
|
||||||
TemplateSafeUser,
|
TemplateSafeUser,
|
||||||
} from "../../utils/templateSafeObjects";
|
} from "../../utils/templateSafeObjects";
|
||||||
import { TRegex } from "../../validatorUtils";
|
|
||||||
import { tBoundedString } from "../../utils/iotsUtils";
|
|
||||||
|
|
||||||
export const tLogFormats = t.record(t.string, t.union([t.string, tMessageContent]));
|
const DEFAULT_BATCH_TIME = 1000;
|
||||||
export type TLogFormats = t.TypeOf<typeof tLogFormats>;
|
const MIN_BATCH_TIME = 250;
|
||||||
|
const MAX_BATCH_TIME = 5000;
|
||||||
|
|
||||||
const LogChannel = t.partial({
|
export const zLogFormats = z.record(
|
||||||
include: t.array(t.string),
|
zBoundedCharacters(1, 255),
|
||||||
exclude: t.array(t.string),
|
zMessageContent,
|
||||||
batched: t.boolean,
|
);
|
||||||
batch_time: t.number,
|
export type TLogFormats = z.infer<typeof zLogFormats>;
|
||||||
excluded_users: t.array(t.string),
|
|
||||||
excluded_message_regexes: t.array(TRegex),
|
const zLogChannel = z.strictObject({
|
||||||
excluded_channels: t.array(t.string),
|
include: z.array(zBoundedCharacters(1, 255)).default([]),
|
||||||
excluded_categories: t.array(t.string),
|
exclude: z.array(zBoundedCharacters(1, 255)).default([]),
|
||||||
excluded_threads: t.array(t.string),
|
batched: z.boolean().default(true),
|
||||||
exclude_bots: t.boolean,
|
batch_time: z.number().min(MIN_BATCH_TIME).max(MAX_BATCH_TIME).default(DEFAULT_BATCH_TIME),
|
||||||
excluded_roles: t.array(t.string),
|
excluded_users: z.array(zSnowflake).nullable().default(null),
|
||||||
format: tNullable(tLogFormats),
|
excluded_message_regexes: z.array(zRegex(z.string())).nullable().default(null),
|
||||||
timestamp_format: t.string,
|
excluded_channels: z.array(zSnowflake).nullable().default(null),
|
||||||
include_embed_timestamp: t.boolean,
|
excluded_categories: z.array(zSnowflake).nullable().default(null),
|
||||||
|
excluded_threads: z.array(zSnowflake).nullable().default(null),
|
||||||
|
exclude_bots: z.boolean().default(false),
|
||||||
|
excluded_roles: z.array(zSnowflake).nullable().default(null),
|
||||||
|
format: zLogFormats.default({}),
|
||||||
|
timestamp_format: z.string().nullable().default(null),
|
||||||
|
include_embed_timestamp: z.boolean().nullable().default(null),
|
||||||
});
|
});
|
||||||
export type TLogChannel = t.TypeOf<typeof LogChannel>;
|
export type TLogChannel = z.infer<typeof zLogChannel>;
|
||||||
|
|
||||||
const LogChannelMap = t.record(t.string, LogChannel);
|
const zLogChannelMap = z.record(zSnowflake, zLogChannel);
|
||||||
export type TLogChannelMap = t.TypeOf<typeof LogChannelMap>;
|
export type TLogChannelMap = z.infer<typeof zLogChannelMap>;
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zLogsConfig = z.strictObject({
|
||||||
channels: LogChannelMap,
|
channels: zLogChannelMap,
|
||||||
format: t.intersection([
|
format: z.intersection(zLogFormats, z.strictObject({
|
||||||
tLogFormats,
|
// Legacy/deprecated, use timestamp_format below instead
|
||||||
t.type({
|
timestamp: zBoundedCharacters(0, 64).nullable(),
|
||||||
timestamp: tBoundedString(0, 64), // Legacy/deprecated
|
})),
|
||||||
}),
|
// 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(),
|
||||||
ping_user: t.boolean, // Legacy/deprecated, if below is false mentions wont actually ping
|
allow_user_mentions: z.boolean(),
|
||||||
allow_user_mentions: t.boolean,
|
timestamp_format: z.string().nullable(),
|
||||||
timestamp_format: tBoundedString(0, 64),
|
include_embed_timestamp: z.boolean(),
|
||||||
include_embed_timestamp: t.boolean,
|
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
// Hacky way of allowing a """null""" default value for config.format.timestamp
|
// Hacky way of allowing a """null""" default value for config.format.timestamp due to legacy io-ts reasons
|
||||||
// The type cannot be made nullable properly because io-ts's intersection type still considers
|
|
||||||
// that it has to match the record type of tLogFormats, which includes string.
|
|
||||||
export const FORMAT_NO_TIMESTAMP = "__NO_TIMESTAMP__";
|
export const FORMAT_NO_TIMESTAMP = "__NO_TIMESTAMP__";
|
||||||
|
|
||||||
export interface LogsPluginType extends BasePluginType {
|
export interface LogsPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zLogsConfig>;
|
||||||
state: {
|
state: {
|
||||||
guildLogs: GuildLogs;
|
guildLogs: GuildLogs;
|
||||||
savedMessages: GuildSavedMessages;
|
savedMessages: GuildSavedMessages;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { PluginOptions } from "knub";
|
import { PluginOptions } from "knub";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
import { makeIoTsConfigParser } from "../../pluginUtils";
|
|
||||||
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
import { zeppelinGuildPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { SaveMessagesToDBCmd } from "./commands/SaveMessagesToDB";
|
import { SaveMessagesToDBCmd } from "./commands/SaveMessagesToDB";
|
||||||
import { SavePinsToDBCmd } from "./commands/SavePinsToDB";
|
import { SavePinsToDBCmd } from "./commands/SavePinsToDB";
|
||||||
import { MessageCreateEvt, MessageDeleteBulkEvt, MessageDeleteEvt, MessageUpdateEvt } from "./events/SaveMessagesEvts";
|
import { MessageCreateEvt, MessageDeleteBulkEvt, MessageDeleteEvt, MessageUpdateEvt } from "./events/SaveMessagesEvts";
|
||||||
import { ConfigSchema, MessageSaverPluginType } from "./types";
|
import { MessageSaverPluginType, zMessageSaverConfig } from "./types";
|
||||||
|
|
||||||
const defaultOptions: PluginOptions<MessageSaverPluginType> = {
|
const defaultOptions: PluginOptions<MessageSaverPluginType> = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -25,7 +24,7 @@ export const MessageSaverPlugin = zeppelinGuildPlugin<MessageSaverPluginType>()(
|
||||||
name: "message_saver",
|
name: "message_saver",
|
||||||
showInDocs: false,
|
showInDocs: false,
|
||||||
|
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zMessageSaverConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import * as t from "io-ts";
|
|
||||||
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
|
import { BasePluginType, guildPluginEventListener, guildPluginMessageCommand } from "knub";
|
||||||
|
import z from "zod";
|
||||||
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
import { GuildSavedMessages } from "../../data/GuildSavedMessages";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const zMessageSaverConfig = z.strictObject({
|
||||||
can_manage: t.boolean,
|
can_manage: z.boolean(),
|
||||||
});
|
});
|
||||||
export type TConfigSchema = t.TypeOf<typeof ConfigSchema>;
|
|
||||||
|
|
||||||
export interface MessageSaverPluginType extends BasePluginType {
|
export interface MessageSaverPluginType extends BasePluginType {
|
||||||
config: TConfigSchema;
|
config: z.infer<typeof zMessageSaverConfig>;
|
||||||
state: {
|
state: {
|
||||||
savedMessages: GuildSavedMessages;
|
savedMessages: GuildSavedMessages;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { onGuildEvent } from "../../data/GuildEvents";
|
||||||
import { GuildLogs } from "../../data/GuildLogs";
|
import { GuildLogs } from "../../data/GuildLogs";
|
||||||
import { GuildMutes } from "../../data/GuildMutes";
|
import { GuildMutes } from "../../data/GuildMutes";
|
||||||
import { GuildTempbans } from "../../data/GuildTempbans";
|
import { GuildTempbans } from "../../data/GuildTempbans";
|
||||||
import { makeIoTsConfigParser, mapToPublicFn } from "../../pluginUtils";
|
import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { MINUTES, trimPluginDescription } from "../../utils";
|
import { MINUTES, trimPluginDescription } from "../../utils";
|
||||||
import { CasesPlugin } from "../Cases/CasesPlugin";
|
import { CasesPlugin } from "../Cases/CasesPlugin";
|
||||||
import { LogsPlugin } from "../Logs/LogsPlugin";
|
import { LogsPlugin } from "../Logs/LogsPlugin";
|
||||||
|
@ -47,7 +47,7 @@ import { offModActionsEvent } from "./functions/offModActionsEvent";
|
||||||
import { onModActionsEvent } from "./functions/onModActionsEvent";
|
import { onModActionsEvent } from "./functions/onModActionsEvent";
|
||||||
import { updateCase } from "./functions/updateCase";
|
import { updateCase } from "./functions/updateCase";
|
||||||
import { warnMember } from "./functions/warnMember";
|
import { warnMember } from "./functions/warnMember";
|
||||||
import { BanOptions, ConfigSchema, KickOptions, ModActionsPluginType, WarnOptions } from "./types";
|
import { BanOptions, KickOptions, ModActionsPluginType, WarnOptions, zModActionsConfig } from "./types";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -121,11 +121,11 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
|
||||||
description: trimPluginDescription(`
|
description: trimPluginDescription(`
|
||||||
This plugin contains the 'typical' mod actions such as warning, muting, kicking, banning, etc.
|
This plugin contains the 'typical' mod actions such as warning, muting, kicking, banning, etc.
|
||||||
`),
|
`),
|
||||||
configSchema: ConfigSchema,
|
configSchema: zModActionsConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
|
dependencies: () => [TimeAndDatePlugin, CasesPlugin, MutesPlugin, LogsPlugin],
|
||||||
configParser: makeIoTsConfigParser(ConfigSchema),
|
configParser: (input) => zModActionsConfig.parse(input),
|
||||||
defaultOptions,
|
defaultOptions,
|
||||||
|
|
||||||
events: [CreateBanCaseOnManualBanEvt, CreateUnbanCaseOnManualUnbanEvt, PostAlertOnMemberJoinEvt, AuditLogEvents],
|
events: [CreateBanCaseOnManualBanEvt, CreateUnbanCaseOnManualUnbanEvt, PostAlertOnMemberJoinEvt, AuditLogEvents],
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue