giftcord
Version:
Giveaway discord.js Package
265 lines (211 loc) • 9.5 kB
JavaScript
const mongoose = require('mongoose');
const Discord = require('discord.js');
const Giveaway = require('./Giveaway');
const moment = require('moment');
const ms = require("ms")
const { schedule } = require('../Functions/Schedule.js');
const { getWinner } = require('../Functions/getWinner.js');
const { endGiveaway } = require('../Functions/endGiveaway.js');
const GiveawayModel = require('../models/Giveaway');
const scheduler = require('node-schedule');
const { EventEmitter } = require('events');
class GiveawayCreator extends EventEmitter {
/**
*
* @param {Discord.Client} client - A discord.js client.
* @param {string} url - A MongoDB connection string.
*/
constructor(client, url = '', color = 0x7289da) {
super();
if (!client) throw new Error("A client wasn't provided.");
if (!url) throw new Error("A connection string wasn't provided.");
this.client = client;
this.mongoUrl = url;
this.color = color;
mongoose.connect(this.mongoUrl);
this.client.on('ready', async () => {
const now = new Date();
const giveaways = await GiveawayModel.find({ endsOn: { $gt: now }, hasEnded: 'False' });
await schedule(this, giveaways);
});
}
/**
*
* @param {GiveawayOptions} options - Options for the giveaway.
*/
async startGiveaway(options) {
if (!options.duration) throw new Error("You didn't provide a duration.");
let validDuration = false;
if (options.duration.endsWith("s") || options.duration.endsWith("m") || options.duration.endsWith("h") || options.duration.endsWith("d")) {
validDuration = true;
}
if (!validDuration) {
throw new Error("Please provide a correct duration format (e.g., 1s, 1m, 1h, 1d)");
}
if (!options.emoji) throw new Error("You didn't provide a emoji.");
if(options.emoji.length > 2) throw new Error("Please Provide one Emoji.")
if (!options.channelId) throw new Error("You didn't provide a channel ID.");
if (!options.guildId) throw new Error("You didn't provide a guild ID.");
if (!options.prize) throw new Error("You didn't provide a prize.");
if (!options.winners || isNaN(options.winners)) throw new Error("You didn't provide an amount of winners OR winners is not a number.");
if (!options.hostedBy) throw new Error("Please provide a user ID for the person who hosted the giveaway.");
const guild = this.client.guilds.cache.get(options.guildId);
const channel = guild.channels.cache.get(options.channelId);
const user = this.client.users.cache.get(options.hostedBy)
const giveawayEmbed = new Discord.EmbedBuilder()
.setTitle(options.prize)
.setThumbnail(guild.iconURL({dynamic: true}))
.setColor(this.color)
.setDescription(`**
・Winners: ${options.winners}
・Ends: <t:${Math.floor((Date.now() + ms(options.duration)) / 1000)}:R>
・Hosted By: ${user.toString()}
・React with ${options.emoji} to participate!
**`)
.setFooter({text: `Ends `})
.setTimestamp(new Date(Date.now() + ms(options.duration)));
const msg = await channel.send({ embeds: [giveawayEmbed] });
await msg.react(options.emoji);
const newGiveaway = new Giveaway({
prize: options.prize,
emoji: options.emoji,
duration: ms(options.duration),
channelId: options.channelId,
guildId: options.guildId,
endsOn: new Date(Date.now() + ms(options.duration)),
startsOn: new Date(),
messageId: msg.id,
winners: options.winners,
hostedBy: options.hostedBy
});
await schedule(this, [newGiveaway]);
this.emit('giveawayStart', newGiveaway);
return newGiveaway;
}
/**
*
* @param {string} messageId - A discord message ID.
*/
async endGiveaway(messageId) {
let data = await GiveawayModel.findOne({ messageId: messageId });
if (!data) return false;
if (data.hasEnded === 'True') return false;
const job = scheduler.scheduledJobs[`${messageId}`];
if (!job) return false;
job.cancel();
const channel = this.client.channels.cache.get(data.channelId);
if (channel) {
const message = await channel.messages.fetch(messageId);
if (message) {
const { embeds, reactions } = message;
const reaction = reactions.cache.get(data.emoji);
const users = await reaction.users.fetch();
const entries = users.filter(user => !user.bot);
if (embeds.length === 1) {
const usersArray = Array.from(entries.values());
const winner = getWinner(usersArray, data.winners);
let finalWinners;
if (!winner) {
finalWinners = 'Nobody Reacted';
}
else {
finalWinners = winner.map(user => user.toString()).join(', ');
}
let embed = new Discord.EmbedBuilder()
embed.setDescription(`**🎖️ Winner(s): ${finalWinners}**`);
embed.setFooter({text: this.client.user.username, iconURL: this.client.user.displayAvatarURL({ extension: 'png', size: 512 })});
embed.setTimestamp();
await message.edit({ embeds: [embed] });
if (!winner) {
message.channel.send(`Nobody reacted to the **${data.prize}** giveaway. `);
}
else {
message.channel.send(`**Congratulations ${finalWinners}, you won the ${data.prize}!**`);
const wins = winner
for (const win of wins) {
win.send(`### Congratulations ${win}, you won the ${data.prize}!\n **MSG LINK: **${message.url}`).catch(() => {})
}
const ended = await endGiveaway(messageId);
this.emit('giveawayEnd', ended);
}
}
}
return data;
}
}
/**
*
* @param {string} messageId - A discord message ID.
*/
async fetchGiveaway(messageId) {
const giveaway = await GiveawayModel.findOne({ messageId: messageId });
if (!giveaway) return false;
return giveaway;
}
/**
*
* @param {string} messageId - A discord message ID.
*/
async rerollGiveaway(messageId) {
const giveaway = await GiveawayModel.findOne({ messageId: messageId });
if (!giveaway) return false;
if (giveaway.hasEnded === 'False') return false;
const channel = this.client.channels.cache.get(giveaway.channelId);
if (channel) {
const message = await channel.messages.fetch(messageId);
if (message) {
const { embeds, reactions } = message;
const reaction = reactions.cache.get(giveaway.emoji);
if (!reaction || reaction.count < 2) {
return message.channel.send("**Nobody Reacted, I Can't Reroll Giveaway**");
}
const users = await reaction.users.fetch();
const entries = users.filter(user => !user.bot);
const usersArray = Array.from(entries.values());
const winner = getWinner(usersArray, giveaway.winners);
let finalWinners;
if (!winner) {
finalWinners = 'Nobody Reacted';
message.channel.send(`Nobody reacted to the **${giveaway.prize}** giveaway. **ID**: \`${messageId}\`\n${message.url}`);
}
else {
finalWinners = winner.map(user => user.toString()).join(', ');
message.channel.send(`**Congratulations ${finalWinners}, you won the ${giveaway.prize}!**`);
const wins = winner
for (const win of wins) {
win.send(`### Congratulations ${win}, you won the ${giveaway.prize}!\n **MSG LINK: **${message.url}`).catch(() => {})
}
if (embeds.length === 1) {
const embed = new Discord.EmbedBuilder()
embed.setDescription(`🎖️ Winner(s): ${finalWinners}`);
await message.edit({ embeds: [embed] });
}
}
}
this.emit('giveawayReroll', giveaway);
return giveaway;
}
}
/**
*
* @param {string} guildId - A discord guild ID.
*/
async listGiveaways(guildId) {
if (!guildId) throw new Error("Please provide a guild ID.");
const Giveaways = await GiveawayModel.find({ guildId: guildId, hasEnded: 'False' });
if (Giveaways.length < 1) return false;
const array = [];
Giveaways.map(async (i) => {
const user = this.client.users.get(i.hostedBy)
if(!user) user = "Unknown"
array.push({
hostedBy:user.displayName,
timeRemaining: i.endsOn - Date.now(),
messageId: i.messageId,
prize: i.prize
});
return array;
})
}
}
module.exports = GiveawayCreator;