diff --git a/site/docs/nodejs/CommandHandler/_category_.json b/site/docs/nodejs/CommandHandler/_category_.json index 384da5c64..dd4267393 100644 --- a/site/docs/nodejs/CommandHandler/_category_.json +++ b/site/docs/nodejs/CommandHandler/_category_.json @@ -1,4 +1,4 @@ { "label": "Command Handler", - "position": 7 + "position": 9 } diff --git a/site/docs/nodejs/CommandHandler/command-manager.md b/site/docs/nodejs/CommandHandler/command-manager.md index 700d6be5e..135a13edc 100644 --- a/site/docs/nodejs/CommandHandler/command-manager.md +++ b/site/docs/nodejs/CommandHandler/command-manager.md @@ -7,11 +7,11 @@ sidebar_position: 2 Currently, you probably have something like this in your code: ```js -const Discord = require("discordeno"); +const Discord = require("discordeno.js"); // Ideally you should move to an `.env` file const config = require("./config.json"); -const client = Discord.createBot({ +const bot = Discord.createBot({ events: { messageCreate(client, message) { if (message.content === "!ping") { @@ -19,9 +19,10 @@ const client = Discord.createBot({ } }, }, - intents: ["Guilds", "GuildMessages"], + intents: Discord.Intents.Guilds | Discord.Intents.GuildMessages, token: config.token, }); +const client = Discord.enableCachePlugin(bot, {}); Discord.startBot(client); ``` diff --git a/site/docs/nodejs/EventHandler/_category_.json b/site/docs/nodejs/EventHandler/_category_.json index 32da17a11..8dc1b47c3 100644 --- a/site/docs/nodejs/EventHandler/_category_.json +++ b/site/docs/nodejs/EventHandler/_category_.json @@ -1,4 +1,4 @@ { "label": "Event Handler", - "position": 6 + "position": 8 } diff --git a/site/docs/nodejs/EventHandler/handle-event.md b/site/docs/nodejs/EventHandler/handle-event.md index ca1369e41..2429f7f1d 100644 --- a/site/docs/nodejs/EventHandler/handle-event.md +++ b/site/docs/nodejs/EventHandler/handle-event.md @@ -27,9 +27,9 @@ This file should be called `messageCreate.js`. const Message = require("./structures/Message"); module.exports = async (client, payload) => { - const message = new Message(client, payload); + const message = client.messages.forge(payload); - if (message.isBot) return; + if (message.author.bot) return; if (message.content === "!ping") return await message.reply("pong"); }; ``` @@ -42,7 +42,7 @@ This file should be called `interactionCreate.js`. const Interaction = require("./structures/Interaction"); module.exports = async (client, payload) => { - const interaction = new Interaction(client, payload); + const interaction = client.interactions.forge(payload); if (interaction.data.name === "ping") return await interaction.reply({ content: "pong" }); }; @@ -65,7 +65,7 @@ In order to fire the "real event" a small code snippet has to be added to the `r const User = require("../Structures/User"); module.exports = async (client, payload) => { - client.user = new User(client, payload.user); + client.user = client.users.forge(payload.user); if (payload.shardId + 1 === client.gateway.maxShards) { // All Shards are ready diff --git a/site/docs/nodejs/Structures/_category_.json b/site/docs/nodejs/Structures/_category_.json index 8bfdb91d2..b7a1b76c1 100644 --- a/site/docs/nodejs/Structures/_category_.json +++ b/site/docs/nodejs/Structures/_category_.json @@ -1,4 +1,4 @@ { "label": "Structures", - "position": 5 + "position": 7 } diff --git a/site/docs/nodejs/Structures/collectors.md b/site/docs/nodejs/Structures/collectors.md new file mode 100644 index 000000000..f999a8957 --- /dev/null +++ b/site/docs/nodejs/Structures/collectors.md @@ -0,0 +1,55 @@ +--- +sidebar_position: 5 +--- + +# Create Collectors + +Some of your commands or features are sometimes based on user interactions. E.g. if a user presses a button and you want +to know whether it was pressed. This is actually done by listening to the `interactionCreate` event. + +But sometimes you need to access locale variables or don't want to "hardcode" the part. + +That's why it's sometimes recommended to create collectors. + +Collectors are listeners that listen to a specific event. In addition, you can provide a filter, so you only receive +certain interactions. + +## Use a Collector + +:::note Template The template code is used below. You must have the EventManager part to use the collector feature. ::: + +We have a pre-made class for collectors which you can find +[here](https://github.com/meister03/discordeno.js/blob/master/Util/Collectors.js). + +```js +const Discord = require("discordeno.js"); +const filter = (m) => m.data?.customId === "warn_modal" && m.user.id === interaction.user.id; +const listener = client.eventListener; // When the eventListener property is named different +const collector = new Discord.Collector("interactionCreate", { + client: client, + timeout: 60000, + filter, + max: 20, + listener, +}); +collector.on("collect", (m) => { + const interaction = client.interactions.forge(m); + // Stop Collector + // collector.stop(); +}); + +// Fires on a timeout, when the collector has reached the max amount of interactions or when it has been closed +collector.on("end", (collected) => { + // Map of Collected Interactions + console.log(collected); +}); +``` + +As you can see, this opens up many possibilities. You can listen to any event and get the interaction you need. + +### Collector Options + +`filter`: Function, just fire the event if the filter returns true. `timeout`: Number, the time in milliseconds until +the collector times out. `max`: Number, the max amount of interactions the collector can collect. `listener`: Function, +the listener that will be fired when the collector collects an interaction. Just required when client property is named +differently. diff --git a/site/docs/nodejs/Structures/components.md b/site/docs/nodejs/Structures/components.md index 68651a284..123d52b70 100644 --- a/site/docs/nodejs/Structures/components.md +++ b/site/docs/nodejs/Structures/components.md @@ -19,7 +19,7 @@ just using raw data because they still execute methods, which takes more time to ::: We already have a Template for `Components`, which can be found -[here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Component.js). +[here](https://github.com/meister03/discordeno.js/tree/master/Structures/Component.js). ## Different Components: @@ -102,12 +102,15 @@ This code will obviously not work because it's a missing a lot required of data. a class to Discord, we need sth. to transform it to a json object. We have a pre-made class for components which you can find -[here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Component.js). +[here](https://github.com/meister03/discordeno.js/tree/master/Structures/Component.js). ### Button ```js -const button = new Component() +const Discord = require("discordeno.js"); +const message = client.messages.forge(rawMessage); + +const button = new Discord.Component() .setType("BUTTON") .setStyle("LINK") .setLabel("Click me!") @@ -115,14 +118,14 @@ const button = new Component() .toJSON(); // Button with raw types -const button2 = new Component() +const button2 = new Discord.Component() .setType(2) .setStyle(4) .setLabel("DO NOT CLICK") .setCustomId("12345") .toJSON(); -const actionRow = new Component() +const actionRow = new Discord.Component() .setType("ACTION_ROW") .setComponents(button, button2) .toJSON(); @@ -130,7 +133,8 @@ const actionRow = new Component() // Message to send const messageOptions = { content: "hello", components: [actionRow] }; -await client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure +// await client.helpers.sendMessage(channelId, messageOptions); // Do it the raw way +message.channel.send(messageOptions); // Do it with the structure ``` As you can see, for simplicity you can use strings instead of numbers (types), which are hard to remember. @@ -138,7 +142,10 @@ As you can see, for simplicity you can use strings instead of numbers (types), w ### Select Menu ```js -const selectMenu = new Component() +const Discord = require("discordeno.js"); +const message = client.messages.forge(rawMessage); + +const selectMenu = new Discord.Component() .setType("SELECT_MENU") .setCustomId("12345") .setOptions([ @@ -162,19 +169,23 @@ const selectMenu = new Component() .setPlaceholder("Select an option") .toJSON(); -const actionRow = new Component() +const actionRow = new Discord.Component() .setType("ACTION_ROW") .setComponents(selectMenu) .toJSON(); const messageOptions = { content: "hello", components: [actionRow] }; -client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure +// await client.helpers.sendMessage(channelId, messageOptions); // Do it the raw way +message.channel.send(messageOptions); // Do it with the structure ``` ### Text Input ```js +const Discord = require("discordeno.js"); +const interaction = client.messages.forge(rawInteraction); + const textInput = new Component() .setType("TEXT_INPUT") .setStyle("SHORT") @@ -199,7 +210,7 @@ const textInput2 = new Component() const actionRow = new Component().setType("ACTION_ROW").setComponents(textInput).toJSON(); const actionRow2 = new Component().setType("ACTION_ROW").setComponents(textInput2).toJSON(); -new Interaction(client, interaction).popupModal({ +interaction.popupModal({ customId: "ban_modal", title: "Ban User", components: [actionRow, actionRow2], @@ -210,10 +221,3 @@ new Interaction(client, interaction).popupModal({ When a user clicks a button or selects an option from a Select Menu, Discord sends an `interactionCreate` event, which contains the information necessary to process it. - -:::note Collecting - -An `InteractionCollector` can also be used to handle prompts, which requires some tweaks, but will be added soon in the -guide and the template repo. - -::: diff --git a/site/docs/nodejs/Structures/create-structure.md b/site/docs/nodejs/Structures/create-structure.md index 39a21b478..3be34dd12 100644 --- a/site/docs/nodejs/Structures/create-structure.md +++ b/site/docs/nodejs/Structures/create-structure.md @@ -52,28 +52,49 @@ the data, how the methods are named and how you want to process the request. ## Using Template Structures: -When you are migrating from another library, you'll likely choose to continue using special structures. Therefore why we -have ready-made structures in our template repo: +When you are migrating from another library and you want to utilize the djs-like wrapper, you'll likely choose to +continue using special structures. Therefore we have ready-made structures for the wrapper `Discordeno.js`. -- [Guild](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/Guild.js) -- [Channel](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/Channel.js) -- [Role](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/Role.js) -- [Member](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/Member.js) -- [User](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/User.js) -- [Message](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/Message.js) -- [Interaction](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/Interaction.js) +- [Guild](https://github.com/meister03/discordeno.js/tree/master/Structures/Guild.js) +- [Channel](https://github.com/meister03/discordeno.js/tree/master/Structures/Channel.js) +- [Role](https://github.com/meister03/discordeno.js/tree/master/Structures/Role.js) +- [Member](https://github.com/meister03/discordeno.js/tree/master/Structures/Member.js) +- [User](https://github.com/meister03/discordeno.js/tree/master/Structures/User.js) +- [Message](https://github.com/meister03/discordeno.js/tree/master/Structures/Message.js) +- [Interaction](https://github.com/meister03/discordeno.js/tree/master/Structures/Interaction.js) +- [Emoji](https://github.com/meister03/discordeno.js/tree/master/Structures/Emoji.js) +- [Webhook](https://github.com/meister03/discordeno.js/tree/master/Structures/Webhook.js) +- [Embed](https://github.com/meister03/discordeno.js/tree/master/Structures/Embed.js) +- [Component](https://github.com/meister03/discordeno.js/tree/master/Structures/Component.js) +- [Collection](https://github.com/meister03/discordeno.js/tree/master/Structures/Collection.js) -We recommend that you clone the whole template repo, since some structures are based on other files. +We recommend that you check the wrappers [Readme](https://github.com/meister03/discordeno.js#discordclient) in order to +construct the client for following the Guide **Using the Structures:** ```js -const Guild = require("./structures/Guild"); // Path to your structure -const guild = new Guild(client, data); // DiscordenoClient and DiscordenoPayloadData +const Discord = require("discordeno.js"); +const client = new Discord.Client(clientOptions, cacheOptions); //See the Readme above +Discord.startBot(client); +const guild = client.guilds.forge(guildData); +const channel = guild.channels.forge(channelData); +const role = guild.roles.forge(roleData); +const member = guild.members.forge(memberData); +const user = guild.users.forge(userData); +const message = guild.messages.forge(messageData); +const interaction = guild.interactions.forge(interactionData); +const emoji = guild.emojis.forge(emojiData); + +const webhook = new Discord.Webhook(client, webhookData); +const embed = new Discord.Embed(embedData); // embedData is optional +const component = new Discord.Component(componentData); // componentData is optional +const collection = new Discord.Collection(); ``` Some popular methods have been added to the structures so that you can use them without having to come up with your own. -Of course, you can add your own methods and customize the structures to fit your needs. +In order to use the Structures from the Wrapper, you need to invoke the `.forge` method with the raw discord data, +whereas it will construct the structure for you. Next we're going to give a better insight into how create [`Embeds`](embeds) and [`Components`](components) with the -template structures. +wrappers structures. diff --git a/site/docs/nodejs/Structures/embeds.md b/site/docs/nodejs/Structures/embeds.md index 48015d54e..9c2864e16 100644 --- a/site/docs/nodejs/Structures/embeds.md +++ b/site/docs/nodejs/Structures/embeds.md @@ -57,16 +57,15 @@ await channel.send({ embeds: [embed] }); ``` You probably want more methods which you can use to create embeds. -[We also have a Template for this](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Embed.js) +[Here is how the Embed Structure looks like](https://github.com/meister03/discordeno.js/blob/master/Structures/Embed.js) ### Using the Embed Structure: ```js -const Embed = require("./structures/Embed"); // Path to structure -const Channel = require("./structures/Channel"); // Path to structure +const Discord = require("discordeno.js"); -const channel = new Channel(client, data); -const showCaseEmbed = new Embed() +const channel = client.channels.forge(channelData); +const showCaseEmbed = new Discord.Embed() .setColor(0x00AE86) .setTitle("A Random Title") .setURL("https://github.com/discordeno") diff --git a/site/docs/nodejs/getting-started.md b/site/docs/nodejs/getting-started.md index 22a0548d2..7ec1a58fb 100644 --- a/site/docs/nodejs/getting-started.md +++ b/site/docs/nodejs/getting-started.md @@ -13,6 +13,9 @@ different language. This guide will help you making your first Discord Bot using Node.js or even migrating your Bot from a other Library. +Moreover this guide will utilize two different options. One option to use the Discordeno package without any frameworks +and one, which uses the wrapper called `Discordeno.js`, which aims to achieve a djs-like interface. + :::important Disclaimer Some features are not documented yet. If you want to know more about them, kindly ask for help in the diff --git a/site/docs/nodejs/installion.md b/site/docs/nodejs/installion.md index 8a991dec5..210daf415 100644 --- a/site/docs/nodejs/installion.md +++ b/site/docs/nodejs/installion.md @@ -22,7 +22,8 @@ In order to keep track of the dependencies, you need to initialize NPM, which ge $ npm init --yes ``` -Then you need to install Discordeno. Go to your terminal and run the following command: +Then you need to install Discordeno. When you want to go along with the wrapper named `Discordeno.js`, then install it +too. Go to your terminal and run the following command: ```cli $ npm install discordeno diff --git a/site/docs/nodejs/slash-command.md b/site/docs/nodejs/slash-command.md index 0d08fec7d..b5effda76 100644 --- a/site/docs/nodejs/slash-command.md +++ b/site/docs/nodejs/slash-command.md @@ -53,7 +53,7 @@ const client = Discord.createBot({ } }, }, - intents: ["Guilds"], + intents: Discord.Intents.Guilds | Discord.Intents.GuildMessages, token: config.token, }); diff --git a/template/nodejs/Managers/ChannelManager.js b/template/nodejs/Managers/ChannelManager.js deleted file mode 100644 index 6258d73f9..000000000 --- a/template/nodejs/Managers/ChannelManager.js +++ /dev/null @@ -1,17 +0,0 @@ -const Channel = require("../Structures/Channel"); -class Channels { - constructor(client, data = {}, options = {}) { - this.client = client; - - if (options.guild) this.guild = options.guild; - } - - async create(options = {}, reason) { - return new Channel(this.client, options).create(options, reason); - } - - forge(data = {}) { - return new Channel(this.client, data); - } -} -module.exports = Channels; diff --git a/template/nodejs/Managers/EventManager.js b/template/nodejs/Managers/EventManager.js index 5d90bb0c2..c954dd9bf 100644 --- a/template/nodejs/Managers/EventManager.js +++ b/template/nodejs/Managers/EventManager.js @@ -5,26 +5,26 @@ const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName); const EventEmitter = require("events"); class EventManager extends EventEmitter { - constructor(client) { + constructor() { super(); this.cache = new Map(); - this._events = {}; + this.allEvents = {}; } load(options = {}) { const eventsFolder = resolveFolder("../events"); + let i = 0; fs.readdirSync(eventsFolder).map(async (file) => { if (!file.endsWith(".js")) return; + i++; const fileName = path.join(eventsFolder, file); const event = require(fileName); const eventName = file.split(".")[0]; - this._events[`${eventName}`] = event; - /* When the event should be emitted on client.events.on(eventName, (...args) => {...}) - this._events[`${eventName}`] = function(...args) { - this.emit(eventName, ...args); - return event(...args); - }; - */ + + this.allEvents[`${eventName}`] = (...args) => { + this.emit(eventName, ...args); + return event(...args); + }; }); return this._events; } diff --git a/template/nodejs/Managers/MemberManager.js b/template/nodejs/Managers/MemberManager.js deleted file mode 100644 index ce719cc48..000000000 --- a/template/nodejs/Managers/MemberManager.js +++ /dev/null @@ -1,13 +0,0 @@ -const Member = require("../Structures/Member"); -class Members { - constructor(client, data = {}, options = {}) { - this.client = client; - - if (options.guild) this.guild = options.guild; - } - - forge(data = {}) { - return new Member(this.client, data, { guild: this.guild }); - } -} -module.exports = Members; diff --git a/template/nodejs/Managers/RoleManager.js b/template/nodejs/Managers/RoleManager.js deleted file mode 100644 index 64997d1f9..000000000 --- a/template/nodejs/Managers/RoleManager.js +++ /dev/null @@ -1,29 +0,0 @@ -const Role = require("../Structures/Role"); -class Roles { - constructor(client, data = {}, options = {}) { - this.client = client; - if (options.member) this.member = options.member; - if (options.guild) this.guild = options.guild; - } - - async create(options = {}, reason) { - return new Role(this.client, options).create(options, reason); - } - - forge(data = {}) { - return new Roles(this.client, data); - } - - async add(options = {}, reason) { - const guildId = (this.guild ? this.guild.id : options.guildId); - const memberId = (this.member ? this.member.id : options.memberId); - return this.client.helpers.addRole(guildId, memberId, options.roleId, reason); - } - - async remove(options = {}, reason) { - const guildId = (this.guild ? this.guild.id : options.guildId); - const memberId = (this.member ? this.member.id : options.memberId); - return this.client.helpers.removeRole(guildId, memberId, options.roleId, reason); - } -} -module.exports = Roles; diff --git a/template/nodejs/Plugins/Developer/commands/eval.js b/template/nodejs/Plugins/Developer/commands/eval.js index 8544b879e..6d5cf9f44 100644 --- a/template/nodejs/Plugins/Developer/commands/eval.js +++ b/template/nodejs/Plugins/Developer/commands/eval.js @@ -1,5 +1,6 @@ +const Discord = require("discordeno.js"); + const BaseCommand = require("../../../Structures/BaseCommand.js"); -const Embed = require("../../../Structures/Embed.js"); class evalcommand extends BaseCommand { static name = "eval"; static description = "danger !!!"; @@ -40,7 +41,7 @@ class evalcommand extends BaseCommand { }, 1) : outputOfEval; - const embed = new Embed() + const embed = new Discord.Embed() .addField({ name: "Input", value: "```js\n" + inputOfEval + "```" }) .addField({ name: "Output", value: "```json\n" + `${outputOfEval}`.slice(0, 1000) + "```" }); this.reply({ embeds: [embed] }); diff --git a/template/nodejs/Plugins/Developer/commands/reload.js b/template/nodejs/Plugins/Developer/commands/reload.js index 4e01117a7..b43d66df0 100644 --- a/template/nodejs/Plugins/Developer/commands/reload.js +++ b/template/nodejs/Plugins/Developer/commands/reload.js @@ -1,5 +1,4 @@ const BaseCommand = require("../../../Structures/BaseCommand.js"); -const Embed = require("../../../Structures/Embed.js"); class reloadcommand extends BaseCommand { static name = "reload"; static description = "Reloads a Command"; diff --git a/template/nodejs/Plugins/General/commands/ping.js b/template/nodejs/Plugins/General/commands/ping.js index 7a3666833..a4ee73cf8 100644 --- a/template/nodejs/Plugins/General/commands/ping.js +++ b/template/nodejs/Plugins/General/commands/ping.js @@ -1,5 +1,5 @@ const BaseCommand = require("../../../Structures/BaseCommand.js"); -const Embed = require("../../../Structures/Embed.js"); +const Discord = require("discordeno.js"); class pingcommand extends BaseCommand { static name = "ping"; static description = "See if the bot latency is okay"; @@ -14,7 +14,7 @@ class pingcommand extends BaseCommand { //Assign properties to the response const ping = msg.timestamp - this.message.timestamp; - const embed = new Embed() + const embed = new Discord.Embed() .setTitle(`The Bots ping is ${ping} ms`) .toJSON(); //Edit Message with the Embed diff --git a/template/nodejs/Plugins/Moderation/commands/ban.js b/template/nodejs/Plugins/Moderation/commands/ban.js index 5d6a7d5f2..24b7d8c3b 100644 --- a/template/nodejs/Plugins/Moderation/commands/ban.js +++ b/template/nodejs/Plugins/Moderation/commands/ban.js @@ -1,5 +1,5 @@ const BaseCommand = require("../../../Structures/BaseCommand.js"); -const Component = require("../../../Structures/Component.js"); +const Discord = require("discordeno.js"); class bancommand extends BaseCommand { static name = "ban"; @@ -16,7 +16,7 @@ class bancommand extends BaseCommand { // Because no permission system has not been added if (!this.client.config.owners.includes(String(this.user.id))) return; - const textinput = new Component() + const textinput = new Discord.Component() .setType("TEXT_INPUT") .setStyle("SHORT") .setCustomId("t1") @@ -27,12 +27,12 @@ class bancommand extends BaseCommand { .setMinLength(1) .setValue(this.args[0]) .toJSON(); - const textinput2 = new Component().setType("TEXT_INPUT").setStyle("PARAGRAPH").setCustomId("t2") + const textinput2 = new Discord.Component().setType("TEXT_INPUT").setStyle("PARAGRAPH").setCustomId("t2") .setLabel("Reason").setPlaceholder("Reason for Ban").setRequired(false) .setMaxLength(300).toJSON(); - const actionrow = new Component().setType(1).setComponents(textinput).toJSON(); - const actionrow2 = new Component().setType(1).setComponents(textinput2).toJSON(); + const actionrow = new Discord.Component().setType(1).setComponents(textinput).toJSON(); + const actionrow2 = new Discord.Component().setType(1).setComponents(textinput2).toJSON(); this.interaction.popupModal({ customId: "ban_modal", title: "Ban User", components: [actionrow, actionrow2] }); } diff --git a/template/nodejs/Plugins/Moderation/commands/warn.js b/template/nodejs/Plugins/Moderation/commands/warn.js new file mode 100644 index 000000000..5c55cd1ee --- /dev/null +++ b/template/nodejs/Plugins/Moderation/commands/warn.js @@ -0,0 +1,81 @@ +const BaseCommand = require("../../../Structures/BaseCommand.js"); + +const { Interaction, Collector, ComponentOptions, Embed, Component } = require("discordeno.js"); + +class warncommand extends BaseCommand { + static name = "warn"; + static description = "Warn a user from the server"; + static usage = ""; + static category = "Moderation"; + static slash = { name: "warn", category: "mod" }; + constructor(data) { + super(data); + } + async execute() { + //Show Case Modal + if (!this.interaction) return this.reply("You currently can just use this command as slash command."); + + if (!this.interaction.member.permissions.has("KICK_MEMBERS")) { + return this.reply("You need the permission `KICK_MEMBERS` to use this command."); + } + + const textinput = new Component() + .setType("TEXT_INPUT") + .setStyle("SHORT") + .setCustomId("t1") + .setLabel("User ID") + .setPlaceholder("User ID") + .setRequired(true) + .setMaxLength(20) + .setMinLength(1) + .setValue(this.args[0]) + .toJSON(); + const textinput2 = new Component().setType("TEXT_INPUT").setStyle("PARAGRAPH").setCustomId("t2") + .setLabel("Reason").setPlaceholder("Reason for Warning").setRequired(false) + .setMaxLength(300).toJSON(); + + const actionrow = new Component().setType(1).setComponents(textinput).toJSON(); + const actionrow2 = new Component().setType(1).setComponents(textinput2).toJSON(); + + this.interaction.popupModal({ customId: "warn_modal", title: "Warn User", components: [actionrow, actionrow2] }); + + const filter = (m) => m.data?.customId === "warn_modal"; + const collector = new Collector("interactionCreate", { client: this.client, timeout: 60000, filter }); + collector.on("collect", (m) => { + const options = new ComponentOptions(m.data.components); + const i = new Interaction(this.client, m); + collector.stop(); + + const memberId = options.get("t1").value; + const reason = options.get("t2").value; + + const embed = new Embed() + .setTitle("Warned User:") + .setDescription(`User ID: <@${memberId}> \n Reason: ${reason}`) + .setColor(0x00ff00) + .toJSON(); + + const warnMessage = new Embed() + .setTitle("Warning:") + .setDescription(`You have been warned in **${this.guild.name}** for ${"`" + reason + "`"}`) + .toJSON(); + + this.guild.members.fetch(memberId).then((m) => { + m.send({ embeds: [warnMessage] }).then(() => { + i.reply({ embeds: [embed] }); + }).catch((e) => { + console.log(e); + i.reply({ content: `Could not warn user ${"<@" + m.id + ">"} | They likely do not have their DMs open.` }); + }); + }).catch((e) => { + const embed = new Embed() + .setTitle("Member not found") + .setDescription(`The member with the ID of ${"`" + memberId + "`"} has not been found in this Server.`) + .setColor(0xff0000) + .toJSON(); + i.reply({ embeds: [embed] }); + }); + }); + } +} +module.exports = warncommand; diff --git a/template/nodejs/Structures/BaseCommand.js b/template/nodejs/Structures/BaseCommand.js index 146f2d78f..88a32d188 100644 --- a/template/nodejs/Structures/BaseCommand.js +++ b/template/nodejs/Structures/BaseCommand.js @@ -4,8 +4,8 @@ const Interaction = require("./Interaction.js"); class BaseCommand extends UtilCommand { constructor(data) { super(data); - this.message = data.message && new Message(data.client, data.message); - this.interaction = data.interaction && new Interaction(data.client, data.interaction); + this.message = data.message; + this.interaction = data.interaction; this.user = this.message ? this.message.author : this.interaction.user; this.guild = this.message ? this.message.guild : this.interaction.guild; this.member = this.message ? this.message.member : this.interaction.member; diff --git a/template/nodejs/Structures/Channel.js b/template/nodejs/Structures/Channel.js deleted file mode 100644 index 0e18fd002..000000000 --- a/template/nodejs/Structures/Channel.js +++ /dev/null @@ -1,29 +0,0 @@ -const DestructObject = require("./DestructObject"); -const Guild = require("./Guild"); - -class Channel extends DestructObject { - constructor(client, channel = {}, options = {}) { - super(channel); - if (options.guild) this.guild = options.guild; - else if (channel.guildId) this.guild = new Guild(client, { id: channel.guildId }); - - this.client = client; - } - - async create(options = {}, reason) { - return this.client.helpers.createChannel(this.guildId, options, reason); - } - - async edit(options = {}, reason) { - return this.client.helpers.editChannel(this.id, options, reason); - } - - async delete(reason) { - return this.client.helpers.deleteChannel(this.id, reason); - } - - async send(options = {}) { - return this.client.helpers.sendMessage(this.id, options); - } -} -module.exports = Channel; diff --git a/template/nodejs/Structures/CommandResponse.js b/template/nodejs/Structures/CommandResponse.js index 9c5b17c8f..6052c7403 100644 --- a/template/nodejs/Structures/CommandResponse.js +++ b/template/nodejs/Structures/CommandResponse.js @@ -1,5 +1,3 @@ -const Message = require("./Message"); - class Responses { constructor(data) { this.manager = data.manager; @@ -13,12 +11,8 @@ class Responses { if (this.interaction) { if (this.replied) return this.followUp(content); const reply = await this.interaction.reply(content); - - //Assign properties to the response - const response = new Message(this.client, reply); - this.replied = true; - return response; + return {}; } if (this.message) { if (this.replied) return this.followUp(content); @@ -26,7 +20,7 @@ class Responses { const msg = await this.message.channel.send(content); //Assign properties to the response - const response = new Message(this.client, msg); + const response = this.client.messages.forge(msg); this.replied = true; return response; } @@ -35,12 +29,11 @@ class Responses { async followUp(content) { if (this.interaction) { const reply = await this.interaction.followUp(content); - const response = new Message(this.client, reply); - return response; + return {}; } if (this.message) { const msg = await this.message.channel.send(content); - const response = new Message(this.client, msg); + const response = this.client.messages.forge(msg); return response; } } diff --git a/template/nodejs/Structures/Component.js b/template/nodejs/Structures/Component.js deleted file mode 100644 index 31dcfc9d1..000000000 --- a/template/nodejs/Structures/Component.js +++ /dev/null @@ -1,171 +0,0 @@ -const Constants = { - PRIMARY: 1, - SECONDARY: 2, - SUCCESS: 3, - DANGER: 4, - LINK: 5, - SHORT: 1, - PARAGRAPH: 2, - - ACTION_ROW: 1, - BUTTON: 2, - SELECT_MENU: 3, - TEXT_INPUT: 4, -}; -class Component { - constructor(options = {}) { - this.type = options.type; - this.custom_id = options.custom_id ?? options.customId; - this.disabled = options.disabled; - this.style = options.style; - this.label = options.label; - this.emoji = options.emoji; - this.url = options.url; - - //Select Menu - this.options = options.options; - this.placeholder = options.placeholder; - this.min_values = options.min_values ?? options.minValues; - this.max_values = options.max_values ?? options.maxValues; - - //Action Row - this.components = options.components; - - //Modal - this.value = options.value; - this.min_length = options.min_length ?? options.minLength; - this.max_length = options.max_length ?? options.maxLength; - this.required = options.required; - } - - setType(type) { - if (typeof type === "string") { - this.type = Constants[type.toUpperCase()]; - if (!this.type) throw new Error(`Invalid Component Type: ${type}`); - } else this.type = type; - return this; - } - - setCustomId(custom_id) { - if (!this.url) this.custom_id = custom_id; - return this; - } - - setDisabled(disabled) { - this.disabled = disabled; - return this; - } - - setRequired(required) { - this.required = required; - return this; - } - - setStyle(style) { - if (!this.url) { - if (typeof style === "string") { - this.style = Constants[style.toUpperCase()]; - if (!this.style) throw new Error(`Invalid Button Style Type: ${type}`); - } else this.style = style; - } - return this; - } - - setLabel(label) { - this.label = label; - return this; - } - - setEmoji(emoji) { - this.emoji = emoji; - return this; - } - - setUrl(url) { - this.url = url; - this.style = 5; - this.custom_id = undefined; - return this; - } - - setOptions(options) { - this.options = options; - return this; - } - - setValue(value) { - this.value = value; - return this; - } - - setPlaceholder(placeholder) { - this.placeholder = placeholder; - return this; - } - - setMinValues(min_values) { - this.min_values = min_values; - return this; - } - - setMaxValues(max_values) { - this.max_values = max_values; - return this; - } - - setMinLength(min_values) { - this.min_length = min_values; - return this; - } - - setMaxLength(max_values) { - this.max_length = max_values; - return this; - } - - setComponents(...components) { - this.components = components; - return this; - } - - toJSON() { - if (!this.type) throw new Error("Component must have a type"); - const json = { - type: this.type, - }; - if (this.type === 1) { - json.components = this.components; - } - - if (this.type === 2) { - json.customId = this.custom_id; - json.style = this.style; - json.label = this.label; - json.emoji = this.emoji; - json.url = this.url; - json.disabled = this.disabled; - } - - if (this.type === 3) { - json.customId = this.custom_id; - json.options = this.options; - json.placeholder = this.placeholder; - json.minValues = this.min_values; - json.maxValues = this.max_values; - json.disabled = this.disabled; - } - - if (this.type === 4) { - json.customId = this.custom_id; - json.style = this.style; - json.label = this.label; - json.minLength = this.min_length; - json.maxLength = this.max_length; - json.required = this.required; - json.value = this.value; - json.placeholder = this.placeholder; - } - return json; - } -} -module.exports = Component; diff --git a/template/nodejs/Structures/DestructObject.js b/template/nodejs/Structures/DestructObject.js deleted file mode 100644 index 2f0dff7b0..000000000 --- a/template/nodejs/Structures/DestructObject.js +++ /dev/null @@ -1,16 +0,0 @@ -class DestructObject { - constructor(message = {}) { - this.destructObject(message); - } - destructObject(message) { - for (let [key, value] of Object.entries(message)) { - this[key] = value; - } - return this; - } - - toJSON() { - return { ...this }; - } -} -module.exports = DestructObject; diff --git a/template/nodejs/Structures/Embed.js b/template/nodejs/Structures/Embed.js deleted file mode 100644 index cb7e88ba0..000000000 --- a/template/nodejs/Structures/Embed.js +++ /dev/null @@ -1,99 +0,0 @@ -class Embed { - constructor(options = {}) { - this.title = options.title; - this.description = options.description; - this.fields = options.fields; - this.thumbnail = options.thumbnail; - this.image = options.image; - this.author = options.author; - this.color = options.color; - this.timestamp = options.timestamp; - this.footer = options.footer; - this.url = options.url; - this.fields = options.fields ?? []; - } - setTitle(title) { - this.title = title; - return this; - } - - setDescription(description) { - this.description = description; - return this; - } - - setThumbnail(thumbnail) { - this.thumbnail = thumbnail; - return this; - } - - setImage(image) { - this.image = image; - return this; - } - - setAuthor(author) { - if (typeof author !== "object") throw new Error("Author must be an object"); - this.author = author; - return this; - } - - setColor(color) { - this.color = color; - return this; - } - - setTimestamp(timestamp) { - this.timestamp = timestamp ?? Date.now(); - return this; - } - - setFooter(footer) { - if (typeof footer !== "object") throw new Error("Footer must be an object"); - this.footer = footer; - return this; - } - - setURL(url) { - this.url = url; - return this; - } - - addField(field) { - this.fields.push(field); - return this; - } - - addFields(...fields) { - fields.map((x) => this.addField(x)); - return this; - } - - toJSON() { - return { - title: this.title, - type: "rich", - description: this.description, - color: this.color, - timestamp: this.timestamp ? new Date(this.timestamp).toISOString() : null, - thumbnail: this.thumbnail, - image: this.image, - fields: this.fields, - url: this.url, - author: this.author - ? { - name: this.author.name, - url: this.author.url, - iconUrl: this.author.icon_url || this.author.iconUrl, - } - : null, - footer: this.footer - ? { - text: this.footer.text, - iconUrl: this.footer.icon_url || this.footer.iconUrl, - } - : null, - }; - } -} -module.exports = Embed; diff --git a/template/nodejs/Structures/Guild.js b/template/nodejs/Structures/Guild.js deleted file mode 100644 index fe3a19d1f..000000000 --- a/template/nodejs/Structures/Guild.js +++ /dev/null @@ -1,18 +0,0 @@ -const DestructObject = require("./DestructObject"); - -const RoleManager = require("../Managers/RoleManager"); -const MemberManager = require("../Managers/MemberManager"); -const ChannelManager = require("../Managers/ChannelManager"); - -class Guild extends DestructObject { - constructor(client, guild = {}) { - super(guild); - this.client = client; - - //Managers: - this.roles = new RoleManager(client, {}, { guild: this }); - this.members = new MemberManager(client, {}, { guild: this }); - this.channels = new ChannelManager(client, {}, { guild: this }); - } -} -module.exports = Guild; diff --git a/template/nodejs/Structures/Interaction.js b/template/nodejs/Structures/Interaction.js deleted file mode 100644 index a21b8123f..000000000 --- a/template/nodejs/Structures/Interaction.js +++ /dev/null @@ -1,116 +0,0 @@ -const DestructObject = require("./DestructObject"); -const Guild = require("./Guild"); -const Channel = require("./Channel"); -const Constants = { - DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE: 5, - CHANNEL_MESSAGE_WITH_SOURCE: 4, - DEFERRED_UPDATE_MESSAGE: 6, - UPDATE_MESSAGE: 7, - APPLICATION_COMMAND_AUTOCOMPLETE_RESULT: 8, - MODAL: 9, - FLAGS: { EPHEMERAL: 64 }, - INTERACTION_TYPES: { - CHAT_INPUT: 1, - APPLICATION_COMMAND: 2, - CONTEXT_MENU: 2, - MESSAGE_COMPONENT: 3, - APPLICATION_COMMAND_AUTOCOMPLETE: 4, - }, -}; -class Interaction extends DestructObject { - constructor(client, interaction = {}) { - super(interaction); - this.raw = interaction; - this.client = client; - - this.guild = new Guild(client, { id: this.guild_id || this.guildId }); - this.channel = new Channel(client, { id: this.channel_id || this.channelId }, { - internal: true, - guild: this.guild, - }); - } - - isCommand() { - return this.type === Constants.INTERACTION_TYPES.APPLICATION_COMMAND; - } - - // @todo check Context Menu type and Component Type - isChatInputCommand() { - return this.type === Constants.INTERACTION_TYPES.CHAT_INPUT; - } - isContextMenuCommand() { - return this.isCommand(); - } - isAutoComplete() { - return this.type === Constants.INTERACTION_TYPES.APPLICATION_COMMAND_AUTOCOMPLETE; - } - isMessageComponent() { - return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT; - } - isSelectMenu() { - return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT; - } - isButton() { - return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT; - } - - async deferReply(options = {}) { - if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); - const Payload = { data: {}, type: Constants.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE }; - options.type = 5; - if (this.ephemeral) options.private = true; - this.ephemeral = options.ephemeral || false; - this.deferred = true; - return this.client.helpers.sendInteractionResponse(this.id, this.token, options); - } - - async deferUpdate(options = {}) { - if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); - this.deferred = true; - const Payload = { data: options, type: Constants.DEFERRED_UPDATE_MESSAGE }; - return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); - } - - async reply(options = {}) { - if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); - this.ephemeral = options.ephemeral || false; - if (this.ephemeral) options.private = true; - this.replied = true; - const Payload = { data: options, type: Constants.CHANNEL_MESSAGE_WITH_SOURCE }; - return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); - } - - async popupModal(options = {}) { - if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); - const Payload = { data: options, type: Constants.MODAL }; - this.replied = true; - return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); - } - - async editReply(options = {}) { - if (!this.deferred && !this.replied) throw new Error("Interaction has not been replied"); - this.replied = true; - const messageId = this.messageId ? this.messageId : options.messageId; - return this.client.helpers.editInteractionResponse(this.token, options); - } - - async deleteReply(options = {}) { - if (this.ephemeral) throw new Error("Ephemeral messages cannot be deleted"); - const messageId = this.messageId ? this.messageId : options.messageId; - return this.client.helpers.deleteInteractionResponse(this.token, messageId); - } - - async followUp(options = {}) { - if (!this.replied || !this.deferred) throw new Error("Interaction has not been replied"); - const Payload = { data: options, type: Constants.CHANNEL_MESSAGE_WITH_SOURCE }; - return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); - } - - async update(options = {}) { - if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); - const Payload = { data: options, type: Constants.UPDATE_MESSAGE }; - this.replied = true; - return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); - } -} -module.exports = Interaction; diff --git a/template/nodejs/Structures/Member.js b/template/nodejs/Structures/Member.js deleted file mode 100644 index 2aab97af5..000000000 --- a/template/nodejs/Structures/Member.js +++ /dev/null @@ -1,16 +0,0 @@ -const DestructObject = require("./DestructObject"); -const Guild = require("./Guild"); -const RoleManager = require("../Managers/RoleManager"); - -class Member extends DestructObject { - constructor(client, member = {}, options = {}) { - super(member); - this.client = client; - - if (options.guild) this.guild = options.guild; - else if (member.guildId) this.guild = new Guild(client, { id: member.guildId }); - - this.roles = new RoleManager(client, {}, { guild: this.guild, member: this }); - } -} -module.exports = Member; diff --git a/template/nodejs/Structures/Message.js b/template/nodejs/Structures/Message.js deleted file mode 100644 index 39d46fb63..000000000 --- a/template/nodejs/Structures/Message.js +++ /dev/null @@ -1,50 +0,0 @@ -const DestructObject = require("./DestructObject"); - -const Channel = require("./Channel"); -const Guild = require("./Guild"); -const Member = require("./Member"); -const User = require("./User"); - -class Message extends DestructObject { - constructor(client, message = {}) { - super(message); - this.client = client; - this.guild = new Guild(client, { id: this.guild_id || this.guildId }); - this.channel = new Channel(client, { id: this.channel_id || this.channelId }, { guild: this.guild }); - this.member = new Member(client, message.member, { guild: this.guild }); - this.author = new User(client, { - id: this.author_id || this.authorId, - username: this.tag?.split("#")[0], - discriminator: this.tag?.split("#")[1], - bot: this.isBot, - }); - } - - async edit(options) { - return this.client.helpers.editMessage(this.channel.id, this.id, options); - } - - async reply(options = {}) { - if (!options.messageReference) { - options.messageReference = { messageId: this.id, channelId: this.channel.id, guildId: this.guild.id }; - } - return this.client.helpers.sendMessage(this.channel.id, options); - } - - async delete(options = {}) { - return this.client.helpers.deleteMessage(this.channel.id, this.id, options.reason, options.delayMilliseconds); - } - - async react(emoji) { - return this.client.helpers.addReaction(this.channel.id, this.id, emoji); - } - - async pin() { - return this.client.helpers.pinMessage(this.channel.id, this.id); - } - - async unpin() { - return this.client.helpers.unpinMessage(this.channel.id, this.id); - } -} -module.exports = Message; diff --git a/template/nodejs/Structures/Permissions.js b/template/nodejs/Structures/Permissions.js deleted file mode 100644 index 1ed537b37..000000000 --- a/template/nodejs/Structures/Permissions.js +++ /dev/null @@ -1,9 +0,0 @@ -/// On work -class Permissions { - constructor(client, data = {}, options = {}) { - this.client = client; - } - - has(bit) { - } -} diff --git a/template/nodejs/Structures/Role.js b/template/nodejs/Structures/Role.js deleted file mode 100644 index 8e92ad114..000000000 --- a/template/nodejs/Structures/Role.js +++ /dev/null @@ -1,12 +0,0 @@ -const DestructObject = require("./DestructObject"); -const Guild = require("./Guild"); - -class Role extends DestructObject { - constructor(client, role = {}, options = {}) { - super(role); - if (options.guild) this.guild = options.guild; - else if (role.guildId) this.guild = new Guild(client, { id: role.guildId }); - this.client = client; - } -} -module.exports = Role; diff --git a/template/nodejs/Structures/User.js b/template/nodejs/Structures/User.js deleted file mode 100644 index 7626a3dfa..000000000 --- a/template/nodejs/Structures/User.js +++ /dev/null @@ -1,13 +0,0 @@ -const DestructObject = require("./DestructObject"); - -class User extends DestructObject { - constructor(client, user = {}) { - super(user); - this.client = client; - } - - get tag() { - return `#${this.username}#${this.discriminator}`; - } -} -module.exports = User; diff --git a/template/nodejs/events/interactionCreate.js b/template/nodejs/events/interactionCreate.js index ff76be71e..3f5b27042 100644 --- a/template/nodejs/events/interactionCreate.js +++ b/template/nodejs/events/interactionCreate.js @@ -1,3 +1,4 @@ module.exports = async (client, interaction) => { + interaction = client.interactions.forge(interaction); client.commands.isInteraction(interaction); }; diff --git a/template/nodejs/events/messageCreate.js b/template/nodejs/events/messageCreate.js index 3b18d1977..b3c96f77e 100644 --- a/template/nodejs/events/messageCreate.js +++ b/template/nodejs/events/messageCreate.js @@ -1,3 +1,4 @@ module.exports = async (client, message) => { + message = client.messages.forge(message); client.commands.isCommand(message); }; diff --git a/template/nodejs/events/ready.js b/template/nodejs/events/ready.js index 5e6fa6aab..d828e60f8 100644 --- a/template/nodejs/events/ready.js +++ b/template/nodejs/events/ready.js @@ -1,7 +1,6 @@ const User = require("../Structures/User"); module.exports = async (client, payload) => { - client.user = new User(client, payload.user); - + client.user = client.users.forge(payload.user); if (payload.shardId + 1 === client.gateway.maxShards) { //All Shards are ready console.log("Successfully connected to the gateway as " + client.user.tag); diff --git a/template/nodejs/index.js b/template/nodejs/index.js index 10c3d81df..549e4fbda 100644 --- a/template/nodejs/index.js +++ b/template/nodejs/index.js @@ -1,4 +1,4 @@ -const Discord = require("discordeno"); +const Discord = require("discordeno.js"); // Ideally you should switch this to .env but for a template a config json is enough const config = require("../config.json"); @@ -7,11 +7,12 @@ const EventManager = require("./Managers/EventManager.js"); // looping through all events and registering them const events = new EventManager({}); -const client = Discord.createBot({ +const baseBot = Discord.createBot({ events: events.load({}), - intents: ["Guilds", "GuildMessages"], + intents: Discord.Intents.Guilds | Discord.Intents.GuildMessages | Discord.Intents.MessageContent, token: config.token, }); +const client = Discord.enableCachePlugin(baseBot, {}); client.config = config; diff --git a/template/nodejs/package.json b/template/nodejs/package.json new file mode 100644 index 000000000..b4af40020 --- /dev/null +++ b/template/nodejs/package.json @@ -0,0 +1,15 @@ +{ + "name": "nodejs-template", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "discordeno.js": "github:meister03/discordeno.js" + } +}