3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-05-25 10:25:01 +00:00
This commit is contained in:
Ruby 2022-05-20 13:55:07 +00:00 committed by GitHub
commit b0053c6849
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 359 additions and 47 deletions

View file

@ -30,6 +30,7 @@ const migrationsDir = path.relative(process.cwd(), path.resolve(backendRoot, "sr
module.exports = { module.exports = {
type: "mysql", type: "mysql",
host: process.env.DB_HOST, host: process.env.DB_HOST,
port: 13306,
username: process.env.DB_USER, username: process.env.DB_USER,
password: process.env.DB_PASSWORD, password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE, database: process.env.DB_DATABASE,

View file

@ -13,7 +13,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
"deep-diff": "^1.0.2", "deep-diff": "^1.0.2",
"discord-api-types": "^0.31.0", "discord-api-types": "^0.31.2",
"discord.js": "^13.6.0", "discord.js": "^13.6.0",
"dotenv": "^4.0.0", "dotenv": "^4.0.0",
"emoji-regex": "^8.0.0", "emoji-regex": "^8.0.0",
@ -1693,8 +1693,9 @@
} }
}, },
"node_modules/discord-api-types": { "node_modules/discord-api-types": {
"version": "0.31.0", "version": "0.31.2",
"license": "MIT" "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.31.2.tgz",
"integrity": "sha512-gpzXTvFVg7AjKVVJFH0oJGC0q0tO34iJGSHZNz9u3aqLxlD6LfxEs9wWVVikJqn9gra940oUTaPFizCkRDcEiA=="
}, },
"node_modules/discord.js": { "node_modules/discord.js": {
"version": "13.6.0", "version": "13.6.0",
@ -3018,8 +3019,9 @@
} }
}, },
"node_modules/moment": { "node_modules/moment": {
"version": "2.24.0", "version": "2.29.3",
"license": "MIT", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==",
"engines": { "engines": {
"node": "*" "node": "*"
} }
@ -6346,7 +6348,9 @@
} }
}, },
"discord-api-types": { "discord-api-types": {
"version": "0.31.0" "version": "0.31.2",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.31.2.tgz",
"integrity": "sha512-gpzXTvFVg7AjKVVJFH0oJGC0q0tO34iJGSHZNz9u3aqLxlD6LfxEs9wWVVikJqn9gra940oUTaPFizCkRDcEiA=="
}, },
"discord.js": { "discord.js": {
"version": "13.6.0", "version": "13.6.0",
@ -6425,7 +6429,7 @@
}, },
"erlpack": { "erlpack": {
"version": "git+ssh://git@github.com/discord/erlpack.git#3b793a333dd3f6a140b9168ea91e9fa9660753ce", "version": "git+ssh://git@github.com/discord/erlpack.git#3b793a333dd3f6a140b9168ea91e9fa9660753ce",
"from": "erlpack@github:discord/erlpack.git", "from": "erlpack@github:discord/erlpack",
"requires": { "requires": {
"bindings": "^1.5.0", "bindings": "^1.5.0",
"nan": "^2.15.0" "nan": "^2.15.0"
@ -7175,7 +7179,9 @@
} }
}, },
"moment": { "moment": {
"version": "2.24.0" "version": "2.29.3",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
}, },
"moment-timezone": { "moment-timezone": {
"version": "0.5.27", "version": "0.5.27",

View file

@ -28,7 +28,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
"deep-diff": "^1.0.2", "deep-diff": "^1.0.2",
"discord-api-types": "^0.31.0", "discord-api-types": "^0.31.2",
"discord.js": "^13.6.0", "discord.js": "^13.6.0",
"dotenv": "^4.0.0", "dotenv": "^4.0.0",
"emoji-regex": "^8.0.0", "emoji-regex": "^8.0.0",

View file

@ -0,0 +1,66 @@
import { getRepository, Repository } from "typeorm";
import { BaseGuildRepository } from "./BaseGuildRepository";
import { TagAlias } from "./entities/TagAlias";
export class GuildTagAliases extends BaseGuildRepository {
private tagAliases: Repository<TagAlias>;
constructor(guildId) {
super(guildId);
this.tagAliases = getRepository(TagAlias);
}
async all(): Promise<TagAlias[]> {
return this.tagAliases.find({
where: {
guild_id: this.guildId,
},
});
}
async find(alias): Promise<TagAlias | undefined> {
return this.tagAliases.findOne({
where: {
guild_id: this.guildId,
alias,
},
});
}
async findAllWithTag(tag): Promise<TagAlias[] | undefined> {
const all = await this.all();
const aliases = all.filter((a) => a.tag === tag);
return aliases.length > 0 ? aliases : undefined;
}
async createOrUpdate(alias, tag, userId) {
const existingTagAlias = await this.find(alias);
if (existingTagAlias) {
await this.tagAliases
.createQueryBuilder()
.update()
.set({
tag,
user_id: userId,
created_at: () => "NOW()",
})
.where("guild_id = :guildId", { guildId: this.guildId })
.andWhere("alias = :alias", { alias })
.execute();
} else {
await this.tagAliases.insert({
guild_id: this.guildId,
user_id: userId,
alias,
tag,
});
}
}
async delete(alias) {
await this.tagAliases.delete({
guild_id: this.guildId,
alias,
});
}
}

View file

@ -0,0 +1,20 @@
import { Column, Entity, PrimaryColumn } from "typeorm";
@Entity("tag_aliases")
export class TagAlias {
@Column()
@PrimaryColumn()
guild_id: string;
@Column()
@PrimaryColumn()
alias: string;
@Column()
@PrimaryColumn()
tag: string;
@Column() user_id: string;
@Column() created_at: string;
}

View file

@ -0,0 +1,43 @@
import { MigrationInterface, QueryRunner, Table } from "typeorm";
export class CreateTagAliasesTable1650721595278 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: "tag_aliases",
columns: [
{
name: "guild_id",
type: "bigint",
isPrimary: true,
},
{
name: "alias",
type: "varchar",
length: "255",
isPrimary: true,
},
{
name: "tag",
type: "varchar",
length: "255",
isPrimary: true,
},
{
name: "user_id",
type: "bigint",
},
{
name: "created_at",
type: "datetime",
default: "now()",
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
queryRunner.dropTable("tag_aliases");
}
}

View file

@ -7,6 +7,7 @@ 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 { GuildTags } from "../../data/GuildTags"; import { GuildTags } from "../../data/GuildTags";
import { GuildTagAliases } from "src/data/GuildTagAliases";
import { mapToPublicFn } from "../../pluginUtils"; import { mapToPublicFn } from "../../pluginUtils";
import { convertDelayStringToMS, trimPluginDescription } from "../../utils"; import { convertDelayStringToMS, trimPluginDescription } from "../../utils";
import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin"; import { TimeAndDatePlugin } from "../TimeAndDate/TimeAndDatePlugin";
@ -123,6 +124,7 @@ export const TagsPlugin = zeppelinGuildPlugin<TagsPluginType>()({
state.archives = GuildArchives.getGuildInstance(guild.id); state.archives = GuildArchives.getGuildInstance(guild.id);
state.tags = GuildTags.getGuildInstance(guild.id); state.tags = GuildTags.getGuildInstance(guild.id);
state.tagAliases = GuildTagAliases.getGuildInstance(guild.id);
state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id); state.savedMessages = GuildSavedMessages.getGuildInstance(guild.id);
state.logs = new GuildLogs(guild.id); state.logs = new GuildLogs(guild.id);

View file

@ -8,11 +8,24 @@ export const TagCreateCmd = tagsCmd({
permission: "can_create", permission: "can_create",
signature: { signature: {
alias: ct.bool({ option: true, shortcut: "a", isSwitch: true }),
tag: ct.string(), tag: ct.string(),
body: ct.string({ catchAll: true }), body: ct.string({ catchAll: true }),
}, },
async run({ message: msg, args, pluginData }) { async run({ message: msg, args, pluginData }) {
const prefix = pluginData.config.get().prefix;
if (args.alias) {
const existingTag = await pluginData.state.tagAliases.find(args.body);
if (existingTag) {
sendErrorMessage(pluginData, msg.channel, `You cannot create an alias of an alias`);
return;
}
await pluginData.state.tagAliases.createOrUpdate(args.tag, args.body, msg.author.id);
sendSuccessMessage(pluginData, msg.channel, `Alias set! Use it with: \`${prefix}${args.tag}\``);
return;
}
try { try {
parseTemplate(args.body); parseTemplate(args.body);
} catch (e) { } catch (e) {
@ -26,7 +39,6 @@ export const TagCreateCmd = tagsCmd({
await pluginData.state.tags.createOrUpdate(args.tag, args.body, msg.author.id); await pluginData.state.tags.createOrUpdate(args.tag, args.body, msg.author.id);
const prefix = pluginData.config.get().prefix;
sendSuccessMessage(pluginData, msg.channel, `Tag set! Use it with: \`${prefix}${args.tag}\``); sendSuccessMessage(pluginData, msg.channel, `Tag set! Use it with: \`${prefix}${args.tag}\``);
}, },
}); });

View file

@ -11,13 +11,25 @@ export const TagDeleteCmd = tagsCmd({
}, },
async run({ message: msg, args, pluginData }) { async run({ message: msg, args, pluginData }) {
const alias = await pluginData.state.tagAliases.find(args.tag);
const tag = await pluginData.state.tags.find(args.tag); const tag = await pluginData.state.tags.find(args.tag);
if (!tag) {
if (!tag && !alias) {
sendErrorMessage(pluginData, msg.channel, "No tag with that name"); sendErrorMessage(pluginData, msg.channel, "No tag with that name");
return; return;
} }
if (tag) {
const aliasesOfTag = await pluginData.state.tagAliases.findAllWithTag(tag?.tag);
if (aliasesOfTag) {
// tslint:disable-next-line:no-shadowed-variable
aliasesOfTag.forEach((alias) => pluginData.state.tagAliases.delete(alias.alias));
}
await pluginData.state.tags.delete(args.tag); await pluginData.state.tags.delete(args.tag);
sendSuccessMessage(pluginData, msg.channel, "Tag deleted!"); } else {
await pluginData.state.tagAliases.delete(alias?.alias);
}
sendSuccessMessage(pluginData, msg.channel, `${tag ? "Tag" : "Alias"} deleted!`);
}, },
}); });

View file

@ -1,3 +1,6 @@
import { sendErrorMessage } from "src/pluginUtils";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { createChunkedMessage } from "../../../utils"; import { createChunkedMessage } from "../../../utils";
import { tagsCmd } from "../types"; import { tagsCmd } from "../types";
@ -5,16 +8,61 @@ export const TagListCmd = tagsCmd({
trigger: ["tag list", "tags", "taglist"], trigger: ["tag list", "tags", "taglist"],
permission: "can_list", permission: "can_list",
async run({ message: msg, pluginData }) { signature: {
noaliases: ct.bool({ option: true, isSwitch: true, shortcut: "na" }),
aliasesonly: ct.bool({ option: true, isSwitch: true, shortcut: "ao" }),
tag: ct.string({ option: true }),
},
async run({ message: msg, args, pluginData }) {
const prefix = (await pluginData.config.getForMessage(msg)).prefix;
const tags = await pluginData.state.tags.all(); const tags = await pluginData.state.tags.all();
if (tags.length === 0) { if (tags.length === 0) {
msg.channel.send(`No tags created yet! Use \`tag create\` command to create one.`); msg.channel.send(`No tags created yet! Use \`tag create\` command to create one.`);
return; return;
} }
const prefix = (await pluginData.config.getForMessage(msg)).prefix; const allAliases = await pluginData.state.tagAliases.all();
const tagNames = tags.map((tag) => tag.tag).sort();
createChunkedMessage(msg.channel, `Available tags (use with ${prefix}tag): \`\`\`${tagNames.join(", ")}\`\`\``); if (args.aliasesonly) {
let aliasesArr: string[] = [];
if (args.tag) {
const tag = await pluginData.state.tags.find(args.tag);
if (!tag) {
sendErrorMessage(pluginData, msg.channel, `Tag \`${args.tag}\` doesn't exist.`);
return;
}
const aliasesForTag = await pluginData.state.tagAliases.findAllWithTag(args.tag);
if (!aliasesForTag) {
sendErrorMessage(pluginData, msg.channel, `No aliases for tag \`${args.tag}\`.`);
return;
}
aliasesArr = aliasesForTag.map((a) => a.alias);
createChunkedMessage(
msg.channel,
`Available aliases for tag \`${args.tag}\` (use with \`${prefix}alias\`: \`\`\`${aliasesArr.join(
", ",
)}\`\`\``,
);
return;
}
aliasesArr = allAliases.map((a) => a.alias);
createChunkedMessage(
msg.channel,
`Available aliases (use with \`${prefix}alias\`: \`\`\`${aliasesArr.join(", ")}\`\`\``,
);
return;
}
const tagNames = tags.map((tag) => tag.tag).sort();
const tagAliasesNames = allAliases.map((alias) => alias.alias).sort();
const tagAndAliasesNames = tagNames
.join(", ")
.concat(args.noaliases ? "" : tagAliasesNames.length > 0 ? `, ${tagAliasesNames.join(", ")}` : "");
createChunkedMessage(
msg.channel,
`Available tags (use with ${prefix}tag/alias): \`\`\`${tagAndAliasesNames}\`\`\``,
);
}, },
}); });

View file

@ -14,24 +14,42 @@ export const TagSourceCmd = tagsCmd({
}, },
async run({ message: msg, args, pluginData }) { async run({ message: msg, args, pluginData }) {
const alias = await pluginData.state.tagAliases.find(args.tag);
const aliasedTag = await pluginData.state.tags.find(alias?.tag ?? null);
const tag = (await pluginData.state.tags.find(args.tag)) || aliasedTag;
if (args.delete) { if (args.delete) {
const actualTag = await pluginData.state.tags.find(args.tag); const actualTag = await pluginData.state.tags.find(args.tag);
if (!actualTag) {
if (!actualTag && !aliasedTag) {
sendErrorMessage(pluginData, msg.channel, "No tag with that name"); sendErrorMessage(pluginData, msg.channel, "No tag with that name");
return; return;
} }
if (actualTag) {
const aliasesOfTag = await pluginData.state.tagAliases.findAllWithTag(actualTag?.tag);
if (aliasesOfTag) {
// tslint:disable-next-line:no-shadowed-variable
aliasesOfTag.forEach((alias) => pluginData.state.tagAliases.delete(alias.alias));
}
await pluginData.state.tags.delete(args.tag); await pluginData.state.tags.delete(args.tag);
sendSuccessMessage(pluginData, msg.channel, "Tag deleted!"); } else {
await pluginData.state.tagAliases.delete(alias?.alias);
}
sendSuccessMessage(pluginData, msg.channel, `${actualTag ? "Tag" : "Alias"} deleted!`);
return; return;
} }
const tag = await pluginData.state.tags.find(args.tag); if (!tag && !aliasedTag) {
if (!tag) {
sendErrorMessage(pluginData, msg.channel, "No tag with that name"); sendErrorMessage(pluginData, msg.channel, "No tag with that name");
return; return;
} }
if (!tag?.body) {
return;
}
const archiveId = await pluginData.state.archives.create(tag.body, moment.utc().add(10, "minutes")); const archiveId = await pluginData.state.archives.create(tag.body, moment.utc().add(10, "minutes"));
const url = pluginData.state.archives.getUrl(getBaseUrl(pluginData), archiveId); const url = pluginData.state.archives.getUrl(getBaseUrl(pluginData), archiveId);

View file

@ -4,6 +4,7 @@ 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 { GuildTags } from "../../data/GuildTags"; import { GuildTags } from "../../data/GuildTags";
import { GuildTagAliases } from "../../data/GuildTagAliases";
import { tEmbed, tNullable } from "../../utils"; import { tEmbed, tNullable } from "../../utils";
export const Tag = t.union([t.string, tEmbed]); export const Tag = t.union([t.string, tEmbed]);
@ -50,6 +51,7 @@ export interface TagsPluginType extends BasePluginType {
state: { state: {
archives: GuildArchives; archives: GuildArchives;
tags: GuildTags; tags: GuildTags;
tagAliases: GuildTagAliases;
savedMessages: GuildSavedMessages; savedMessages: GuildSavedMessages;
logs: GuildLogs; logs: GuildLogs;

View file

@ -20,8 +20,18 @@ export async function findTagByName(
return config.categories[categoryName]?.tags[tagName] ?? null; return config.categories[categoryName]?.tags[tagName] ?? null;
} }
let tag: string | null;
// Dynamic tag // Dynamic tag
// Format: "tag" // Format: "tag"
const dynamicTag = await pluginData.state.tags.find(name); const dynamicTag = await pluginData.state.tags.find(name);
return dynamicTag?.body ?? null; tag = dynamicTag?.body ?? null;
// Aliased tag
// Format: "alias"
const aliasedTagName = await pluginData.state.tagAliases.find(name);
const aliasedTag = await pluginData.state.tags.find(aliasedTagName?.tag);
tag ? (tag = tag) : (tag = aliasedTag?.body ?? null);
return tag;
} }

View file

@ -0,0 +1,30 @@
// https://rosettacode.org/wiki/Levenshtein_distance#JavaScript
function levenshtein(a: string, b: string): number {
let t: number[] = [];
let u: number[] = [];
const m = a.length;
const n = b.length;
if (!m) {
return n;
}
if (!n) {
return m;
}
for (let j = 0; j <= n; j++) {
t[j] = j;
}
for (let i = 1; i <= m; i++) {
let j: number;
// tslint:disable-next-line:ban-comma-operator
for (u = [i], j = 1; j <= n; j++) {
u[j] = a[i - 1] === b[j - 1] ? t[j - 1] : Math.min(t[j - 1], t[j], u[j - 1]) + 1;
}
t = u;
}
return u[n];
}
export function distance(str: string, t: string): number {
return levenshtein(str, t);
}

View file

@ -1,9 +1,12 @@
import { GuildMember } from "discord.js"; import { GuildMember, Snowflake, TextChannel } from "discord.js";
import escapeStringRegexp from "escape-string-regexp"; import escapeStringRegexp from "escape-string-regexp";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { ExtendedMatchParams } from "knub/dist/config/PluginConfigManager"; import { ExtendedMatchParams } from "knub/dist/config/PluginConfigManager";
import { StrictMessageContent } from "../../../utils"; import { StrictMessageContent } from "../../../utils";
import { TagsPluginType, TTagCategory } from "../types"; import { TagsPluginType, TTagCategory } from "../types";
import { distance } from "./fuzzySearch";
import { renderTagFromString } from "./renderTagFromString"; import { renderTagFromString } from "./renderTagFromString";
interface BaseResult { interface BaseResult {
@ -44,7 +47,8 @@ export async function matchAndRenderTagFromString(
const withoutPrefix = str.slice(prefix.length); const withoutPrefix = str.slice(prefix.length);
for (const [tagName, tagBody] of Object.entries(category.tags)) { // tslint:disable-next-line:no-shadowed-variable
for (const [tagName, _tagBody] of Object.entries(category.tags)) {
const regex = new RegExp(`^${escapeStringRegexp(tagName)}(?:\\s|$)`); const regex = new RegExp(`^${escapeStringRegexp(tagName)}(?:\\s|$)`);
if (regex.test(withoutPrefix)) { if (regex.test(withoutPrefix)) {
const renderedContent = await renderTagFromString( const renderedContent = await renderTagFromString(
@ -70,43 +74,79 @@ export async function matchAndRenderTagFromString(
} }
} }
// Dynamic tags // Dynamic + Aliased tags
if (config.can_use !== true) { if (config.can_use !== true) {
return null; return null;
} }
const dynamicTagPrefix = config.prefix; const tagPrefix = config.prefix;
if (!str.startsWith(dynamicTagPrefix)) { if (!str.startsWith(tagPrefix)) {
return null; return null;
} }
const dynamicTagNameMatch = str.slice(dynamicTagPrefix.length).match(/^\S+/); const tagNameMatch = str.slice(tagPrefix.length).match(/^\S+/);
if (dynamicTagNameMatch === null) { if (tagNameMatch == null) {
return null; return null;
} }
const dynamicTagName = dynamicTagNameMatch[0]; const tagName = tagNameMatch[0];
const dynamicTag = await pluginData.state.tags.find(dynamicTagName);
if (!dynamicTag) { const aliasName = await pluginData.state.tagAliases.find(tagName);
const aliasedTag = await pluginData.state.tags.find(aliasName?.tag);
const dynamicTag = await pluginData.state.tags.find(tagName);
if (!aliasedTag && !dynamicTag) {
// fuzzy search the list of aliases and tags to see if there's a match and
// inform the user
const tags = await pluginData.state.tags.all();
const aliases = await pluginData.state.tagAliases.all();
let lowest: [number, [string]] = [999999, [""]];
tags.forEach((tag) => {
const tagname = tag?.tag;
const dist = distance(tagname, tagName);
if (dist < lowest[0]) {
lowest = [dist, [`**${tagname}**`]];
} else if (dist === lowest[0]) {
lowest[1].push(`**${tagname}**`);
}
});
aliases.forEach((alias) => {
const aliasname = alias?.alias;
const dist = distance(aliasname, tagName);
if (dist < lowest[0]) {
lowest = [dist, [`**${aliasname}**`]];
} else if (dist === lowest[0]) {
lowest[1].push(`**${aliasname}**`);
}
});
if (lowest[0] > 6) return null;
const content: StrictMessageContent = {
content: `Did you mean:\n${lowest[1].join("\n")}`,
};
return {
renderedContent: content,
tagName: "",
category: null,
categoryName: null,
};
}
const tagBody = aliasedTag?.body ?? dynamicTag?.body;
if (!tagBody) {
return null; return null;
} }
const renderedDynamicTagContent = await renderTagFromString( const renderedTagContent = await renderTagFromString(pluginData, str, tagPrefix, tagName, tagBody, member);
pluginData,
str,
dynamicTagPrefix,
dynamicTagName,
dynamicTag.body,
member,
);
if (renderedDynamicTagContent == null) { if (renderedTagContent == null) {
return null; return null;
} }
return { return {
renderedContent: renderedDynamicTagContent, renderedContent: renderedTagContent,
tagName: dynamicTagName, tagName,
categoryName: null, categoryName: null,
category: null, category: null,
}; };

View file

@ -1,14 +1,16 @@
import { Snowflake, TextChannel } from "discord.js"; import { Snowflake, TextChannel } from "discord.js";
import { GuildPluginData } from "knub"; import { GuildPluginData } from "knub";
import { erisAllowedMentionsToDjsMentionOptions } from "src/utils/erisAllowedMentionsToDjsMentionOptions"; import { erisAllowedMentionsToDjsMentionOptions } from "src/utils/erisAllowedMentionsToDjsMentionOptions";
import { SavedMessage } from "../../../data/entities/SavedMessage"; import { SavedMessage } from "../../../data/entities/SavedMessage";
import { LogType } from "../../../data/LogType"; import { LogType } from "../../../data/LogType";
import { convertDelayStringToMS, resolveMember, tStrictMessageContent } from "../../../utils"; import { convertDelayStringToMS, resolveMember, tStrictMessageContent } from "../../../utils";
import { messageIsEmpty } from "../../../utils/messageIsEmpty"; import { messageIsEmpty } from "../../../utils/messageIsEmpty";
import { validate } from "../../../validatorUtils"; import { validate } from "../../../validatorUtils";
import { TagsPluginType } from "../types";
import { matchAndRenderTagFromString } from "./matchAndRenderTagFromString";
import { LogsPlugin } from "../../Logs/LogsPlugin"; import { LogsPlugin } from "../../Logs/LogsPlugin";
import { TagsPluginType } from "../types";
import { matchAndRenderTagFromString } from "./matchAndRenderTagFromString";
export async function onMessageCreate(pluginData: GuildPluginData<TagsPluginType>, msg: SavedMessage) { export async function onMessageCreate(pluginData: GuildPluginData<TagsPluginType>, msg: SavedMessage) {
if (msg.is_bot) return; if (msg.is_bot) return;