mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-03-18 06:51:51 +00:00
refactor: don't create 'name' property in config dynamically
This commit is contained in:
parent
0810dd3f0e
commit
395a750e9d
19 changed files with 86 additions and 154 deletions
|
@ -2,8 +2,8 @@ import { GuildPluginData } from "knub";
|
||||||
import { convertDelayStringToMS } from "../../../utils.js";
|
import { convertDelayStringToMS } from "../../../utils.js";
|
||||||
import { AutomodContext, AutomodPluginType, TRule } from "../types.js";
|
import { AutomodContext, AutomodPluginType, TRule } from "../types.js";
|
||||||
|
|
||||||
export function applyCooldown(pluginData: GuildPluginData<AutomodPluginType>, rule: TRule, context: AutomodContext) {
|
export function applyCooldown(pluginData: GuildPluginData<AutomodPluginType>, rule: TRule, ruleName: string, context: AutomodContext) {
|
||||||
const cooldownKey = `${rule.name}-${context.user?.id}`;
|
const cooldownKey = `${ruleName}-${context.user?.id}`;
|
||||||
|
|
||||||
const cooldownTime = convertDelayStringToMS(rule.cooldown, "s");
|
const cooldownTime = convertDelayStringToMS(rule.cooldown, "s");
|
||||||
if (cooldownTime) pluginData.state.cooldownManager.setCooldown(cooldownKey, cooldownTime);
|
if (cooldownTime) pluginData.state.cooldownManager.setCooldown(cooldownKey, cooldownTime);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { AutomodContext, AutomodPluginType, TRule } from "../types.js";
|
import { AutomodContext, AutomodPluginType, TRule } from "../types.js";
|
||||||
|
|
||||||
export function checkCooldown(pluginData: GuildPluginData<AutomodPluginType>, rule: TRule, context: AutomodContext) {
|
export function checkCooldown(pluginData: GuildPluginData<AutomodPluginType>, rule: TRule, ruleName: string, context: AutomodContext) {
|
||||||
const cooldownKey = `${rule.name}-${context.user?.id}`;
|
const cooldownKey = `${ruleName}-${context.user?.id}`;
|
||||||
|
|
||||||
return pluginData.state.cooldownManager.isOnCooldown(cooldownKey);
|
return pluginData.state.cooldownManager.isOnCooldown(cooldownKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ export async function runAutomod(pluginData: GuildPluginData<AutomodPluginType>,
|
||||||
}
|
}
|
||||||
if (!rule.affects_self && userId && userId === pluginData.client.user?.id) continue;
|
if (!rule.affects_self && userId && userId === pluginData.client.user?.id) continue;
|
||||||
|
|
||||||
if (rule.cooldown && checkCooldown(pluginData, rule, context)) {
|
if (rule.cooldown && checkCooldown(pluginData, rule, ruleName, context)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ export async function runAutomod(pluginData: GuildPluginData<AutomodPluginType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchResult) {
|
if (matchResult) {
|
||||||
if (rule.cooldown) applyCooldown(pluginData, rule, context);
|
if (rule.cooldown) applyCooldown(pluginData, rule, ruleName, context);
|
||||||
|
|
||||||
contexts = [context, ...(matchResult.extraContexts || [])];
|
contexts = [context, ...(matchResult.extraContexts || [])];
|
||||||
|
|
||||||
|
|
|
@ -9,30 +9,23 @@ interface MatchResultType {
|
||||||
mode: "blacklist" | "whitelist";
|
mode: "blacklist" | "whitelist";
|
||||||
}
|
}
|
||||||
|
|
||||||
const configSchema = z
|
const baseConfig = z.strictObject({
|
||||||
.strictObject({
|
filetype_blacklist: z.array(z.string().max(32)).max(255).default([]),
|
||||||
filetype_blacklist: z.array(z.string().max(32)).max(255).default([]),
|
filetype_whitelist: z.array(z.string().max(32)).max(255).default([]),
|
||||||
blacklist_enabled: z.boolean().default(false),
|
});
|
||||||
filetype_whitelist: z.array(z.string().max(32)).max(255).default([]),
|
const configWithWhitelist = baseConfig.merge(z.strictObject({
|
||||||
whitelist_enabled: z.boolean().default(false),
|
whitelist_enabled: z.literal(true),
|
||||||
})
|
blacklist_enabled: z.literal(false).default(false),
|
||||||
.transform((parsed, ctx) => {
|
}));
|
||||||
if (parsed.blacklist_enabled && parsed.whitelist_enabled) {
|
const configWithBlacklist = baseConfig.merge(z.strictObject({
|
||||||
ctx.addIssue({
|
blacklist_enabled: z.literal(true),
|
||||||
code: z.ZodIssueCode.custom,
|
whitelist_enabled: z.literal(false).default(false),
|
||||||
message: "Cannot have both blacklist and whitelist enabled",
|
}));
|
||||||
});
|
|
||||||
return z.NEVER;
|
const configSchema = z.union([
|
||||||
}
|
configWithWhitelist,
|
||||||
if (!parsed.blacklist_enabled && !parsed.whitelist_enabled) {
|
configWithBlacklist,
|
||||||
ctx.addIssue({
|
]);
|
||||||
code: z.ZodIssueCode.custom,
|
|
||||||
message: "Must have either blacklist or whitelist enabled",
|
|
||||||
});
|
|
||||||
return z.NEVER;
|
|
||||||
}
|
|
||||||
return parsed;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
|
export const MatchAttachmentTypeTrigger = automodTrigger<MatchResultType>()({
|
||||||
configSchema,
|
configSchema,
|
||||||
|
|
|
@ -8,30 +8,23 @@ interface MatchResultType {
|
||||||
mode: "blacklist" | "whitelist";
|
mode: "blacklist" | "whitelist";
|
||||||
}
|
}
|
||||||
|
|
||||||
const configSchema = z
|
const baseConfig = z.strictObject({
|
||||||
.strictObject({
|
mime_type_blacklist: z.array(z.string().max(32)).max(255).default([]),
|
||||||
mime_type_blacklist: z.array(z.string().max(255)).max(255).default([]),
|
mime_type_whitelist: z.array(z.string().max(32)).max(255).default([]),
|
||||||
blacklist_enabled: z.boolean().default(false),
|
});
|
||||||
mime_type_whitelist: z.array(z.string().max(255)).max(255).default([]),
|
const configWithWhitelist = baseConfig.merge(z.strictObject({
|
||||||
whitelist_enabled: z.boolean().default(false),
|
whitelist_enabled: z.literal(true),
|
||||||
})
|
blacklist_enabled: z.literal(false).default(false),
|
||||||
.transform((parsed, ctx) => {
|
}));
|
||||||
if (parsed.blacklist_enabled && parsed.whitelist_enabled) {
|
const configWithBlacklist = baseConfig.merge(z.strictObject({
|
||||||
ctx.addIssue({
|
blacklist_enabled: z.literal(true),
|
||||||
code: z.ZodIssueCode.custom,
|
whitelist_enabled: z.literal(false).default(false),
|
||||||
message: "Cannot have both blacklist and whitelist enabled",
|
}));
|
||||||
});
|
|
||||||
return z.NEVER;
|
const configSchema = z.union([
|
||||||
}
|
configWithWhitelist,
|
||||||
if (!parsed.blacklist_enabled && !parsed.whitelist_enabled) {
|
configWithBlacklist,
|
||||||
ctx.addIssue({
|
]);
|
||||||
code: z.ZodIssueCode.custom,
|
|
||||||
message: "Must have either blacklist or whitelist enabled",
|
|
||||||
});
|
|
||||||
return z.NEVER;
|
|
||||||
}
|
|
||||||
return parsed;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const MatchMimeTypeTrigger = automodTrigger<MatchResultType>()({
|
export const MatchMimeTypeTrigger = automodTrigger<MatchResultType>()({
|
||||||
configSchema,
|
configSchema,
|
||||||
|
|
|
@ -46,22 +46,6 @@ const zActionsMap = z
|
||||||
|
|
||||||
const zRule = z.strictObject({
|
const zRule = z.strictObject({
|
||||||
enabled: z.boolean().default(true),
|
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;
|
|
||||||
}),
|
|
||||||
pretty_name: z.string().optional(),
|
pretty_name: z.string().optional(),
|
||||||
presets: z.array(z.string().max(100)).max(25).default([]),
|
presets: z.array(z.string().max(100)).max(25).default([]),
|
||||||
affects_bots: z.boolean().default(false),
|
affects_bots: z.boolean().default(false),
|
||||||
|
@ -69,9 +53,7 @@ const zRule = z.strictObject({
|
||||||
cooldown: zDelayString.nullable().default(null),
|
cooldown: zDelayString.nullable().default(null),
|
||||||
allow_further_rules: z.boolean().default(false),
|
allow_further_rules: z.boolean().default(false),
|
||||||
triggers: z.array(zTriggersMap),
|
triggers: z.array(zTriggersMap),
|
||||||
actions: zActionsMap.refine((v) => !(v.clean && v.start_thread), {
|
actions: zActionsMap,
|
||||||
message: "Cannot have both clean and start_thread active at the same time",
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
export type TRule = z.infer<typeof zRule>;
|
export type TRule = z.infer<typeof zRule>;
|
||||||
|
|
||||||
|
|
|
@ -97,20 +97,20 @@ export const CountersPlugin = guildPlugin<CountersPluginType>()({
|
||||||
// Initialize and store the IDs of each of the counters internally
|
// Initialize and store the IDs of each of the counters internally
|
||||||
state.counterIds = {};
|
state.counterIds = {};
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
for (const counter of Object.values(config.counters)) {
|
for (const [counterName, counter] of Object.entries(config.counters)) {
|
||||||
const dbCounter = await state.counters.findOrCreateCounter(counter.name, counter.per_channel, counter.per_user);
|
const dbCounter = await state.counters.findOrCreateCounter(counterName, counter.per_channel, counter.per_user);
|
||||||
state.counterIds[counter.name] = dbCounter.id;
|
state.counterIds[counterName] = dbCounter.id;
|
||||||
|
|
||||||
const thisCounterTriggers: CounterTrigger[] = [];
|
const thisCounterTriggers: CounterTrigger[] = [];
|
||||||
state.counterTriggersByCounterId.set(dbCounter.id, thisCounterTriggers);
|
state.counterTriggersByCounterId.set(dbCounter.id, thisCounterTriggers);
|
||||||
|
|
||||||
// Initialize triggers
|
// Initialize triggers
|
||||||
for (const trigger of values(counter.triggers)) {
|
for (const [triggerName, trigger] of Object.entries(counter.triggers)) {
|
||||||
const parsedCondition = parseCounterConditionString(trigger.condition)!;
|
const parsedCondition = parseCounterConditionString(trigger.condition)!;
|
||||||
const parsedReverseCondition = parseCounterConditionString(trigger.reverse_condition)!;
|
const parsedReverseCondition = parseCounterConditionString(trigger.reverse_condition)!;
|
||||||
const counterTrigger = await state.counters.initCounterTrigger(
|
const counterTrigger = await state.counters.initCounterTrigger(
|
||||||
dbCounter.id,
|
dbCounter.id,
|
||||||
trigger.name,
|
triggerName,
|
||||||
parsedCondition[0],
|
parsedCondition[0],
|
||||||
parsedCondition[1],
|
parsedCondition[1],
|
||||||
parsedReverseCondition[0],
|
parsedReverseCondition[0],
|
||||||
|
|
|
@ -119,18 +119,17 @@ export const AddCounterCmd = guildPluginMessageCommand<CountersPluginType>()({
|
||||||
|
|
||||||
await changeCounterValue(pluginData, args.counterName, channel?.id ?? null, user?.id ?? null, amount);
|
await changeCounterValue(pluginData, args.counterName, channel?.id ?? null, user?.id ?? null, amount);
|
||||||
const newValue = await pluginData.state.counters.getCurrentValue(counterId, channel?.id ?? null, user?.id ?? null);
|
const newValue = await pluginData.state.counters.getCurrentValue(counterId, channel?.id ?? null, user?.id ?? null);
|
||||||
const counterName = counter.name || args.counterName;
|
|
||||||
|
|
||||||
if (channel && user) {
|
if (channel && user) {
|
||||||
message.channel.send(
|
message.channel.send(
|
||||||
`Added ${amount} to **${counterName}** for <@!${user.id}> in <#${channel.id}>. The value is now ${newValue}.`,
|
`Added ${amount} to **${args.counterName}** for <@!${user.id}> in <#${channel.id}>. The value is now ${newValue}.`,
|
||||||
);
|
);
|
||||||
} else if (channel) {
|
} else if (channel) {
|
||||||
message.channel.send(`Added ${amount} to **${counterName}** in <#${channel.id}>. The value is now ${newValue}.`);
|
message.channel.send(`Added ${amount} to **${args.counterName}** in <#${channel.id}>. The value is now ${newValue}.`);
|
||||||
} else if (user) {
|
} else if (user) {
|
||||||
message.channel.send(`Added ${amount} to **${counterName}** for <@!${user.id}>. The value is now ${newValue}.`);
|
message.channel.send(`Added ${amount} to **${args.counterName}** for <@!${user.id}>. The value is now ${newValue}.`);
|
||||||
} else {
|
} else {
|
||||||
message.channel.send(`Added ${amount} to **${counterName}**. The value is now ${newValue}.`);
|
message.channel.send(`Added ${amount} to **${args.counterName}**. The value is now ${newValue}.`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,14 +12,14 @@ export const CountersListCmd = guildPluginMessageCommand<CountersPluginType>()({
|
||||||
async run({ pluginData, message }) {
|
async run({ pluginData, message }) {
|
||||||
const config = await pluginData.config.getForMessage(message);
|
const config = await pluginData.config.getForMessage(message);
|
||||||
|
|
||||||
const countersToShow = Array.from(Object.values(config.counters)).filter((c) => c.can_view !== false);
|
const countersToShow = Object.entries(config.counters).filter(([, c]) => c.can_view !== false);
|
||||||
if (!countersToShow.length) {
|
if (!countersToShow.length) {
|
||||||
void pluginData.state.common.sendErrorMessage(message, "No counters are configured for this server");
|
void pluginData.state.common.sendErrorMessage(message, "No counters are configured for this server");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const counterLines = countersToShow.map((counter) => {
|
const counterLines = countersToShow.map(([counterName, counter]) => {
|
||||||
const title = counter.pretty_name ? `**${counter.pretty_name}** (\`${counter.name}\`)` : `\`${counter.name}\``;
|
const title = counter.pretty_name ? `**${counter.pretty_name}** (\`${counterName}\`)` : `\`${counterName}\``;
|
||||||
|
|
||||||
const types: string[] = [];
|
const types: string[] = [];
|
||||||
if (counter.per_user) types.push("per user");
|
if (counter.per_user) types.push("per user");
|
||||||
|
|
|
@ -29,10 +29,9 @@ export const ResetAllCounterValuesCmd = guildPluginMessageCommand<CountersPlugin
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const counterName = counter.name || args.counterName;
|
|
||||||
const confirmed = await confirm(message, message.author.id, {
|
const confirmed = await confirm(message, message.author.id, {
|
||||||
content: trimMultilineString(`
|
content: trimMultilineString(`
|
||||||
Do you want to reset **ALL** values for counter **${counterName}**?
|
Do you want to reset **ALL** values for counter **${args.counterName}**?
|
||||||
This will reset the counter for **all** users and channels.
|
This will reset the counter for **all** users and channels.
|
||||||
**Note:** This will *not* trigger any triggers or counter triggers.
|
**Note:** This will *not* trigger any triggers or counter triggers.
|
||||||
`),
|
`),
|
||||||
|
@ -43,7 +42,7 @@ export const ResetAllCounterValuesCmd = guildPluginMessageCommand<CountersPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadingMessage = await message.channel
|
const loadingMessage = await message.channel
|
||||||
.send(`Resetting counter **${counterName}**. This might take a while. Please don't reload the config.`)
|
.send(`Resetting counter **${args.counterName}**. This might take a while. Please don't reload the config.`)
|
||||||
.catch(() => null);
|
.catch(() => null);
|
||||||
|
|
||||||
await resetAllCounterValues(pluginData, args.counterName);
|
await resetAllCounterValues(pluginData, args.counterName);
|
||||||
|
@ -51,7 +50,7 @@ export const ResetAllCounterValuesCmd = guildPluginMessageCommand<CountersPlugin
|
||||||
loadingMessage?.delete().catch(noop);
|
loadingMessage?.delete().catch(noop);
|
||||||
void pluginData.state.common.sendSuccessMessage(
|
void pluginData.state.common.sendSuccessMessage(
|
||||||
message,
|
message,
|
||||||
`All counter values for **${counterName}** have been reset`,
|
`All counter values for **${args.counterName}** have been reset`,
|
||||||
);
|
);
|
||||||
|
|
||||||
pluginData.getKnubInstance().reloadGuild(pluginData.guild.id);
|
pluginData.getKnubInstance().reloadGuild(pluginData.guild.id);
|
||||||
|
|
|
@ -95,16 +95,15 @@ export const ResetCounterCmd = guildPluginMessageCommand<CountersPluginType>()({
|
||||||
}
|
}
|
||||||
|
|
||||||
await setCounterValue(pluginData, args.counterName, channel?.id ?? null, user?.id ?? null, counter.initial_value);
|
await setCounterValue(pluginData, args.counterName, channel?.id ?? null, user?.id ?? null, counter.initial_value);
|
||||||
const counterName = counter.name || args.counterName;
|
|
||||||
|
|
||||||
if (channel && user) {
|
if (channel && user) {
|
||||||
message.channel.send(`Reset **${counterName}** for <@!${user.id}> in <#${channel.id}>`);
|
message.channel.send(`Reset **${args.counterName}** for <@!${user.id}> in <#${channel.id}>`);
|
||||||
} else if (channel) {
|
} else if (channel) {
|
||||||
message.channel.send(`Reset **${counterName}** in <#${channel.id}>`);
|
message.channel.send(`Reset **${args.counterName}** in <#${channel.id}>`);
|
||||||
} else if (user) {
|
} else if (user) {
|
||||||
message.channel.send(`Reset **${counterName}** for <@!${user.id}>`);
|
message.channel.send(`Reset **${args.counterName}** for <@!${user.id}>`);
|
||||||
} else {
|
} else {
|
||||||
message.channel.send(`Reset **${counterName}**`);
|
message.channel.send(`Reset **${args.counterName}**`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -123,16 +123,15 @@ export const SetCounterCmd = guildPluginMessageCommand<CountersPluginType>()({
|
||||||
}
|
}
|
||||||
|
|
||||||
await setCounterValue(pluginData, args.counterName, channel?.id ?? null, user?.id ?? null, value);
|
await setCounterValue(pluginData, args.counterName, channel?.id ?? null, user?.id ?? null, value);
|
||||||
const counterName = counter.name || args.counterName;
|
|
||||||
|
|
||||||
if (channel && user) {
|
if (channel && user) {
|
||||||
message.channel.send(`Set **${counterName}** for <@!${user.id}> in <#${channel.id}> to ${value}`);
|
message.channel.send(`Set **${args.counterName}** for <@!${user.id}> in <#${channel.id}> to ${value}`);
|
||||||
} else if (channel) {
|
} else if (channel) {
|
||||||
message.channel.send(`Set **${counterName}** in <#${channel.id}> to ${value}`);
|
message.channel.send(`Set **${args.counterName}** in <#${channel.id}> to ${value}`);
|
||||||
} else if (user) {
|
} else if (user) {
|
||||||
message.channel.send(`Set **${counterName}** for <@!${user.id}> to ${value}`);
|
message.channel.send(`Set **${args.counterName}** for <@!${user.id}> to ${value}`);
|
||||||
} else {
|
} else {
|
||||||
message.channel.send(`Set **${counterName}** to ${value}`);
|
message.channel.send(`Set **${args.counterName}** to ${value}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -95,16 +95,15 @@ export const ViewCounterCmd = guildPluginMessageCommand<CountersPluginType>()({
|
||||||
|
|
||||||
const value = await pluginData.state.counters.getCurrentValue(counterId, channel?.id ?? null, user?.id ?? null);
|
const value = await pluginData.state.counters.getCurrentValue(counterId, channel?.id ?? null, user?.id ?? null);
|
||||||
const finalValue = value ?? counter.initial_value;
|
const finalValue = value ?? counter.initial_value;
|
||||||
const counterName = counter.name || args.counterName;
|
|
||||||
|
|
||||||
if (channel && user) {
|
if (channel && user) {
|
||||||
message.channel.send(`**${counterName}** for <@!${user.id}> in <#${channel.id}> is ${finalValue}`);
|
message.channel.send(`**${args.counterName}** for <@!${user.id}> in <#${channel.id}> is ${finalValue}`);
|
||||||
} else if (channel) {
|
} else if (channel) {
|
||||||
message.channel.send(`**${counterName}** in <#${channel.id}> is ${finalValue}`);
|
message.channel.send(`**${args.counterName}** in <#${channel.id}> is ${finalValue}`);
|
||||||
} else if (user) {
|
} else if (user) {
|
||||||
message.channel.send(`**${counterName}** for <@!${user.id}> is ${finalValue}`);
|
message.channel.send(`**${args.counterName}** for <@!${user.id}> is ${finalValue}`);
|
||||||
} else {
|
} else {
|
||||||
message.channel.send(`**${counterName}** is ${finalValue}`);
|
message.channel.send(`**${args.counterName}** is ${finalValue}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,5 +4,5 @@ import { CountersPluginType } from "../types.js";
|
||||||
export function getPrettyNameForCounter(pluginData: GuildPluginData<CountersPluginType>, counterName: string) {
|
export function getPrettyNameForCounter(pluginData: GuildPluginData<CountersPluginType>, counterName: string) {
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
const counter = config.counters[counterName];
|
const counter = config.counters[counterName];
|
||||||
return counter ? counter.pretty_name || counter.name : "Unknown Counter";
|
return counter ? counter.pretty_name || counterName : "Unknown Counter";
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,22 +75,6 @@ const zTriggerFromString = zBoundedCharacters(0, 100).transform((val, ctx) => {
|
||||||
const zTriggerInput = z.union([zTrigger, zTriggerFromString]);
|
const zTriggerInput = z.union([zTrigger, zTriggerFromString]);
|
||||||
|
|
||||||
export const zCounter = z.strictObject({
|
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),
|
pretty_name: zBoundedCharacters(0, 100).nullable().default(null),
|
||||||
per_channel: z.boolean().default(false),
|
per_channel: z.boolean().default(false),
|
||||||
per_user: z.boolean().default(false),
|
per_user: z.boolean().default(false),
|
||||||
|
|
|
@ -6,26 +6,26 @@ import { applyRoleButtons } from "./applyRoleButtons.js";
|
||||||
export async function applyAllRoleButtons(pluginData: GuildPluginData<RoleButtonsPluginType>) {
|
export async function applyAllRoleButtons(pluginData: GuildPluginData<RoleButtonsPluginType>) {
|
||||||
const savedRoleButtons = await pluginData.state.roleButtons.getSavedRoleButtons();
|
const savedRoleButtons = await pluginData.state.roleButtons.getSavedRoleButtons();
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
for (const buttons of Object.values(config.buttons)) {
|
for (const [configName, configItem] of Object.entries(config.buttons)) {
|
||||||
// Use the hash of the config to quickly check if we need to update buttons
|
// Use the hash of the config to quickly check if we need to update buttons
|
||||||
const hash = createHash("md5").update(JSON.stringify(buttons)).digest("hex");
|
const hash = createHash("md5").update(JSON.stringify(configItem)).digest("hex");
|
||||||
const savedButtonsItem = savedRoleButtons.find((bt) => bt.name === buttons.name);
|
const savedButtonsItem = savedRoleButtons.find((bt) => bt.name === configName);
|
||||||
if (savedButtonsItem?.hash === hash) {
|
if (savedButtonsItem?.hash === hash) {
|
||||||
// No changes
|
// No changes
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedButtonsItem) {
|
if (savedButtonsItem) {
|
||||||
await pluginData.state.roleButtons.deleteRoleButtonItem(buttons.name);
|
await pluginData.state.roleButtons.deleteRoleButtonItem(configName);
|
||||||
}
|
}
|
||||||
|
|
||||||
const applyResult = await applyRoleButtons(pluginData, buttons, savedButtonsItem ?? null);
|
const applyResult = await applyRoleButtons(pluginData, configItem, configName, savedButtonsItem ?? null);
|
||||||
if (!applyResult) {
|
if (!applyResult) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await pluginData.state.roleButtons.saveRoleButtonItem(
|
await pluginData.state.roleButtons.saveRoleButtonItem(
|
||||||
buttons.name,
|
configName,
|
||||||
applyResult.channel_id,
|
applyResult.channel_id,
|
||||||
applyResult.message_id,
|
applyResult.message_id,
|
||||||
hash,
|
hash,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { createButtonComponents } from "./createButtonComponents.js";
|
||||||
export async function applyRoleButtons(
|
export async function applyRoleButtons(
|
||||||
pluginData: GuildPluginData<RoleButtonsPluginType>,
|
pluginData: GuildPluginData<RoleButtonsPluginType>,
|
||||||
configItem: TRoleButtonsConfigItem,
|
configItem: TRoleButtonsConfigItem,
|
||||||
|
configName: string,
|
||||||
existingSavedButtons: RoleButtonsItem | null,
|
existingSavedButtons: RoleButtonsItem | null,
|
||||||
): Promise<{ channel_id: string; message_id: string } | null> {
|
): Promise<{ channel_id: string; message_id: string } | null> {
|
||||||
let message: Message;
|
let message: Message;
|
||||||
|
@ -32,7 +33,7 @@ export async function applyRoleButtons(
|
||||||
channel.messages.fetch(configItem.message.message_id).catch(() => null));
|
channel.messages.fetch(configItem.message.message_id).catch(() => null));
|
||||||
if (!messageCandidate) {
|
if (!messageCandidate) {
|
||||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||||
body: `Message not found for role_buttons/${configItem.name}`,
|
body: `Message not found for role_buttons/${configName}`,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +46,7 @@ export async function applyRoleButtons(
|
||||||
: Boolean(configItem.message.content.content?.trim()) || configItem.message.content.embeds?.length;
|
: Boolean(configItem.message.content.content?.trim()) || configItem.message.content.embeds?.length;
|
||||||
if (!contentIsValid) {
|
if (!contentIsValid) {
|
||||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||||
body: `Invalid message content for role_buttons/${configItem.name}`,
|
body: `Invalid message content for role_buttons/${configName}`,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +59,7 @@ export async function applyRoleButtons(
|
||||||
}
|
}
|
||||||
if (!channel || !channel?.isTextBased()) {
|
if (!channel || !channel?.isTextBased()) {
|
||||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||||
body: `Text channel not found for role_buttons/${configItem.name}`,
|
body: `Text channel not found for role_buttons/${configName}`,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +90,7 @@ export async function applyRoleButtons(
|
||||||
candidateMessage = await channel.send(configItem.message.content as string | MessageCreateOptions);
|
candidateMessage = await channel.send(configItem.message.content as string | MessageCreateOptions);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||||
body: `Error while posting message for role_buttons/${configItem.name}: ${String(err)}`,
|
body: `Error while posting message for role_buttons/${configName}: ${String(err)}`,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -100,16 +101,16 @@ export async function applyRoleButtons(
|
||||||
|
|
||||||
if (message.author.id !== pluginData.client.user?.id) {
|
if (message.author.id !== pluginData.client.user?.id) {
|
||||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||||
body: `Error applying role buttons for role_buttons/${configItem.name}: target message must be posted by Zeppelin`,
|
body: `Error applying role buttons for role_buttons/${configName}: target message must be posted by Zeppelin`,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply role buttons
|
// Apply role buttons
|
||||||
const components = createButtonComponents(configItem);
|
const components = createButtonComponents(configItem, configName);
|
||||||
await message.edit({ components }).catch((err) => {
|
await message.edit({ components }).catch((err) => {
|
||||||
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
pluginData.getPlugin(LogsPlugin).logBotAlert({
|
||||||
body: `Error applying role buttons for role_buttons/${configItem.name}: ${String(err)}`,
|
body: `Error applying role buttons for role_buttons/${configName}: ${String(err)}`,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { TRoleButtonsConfigItem } from "../types.js";
|
||||||
import { TooManyComponentsError } from "./TooManyComponentsError.js";
|
import { TooManyComponentsError } from "./TooManyComponentsError.js";
|
||||||
import { convertButtonStyleStringToEnum } from "./convertButtonStyleStringToEnum.js";
|
import { convertButtonStyleStringToEnum } from "./convertButtonStyleStringToEnum.js";
|
||||||
|
|
||||||
export function createButtonComponents(configItem: TRoleButtonsConfigItem): Array<ActionRowBuilder<ButtonBuilder>> {
|
export function createButtonComponents(configItem: TRoleButtonsConfigItem, configName: string): Array<ActionRowBuilder<ButtonBuilder>> {
|
||||||
const rows: Array<ActionRowBuilder<ButtonBuilder>> = [];
|
const rows: Array<ActionRowBuilder<ButtonBuilder>> = [];
|
||||||
|
|
||||||
let currentRow = new ActionRowBuilder<ButtonBuilder>();
|
let currentRow = new ActionRowBuilder<ButtonBuilder>();
|
||||||
|
@ -17,7 +17,7 @@ export function createButtonComponents(configItem: TRoleButtonsConfigItem): Arra
|
||||||
const button = new ButtonBuilder()
|
const button = new ButtonBuilder()
|
||||||
.setLabel(option.label ?? "")
|
.setLabel(option.label ?? "")
|
||||||
.setStyle(convertButtonStyleStringToEnum(option.style) ?? ButtonStyle.Primary)
|
.setStyle(convertButtonStyleStringToEnum(option.style) ?? ButtonStyle.Primary)
|
||||||
.setCustomId(buildCustomId("roleButtons", { name: configItem.name, index }));
|
.setCustomId(buildCustomId("roleButtons", { name: configName, index }));
|
||||||
|
|
||||||
if (option.emoji) {
|
if (option.emoji) {
|
||||||
button.setEmoji(option.emoji);
|
button.setEmoji(option.emoji);
|
||||||
|
|
|
@ -34,22 +34,6 @@ export type TRoleButtonOption = z.infer<typeof zRoleButtonOption>;
|
||||||
|
|
||||||
const zRoleButtonsConfigItem = z
|
const zRoleButtonsConfigItem = z
|
||||||
.strictObject({
|
.strictObject({
|
||||||
// Typed as "never" because you are not expected to supply this directly.
|
|
||||||
// The transform instead picks it up from the property key and the output type is a string.
|
|
||||||
name: z
|
|
||||||
.never()
|
|
||||||
.optional()
|
|
||||||
.transform((_, ctx) => {
|
|
||||||
const ruleName = String(ctx.path[ctx.path.length - 2]).trim();
|
|
||||||
if (!ruleName) {
|
|
||||||
ctx.addIssue({
|
|
||||||
code: z.ZodIssueCode.custom,
|
|
||||||
message: "Role buttons must have names",
|
|
||||||
});
|
|
||||||
return z.NEVER;
|
|
||||||
}
|
|
||||||
return ruleName;
|
|
||||||
}),
|
|
||||||
message: z.union([
|
message: z.union([
|
||||||
z.strictObject({
|
z.strictObject({
|
||||||
channel_id: zSnowflake,
|
channel_id: zSnowflake,
|
||||||
|
@ -66,7 +50,7 @@ const zRoleButtonsConfigItem = z
|
||||||
.refine(
|
.refine(
|
||||||
(parsed) => {
|
(parsed) => {
|
||||||
try {
|
try {
|
||||||
createButtonComponents(parsed);
|
createButtonComponents(parsed, "test"); // We can use any configName here
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof TooManyComponentsError) {
|
if (err instanceof TooManyComponentsError) {
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Add table
Reference in a new issue