├── award.png ├── .env.example ├── src ├── handlers │ ├── antiCrash.js │ ├── clientEvents.js │ ├── mongoose.js │ └── slashCommands.js ├── commands │ ├── Information │ │ ├── ping.js │ │ ├── help.js │ │ ├── uptime.js │ │ ├── invite.js │ │ └── botinfo.js │ └── Giveaways │ │ ├── delete.js │ │ ├── resume.js │ │ ├── end.js │ │ ├── pause.js │ │ ├── reroll.js │ │ ├── drop.js │ │ ├── create.js │ │ └── edit.js ├── config.js ├── events │ └── client │ │ ├── messageCreate.js │ │ ├── guildDelete.js │ │ ├── guildCreate.js │ │ ├── ready.js │ │ └── interactionCreate.js ├── utils │ └── messages.js ├── Schema │ └── giveaway.js └── bot.js ├── package.json ├── LICENSE ├── index.js └── README.md /award.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unf6/award-bot/HEAD/award.png -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | TOKEN= 2 | CLIENT_ID= 3 | OWNERS= 4 | MONGO= 5 | COLOR= 6 | LOGS= 7 | everyoneMention= 8 | -------------------------------------------------------------------------------- /src/handlers/antiCrash.js: -------------------------------------------------------------------------------- 1 | module.exports = (client) => { 2 | process.on("unhandledRejection", (reason, p) => { 3 | console.log(reason, p); 4 | }); 5 | process.on("uncaughtException", (err, origin) => { 6 | console.log(err, origin); 7 | }); 8 | process.on("uncaughtExceptionMonitor", (err, origin) => { 9 | console.log(err, origin); 10 | }); 11 | }; -------------------------------------------------------------------------------- /src/handlers/clientEvents.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require("fs"); 2 | const { Client } = require("discord.js"); 3 | /** 4 | * @param {Client} client 5 | */ 6 | module.exports = (client) => { 7 | readdirSync("./src/events/client/").forEach((file) => { 8 | const event = require(`../events/client/${file}`); 9 | client.on(event.name, (...args) => event.run(client, ...args)); 10 | }); 11 | }; -------------------------------------------------------------------------------- /src/commands/Information/ping.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: 'ping', 5 | description: 'Displays the bot ping', 6 | botPerms: [''], 7 | userPerms: [''], 8 | owner: false, 9 | 10 | run: async (client, interaction, args ) => { 11 | 12 | const embed = new EmbedBuilder() 13 | .setDescription(`${client.ws.ping} Ms`) 14 | 15 | interaction.followUp({ embeds: [embed] }); 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | 3 | module.exports = { 4 | token: process.env.TOKEN || "", // your bot token 5 | clientID: process.env.CLIENT_ID || "", // your bot client id 6 | owners: process.env.OWNERS || "", // your account id 7 | mongourl: process.env.MONGO || "", //MongoDb Url 8 | embedcolor: process.env.COLOR || 0x303236, // embed colour 9 | logs: process.env.LOGS || "", // channel id for guild create and delete logs 10 | everyoneMention: process.env.everyoneMention || false, 11 | 12 | } -------------------------------------------------------------------------------- /src/events/client/messageCreate.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder, Message } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "messageCreate", 5 | run: async (client, message) => { 6 | if ( 7 | message.content === `<@${client.user.id}>` || 8 | message.content === `<@!${client.user.id}>` 9 | ) 10 | return message.reply({ 11 | content: `**› Hi ${message.author} I'm **${client.user.username}**\nA Powerful Slash Giveaway Discord Bot**`, 12 | }); 13 | 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/events/client/guildDelete.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "guildDelete", 5 | run: async (client, guild) => { 6 | let channel = client.channels.cache.get(client.config.logs); 7 | let embed = new EmbedBuilder() 8 | .setAuthor({ name: `${client.user.username}#${client.user.discriminator} | ${client.user.id}`, iconURL: client.user.displayAvatarURL() }) 9 | .setDescription(`left this ${guild.name}!`) 10 | .setColor("800080") 11 | channel.send({ embeds: [embed] }) 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/utils/messages.js: -------------------------------------------------------------------------------- 1 | const config = require("../config") 2 | 3 | module.exports = { 4 | 5 | giveaway: 6 | (config.everyoneMention ? "@everyone\n\n" : "") + 7 | "🎉 **GIVEAWAY** 🎉", 8 | giveawayEnded: 9 | (config.everyoneMention ? "@everyone\n\n" : "") + 10 | "🎉 **GIVEAWAY ENDED** 🎉", 11 | inviteToParticipate: "React with 🎉 to participate!", 12 | dropMessage: "Be the first to react with 🎉 !", 13 | drawing: "Drawing: {timestamp}", 14 | winMessage: "Congratulations, {winners}! You won **{this.prize}**!", 15 | embedFooter: "Giveaways", 16 | noWinner: "Giveaway cancelled, no valid participations.", 17 | hostedBy: "Hosted by: {this.hostedBy}", 18 | winners: "winner(s)", 19 | endedAt: "Ended at", 20 | 21 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Award-Bot", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js" 9 | }, 10 | "keywords": [], 11 | "author": "Rama 🐉'#9901", 12 | "license": "MIT", 13 | "dependencies": { 14 | "@discordjs/rest": "^1.2.0", 15 | "ascii-table": "^0.0.9", 16 | "chalk": "^4.1.2", 17 | "colors": "^1.4.0", 18 | "discord-giveaways": "^6.0.1", 19 | "discord-hybrid-sharding": "^1.7.4", 20 | "discord.js": "^14.5.0", 21 | "dotenv": "^16.0.3", 22 | "fs": "^0.0.1-security", 23 | "moment": "^2.29.4", 24 | "moment-duration-format": "^2.3.2", 25 | "mongoose": "^6.6.4", 26 | "ms": "^2.1.3", 27 | "os": "^0.1.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/events/client/guildCreate.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "guildCreate", 5 | run: async (client, guild) => { 6 | const channel = await client.channels.fetch(client.config.logs); 7 | const embed = new EmbedBuilder() 8 | .setAuthor({ name: `${client.user.username}#${client.user.discriminator} | ${client.user.id}`, iconURL: client.user.displayAvatarURL() }) 9 | .setDescription(`joined this ${guild.name}!`) 10 | .addFields( 11 | { name: 'GuildID', value: `\`${guild.id}\``, inline: true }, 12 | { name: 'GuildOwner', value: `<@${guild.ownerId}> (\`${guild.ownerId}\`)`, inline: true }, 13 | { name: "Guild Member Count", value: `${guild.memberCount}`, inline: true }, 14 | ) 15 | .setColor("800080") 16 | await channel.send({ embeds: [embed] }) 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/commands/Information/help.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder, Client } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "help", 5 | description: "Shows a list of all commands", 6 | 7 | run: async (client, interaction) => { 8 | 9 | const embed = new EmbedBuilder() 10 | 11 | .setAuthor({ name: `${interaction.user.username}!`, iconURL: interaction.user.displayAvatarURL() }) 12 | .setTitle(`${client.user.username} Help Menu`) 13 | .setDescription(`• Total Commands: **13**`) 14 | .addFields( 15 | 16 | { name: '❔ Information', value: `\`help,invite,ping,botinfo,uptime\``, inline: true }, 17 | { name: '🎉 Giveaways', value: `\`create,delete,drop,edit,end,pause,reroll,resume\``, inline: true }, 18 | 19 | ) 20 | 21 | interaction.followUp({ embeds: [embed] }); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/commands/Giveaways/delete.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: "delete", 3 | description: "Delete a giveaway.", 4 | options: [ 5 | { 6 | name: "message_id", 7 | description: "Message id for giveaway to delete", 8 | type: 3, 9 | required: true 10 | } 11 | ], 12 | 13 | run: async(client, interaction) => { 14 | const giveawayId = interaction.options.getString('message_id'); 15 | const fetchGiveaway = client.giveawaysManager.giveaways.find(r => r.messageId === giveawayId); 16 | if (!fetchGiveaway) { 17 | return interaction.followUp({ content: `Unable to find giveaway \`${giveawayId}\``, ephemeral: true }); 18 | } 19 | await client.giveawaysManager.delete(giveawayId); 20 | interaction.followUp({ content: `✅ Successfully deleted giveaway with id \`${giveawayId}\`` }) 21 | } 22 | } -------------------------------------------------------------------------------- /src/events/client/ready.js: -------------------------------------------------------------------------------- 1 | const { Activity } = require("discord.js"); 2 | const fs = require("fs"); 3 | const chalk = require("chalk"); 4 | 5 | module.exports = { 6 | name: "ready", 7 | run: async (client) => { 8 | 9 | console.log(`${client.user.username} online!`, "ready"); 10 | 11 | const activities = [ 12 | { name: `/help | ${client.guilds.cache.size} Guilds`, type: 3 }, // WATCHING 13 | { name: `Discord.js v14 by Liaam#9901 `, type: 3 }, // WATCHING 14 | ]; 15 | const status = ["online"]; 16 | let i = 0; 17 | setInterval(() => { 18 | if (i >= activities.length) i = 0; 19 | client.user.setActivity(activities[i]); 20 | i++; 21 | }, 5000); 22 | 23 | let s = 0; 24 | setInterval(() => { 25 | if (s >= activities.length) s = 0; 26 | client.user.setStatus(status[s]); 27 | s++; 28 | }, 30000); 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /src/handlers/mongoose.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const { Client } = require("discord.js"); 3 | const chalk = require("chalk"); 4 | const config = require("../config"); 5 | 6 | /** 7 | * @param {Client} client 8 | */ 9 | module.exports = (client) => { 10 | const dbOptions = { 11 | useNewUrlParser: true, 12 | autoIndex: false, 13 | connectTimeoutMS: 10000, 14 | family: 4, 15 | useUnifiedTopology: true, 16 | }; 17 | mongoose.connect(process.env.MONGO || client.config.mongourl, dbOptions); 18 | mongoose.Promise = global.Promise; 19 | mongoose.connection.on("connected", () => { 20 | console.log(console.log(`${chalk.grey.bold('[INFO] ')}${chalk.green.bold('Connected to the database!')}`)); 21 | }); 22 | mongoose.connection.on("err", (err) => { 23 | console.log(`Mongoose connection error: \n ${err.stack}`, "error"); 24 | }); 25 | mongoose.connection.on("disconnected", () => { 26 | console.log("Mongoose disconnected"); 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Liaam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/commands/Information/uptime.js: -------------------------------------------------------------------------------- 1 | const { Client, EmbedBuilder } = require("discord.js"); 2 | const moment = require("moment"); 3 | 4 | module.exports = { 5 | name: "uptime", 6 | description: "Display client uptime", 7 | /** 8 | * 9 | * @param {Client} client 10 | * @param {CommandInteraction} interaction 11 | */ 12 | run: async (client, interaction) => { 13 | const d = moment.duration(interaction.client.uptime); 14 | const days = d.days() == 1 ? `${d.days()} day` : `${d.days()} days`; 15 | const hours = d.hours() == 1 ? `${d.hours()} hour` : `${d.hours()} hours`; 16 | const minutes = 17 | d.minutes() == 1 ? `${d.minutes()} minute` : `${d.minutes()} minutes`; 18 | const seconds = 19 | d.seconds() == 1 ? `${d.seconds()} second` : `${d.seconds()} seconds`; 20 | const date = moment().subtract(d, "ms").format("dddd, MMMM Do YYYY"); 21 | 22 | const replyEmbed = new EmbedBuilder() 23 | .setTitle(`${client.user.username} Uptime`) 24 | .setDescription( 25 | `\`\`\`prolog\n${days}, ${hours}, ${minutes}, and ${seconds}\`\`\`` 26 | ) 27 | .setTimestamp() 28 | .setColor("Blue"); 29 | 30 | interaction.followUp({ embeds: [replyEmbed] }); 31 | }, 32 | }; -------------------------------------------------------------------------------- /src/commands/Giveaways/resume.js: -------------------------------------------------------------------------------- 1 | const { Client, ApplicationCommandOptionType } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "resume", 5 | description: "resume a giveaway", 6 | options: [ 7 | { 8 | name: "giveaway", 9 | description: "The giveaway to resume (message ID)", 10 | type: ApplicationCommandOptionType.String, 11 | required: true, 12 | }, 13 | ], 14 | 15 | run: async (client, interaction, args) => { 16 | const giveaway = interaction.options.getString("giveaway"); 17 | 18 | const giveawaysObj = 19 | 20 | client.giveawaysManager.giveaways.find( 21 | (g) => g.messageId === giveaway && g.guildId === interaction.guild.id 22 | ); 23 | 24 | if (!giveawaysObj) { 25 | interaction.followUp("Giveaway not found."); 26 | return; 27 | } 28 | if (!giveawaysObj.pauseOptions.isPaused) { 29 | interaction.followUp("Giveaway is already paused."); 30 | return; 31 | } 32 | client.giveawaysManager.unpause(giveawaysObj.messageId).then(() => { 33 | return interaction.followUp("Giveaway paused."); 34 | }); 35 | }, 36 | }; -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Cluster = require('discord-hybrid-sharding'); 2 | 3 | const manager = new Cluster.Manager(`./src/bot.js`, { 4 | totalShards: 1, 5 | shardsPerClusters: 1, 6 | totalClusters: 1, 7 | mode: "process", 8 | token: process.env.TOKEN, 9 | }); 10 | 11 | manager.extend( 12 | new Cluster.HeartbeatManager({ 13 | interval: 2000, 14 | maxMissedHeartbeats: 5, 15 | }) 16 | ); 17 | 18 | manager.on("clusterCreate", (cluster) => { 19 | console.log(`Launched Cluster ${cluster.id}`); 20 | 21 | cluster.on("ready", () => { 22 | console.log(`Cluster ${cluster.id} seems ready`); 23 | }); 24 | 25 | cluster.on("reconnecting", () => { 26 | console.log(`Cluster ${cluster.id} is reconnecting`); 27 | }); 28 | 29 | cluster.on("disconnect", async () => { 30 | console.log(`Cluster ${cluster.id} disconnected`); 31 | }); 32 | 33 | cluster.on("death", () => { 34 | console.log(`Cluster ${cluster.id} died`); 35 | }); 36 | 37 | cluster.on("error", () => { 38 | console.log(`Cluster ${cluster.id} errored`); 39 | }); 40 | 41 | cluster.on("spawn", () => { 42 | console.log(`Cluster ${cluster.id} has spawned`); 43 | }); 44 | }); 45 | manager.spawn({ timeout: -1 }); 46 | -------------------------------------------------------------------------------- /src/commands/Giveaways/end.js: -------------------------------------------------------------------------------- 1 | const { Client, ApplicationCommandOptionType } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "end", 5 | description: "end a giveaway", 6 | userPerms: ['ManageGuild'], 7 | botPerms: ['ManageGuild'], 8 | owner: false, 9 | 10 | options: [ 11 | { 12 | name: "giveaway", 13 | description: "The giveaway to end (message ID)", 14 | type: ApplicationCommandOptionType.String, 15 | required: true, 16 | }, 17 | ], 18 | 19 | run: async (client, interaction, args) => { 20 | 21 | const giveaway = interaction.options.getString("giveaway"); 22 | 23 | client.giveawaysManager.giveaways.find( 24 | (g) => g.messageId === giveaway && g.guildId === interaction.guild.id 25 | ); 26 | 27 | if (!giveawaysObj) { 28 | interaction.followUp("Giveaway not found."); 29 | return; 30 | } 31 | if (giveawaysObj.ended) { 32 | interaction.followUp("Giveaway already ended."); 33 | return; 34 | } 35 | client.giveawaysManager.end(giveawaysObj.messageId).then(() => { 36 | return interaction.followUp("Giveaway ended."); 37 | }); 38 | }, 39 | }; -------------------------------------------------------------------------------- /src/commands/Giveaways/pause.js: -------------------------------------------------------------------------------- 1 | const { Client, ApplicationCommandOptionType } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "pause", 5 | description: "pause a giveaway", 6 | userPerms: ['ManageGuild'], 7 | botPerms: ['ManageGuild'], 8 | owner: false, 9 | 10 | options: [ 11 | { 12 | name: "giveaway", 13 | description: "The giveaway to pause (message ID)", 14 | type: ApplicationCommandOptionType.String, 15 | required: true, 16 | }, 17 | ], 18 | 19 | run: async (client, interaction, args) => { 20 | 21 | const giveaway = interaction.options.getString("giveaway"); 22 | 23 | client.giveawaysManager.giveaways.find( 24 | (g) => g.messageId === giveaway && g.guildId === interaction.guild.id 25 | ); 26 | 27 | if (!giveawaysObj) { 28 | interaction.followUp("Giveaway not found."); 29 | return; 30 | } 31 | if (giveawaysObj.pauseOptions.isPaused) { 32 | interaction.followUp("Giveaway is already paused."); 33 | return; 34 | } 35 | client.giveawaysManager.pause(giveawaysObj.messageId).then(() => { 36 | return interaction.followUp("Giveaway paused."); 37 | }); 38 | }, 39 | }; -------------------------------------------------------------------------------- /src/commands/Giveaways/reroll.js: -------------------------------------------------------------------------------- 1 | const { Client, ApplicationCommandOptionType } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "reroll", 5 | description: "reroll a giveaway", 6 | userPerms: ['ManageGuild'], 7 | botPerms: ['ManageGuild'], 8 | owner: false, 9 | 10 | options: [ 11 | { 12 | name: "giveaway", 13 | description: "The giveaway to reroll (message ID)", 14 | type: ApplicationCommandOptionType.String, 15 | required: true, 16 | }, 17 | ], 18 | 19 | run: async (client, interaction, args) => { 20 | 21 | const giveaway = interaction.options.getString("giveaway"); 22 | 23 | const giveawaysObj = 24 | 25 | client.giveawaysManager.giveaways.find( 26 | (g) => g.messageId === giveaway && g.guildId === interaction.guild.id 27 | ); 28 | 29 | if (!giveawaysObj) { 30 | interaction.followUp("Giveaway not found."); 31 | return; 32 | } 33 | if (!giveawaysObj.ended) { 34 | interaction.followUp("Giveaway hasnt ended yet."); 35 | return; 36 | } 37 | client.giveawaysManager.reroll(giveawaysObj.messageId).then(() => { 38 | return interaction.followUp("Giveaway ended."); 39 | }); 40 | }, 41 | }; -------------------------------------------------------------------------------- /src/commands/Information/invite.js: -------------------------------------------------------------------------------- 1 | const { 2 | Client, 3 | EmbedBuilder, 4 | ActionRowBuilder, 5 | ButtonBuilder, 6 | ButtonStyle 7 | } = require("discord.js"); 8 | 9 | module.exports = { 10 | name: "invite", 11 | description: "Get the bot's invite link.", 12 | run: async (client, interaction, args) => { 13 | 14 | const emb = new EmbedBuilder() 15 | .setColor("Blue") 16 | .setTitle(`Invite ${client.user.username}`) 17 | .setDescription( 18 | `**${client.user.username}**,Thank you for choosing me to use you can click the button below to invite me!` 19 | ) 20 | .setThumbnail(client.user.displayAvatarURL({ dynamic: true })) 21 | .setFooter({ text: `Award-bot - Made By ❤️ Liaam` }); 22 | 23 | const row = new ActionRowBuilder().addComponents( 24 | new ButtonBuilder() 25 | .setURL( 26 | `https://discord.com/api/oauth2/authorize?client_id=${client.user.id}&permissions=36768832&scope=applications.commands%20bot` 27 | ) 28 | .setLabel("Invite") 29 | .setStyle(ButtonStyle.Link), 30 | 31 | new ButtonBuilder() 32 | .setLabel("Github") 33 | .setStyle(ButtonStyle.Link) 34 | .setURL("https://github.com/liaam-dev/award-bot"), 35 | 36 | new ButtonBuilder() 37 | .setURL( 38 | `https://discord.gg/PeV2Qj5SHD` 39 | ) 40 | .setLabel("Support") 41 | .setStyle(ButtonStyle.Link) 42 | 43 | ); 44 | 45 | interaction.followUp({ content: ` `, embeds: [emb], components: [row] }); 46 | }, 47 | }; -------------------------------------------------------------------------------- /src/commands/Giveaways/drop.js: -------------------------------------------------------------------------------- 1 | const { Client, ApplicationCommandOptionType, ChannelType } = require("discord.js"); 2 | const ms = require("ms"); 3 | const messages = require("../../utils/messages"); 4 | module.exports = { 5 | name: "drop", 6 | description: "start a giveaway", 7 | userPerms: ['ManageGuild'], 8 | botPerms: ['ManageGuild'], 9 | owner: false, 10 | 11 | options: [ 12 | { 13 | name: "winners", 14 | description: "How many winners the drop should have", 15 | type: ApplicationCommandOptionType.Number, 16 | required: true, 17 | }, 18 | { 19 | name: "prize", 20 | description: "What the prize of the drop should be", 21 | type: ApplicationCommandOptionType.String, 22 | required: true, 23 | }, 24 | { 25 | name: "channel", 26 | description: "The channel to start the drop in", 27 | type: ApplicationCommandOptionType.Channel, 28 | ChannelTypes: ['GUILD_TEXT'], 29 | required: true, 30 | }, 31 | ], 32 | 33 | run: async (client, interaction, args) => { 34 | 35 | const winners = interaction.options.getNumber("winners"); 36 | const prize = interaction.options.getString("prize"); 37 | const channel = interaction.options.getChannel("channel"); 38 | 39 | client.giveawaysManager.start(channel, { 40 | isDrop: true, 41 | winnerCount: winners, 42 | prize, 43 | hostedBy: interaction.member, 44 | messages, 45 | }); 46 | 47 | return interaction.followUp("Drop started!"); 48 | }, 49 | }; -------------------------------------------------------------------------------- /src/Schema/giveaway.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const giveawaySchema = new mongoose.Schema( 4 | { 5 | messageId: String, 6 | channelId: String, 7 | guildId: String, 8 | startAt: Number, 9 | endAt: Number, 10 | ended: Boolean, 11 | winnerCount: Number, 12 | prize: String, 13 | messages: { 14 | giveaway: String, 15 | giveawayEnded: String, 16 | inviteToParticipate: String, 17 | drawing: String, 18 | dropMessage: String, 19 | winMessage: mongoose.Mixed, 20 | embedFooter: mongoose.Mixed, 21 | noWinner: String, 22 | winners: String, 23 | endedAt: String, 24 | hostedBy: String, 25 | }, 26 | thumbnail: String, 27 | hostedBy: String, 28 | winnerIds: { type: [String], default: undefined }, 29 | reaction: mongoose.Mixed, 30 | botsCanWin: Boolean, 31 | embedColor: mongoose.Mixed, 32 | embedColorEnd: mongoose.Mixed, 33 | exemptPermissions: { type: [], default: undefined }, 34 | exemptMembers: String, 35 | bonusEntries: String, 36 | extraData: mongoose.Mixed, 37 | lastChance: { 38 | enabled: Boolean, 39 | content: String, 40 | threshold: Number, 41 | embedColor: mongoose.Mixed, 42 | }, 43 | pauseOptions: { 44 | isPaused: Boolean, 45 | content: String, 46 | unPauseAfter: Number, 47 | embedColor: mongoose.Mixed, 48 | durationAfterPause: Number, 49 | }, 50 | isDrop: Boolean, 51 | allowedMentions: { 52 | parse: { type: [String], default: undefined }, 53 | users: { type: [String], default: undefined }, 54 | roles: { type: [String], default: undefined }, 55 | }, 56 | }, 57 | { id: false } 58 | ); 59 | 60 | module.exports = mongoose.model("giveaways", giveawaySchema); -------------------------------------------------------------------------------- /src/handlers/slashCommands.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('fs'); 2 | const { PermissionsBitField, Routes, Client } = require('discord.js'); 3 | const { REST } = require('@discordjs/rest'); 4 | /** 5 | * @param {Client} client 6 | */ 7 | module.exports = (client) => { 8 | const data = []; 9 | let count = 0; 10 | readdirSync("./src/commands/").forEach((dir) => { 11 | const slashCommandFile = readdirSync(`./src/commands/${dir}/`).filter((files) => files.endsWith(".js")); 12 | 13 | for (const file of slashCommandFile) { 14 | const slashCommand = require(`../commands/${dir}/${file}`); 15 | if (!slashCommand.name) return console.error(`slashCommandNameError: ${slashCommand.split(".")[0]} application command name is required.`); 16 | if (!slashCommand.description) return console.error(`slashCommandDescriptionError: ${slashCommand.split(".")[0]} application command description is required.`); 17 | client.slashCommands.set(slashCommand.name, slashCommand); 18 | 19 | data.push({ 20 | name: slashCommand.name, 21 | description: slashCommand.description, 22 | type: slashCommand.type, 23 | options: slashCommand.options ? slashCommand.options : null, 24 | default_member_permissions: slashCommand.default_member_permissions ? PermissionsBitField.resolve(slashCommand.default_member_permissions).toString() : null 25 | }); 26 | count++; 27 | } 28 | }); 29 | console.log(`Loaded: ${count} SlashCommands (/)`); 30 | const rest = new REST({ version: '10' }).setToken(client.config.token); 31 | (async () => { 32 | try { 33 | console.log('Started refreshing application (/) commands.'); 34 | await rest.put(Routes.applicationCommands(client.config.clientID), { body: data }); 35 | console.log('Successfully reloaded application (/) commands.'); 36 | } catch (error) { 37 | console.error(error); 38 | } 39 | })(); 40 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 | Logo 5 | 6 | 7 |

Giveaway - Discord Bot

8 | 9 |

10 | A feature-rich Giveaway Bot For Discord Written In Discord.js v14. Ft. Slash Commands. Make Giveaways and more..! 11 |
12 |
13 | 14 | [![Run on Repl.it](https://repl.it/badge/github/unf6/award-bot)](https://repl.it/github/unf6/award-bot) 15 | [![Remix on Glitch](https://cdn.glitch.com/2703baf2-b643-4da7-ab91-7ee2a2d00b5b%2Fremix-button.svg)](https://glitch.com/edit/#!/import/github/unf6/award-bot) 16 | 17 | ![Contributors](https://img.shields.io/github/contributors/unf6/award-bot?color=dark-green) 18 | ![Forks](https://img.shields.io/github/forks/unf6/award-bot?style=social) 19 | ![Stargazers](https://img.shields.io/github/stars/unf6/award-bot?style=social) 20 | ![Issues](https://img.shields.io/github/issues/unf6/award-bot) 21 | ![License](https://img.shields.io/github/license/unf6/award-bot) 22 | 23 | ### Installation 24 | 25 | 1. Get a BOT_TOKEN at [Discord Developer Portal](https://discord.com/developers/applications) 26 | 27 | 2. Clone the repo 28 | 29 | ```sh 30 | git clone https://github.com/liaam-dev/award-bot.git 31 | ``` 32 | 33 | 3. Install NPM packages 34 | 35 | ```sh 36 | npm install 37 | ``` 38 | 39 | 4. Enter your BOT_TOKEN in `config.js` 40 | 41 | 5. Run Bot: node index.js 42 | 43 | ## Intents 44 | 45 | 46 |

47 | 48 | 49 | 50 | 51 |

52 | Then turn on both of those Settings and click "Save Changes". Then you are done! 53 | 54 | ## 💌 Support Server 55 | 56 | [Support Server](https://discord.gg/PeV2Qj5SHD) - award-bot's Support Server Invite 57 | 58 | 59 | ## 🔐 License 60 | 61 | Distributed under the MIT license. See [`LICENSE`](https://github.com/unf6/award-bot/blob/master/LICENSE) for more information. 62 | -------------------------------------------------------------------------------- /src/commands/Giveaways/create.js: -------------------------------------------------------------------------------- 1 | const { Client, ApplicationCommandOptionType, ChannelType, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); 2 | const ms = require("ms"); 3 | const messages = require("../../utils/messages"); 4 | 5 | module.exports = { 6 | name: "create", 7 | description: "start a giveaway", 8 | userPerms: ['ManageGuild'], 9 | botPerms: ['ManageGuild'], 10 | owner: false, 11 | 12 | options: [ 13 | { 14 | name: "duration", 15 | description: 16 | "How long the giveaway should last for. Example values: 1m, 1h, 1d", 17 | type: ApplicationCommandOptionType.String, 18 | required: true, 19 | }, 20 | { 21 | name: "winners", 22 | description: "How many winners the giveaway should have", 23 | type: ApplicationCommandOptionType.Number, 24 | required: true, 25 | }, 26 | { 27 | name: "prize", 28 | description: "What the prize of the giveaway should be", 29 | type: ApplicationCommandOptionType.String, 30 | required: true, 31 | }, 32 | { 33 | name: "channel", 34 | description: "The channel to start the giveaway in", 35 | type: ApplicationCommandOptionType.Channel, 36 | ChannelTypes: ['GUILD_TEXT'], 37 | required: true, 38 | }, 39 | ], 40 | 41 | 42 | run: async (client, interaction) => { 43 | 44 | const duration = ms(interaction.options.getString("duration")); 45 | const winners = interaction.options.getNumber("winners"); 46 | const prize = interaction.options.getString("prize"); 47 | const channel = interaction.options.getChannel("channel"); 48 | 49 | const giveawayInfo = await client.giveawaysManager.start(channel, { 50 | duration, 51 | winnerCount: winners, 52 | prize, 53 | hostedBy: interaction.member, 54 | messages, 55 | 56 | }); 57 | 58 | const row = new ActionRowBuilder() 59 | .addComponents( 60 | new ButtonBuilder() 61 | .setStyle(ButtonStyle.Link) 62 | .setLabel('Giveaway URL') 63 | .setURL(giveawayInfo.messageURL) 64 | ) 65 | 66 | return interaction.followUp({ content: `Giveaway started!`, components: [row] }); 67 | }, 68 | }; -------------------------------------------------------------------------------- /src/commands/Giveaways/edit.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder, ApplicationCommandOptionType } = require("discord.js"); 2 | const ms = require("ms"); 3 | 4 | module.exports = { 5 | name: 'editt', 6 | description: 'edit a giveaway', 7 | botPerms: [], 8 | userPerms: [], 9 | owner: false, 10 | 11 | options: [ 12 | { 13 | name: 'giveaway', 14 | description: 'The giveaway to end (message ID)', 15 | type: ApplicationCommandOptionType.String, 16 | required: true 17 | }, 18 | { 19 | name: 'duration', 20 | description: 'Setting time of mentioned giveaway. Eg. 1h sets the current giveaway to end after an hour!', 21 | type: ApplicationCommandOptionType.String, 22 | required: true 23 | }, 24 | { 25 | name: 'winners', 26 | description: 'How many winners the giveaway should have', 27 | type: ApplicationCommandOptionType.Integer, 28 | required: true 29 | }, 30 | { 31 | name: 'prize', 32 | description: 'What the prize of the giveaway should be', 33 | type: ApplicationCommandOptionType.String, 34 | required: true 35 | } 36 | ], 37 | 38 | run: async (client, interaction, args ) => { 39 | 40 | const gid = interaction.options.getString('giveaway'); 41 | const time = ms(interaction.options.getString('duration')); 42 | const winnersCount = interaction.options.getInteger('winners'); 43 | const prize = interaction.options.getString('prize'); 44 | 45 | // Edit the giveaway 46 | try { 47 | await client.giveawaysManager.edit(gid, { 48 | newWinnersCount: winnersCount, 49 | newPrize: prize, 50 | addTime: time 51 | }) 52 | } catch(e) { 53 | return interaction.followUp({ 54 | content: 55 | `No giveaway found with the given message ID: \`${gid}\``, 56 | ephemeral: true 57 | }); 58 | } 59 | interaction.followUp({ 60 | content: 61 | `This giveaway has now been edited!`, 62 | ephemeral: true 63 | }); 64 | 65 | } 66 | } -------------------------------------------------------------------------------- /src/events/client/interactionCreate.js: -------------------------------------------------------------------------------- 1 | const { InteractionType, EmbedBuilder, PermissionsBitField } = require("discord.js"); 2 | const client = require("../../bot"); 3 | 4 | module.exports = { 5 | name: "interactionCreate", 6 | run: async (client, interaction) => { 7 | if (!interaction.inGuild()) return; 8 | if (interaction.type === InteractionType.ApplicationCommand) { 9 | await interaction.deferReply(); 10 | 11 | const cmd = client.slashCommands.get(interaction.commandName); 12 | if (!cmd) 13 | return interaction.followUp({ 14 | embeds: [ 15 | { 16 | color: 13584458, 17 | description: "There was an error - please try again! ", 18 | }, 19 | ], 20 | }); 21 | 22 | const args = []; 23 | 24 | for (let option of interaction.options.data) { 25 | if (option.type === "SUB_COMMAND") { 26 | if (option.name) args.push(option.name); 27 | option.options?.forEach((x) => { 28 | if (x.value) args.push(x.value); 29 | }); 30 | } else if (option.value) args.push(option.value); 31 | } 32 | interaction.member = interaction.guild.members.cache.get( 33 | interaction.user.id 34 | ); 35 | 36 | const embed = new EmbedBuilder() 37 | .setColor("Blue") 38 | 39 | if (cmd.botPerms) { 40 | if (!interaction.guild.members.me.permissions.has(PermissionsBitField.resolve(cmd.botPerms || []))) { 41 | embed.setDescription(`I don't have **\`${cmd.botPerms}\`** permission in ${interaction.channel.toString()} to execute this **\`${cmd.name}\`** command.`); 42 | return interaction.followUp({ embeds: [embed] }); 43 | } 44 | } 45 | 46 | if (cmd.userPerms) { 47 | if (!interaction.member.permissions.has(PermissionsBitField.resolve(cmd.userPerms || []))) { 48 | embed.setDescription(`You don't have **\`${cmd.userPerms}\`** permission in ${interaction.channel.toString()} to execute this **\`${cmd.name}\`** command.`); 49 | return interaction.followUp({ embeds: [embed] }); 50 | } 51 | } 52 | 53 | const embed2 = new EmbedBuilder() 54 | .setDescription("Only bot developer can use this command") 55 | 56 | const { owners } = require("../../config"); 57 | if (cmd) { 58 | if (cmd.owner) { 59 | if 60 | (!owners.includes(interaction.user.id)) 61 | return interaction.followUp({ embeds: [embed2] }); 62 | 63 | }} 64 | 65 | // ==============================< If command doesn't found >=============================\\ 66 | if (!cmd) return client.slashCommands.delete(interaction.commandName); 67 | 68 | return cmd.run(client, interaction, args); 69 | 70 | } 71 | // Context Menu Handling 72 | if (interaction.isUserContextMenuCommand()) { 73 | await interaction.deferReply({ ephemeral: false }); 74 | const command = client.slashCommands.get(interaction.commandName); 75 | if (command) command.run(client, interaction); 76 | } 77 | }, 78 | }; -------------------------------------------------------------------------------- /src/commands/Information/botinfo.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder, Client, version } = require("discord.js"); 2 | const { readdirSync } = require("fs"); 3 | require("moment-duration-format"); 4 | const os = require("os"); 5 | 6 | module.exports = { 7 | name: "botinfo", 8 | description: "Information about the bot", 9 | 10 | run: async (client, interaction, args) => { 11 | 12 | var commands = []; 13 | readdirSync("./src/commands/").forEach((dir) => { 14 | var dircmds = readdirSync(`./src/commands/${dir}/`).filter((file) => 15 | file.endsWith(".js") 16 | ); 17 | 18 | commands = commands.concat(dircmds); 19 | }); 20 | 21 | const embed = new EmbedBuilder() 22 | .setAuthor({ name: `${interaction.user.username} Stats/Info!`, iconURL: client.user.displayAvatarURL() }) 23 | .addFields( 24 | { 25 | name: "Name", 26 | value: `┕ \`${client.user.username}\``, 27 | inline: true, 28 | }, 29 | { 30 | name: "Developers", 31 | value: `┕ <@755566952449310842>`, 32 | inline: true, 33 | }, 34 | { 35 | name: "💻 **Memory usage**", 36 | value: `​ ┕ \`${Math.round( 37 | process.memoryUsage().heapUsed / 1024 / 1024 38 | )}mb\``, 39 | inline: true, 40 | }, 41 | { 42 | name: "🏘️ **Guilds**", 43 | value: `​ ┕ \`${client.guilds.cache.size}\``, 44 | inline: true, 45 | }, 46 | { 47 | name: "👥 **Users**", 48 | value: `​ ┕ \`${client.guilds.cache.reduce((acc, guild) => acc + guild.memberCount, 0)}\``, 49 | inline: true, 50 | }, 51 | { 52 | name: "🇨🇭 **Channels**", 53 | value: `​ ┕ \`${client.channels.cache.size}\``, 54 | inline: true, 55 | }, 56 | { 57 | name: `Node.js Version`, 58 | value: `┕ \`${process.version}\``, 59 | inline: true, 60 | }, 61 | { 62 | name: `Discord.js Version`, 63 | value: `┕ \`${version}\``, 64 | inline: true, 65 | }, 66 | { 67 | name: `Commands`, 68 | value: `┕ \`${commands.length}\``, 69 | inline: true, 70 | }, 71 | { 72 | name: `Platform`, 73 | value: `┕ ${os.type}`, 74 | inline: true, 75 | }, 76 | { 77 | name: `Cores`, 78 | value: `┕ ${os.cpus().length}`, 79 | inline: true, 80 | }, 81 | { 82 | name: `Model`, 83 | value: `┕ ${os.cpus()[0].model}`, 84 | inline: true, 85 | }, 86 | { 87 | name: `Speed`, 88 | value: `┕ ${os.cpus()[0].speed} MHz`, 89 | inline: true, 90 | }, 91 | 92 | ) 93 | 94 | interaction.followUp({ embeds: [embed] }); 95 | }, 96 | }; -------------------------------------------------------------------------------- /src/bot.js: -------------------------------------------------------------------------------- 1 | const { Client, Collection, GatewayIntentBits } = require("discord.js"); 2 | const Discord = require("discord.js"); 3 | require("dotenv").config(); 4 | const Cluster = require('discord-hybrid-sharding'); 5 | const fs = require("fs"); 6 | 7 | const client = new Client({ 8 | intents: [ 9 | GatewayIntentBits.Guilds, 10 | GatewayIntentBits.GuildMessages, 11 | GatewayIntentBits.MessageContent, 12 | GatewayIntentBits.GuildMembers, 13 | GatewayIntentBits.GuildVoiceStates, 14 | GatewayIntentBits.GuildMessageReactions, 15 | GatewayIntentBits.GuildEmojisAndStickers, 16 | ], 17 | disableMentions: "everyone", 18 | shards: Cluster.data.SHARD_LIST, // An array of shards that will get spawned 19 | shardCount: Cluster.data.TOTAL_SHARDS, // Total number of shards 20 | }); 21 | 22 | client.config = require('./config'); 23 | client.slashCommands = new Collection(); 24 | 25 | client.on("disconnect", () => console.log("Bot is disconnecting...")); 26 | client.on("reconnecting", () => console.log("Bot reconnecting...")); 27 | client.on("warn", (error) => console.log(error)); 28 | client.on("error", (error) => console.log(error)); 29 | 30 | ["clientEvents", "slashCommands", "mongoose", "antiCrash"].forEach((handler) => { 31 | require(`./handlers/${handler}`)(client); 32 | }); 33 | 34 | const giveawayModel = require("./Schema/giveaway"); 35 | const { GiveawaysManager } = require("discord-giveaways"); 36 | const GiveawayManagerWithOwnDatabase = class extends GiveawaysManager { 37 | // This function is called when the manager needs to get all giveaways which are stored in the database. 38 | async getAllGiveaways() { 39 | // Get all giveaways from the database. We fetch all documents by passing an empty condition. 40 | return await giveawayModel.find().lean().exec(); 41 | } 42 | 43 | // This function is called when a giveaway needs to be saved in the database. 44 | async saveGiveaway(messageId, giveawayData) { 45 | // Add the new giveaway to the database 46 | await giveawayModel.create(giveawayData); 47 | // Don't forget to return something! 48 | return true; 49 | } 50 | 51 | // This function is called when a giveaway needs to be edited in the database. 52 | async editGiveaway(messageId, giveawayData) { 53 | // Find by messageId and update it 54 | await giveawayModel 55 | .updateOne({ messageId }, giveawayData, { omitUndefined: true }) 56 | .exec(); 57 | // Don't forget to return something! 58 | return true; 59 | } 60 | 61 | // This function is called when a giveaway needs to be deleted from the database. 62 | async deleteGiveaway(messageId) { 63 | // Find by messageId and delete it 64 | await giveawayModel.deleteOne({ messageId }).exec(); 65 | // Don't forget to return something! 66 | return true; 67 | } 68 | }; 69 | 70 | // Create a new instance of your new class 71 | const manager = new GiveawayManagerWithOwnDatabase(client, { 72 | default: { 73 | botsCanWin: false, 74 | embedColor: "#FF0000", 75 | embedColorEnd: "#000000", 76 | reaction: "🎉", 77 | }, 78 | }); 79 | // We now have a giveawaysManager property to access the manager everywhere! 80 | client.giveawaysManager = manager; 81 | client.giveawaysManager.on( 82 | "giveawayReactionAdded", 83 | (giveaway, member, reaction) => { 84 | console.log( 85 | `${member.user.tag} entered giveaway #${giveaway.messageId} (${reaction.emoji.name})` 86 | ); 87 | } 88 | ); 89 | 90 | client.giveawaysManager.on( 91 | "giveawayReactionRemoved", 92 | (giveaway, member, reaction) => { 93 | console.log( 94 | `${member.user.tag} unreact to giveaway #${giveaway.messageId} (${reaction.emoji.name})` 95 | ); 96 | } 97 | ); 98 | 99 | client.giveawaysManager.on("giveawayEnded", (giveaway, winners) => { 100 | console.log( 101 | `Giveaway #${giveaway.messageId} ended! Winners: ${winners 102 | .map((member) => member.user.username) 103 | .join(", ")}` 104 | ); 105 | }); 106 | 107 | client.login(client.config.token || process.env.TOKEN); --------------------------------------------------------------------------------