diff --git a/.dockerignore b/.dockerignore index 5171c5408..2aca7dfd6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,6 @@ -node_modules -npm-debug.log \ No newline at end of file +.DS_Store +node_modules/ +.vscode/ +*.log +*.tar.gz +.env \ No newline at end of file diff --git a/.gitignore b/.gitignore index de6c79883..7d0b3e132 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +.DS_Store .vscode/ node_modules/ -logs/* +*.log +*.tar.gz .env \ No newline at end of file diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 75800ecb9..000000000 --- a/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -.DS_Store -.eslintrc*.yml -*.log -*.tar.gz -CONTRIBUTING.md -examples -docgen -docs -node_modules -test \ No newline at end of file diff --git a/config.js b/config.js index 9ba79ab40..b2d71dd1a 100644 --- a/config.js +++ b/config.js @@ -51,7 +51,17 @@ module.exports = { ENABLED: false, IDLE_TIME: 60, // Time in seconds before the bot disconnects from the voice channel MAX_SEARCH_RESULTS: 5, - NODES: [], + // Add any number of lavalink nodes here + // Refer to https://github.com/freyacodes/Lavalink to host your own lavalink server + NODES: [ + { + host: "localhost", + port: 2333, + password: "youshallnotpass", + identifier: "Local Node", + secure: false, + }, + ], }, GIVEAWAYS: { diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index e914e2c15..034755138 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,25 +1,24 @@ # Table of contents -* [🤖 About Me](../README.md) -* [📘 Commands](commands/README.md) - * [⚙ Admin](commands/admin.md) - * [🔞 Anime](commands/anime.md) - * [🪙 Economy](commands/economy.md) - * [😂 Fun](commands/fun.md) - * [🎉 Giveaways](commands/giveaways.md) - * [🖼 Image](commands/image.md) - * [🪧 Information](commands/information.md) - * [📨 Invites](commands/invites.md) - * [🔨 Moderation](commands/moderation.md) - * [🎵 Music](commands/music.md) - * [🔏 Owner](commands/owner.md) - * [🧑 Social](commands/social.md) - * [📈 Stats](commands/stats.md) - * [🛠 Utility](commands/utility.md) -* [🗒 Contexts](contexts.md) +- [🤖 About Me](../README.md) +- [📘 Commands](commands/README.md) + - [⚙ Admin](commands/admin.md) + - [🔞 Anime](commands/anime.md) + - [🪙 Economy](commands/economy.md) + - [😂 Fun](commands/fun.md) + - [🎉 Giveaways](commands/giveaways.md) + - [🖼 Image](commands/image.md) + - [🪧 Information](commands/information.md) + - [📨 Invites](commands/invites.md) + - [🔨 Moderation](commands/moderation.md) + - [🎵 Music](commands/music.md) + - [🔏 Owner](commands/owner.md) + - [🧑 Social](commands/social.md) + - [📈 Stats](commands/stats.md) + - [🛠 Utility](commands/utility.md) +- [🗒 Contexts](contexts.md) ## Additional -* [✍ Guides](additional/installation.md) - * [Replit](additional/replit.md) -* [❓ FAQ](additional/faq.md) +- [✍ Guides](additional/installation.md) +- [❓ FAQ](additional/faq.md) diff --git a/docs/additional/installation.md b/docs/additional/installation.md index f95a064ae..6637499df 100644 --- a/docs/additional/installation.md +++ b/docs/additional/installation.md @@ -2,9 +2,9 @@ ### Setting up Slash Commands -* Slash commands are disabled by default -* In the **config.js** set **SLASH = true** and **CONTEXT = true** and replace TEST\_GUILD\_ID with the guild ID where you want to initially test the commands. This will ensure that all the commands are registered immediately -* Once you are happy with the commands, set **GLOBAL = true** to register these interactions globally +- Slash commands are disabled by default +- In the **config.js** set **SLASH = true** and **CONTEXT = true** and replace TEST_GUILD_ID with the guild ID where you want to initially test the commands. This will ensure that all the commands are registered immediately +- Once you are happy with the commands, set **GLOBAL = true** to register these interactions globally {% hint style="warning" %} _**Global slash commands** can take upto 1 hour to be shown across all guilds_ @@ -12,8 +12,8 @@ _**Global slash commands** can take upto 1 hour to be shown across all guilds_ ### Setting up Dashboard -* In the config.js, make sure you set dashboard enabled to **true** -* Add your baseURL, `http://localhost:8080/api/callback` in your application OAuth2 redirects page in the [discord developer portal](https://discord.com/developers/applications) +- In the config.js, make sure you set dashboard enabled to **true** +- Add your baseURL, `http://localhost:8080/api/callback` in your application OAuth2 redirects page in the [discord developer portal](https://discord.com/developers/applications) ``` DASHBOARD: { diff --git a/docs/additional/replit.md b/docs/additional/replit.md deleted file mode 100644 index 8f3a72d09..000000000 --- a/docs/additional/replit.md +++ /dev/null @@ -1,58 +0,0 @@ - ✍ Guides | Setting up Strangebot for Replit! - -### Intro - -Replit does not automatically update node to the latest version. **This is a problem as Strangebot runs on Discord.js V13 - -{% hint style="warning" %} -Migration to V13 will take a while, But once it is done, it is done forever! -{% endhint %} - -### Guide - -* 1. Create a new repl. **Set the language as "Nix (Beta)" ** [Language Setup](https://i.imgur.com/4cxgFKg.png) - -* 2. Go to the file "replit.nix" and copy the code below (You can get rid of cowsay if you want, but who doesnt love cowsay?) **Save this file, Replit does this automatically... Sometimes** -``` -{ pkgs }: { - deps = [ - pkgs.cowsay - pkgs.nodejs-16_x - ]; -} -``` -* 3. Go to the file ".replit" and change its contents to the code below. (We will change this later, this is just for our testing purposes) - -```run = "node test.js"``` - -* 4. Create a new file named "test.js", its contents should look like this. - -```console.log(process.version)``` -* 5. Run the replit. The console should output the correct Node version. (Anything around V16) [Something like this](https://imgur.com/dLq6N3e) - -### Main part of Guide -* 6. Clone the git repository. - -```git clone https://github.com/saiteja-madha/discord-js-bot.git``` - -* 7. Move the contents of the cloned folder into the main directory. **Do this for all files** [Like this](https://imgur.com/ki5ugSk) - - (I do this by hand, There is probably a linux command I dont know that could do this for us.) - -* 8. Go to the **Shell** and type - -```npm i``` - -* 9. Go to the ".replit" file and make sure it looks like this - -```run = "node ."``` - -* 10. **Your Done!** Now all you have to do is edit the config.js file and add your env secrets. [Should look like this](https://imgur.com/AEhiHLk) - -### Closing Remarks -Good job, Your bot is done. -Replit is a really good host for discord bots as it allows for powerful machinery with low costs and 24/7 uptime. IMO, The hacker plan is the best plan for hosting a discord bot for beginners or even serious developers. - -This guide was created by mid (mid#0002). My bot is available at https://www.beemo.best. - -Join the Strangebot support server for any further help. diff --git a/docs/contexts.md b/docs/contexts.md index b5322cde1..6905d79a5 100644 --- a/docs/contexts.md +++ b/docs/contexts.md @@ -1,2 +1 @@ # 🗒 Contexts - diff --git a/jsconfig.json b/jsconfig.json index a3a291f79..d70b46d96 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -5,7 +5,6 @@ "baseUrl": "./", "paths": { "@root/*": ["./*"], - "@features/*": ["./src/features/*"], "@handlers/*": ["./src/handlers/*"], "@helpers/*": ["./src/helpers/*"], "@schemas/*": ["./src/database/schemas/*"], diff --git a/package.json b/package.json index 1034b2282..77a83769d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord-js-bot", - "version": "5.0.0", + "version": "5.0.1", "description": "An open-source, multipurpose discord bot built using discord-js", "main": "bot.js", "author": "Sai Teja M", diff --git a/src/commands/admin/automod/anti.js b/src/commands/admin/automod/anti.js index 3a1be6004..12c0519ae 100644 --- a/src/commands/admin/automod/anti.js +++ b/src/commands/admin/automod/anti.js @@ -147,7 +147,11 @@ module.exports = { if (sub == "ghostping") response = await antiGhostPing(settings, interaction.options.getString("status")); else if (sub == "spam") response = await antiSpam(settings, interaction.options.getString("status")); else if (sub === "massmention") { - response = await antiMassMention(settings, interaction.options.getInteger("amount")); + response = await antiMassMention( + settings, + interaction.options.getString("status"), + interaction.options.getInteger("amount") + ); } else response = "Invalid command usage!"; await interaction.followUp(response); diff --git a/src/commands/giveaways/giveaway.js b/src/commands/giveaways/giveaway.js index bacbbab92..865ada937 100644 --- a/src/commands/giveaways/giveaway.js +++ b/src/commands/giveaways/giveaway.js @@ -303,11 +303,13 @@ async function runModalSetup({ member, channel, guild }, targetCh) { new ButtonBuilder().setCustomId("giveaway_btnSetup").setLabel("Setup Giveaway").setStyle(ButtonStyle.Primary) ); - const sentMsg = await channel.send({ + const sentMsg = await channel.safeSend({ content: "Please click the button below to setup new giveaway", components: [buttonRow], }); + if (!sentMsg) return; + const btnInteraction = await channel .awaitMessageComponent({ componentType: ComponentType.Button, @@ -393,12 +395,18 @@ async function runModalSetup({ member, channel, guild }, targetCh) { modal.fields .getTextInputValue("roles") ?.split(",") - ?.filter((roleId) => guild.roles.cache.get(roleId)) || []; + ?.filter((roleId) => guild.roles.cache.get(roleId.trim())) || []; // host - const host = modal.fields.getTextInputValue("host") - ? await guild.client.users.fetch(modal.fields.getTextInputValue("host")) - : null; + const hostId = modal.fields.getTextInputValue("host"); + let host = null; + if (hostId) { + try { + host = await guild.client.users.fetch(hostId); + } catch (ex) { + return modal.editReply("Setup has been cancelled. You need to provide a valid userId for host"); + } + } const response = await start(member, targetCh, duration, prize, winners, host, allowedRoles); await modal.editReply(response); diff --git a/src/commands/moderation/timeout.js b/src/commands/moderation/timeout.js index 9f34803b2..65c57875f 100644 --- a/src/commands/moderation/timeout.js +++ b/src/commands/moderation/timeout.js @@ -70,8 +70,9 @@ module.exports = { }, }; -async function timeout(issuer, target, minutes, reason) { - const response = await timeoutTarget(issuer, target, minutes, reason); +async function timeout(issuer, target, ms, reason) { + if (!NaN(Number(ms))) return "Please provide a valid duration. Example: 1d/1h/1m/1s"; + const response = await timeoutTarget(issuer, target, ms, reason); if (typeof response === "boolean") return `${target.user.tag} is timed out!`; if (response === "BOT_PERM") return `I do not have permission to timeout ${target.user.tag}`; else if (response === "MEMBER_PERM") return `You do not have permission to timeout ${target.user.tag}`; diff --git a/src/commands/ticket/ticket.js b/src/commands/ticket/ticket.js index e57b42b4c..cdf612879 100644 --- a/src/commands/ticket/ticket.js +++ b/src/commands/ticket/ticket.js @@ -275,11 +275,13 @@ async function ticketModalSetup({ guild, channel, member }, targetChannel, setti new ButtonBuilder().setCustomId("ticket_btnSetup").setLabel("Setup Message").setStyle(ButtonStyle.Primary) ); - const sentMsg = await channel.send({ + const sentMsg = await channel.safeSend({ content: "Please click the button below to setup ticket message", components: [buttonRow], }); + if (!sentMsg) return; + const btnInteraction = await channel .awaitMessageComponent({ componentType: ComponentType.Button, diff --git a/src/events/guild/guildCreate.js b/src/events/guild/guildCreate.js index 7b8e9202a..d453862a0 100644 --- a/src/events/guild/guildCreate.js +++ b/src/events/guild/guildCreate.js @@ -6,7 +6,8 @@ const { getSettings: registerGuild } = require("@schemas/Guild"); * @param {import('discord.js').Guild} guild */ module.exports = async (client, guild) => { - if (!guild.members.cache.has(guild.ownerId)) await guild.fetchOwner({ cache: true }); + if (!guild.available) return; + if (!guild.members.cache.has(guild.ownerId)) await guild.fetchOwner({ cache: true }).catch(() => {}); client.logger.log(`Guild Joined: ${guild.name} Members: ${guild.memberCount}`); await registerGuild(guild); diff --git a/src/handlers/automod.js b/src/handlers/automod.js index 56835b7c8..e883424e8 100644 --- a/src/handlers/automod.js +++ b/src/handlers/automod.js @@ -25,7 +25,7 @@ const shouldModerate = (message) => { const { member, guild, channel } = message; // Ignore if bot cannot delete channel messages - if (!channel.permissionsFor(guild.members.me).has("ManageMessages")) return false; + if (!channel.permissionsFor(guild.members.me)?.has("ManageMessages")) return false; // Ignore Possible Guild Moderators if (member.permissions.has(["KickMembers", "BanMembers", "ManageGuild"])) return false; @@ -171,15 +171,15 @@ async function performAutomod(message, settings) { // send automod log if (logChannel) { const logEmbed = new EmbedBuilder() - .setAuthor({ name: "Auto Moderation" }) - .setThumbnail(author.displayAvatarURL()) - .setColor(AUTOMOD.LOG_EMBED) - .addFields(fields) - .setDescription(`**Channel:** ${channel.toString()}\n**Content:**\n${content}`) - .setFooter({ - text: `By ${author.tag} | ${author.id}`, - iconURL: author.avatarURL(), - }); + .setAuthor({ name: "Auto Moderation" }) + .setThumbnail(author.displayAvatarURL()) + .setColor(AUTOMOD.LOG_EMBED) + .addFields(fields) + .setDescription(`**Channel:** ${channel.toString()}\n**Content:**\n${content}`) + .setFooter({ + text: `By ${author.tag} | ${author.id}`, + iconURL: author.avatarURL(), + }); logChannel.safeSend({ embeds: [logEmbed] }); } @@ -195,7 +195,7 @@ async function performAutomod(message, settings) { `**Guild:** ${guild.name}\n` + `**Total Strikes:** ${memberDb.strikes} out of ${automod.strikes}` ); - + author.send({ embeds: [strikeEmbed] }).catch((ex) => {}); // check if max strikes are received diff --git a/src/helpers/extenders/Message.js b/src/helpers/extenders/Message.js index f1df811a0..9138eb215 100644 --- a/src/helpers/extenders/Message.js +++ b/src/helpers/extenders/Message.js @@ -12,7 +12,7 @@ Message.prototype.safeReply = async function (content, seconds) { perms.push("ReadMessageHistory"); if (this.channel.type !== "DM" && !this.channel.permissionsFor(this.guild.members.me).has(perms)) { - return this.safeSend(content, seconds); + return this.channel.safeSend(content, seconds); } try { diff --git a/src/structures/BotClient.js b/src/structures/BotClient.js index bca103ecd..bd9c3b8d2 100644 --- a/src/structures/BotClient.js +++ b/src/structures/BotClient.js @@ -37,6 +37,7 @@ module.exports = class BotClient extends Client { restRequestTimeout: 20000, }); + this.wait = require("util").promisify(setTimeout); // await client.wait(1000) - Wait 1 second this.config = require("@root/config"); // load the config file /**