From 4bc507be4873a9b3086c0e7b8d9d6ab980111a73 Mon Sep 17 00:00:00 2001 From: toast-ts <96593068+toast-ts@users.noreply.github.com> Date: Tue, 15 Aug 2023 00:36:29 +1000 Subject: [PATCH] Add tag system --- src/client.ts | 5 +- src/commands/tag.ts | 133 ++++++++++++++++++++++++++++++++ src/events/interactionCreate.ts | 12 ++- src/models/tagSystem.ts | 22 ++++++ 4 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 src/commands/tag.ts create mode 100644 src/models/tagSystem.ts diff --git a/src/client.ts b/src/client.ts index d286500..4288af6 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,5 +1,5 @@ import Discord, {Client, WebhookClient, GatewayIntentBits, Partials} from 'discord.js'; -import {readFileSync, readdirSync, promises} from 'node:fs'; +import {readFileSync, readdirSync} from 'node:fs'; import {exec} from 'node:child_process'; import mongoose from 'mongoose'; import {formatTimeOpt, Tokens, Config, repeatedMessages, MPServerCache} from './typings/interfaces'; @@ -7,6 +7,7 @@ import bannedWords from './models/bannedWords.js'; import userLevels from './models/userLevels.js'; import suggestion from './models/suggestion.js'; import punishments from './models/punishments.js'; +import tags from './models/tagSystem.js'; import bonkCount from './models/bonkCount.js'; import MPServer from './models/MPServer.js'; import xjs from 'xml-js'; @@ -46,6 +47,7 @@ export default class TClient extends Client { MPServer: MPServer; MPServerCache: MPServerCache; suggestion: suggestion; + tags: tags; repeatedMessages: repeatedMessages; statsGraph: number; @@ -85,6 +87,7 @@ export default class TClient extends Client { this.MPServer = new MPServer(this); this.MPServerCache = {players: [], status: null, name: null} as MPServerCache; this.suggestion = new suggestion(this); + this.tags = new tags(this); this.repeatedMessages = {}; this.setMaxListeners(45); this.statsGraph = -60; diff --git a/src/commands/tag.ts b/src/commands/tag.ts new file mode 100644 index 0000000..010ce8a --- /dev/null +++ b/src/commands/tag.ts @@ -0,0 +1,133 @@ +import Discord from 'discord.js'; +import TClient from '../client.js'; +export default { + async autocomplete(client: TClient, interaction: Discord.AutocompleteInteraction){ + const array = (await client.tags?._content.find())?.map(x=>x._id).filter(c=>c.startsWith(interaction.options.getFocused())); + await interaction?.respond(array?.map(c=>({name: c, value: c}))); + // If you question all those '?.', let me tell you: Discord.JS is fricking stupid and I am too stressed to find a solution for it. + }, + async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ + if (!client.isStaff(interaction.member) && !client.config.whitelist.includes(interaction.member.id)) return client.youNeedRole(interaction, 'dcmod'); + const tagData = async()=>await client.tags._content.findOne({_id: interaction.options.getString('name')}); + const tagMeta = { + isEmbedTrue: async()=>(await tagData()).embedBool, + title: async()=>(await tagData())._id, + message: async()=>(await tagData()).message, + creatorName: async()=>(await client.users.fetch((await tagData()).user._id)).displayName + }; + ({ + send: async()=>{ + let targetField = ''; + const targetMember = interaction.options.getMember('target_user'); + if (targetMember) targetField = `*This tag is for <@${targetMember.id}>*`; + //console.log(targetMember) + const embedTemplate = new client.embed().setColor(client.config.embedColor).setTitle(await tagMeta.title()).setDescription(await tagMeta.message()).setFooter({text: `Tag creator: ${await tagMeta.creatorName()}`}); + const messageTemplate = [ + targetField ? targetField : '', + `**${await tagMeta.title()}**`, + await tagMeta.message(), + '', + `Tag creator: **${await tagMeta.creatorName()}**` + ].join('\n'); + if (await tagMeta.isEmbedTrue()) return interaction.reply({content: targetField ? targetField : null, embeds: [embedTemplate], allowedMentions:{parse:['users']}}); + else return interaction.reply({content: messageTemplate, allowedMentions:{parse:['users']}}) + }, + create: async()=>await client.tags._content.create({ + _id: interaction.options.getString('name'), + message: interaction.options.getString('message'), + embedBool: interaction.options.getBoolean('embed'), + user: { + _id: interaction.member.id, + name: interaction.user.username + } + }) + .then(()=>interaction.reply('Tag is now created and available to use.')) + .catch(err=>interaction.reply(`There was an error while trying to create your tag:\n\`\`\`${err}\`\`\``)), + delete: async()=>await client.tags._content.findByIdAndDelete(interaction.options.getString('name')).then(()=>interaction.reply('Tag successfully deleted.')).catch(err=>interaction.reply(`Failed to delete the tag:\n\`\`\`${err}\`\`\``)), + edit: async()=>await client.tags._content.findByIdAndUpdate(interaction.options.getString('name'), { + $set: { + message: interaction.options.getString('new-message'), + embedBool: interaction.options.getBoolean('embed') + } + }) + .then(()=>interaction.reply('Tag successfully updated, enjoy!')) + .catch(err=>interaction.reply(`Tag couldn\'t be updated:\n\`\`\`${err}\`\`\``)) + } as any)[interaction.options.getSubcommand() ?? interaction.options.getSubcommandGroup()](); + }, + data: new Discord.SlashCommandBuilder() + .setName('tag') + .setDescription('Send user the resources/FAQ provided in the tag') + .addSubcommand(x=>x + .setName('send') + .setDescription('Send a resource tag') + .addStringOption(x=>x + .setName('name') + .setDescription('Name of an existing tag to send') + .setAutocomplete(true) + .setRequired(true)) + .addUserOption(x=>x + .setName('target_user') + .setDescription('Directly mention the target with this tag'))) + .addSubcommandGroup(x=>x + .setName('management') + .setDescription('Add a new tag or delete/edit your current tag') + .addSubcommand(x=>x + .setName('create') + .setDescription('Create a new tag') + .addStringOption(x=>x + .setName('name') + .setDescription('Name of your tag, must be within 3-25 characters') + .setMinLength(3) + .setMaxLength(25) + .setRequired(true)) + .addStringOption(x=>x + .setName('message') + .setDescription('Message to be included in your tag; e.g, you\'re giving the user some instructions') + .setMinLength(6) + .setMaxLength(2048) + .setRequired(true)) + .addBooleanOption(x=>x + .setName('embed') + .setDescription('Toggle this option if you want your message to be inside the embed or not') + .setRequired(true))) + .addSubcommand(x=>x + .setName('delete') + .setDescription('Delete a tag') + .addStringOption(x=>x + .setName('name') + .setDescription('Name of the tag to be deleted') + .setAutocomplete(true) + .setRequired(true))) + .addSubcommand(x=>x + .setName('edit') + .setDescription('Edit an existing tag') + .addStringOption(x=>x + .setName('name') + .setDescription('Name of the tag to be edited') + .setAutocomplete(true) + .setRequired(true)) + .addStringOption(x=>x + .setName('new-message') + .setDescription('Replace the current tag\'s message with a new one') + .setRequired(true)) + .addBooleanOption(x=>x + .setName('embed') + .setDescription('Toggle this option on an existing tag to be updated with embed or not') + .setRequired(true)))) +} + +// createTag +/*if (interaction.options.getString('name') === await tagMeta.tagTitle()) return interaction.reply('This tag already exists!'); + else { + await client.tags._content.create({ + _id: interaction.options.getString('name'), + message: interaction.options.getString('message'), + embedBool: interaction.options.getBoolean('embed'), + user: { + _id: interaction.member.id, + name: interaction.user.username + } + }) + .then(()=>interaction.reply('Tag is now created and available to use.')) + .catch(err=>interaction.reply(`There was an error while trying to create your tag:\n\`\`\`${err}\`\`\``)) + }*/ \ No newline at end of file diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index d3405e8..1b04132 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -1,21 +1,29 @@ import Discord from 'discord.js'; import TClient from '../client.js'; export default { - run(client:TClient, interaction:Discord.BaseInteraction){ + async run(client:TClient, interaction:Discord.BaseInteraction){ if (!interaction.inGuild() || !interaction.inCachedGuild()) return; if (interaction.isChatInputCommand()){ const commandFile = client.commands.get(interaction.commandName); - console.log(client.logTime(), `${interaction.user.username} used /${interaction.commandName} ${interaction.options.getSubcommand(false) ?? ''} in #${interaction.channel.name}`); + console.log(client.logTime(), `${interaction.user.username} used /${interaction.commandName} ${interaction.options.getSubcommandGroup(false) ?? ''} ${interaction.options.getSubcommand(false) ?? ''} in #${interaction.channel.name}`); if (!client.config.botSwitches.commands && !client.config.whitelist.includes(interaction.user.id)) return interaction.reply({content: `I am currently operating in development mode.\nPlease notify <@${client.config.whitelist[0]}> if this is a mistake.`, ephemeral: true}); if (commandFile){ try{ commandFile.command.default.run(client, interaction); + commandFile.command.default.autocomplete ? commandFile.command.default.autocomplete(interaction) : undefined; commandFile.uses ? commandFile.uses++ : commandFile.uses = 1; } catch (error){ console.log(`An error occurred while running command "${interaction.commandName} ${interaction.options.getSubcommand(false) ?? ''}"`, error, error.stack); return interaction.reply('An error occurred while executing that command.'); } } + } else if (interaction.isAutocomplete()){ + const AC = client.commands.get(interaction.commandName); + try { + await AC.command.default.autocomplete(client, interaction) + } catch (error){ + return console.log('An error occurred while running autocomplete:\n', error) + } } else if (interaction.isButton()){ if (interaction.customId.startsWith('reaction-') && client.config.botSwitches.buttonRoles){ const RoleID = interaction.customId.replace('reaction-',''); diff --git a/src/models/tagSystem.ts b/src/models/tagSystem.ts new file mode 100644 index 0000000..dff11e3 --- /dev/null +++ b/src/models/tagSystem.ts @@ -0,0 +1,22 @@ +import TClient from '../client.js'; +import mongoose from 'mongoose'; + +const Schema = mongoose.model('tags', new mongoose.Schema({ + _id: {type: String, required:true}, + message: {type: String, required:true}, + embedBool: {type: Boolean, required:true}, + user: {required:true, type: new mongoose.Schema({ + name: {type: String, required:true}, + _id: {type: String, required:true} + }, {versionKey: false})} +}, {versionKey: false})); + +export default class tags extends Schema { + client: TClient; + _content: typeof Schema; + constructor(client:TClient){ + super(); + this.client = client; + this._content = Schema; + } +}