mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-03-15 05:41:51 +00:00
Reorganize/clean up TagsPlugin code
This commit is contained in:
parent
b758c9cfe0
commit
fc8b78fb55
6 changed files with 171 additions and 122 deletions
|
@ -1,9 +1,9 @@
|
|||
import { tagsCmd } from "../types";
|
||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||
import { renderTag } from "../util/renderTag";
|
||||
import { MessageContent } from "eris";
|
||||
import { TemplateParseError } from "../../../templateFormatter";
|
||||
import { sendErrorMessage } from "../../../pluginUtils";
|
||||
import { renderTagBody } from "../util/renderTagBody";
|
||||
|
||||
export const TagEvalCmd = tagsCmd({
|
||||
trigger: "tag eval",
|
||||
|
@ -15,7 +15,7 @@ export const TagEvalCmd = tagsCmd({
|
|||
|
||||
async run({ message: msg, args, pluginData }) {
|
||||
try {
|
||||
const rendered = await renderTag(pluginData, args.body);
|
||||
const rendered = await renderTagBody(pluginData, args.body);
|
||||
msg.channel.createMessage(rendered);
|
||||
} catch (e) {
|
||||
if (e instanceof TemplateParseError) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { GuildLogs } from "src/data/GuildLogs";
|
|||
|
||||
export const Tag = t.union([t.string, tEmbed]);
|
||||
|
||||
const TagCategory = t.type({
|
||||
export const TagCategory = t.type({
|
||||
prefix: tNullable(t.string),
|
||||
delete_with_command: tNullable(t.boolean),
|
||||
|
||||
|
@ -21,6 +21,7 @@ const TagCategory = t.type({
|
|||
|
||||
can_use: tNullable(t.boolean),
|
||||
});
|
||||
export type TTagCategory = t.TypeOf<typeof TagCategory>;
|
||||
|
||||
export const ConfigSchema = t.type({
|
||||
prefix: t.string,
|
||||
|
|
94
backend/src/plugins/Tags/util/matchAndRenderTagFromString.ts
Normal file
94
backend/src/plugins/Tags/util/matchAndRenderTagFromString.ts
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { ExtendedMatchParams } from "knub/dist/config/PluginConfigManager";
|
||||
import { PluginData } from "knub";
|
||||
import { TagsPluginType, TTagCategory } from "../types";
|
||||
import { renderTagFromString } from "./renderTagFromString";
|
||||
import { convertDelayStringToMS } from "../../../utils";
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
import { Member, MessageContent } from "eris";
|
||||
|
||||
interface Result {
|
||||
renderedContent: MessageContent;
|
||||
tagName: string;
|
||||
categoryName: string | null;
|
||||
category: TTagCategory | null;
|
||||
}
|
||||
|
||||
export async function matchAndRenderTagFromString(
|
||||
pluginData: PluginData<TagsPluginType>,
|
||||
str: string,
|
||||
member: Member,
|
||||
extraMatchParams: ExtendedMatchParams = {},
|
||||
): Promise<Result | null> {
|
||||
const config = pluginData.config.getMatchingConfig({
|
||||
...extraMatchParams,
|
||||
member,
|
||||
});
|
||||
|
||||
// Hard-coded tags in categories
|
||||
for (const [name, category] of Object.entries(config.categories)) {
|
||||
const canUse = category.can_use != null ? category.can_use : config.can_use;
|
||||
if (canUse !== true) continue;
|
||||
|
||||
const prefix = category.prefix != null ? category.prefix : config.prefix;
|
||||
if (prefix !== "" && !str.startsWith(prefix)) continue;
|
||||
|
||||
const withoutPrefix = str.slice(prefix.length);
|
||||
|
||||
for (const [tagName, tagBody] of Object.entries(category.tags)) {
|
||||
const regex = new RegExp(`^${escapeStringRegexp(tagName)}(?:\\s|$)`);
|
||||
if (regex.test(withoutPrefix)) {
|
||||
const renderedContent = await renderTagFromString(
|
||||
pluginData,
|
||||
str,
|
||||
prefix,
|
||||
tagName,
|
||||
category.tags[tagName],
|
||||
member,
|
||||
);
|
||||
|
||||
return {
|
||||
renderedContent,
|
||||
tagName,
|
||||
categoryName: name,
|
||||
category,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic tags
|
||||
if (config.can_use !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dynamicTagPrefix = config.prefix;
|
||||
if (!str.startsWith(dynamicTagPrefix)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dynamicTagNameMatch = str.slice(dynamicTagPrefix.length).match(/^\S+/);
|
||||
if (dynamicTagNameMatch === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dynamicTagName = dynamicTagNameMatch[0];
|
||||
const dynamicTag = await pluginData.state.tags.find(dynamicTagName);
|
||||
if (!dynamicTag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderedDynamicTagContent = await renderTagFromString(
|
||||
pluginData,
|
||||
str,
|
||||
dynamicTagPrefix,
|
||||
dynamicTagName,
|
||||
dynamicTag.body,
|
||||
member,
|
||||
);
|
||||
return {
|
||||
renderedContent: renderedDynamicTagContent,
|
||||
tagName: dynamicTagName,
|
||||
categoryName: null,
|
||||
category: null,
|
||||
};
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
import { TagsPluginType } from "../types";
|
||||
import { SavedMessage } from "src/data/entities/SavedMessage";
|
||||
import { PluginData } from "knub";
|
||||
import { resolveMember, convertDelayStringToMS, tStrictMessageContent } from "src/utils";
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
import { convertDelayStringToMS, resolveMember, tStrictMessageContent } from "src/utils";
|
||||
import { validate } from "src/validatorUtils";
|
||||
import { LogType } from "src/data/LogType";
|
||||
import { TextChannel } from "eris";
|
||||
import { renderSafeTagFromMessage } from "./renderSafeTagFromMessage";
|
||||
import { matchAndRenderTagFromString } from "./matchAndRenderTagFromString";
|
||||
|
||||
export async function onMessageCreate(pluginData: PluginData<TagsPluginType>, msg: SavedMessage) {
|
||||
if (msg.is_bot) return;
|
||||
|
@ -21,105 +20,59 @@ export async function onMessageCreate(pluginData: PluginData<TagsPluginType>, ms
|
|||
channelId: msg.channel_id,
|
||||
categoryId: channel.parentID,
|
||||
});
|
||||
let deleteWithCommand = false;
|
||||
|
||||
// Find potential matching tag, looping through categories first and checking dynamic tags last
|
||||
let renderedTag = null;
|
||||
let matchedTagName;
|
||||
const tagResult = await matchAndRenderTagFromString(pluginData, msg.data.content, member, {
|
||||
channelId: msg.channel_id,
|
||||
categoryId: channel.parentID,
|
||||
});
|
||||
|
||||
if (!tagResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for cooldowns
|
||||
const cooldowns = [];
|
||||
|
||||
for (const [name, category] of Object.entries(config.categories)) {
|
||||
const canUse = category.can_use != null ? category.can_use : config.can_use;
|
||||
if (canUse !== true) continue;
|
||||
|
||||
const prefix = category.prefix != null ? category.prefix : config.prefix;
|
||||
if (prefix !== "" && !msg.data.content.startsWith(prefix)) continue;
|
||||
|
||||
const withoutPrefix = msg.data.content.slice(prefix.length);
|
||||
|
||||
for (const [tagName, tagBody] of Object.entries(category.tags)) {
|
||||
const regex = new RegExp(`^${escapeStringRegexp(tagName)}(?:\\s|$)`);
|
||||
if (regex.test(withoutPrefix)) {
|
||||
renderedTag = await renderSafeTagFromMessage(
|
||||
pluginData,
|
||||
msg.data.content,
|
||||
prefix,
|
||||
tagName,
|
||||
category.tags[tagName],
|
||||
member,
|
||||
);
|
||||
if (renderedTag) {
|
||||
matchedTagName = tagName;
|
||||
break;
|
||||
if (tagResult.category) {
|
||||
// Category-specific cooldowns
|
||||
if (tagResult.category.user_tag_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(tagResult.category.user_tag_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${tagResult.categoryName}-user-${msg.user_id}-tag-${tagResult.tagName}`, delay]);
|
||||
}
|
||||
if (tagResult.category.global_tag_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(tagResult.category.global_tag_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${tagResult.categoryName}-tag-${tagResult.tagName}`, delay]);
|
||||
}
|
||||
if (tagResult.category.user_category_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(tagResult.category.user_category_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${tagResult.categoryName}-user--${msg.user_id}`, delay]);
|
||||
}
|
||||
|
||||
if (renderedTag) {
|
||||
if (category.user_tag_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(category.user_tag_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${name}-user-${msg.user_id}-tag-${matchedTagName}`, delay]);
|
||||
if (tagResult.category.global_category_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(tagResult.category.global_category_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${tagResult.categoryName}`, delay]);
|
||||
}
|
||||
if (category.global_tag_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(category.global_tag_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${name}-tag-${matchedTagName}`, delay]);
|
||||
}
|
||||
if (category.user_category_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(category.user_category_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${name}-user--${msg.user_id}`, delay]);
|
||||
}
|
||||
if (category.global_category_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(category.global_category_cooldown), "s");
|
||||
cooldowns.push([`tags-category-${name}`, delay]);
|
||||
}
|
||||
|
||||
deleteWithCommand =
|
||||
category.delete_with_command != null ? category.delete_with_command : config.delete_with_command;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Matching tag was not found from the config, try a dynamic tag
|
||||
if (!renderedTag) {
|
||||
if (config.can_use !== true) return;
|
||||
|
||||
const prefix = config.prefix;
|
||||
if (!msg.data.content.startsWith(prefix)) return;
|
||||
|
||||
const tagNameMatch = msg.data.content.slice(prefix.length).match(/^\S+/);
|
||||
if (tagNameMatch === null) return;
|
||||
|
||||
const tagName = tagNameMatch[0];
|
||||
const tag = await pluginData.state.tags.find(tagName);
|
||||
if (!tag) return;
|
||||
|
||||
matchedTagName = tagName;
|
||||
|
||||
renderedTag = await renderSafeTagFromMessage(pluginData, msg.data.content, prefix, tagName, tag.body, member);
|
||||
}
|
||||
|
||||
if (!renderedTag) return;
|
||||
|
||||
} else {
|
||||
// Dynamic tag cooldowns
|
||||
if (config.user_tag_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(config.user_tag_cooldown), "s");
|
||||
cooldowns.push([`tags-user-${msg.user_id}-tag-${matchedTagName}`, delay]);
|
||||
cooldowns.push([`tags-user-${msg.user_id}-tag-${tagResult.tagName}`, delay]);
|
||||
}
|
||||
|
||||
if (config.global_tag_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(config.global_tag_cooldown), "s");
|
||||
cooldowns.push([`tags-tag-${matchedTagName}`, delay]);
|
||||
cooldowns.push([`tags-tag-${tagResult.tagName}`, delay]);
|
||||
}
|
||||
|
||||
if (config.user_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(config.user_cooldown), "s");
|
||||
cooldowns.push([`tags-user-${matchedTagName}`, delay]);
|
||||
cooldowns.push([`tags-user-${tagResult.tagName}`, delay]);
|
||||
}
|
||||
|
||||
if (config.global_cooldown) {
|
||||
const delay = convertDelayStringToMS(String(config.global_cooldown), "s");
|
||||
cooldowns.push([`tags`, delay]);
|
||||
}
|
||||
}
|
||||
|
||||
const isOnCooldown = cooldowns.some(cd => pluginData.cooldowns.isOnCooldown(cd[0]));
|
||||
if (isOnCooldown) return;
|
||||
|
@ -128,26 +81,25 @@ export async function onMessageCreate(pluginData: PluginData<TagsPluginType>, ms
|
|||
pluginData.cooldowns.setCooldown(cd[0], cd[1]);
|
||||
}
|
||||
|
||||
deleteWithCommand = config.delete_with_command;
|
||||
|
||||
const validationError = await validate(tStrictMessageContent, renderedTag);
|
||||
const validationError = await validate(tStrictMessageContent, tagResult.renderedContent);
|
||||
if (validationError) {
|
||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||
body: `Rendering tag ${matchedTagName} resulted in an invalid message: ${validationError.message}`,
|
||||
body: `Rendering tag ${tagResult.tagName} resulted in an invalid message: ${validationError.message}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof renderedTag === "string" && renderedTag.trim() === "") {
|
||||
if (typeof tagResult.renderedContent === "string" && tagResult.renderedContent.trim() === "") {
|
||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||
body: `Tag \`${matchedTagName}\` resulted in an empty message, so it couldn't be sent`,
|
||||
body: `Tag \`${tagResult.tagName}\` resulted in an empty message, so it couldn't be sent`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const responseMsg = await channel.createMessage(renderedTag);
|
||||
const responseMsg = await channel.createMessage(tagResult.renderedContent);
|
||||
|
||||
// Save the command-response message pair once the message is in our database
|
||||
const deleteWithCommand = tagResult.category?.delete_with_command ?? config.delete_with_command;
|
||||
if (deleteWithCommand) {
|
||||
pluginData.state.savedMessages.onceMessageAvailable(responseMsg.id, async () => {
|
||||
await pluginData.state.tags.addResponse(msg.id, responseMsg.id);
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import { renderTemplate } from "src/templateFormatter";
|
||||
import { renderTemplate } from "../../../templateFormatter";
|
||||
import { PluginData, plugin } from "knub";
|
||||
import { TagsPluginType } from "../types";
|
||||
import { Tag, TagsPluginType } from "../types";
|
||||
import { renderRecursively, StrictMessageContent } from "../../../utils";
|
||||
import * as t from "io-ts";
|
||||
|
||||
export async function renderTag(pluginData: PluginData<TagsPluginType>, body, args = [], extraData = {}) {
|
||||
export async function renderTagBody(
|
||||
pluginData: PluginData<TagsPluginType>,
|
||||
body: t.TypeOf<typeof Tag>,
|
||||
args = [],
|
||||
extraData = {},
|
||||
): Promise<StrictMessageContent> {
|
||||
const dynamicVars = {};
|
||||
const maxTagFnCalls = 25;
|
||||
let tagFnCalls = 0;
|
||||
|
@ -22,6 +29,7 @@ export async function renderTag(pluginData: PluginData<TagsPluginType>, body, ar
|
|||
if (tagFnCalls++ > maxTagFnCalls) return "\\_recursion\\_";
|
||||
if (typeof name !== "string") return "";
|
||||
if (name === "") return "";
|
||||
|
||||
// TODO: Incorporate tag categories here
|
||||
const subTag = await pluginData.state.tags.find(name);
|
||||
if (!subTag) return "";
|
||||
|
@ -29,5 +37,11 @@ export async function renderTag(pluginData: PluginData<TagsPluginType>, body, ar
|
|||
},
|
||||
};
|
||||
|
||||
return renderTemplate(body, data);
|
||||
if (typeof body === "string") {
|
||||
// Plain text tag
|
||||
return { content: await renderTemplate(body, data) };
|
||||
} else {
|
||||
// Embed
|
||||
return renderRecursively(body, str => renderTemplate(str, data));
|
||||
}
|
||||
}
|
|
@ -5,12 +5,12 @@ import { renderRecursively, StrictMessageContent, stripObjectToScalars } from "s
|
|||
import { parseArguments } from "knub-command-manager";
|
||||
import { TemplateParseError } from "src/templateFormatter";
|
||||
import { PluginData } from "knub";
|
||||
import { renderTag } from "./renderTag";
|
||||
import { logger } from "src/logger";
|
||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||
import { LogType } from "../../../data/LogType";
|
||||
import { renderTagBody } from "./renderTagBody";
|
||||
|
||||
export async function renderSafeTagFromMessage(
|
||||
export async function renderTagFromString(
|
||||
pluginData: PluginData<TagsPluginType>,
|
||||
str: string,
|
||||
prefix: string,
|
||||
|
@ -21,21 +21,9 @@ export async function renderSafeTagFromMessage(
|
|||
const variableStr = str.slice(prefix.length + tagName.length).trim();
|
||||
const tagArgs = parseArguments(variableStr).map(v => v.value);
|
||||
|
||||
const renderTagString = async _str => {
|
||||
let rendered = await renderTag(pluginData, _str, tagArgs, {
|
||||
member: stripObjectToScalars(member, ["user"]),
|
||||
user: stripObjectToScalars(member.user),
|
||||
});
|
||||
rendered = rendered.trim();
|
||||
|
||||
return rendered;
|
||||
};
|
||||
|
||||
// Format the string
|
||||
try {
|
||||
return typeof tagBody === "string"
|
||||
? { content: await renderTagString(tagBody) }
|
||||
: await renderRecursively(tagBody, renderTagString);
|
||||
return renderTagBody(pluginData, tagBody, tagArgs);
|
||||
} catch (e) {
|
||||
if (e instanceof TemplateParseError) {
|
||||
const logs = pluginData.getPlugin(LogsPlugin);
|
Loading…
Add table
Reference in a new issue