From a21eef52f4fd6b4e16e07a37ab3c1ff33550140b Mon Sep 17 00:00:00 2001 From: Jacxk Date: Thu, 5 Dec 2019 12:22:14 -0500 Subject: [PATCH 1/7] Added function to split strings sorrounded by a divider --- src/Utils.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Utils.js b/src/Utils.js index 73a9be9..d020bf0 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -35,6 +35,34 @@ class Utils { } return String(bool); } + + /** + * @description Takes a simple string and splits up the messages + * surrounded by the divider. (Strings not on divider will be ignored) + * @param {string} string - String to split. + * @param {string} divider - Where the string would be splitted. + * @returns {Array} Array of string splitted. + */ + static splitOnDivider(string, divider) { + let open = false; + let message = ''; + const array = []; + for (let i = 0; i < string.length; i++) { + const char = string.charAt(i); + if (char === divider) { + if (!open) { + open = true; + } else { + open = false; + array.push(message); + message = ''; + } + } else if (open) { + message += char; + } + } + return array; + } } module.exports = Utils; From 9457d696e3e17b43072ee791aa6062887fc22182 Mon Sep 17 00:00:00 2001 From: Jacxk Date: Thu, 5 Dec 2019 12:22:40 -0500 Subject: [PATCH 2/7] Added giveaway command --- src/modules/general/commands/giveaway.js | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/modules/general/commands/giveaway.js diff --git a/src/modules/general/commands/giveaway.js b/src/modules/general/commands/giveaway.js new file mode 100644 index 0000000..9b335f6 --- /dev/null +++ b/src/modules/general/commands/giveaway.js @@ -0,0 +1,45 @@ +const { RichEmbed } = require('discord.js'); +const { stripIndents } = require('common-tags'); +const moment = require('moment'); +const timestring = require('timestring'); + +const { Command } = require('../../../handler'); +const Utils = require('../../../Utils.js'); + +module.exports = class extends Command { + constructor() { + super('giveaway', { + aliases: ['ga'], + info: + 'Wanna give things to people? Use this command to create giveaways.', + usage: 'giveaway "[time]" "[title]" "{description}"', + guildOnly: false, + }); + } + + async run(message, args) { + const gArgs = Utils.splitOnDivider(args.join(' '), '"'); + + if (gArgs.length < 2) { + return message.reply('Wrong usage'); + } + + const time = timestring(gArgs[0], 'ms'); + const price = gArgs[1]; + const description = gArgs[2]; + + const embed = new RichEmbed() + .setTitle(price) + .setDescription( + ` + ${description ? `\n${description}\n` : ''} + Ends in **${moment.duration(time).humanize()}** + `, + ) + .setFooter('Click the reaction to enter!') + .setTimestamp(Date.now() + time); + + const gMsg = await message.channel.send(embed); + await gMsg.react('🎉'); + } +}; \ No newline at end of file From 0497539f8449f7b3f31b6f417ce8d18fa8e59ac8 Mon Sep 17 00:00:00 2001 From: Jacxk Date: Fri, 6 Dec 2019 12:46:50 -0500 Subject: [PATCH 3/7] Added giveaway countdown --- package.json | 4 +- src/modules/Giveaway.js | 87 ++++++++++++++++++++++++ src/modules/general/commands/giveaway.js | 35 +++++----- 3 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 src/modules/Giveaway.js diff --git a/package.json b/package.json index 67c21a3..8dd2aac 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "dependencies": { "common-tags": "^1.8.0", "discord.js": "^11.5.1", - "got": "^9.6.0" + "got": "^9.6.0", + "moment": "^2.24.0", + "timestring": "^6.0.0" }, "devDependencies": { "eslint": "^5.16.0", diff --git a/src/modules/Giveaway.js b/src/modules/Giveaway.js new file mode 100644 index 0000000..5a90b9d --- /dev/null +++ b/src/modules/Giveaway.js @@ -0,0 +1,87 @@ +const {Collection, RichEmbed} = require('discord.js'); +const moment = require('moment'); +const _active = new Collection(); + +class Giveaway { + constructor({time, description, price, channelID, client}) { + this._client = client; + this._time = time; + this._price = price; + this._description = description; + this._messageID = null; + this._channelID = channelID; + this._interval = null; + this._paused = false; + this._pausedTime = 0; + } + + run() { + return new Promise(resolve => { + const interval = () => { + let every = Math.sqrt(this.getTimeLeft() / 60000); + this._interval = setTimeout(async () => { + const message = await this._client.channels + .get(this._channelID) + .fetchMessage(this._messageID); + + if (this.getTimeLeft() < 1) { + clearTimeout(this._interval); + await message.edit(this.embed()); + return resolve(this); + } else { + await message.edit(this.embed()); + interval(); + } + }, Math.floor(every * 60000)) + }; + interval(); + }); + } + + embed() { + let duration = `Ends in **${moment.duration(this.getTimeLeft(), "ms").humanize()}**`; + if (this.getTimeLeft() < 1) duration = '**Giveaway ended**'; + else if (this._paused) duration = '**Giveaway Paused**'; + return new RichEmbed() + .setTitle(this._price) + .setDescription( + ` + ${this._description ? `\n${this._description}\n` : ''} + ${duration} + `, + ) + .setFooter('Click the reaction to enter!') + .setTimestamp(this._time); + } + + getTimeLeft() { + return this._time - Date.now(); + } + + async start() { + const channel = await this._client.channels.get(this._channelID); + + const message = await channel.send(this.embed()); + await message.react('🎉'); + this._messageID = message.id; + + _active.set(this._messageID, this); + return this.run(); + } + + async pause() { + this._paused = true; + this._pausedTime = Date.now(); + clearTimeout(this._interval); + const channel = await this._client.channels.get(this._channelID); + return channel.send(this.embed()) + } + + resume() { + this._paused = false; + this._pausedTime = 0; + this.run(); + } +} + +module.exports = Giveaway; diff --git a/src/modules/general/commands/giveaway.js b/src/modules/general/commands/giveaway.js index 9b335f6..ac5baf8 100644 --- a/src/modules/general/commands/giveaway.js +++ b/src/modules/general/commands/giveaway.js @@ -1,13 +1,15 @@ -const { RichEmbed } = require('discord.js'); -const { stripIndents } = require('common-tags'); +const {RichEmbed} = require('discord.js'); +const {stripIndents} = require('common-tags'); const moment = require('moment'); const timestring = require('timestring'); -const { Command } = require('../../../handler'); + +const {Command} = require('../../../handler'); const Utils = require('../../../Utils.js'); +const Giveaway = require('../../Giveaway'); module.exports = class extends Command { - constructor() { + constructor({client}) { super('giveaway', { aliases: ['ga'], info: @@ -15,6 +17,8 @@ module.exports = class extends Command { usage: 'giveaway "[time]" "[title]" "{description}"', guildOnly: false, }); + + this.client = client; } async run(message, args) { @@ -28,18 +32,13 @@ module.exports = class extends Command { const price = gArgs[1]; const description = gArgs[2]; - const embed = new RichEmbed() - .setTitle(price) - .setDescription( - ` - ${description ? `\n${description}\n` : ''} - Ends in **${moment.duration(time).humanize()}** - `, - ) - .setFooter('Click the reaction to enter!') - .setTimestamp(Date.now() + time); - - const gMsg = await message.channel.send(embed); - await gMsg.react('🎉'); + const giveaway = new Giveaway({ + time: moment().add(time).toDate().getTime(), + description, + price, + channelID: message.channel.id, + client: this.client + }); + await giveaway.start(); } -}; \ No newline at end of file +}; From 694cba6d98610607e2e3721b06154cd99953b2f1 Mon Sep 17 00:00:00 2001 From: Jacxk Date: Fri, 6 Dec 2019 13:22:14 -0500 Subject: [PATCH 4/7] Added reaction handler and winner --- src/modules/Giveaway.js | 21 +++++++++++++++++---- src/modules/general/commands/giveaway.js | 2 +- src/modules/general/events/reactionAdd.js | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/modules/general/events/reactionAdd.js diff --git a/src/modules/Giveaway.js b/src/modules/Giveaway.js index 5a90b9d..9660924 100644 --- a/src/modules/Giveaway.js +++ b/src/modules/Giveaway.js @@ -12,6 +12,7 @@ class Giveaway { this._channelID = channelID; this._interval = null; this._paused = false; + this._users = []; this._pausedTime = 0; } @@ -40,18 +41,23 @@ class Giveaway { embed() { let duration = `Ends in **${moment.duration(this.getTimeLeft(), "ms").humanize()}**`; - if (this.getTimeLeft() < 1) duration = '**Giveaway ended**'; - else if (this._paused) duration = '**Giveaway Paused**'; + if (this.getTimeLeft() < 1) { + const winner = this._users[Math.floor(Math.random() * this._users.length)]; + this._client.users.get(winner).send(`You wont the giveaway: **${this._price}** :tada: :tada:`); + duration = `**Giveaway ended**\nWinner is: <@${winner}>`; + } else if (this._paused) duration = '**Giveaway Paused**'; return new RichEmbed() .setTitle(this._price) .setDescription( ` ${this._description ? `\n${this._description}\n` : ''} ${duration} + *Users participating: ${this._users.length}* `, ) .setFooter('Click the reaction to enter!') - .setTimestamp(this._time); + .setTimestamp(this._time) + .setColor(this.getTimeLeft() > 0 ? "green" : "red"); } getTimeLeft() { @@ -82,6 +88,13 @@ class Giveaway { this._pausedTime = 0; this.run(); } + + enter(userID) { + this._users.push(userID); + } } -module.exports = Giveaway; +module.exports = { + Giveaway, + activeGiveaways: _active +}; diff --git a/src/modules/general/commands/giveaway.js b/src/modules/general/commands/giveaway.js index ac5baf8..0e220a7 100644 --- a/src/modules/general/commands/giveaway.js +++ b/src/modules/general/commands/giveaway.js @@ -6,7 +6,7 @@ const timestring = require('timestring'); const {Command} = require('../../../handler'); const Utils = require('../../../Utils.js'); -const Giveaway = require('../../Giveaway'); +const {Giveaway} = require('../../Giveaway'); module.exports = class extends Command { constructor({client}) { diff --git a/src/modules/general/events/reactionAdd.js b/src/modules/general/events/reactionAdd.js new file mode 100644 index 0000000..d882cab --- /dev/null +++ b/src/modules/general/events/reactionAdd.js @@ -0,0 +1,21 @@ +const {Event} = require('../../../handler'); +const {activeGiveaways} = require('../../Giveaway'); + +module.exports = class extends Event { + constructor() { + super('messageReactionAdd'); + } + + run(client, reaction, user) { + if (user.bot) return; + + const message = reaction.message; + if (activeGiveaways.has(message.id)) { + const emoji = reaction.emoji; + if (emoji.name !== "🎉") return; + + const giveaway = activeGiveaways.get(message.id); + giveaway.enter(user.id); + } + } +}; From 998b115fbf1267235fe12527414545b7f5a6971d Mon Sep 17 00:00:00 2001 From: Jacxk Date: Fri, 6 Dec 2019 13:47:40 -0500 Subject: [PATCH 5/7] Added support for multiple winners --- src/modules/Giveaway.js | 29 ++++++++++++++++++++---- src/modules/general/commands/giveaway.js | 3 ++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/modules/Giveaway.js b/src/modules/Giveaway.js index 9660924..bbc3ff6 100644 --- a/src/modules/Giveaway.js +++ b/src/modules/Giveaway.js @@ -3,10 +3,11 @@ const moment = require('moment'); const _active = new Collection(); class Giveaway { - constructor({time, description, price, channelID, client}) { + constructor({time, description, price, winners, channelID, client}) { this._client = client; this._time = time; this._price = price; + this._winners = winners || 1; this._description = description; this._messageID = null; this._channelID = channelID; @@ -42,9 +43,11 @@ class Giveaway { embed() { let duration = `Ends in **${moment.duration(this.getTimeLeft(), "ms").humanize()}**`; if (this.getTimeLeft() < 1) { - const winner = this._users[Math.floor(Math.random() * this._users.length)]; - this._client.users.get(winner).send(`You wont the giveaway: **${this._price}** :tada: :tada:`); - duration = `**Giveaway ended**\nWinner is: <@${winner}>`; + const winners = this.drawWinners(); + winners.forEach(winner => { + this._client.users.get(winner).send(`You wont the giveaway: **${this._price}** :tada: :tada:`); + }); + duration = `**Giveaway ended**\nWinner: <@${winners.join(", ")}>`; } else if (this._paused) duration = '**Giveaway Paused**'; return new RichEmbed() .setTitle(this._price) @@ -52,7 +55,8 @@ class Giveaway { ` ${this._description ? `\n${this._description}\n` : ''} ${duration} - *Users participating: ${this._users.length}* + Users participating: **${this._users.length}** + Total winners: **${this._winners}** `, ) .setFooter('Click the reaction to enter!') @@ -92,6 +96,21 @@ class Giveaway { enter(userID) { this._users.push(userID); } + + drawWinners() { + const winners = []; + if (this._winners && !isNaN(this._winners)) { + for (let i = 0; i < parseInt(this._winners); i++) { + const user = this._users[Math.floor(Math.random() * this._users.length)]; + if (!winners.includes(`<@${user}>`)) winners.push(`<@${user}>`); + else i--; + + if (this._users.length === i + 1) break; + } + } + + return winners; + } } module.exports = { diff --git a/src/modules/general/commands/giveaway.js b/src/modules/general/commands/giveaway.js index 0e220a7..681eb38 100644 --- a/src/modules/general/commands/giveaway.js +++ b/src/modules/general/commands/giveaway.js @@ -14,7 +14,7 @@ module.exports = class extends Command { aliases: ['ga'], info: 'Wanna give things to people? Use this command to create giveaways.', - usage: 'giveaway "[time]" "[title]" "{description}"', + usage: 'giveaway "[time]" "[title]" "{description}" {winners}', guildOnly: false, }); @@ -36,6 +36,7 @@ module.exports = class extends Command { time: moment().add(time).toDate().getTime(), description, price, + winners: args[args.length - 1], channelID: message.channel.id, client: this.client }); From 06ed385d94fe3e4ed13ec9e280f433949f71d272 Mon Sep 17 00:00:00 2001 From: Jacxk Date: Fri, 6 Dec 2019 22:02:39 -0500 Subject: [PATCH 6/7] Fixed showing wrong output on winners --- src/modules/Giveaway.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/modules/Giveaway.js b/src/modules/Giveaway.js index bbc3ff6..8b4262b 100644 --- a/src/modules/Giveaway.js +++ b/src/modules/Giveaway.js @@ -7,7 +7,7 @@ class Giveaway { this._client = client; this._time = time; this._price = price; - this._winners = winners || 1; + this._winners = isNaN(winners) ? 1 : parseInt(winners); this._description = description; this._messageID = null; this._channelID = channelID; @@ -99,14 +99,12 @@ class Giveaway { drawWinners() { const winners = []; - if (this._winners && !isNaN(this._winners)) { - for (let i = 0; i < parseInt(this._winners); i++) { - const user = this._users[Math.floor(Math.random() * this._users.length)]; - if (!winners.includes(`<@${user}>`)) winners.push(`<@${user}>`); - else i--; + for (let i = 0; i < this._winners; i++) { + const user = this._users[Math.floor(Math.random() * this._users.length)]; + if (!winners.includes(`<@${user}>`)) winners.push(`<@${user}>`); + else i--; - if (this._users.length === i + 1) break; - } + if (this._users.length === i + 1) break; } return winners; From d29ebbfd7a390a07a5feca141d1f683a8d4c2e9d Mon Sep 17 00:00:00 2001 From: Jacxk Date: Fri, 6 Dec 2019 22:42:09 -0500 Subject: [PATCH 7/7] Prettifed and removed anyiong lint errors --- .eslintrc.js | 5 ++ src/modules/Giveaway.js | 104 +++++++++++----------- src/modules/general/commands/giveaway.js | 20 ++--- src/modules/general/events/reactionAdd.js | 6 +- 4 files changed, 72 insertions(+), 63 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 083116c..1d621db 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -56,5 +56,10 @@ module.exports = { 'eslint-comments/no-unlimited-disable': 'error', 'eslint-comments/no-unused-disable': 'error', 'eslint-comments/no-unused-enable': 'error', + + 'no-plusplus': 'off', + 'no-restricted-globals': "off", + 'radix': "off", + "consistent-return": "off", }, }; diff --git a/src/modules/Giveaway.js b/src/modules/Giveaway.js index 8b4262b..00d10ef 100644 --- a/src/modules/Giveaway.js +++ b/src/modules/Giveaway.js @@ -1,110 +1,114 @@ -const {Collection, RichEmbed} = require('discord.js'); +const { Collection, RichEmbed } = require('discord.js'); const moment = require('moment'); -const _active = new Collection(); + +const active = new Collection(); class Giveaway { - constructor({time, description, price, winners, channelID, client}) { - this._client = client; - this._time = time; - this._price = price; - this._winners = isNaN(winners) ? 1 : parseInt(winners); - this._description = description; - this._messageID = null; - this._channelID = channelID; - this._interval = null; - this._paused = false; - this._users = []; - this._pausedTime = 0; + constructor({ time, description, price, winners, channelID, client }) { + this.client = client; + this.time = time; + this.price = price; + this.winners = isNaN(winners) ? 1 : parseInt(winners); + this.description = description; + this.messageID = null; + this.channelID = channelID; + this.interval = null; + this.paused = false; + this.users = []; + this.pausedTime = 0; } run() { return new Promise(resolve => { const interval = () => { - let every = Math.sqrt(this.getTimeLeft() / 60000); - this._interval = setTimeout(async () => { - const message = await this._client.channels - .get(this._channelID) - .fetchMessage(this._messageID); + const every = Math.sqrt(this.getTimeLeft() / 60000); + this.interval = setTimeout(async () => { + const message = await this.client.channels + .get(this.channelID) + .fetchMessage(this.messageID); if (this.getTimeLeft() < 1) { - clearTimeout(this._interval); + clearTimeout(this.interval); await message.edit(this.embed()); return resolve(this); - } else { - await message.edit(this.embed()); - interval(); } - }, Math.floor(every * 60000)) + await message.edit(this.embed()); + interval(); + }, Math.floor(every * 60000)); }; interval(); }); } embed() { - let duration = `Ends in **${moment.duration(this.getTimeLeft(), "ms").humanize()}**`; + let duration = `Ends in **${moment + .duration(this.getTimeLeft(), 'ms') + .humanize()}**`; if (this.getTimeLeft() < 1) { const winners = this.drawWinners(); winners.forEach(winner => { - this._client.users.get(winner).send(`You wont the giveaway: **${this._price}** :tada: :tada:`); + this.client.users + .get(winner) + .send(`You wont the giveaway: **${this.price}** :tada: :tada:`); }); - duration = `**Giveaway ended**\nWinner: <@${winners.join(", ")}>`; - } else if (this._paused) duration = '**Giveaway Paused**'; + duration = `**Giveaway ended**\nWinner: <@${winners.join(', ')}>`; + } else if (this.paused) duration = '**Giveaway Paused**'; return new RichEmbed() - .setTitle(this._price) + .setTitle(this.price) .setDescription( ` - ${this._description ? `\n${this._description}\n` : ''} + ${this.description ? `\n${this.description}\n` : ''} ${duration} - Users participating: **${this._users.length}** - Total winners: **${this._winners}** + Users participating: **${this.users.length}** + Total winners: **${this.winners}** `, ) .setFooter('Click the reaction to enter!') - .setTimestamp(this._time) - .setColor(this.getTimeLeft() > 0 ? "green" : "red"); + .setTimestamp(this.time) + .setColor(this.getTimeLeft() > 0 ? 'green' : 'red'); } getTimeLeft() { - return this._time - Date.now(); + return this.time - Date.now(); } async start() { - const channel = await this._client.channels.get(this._channelID); + const channel = await this.client.channels.get(this.channelID); const message = await channel.send(this.embed()); await message.react('🎉'); - this._messageID = message.id; + this.messageID = message.id; - _active.set(this._messageID, this); + active.set(this.messageID, this); return this.run(); } async pause() { - this._paused = true; - this._pausedTime = Date.now(); - clearTimeout(this._interval); - const channel = await this._client.channels.get(this._channelID); - return channel.send(this.embed()) + this.paused = true; + this.pausedTime = Date.now(); + clearTimeout(this.interval); + const channel = await this.client.channels.get(this.channelID); + return channel.send(this.embed()); } resume() { - this._paused = false; - this._pausedTime = 0; + this.paused = false; + this.pausedTime = 0; this.run(); } enter(userID) { - this._users.push(userID); + this.users.push(userID); } drawWinners() { const winners = []; - for (let i = 0; i < this._winners; i++) { - const user = this._users[Math.floor(Math.random() * this._users.length)]; + for (let i = 0; i < this.winners; i++) { + const user = this.users[Math.floor(Math.random() * this.users.length)]; if (!winners.includes(`<@${user}>`)) winners.push(`<@${user}>`); else i--; - if (this._users.length === i + 1) break; + if (this.users.length === i + 1) break; } return winners; @@ -113,5 +117,5 @@ class Giveaway { module.exports = { Giveaway, - activeGiveaways: _active + activeGiveaways: active, }; diff --git a/src/modules/general/commands/giveaway.js b/src/modules/general/commands/giveaway.js index 681eb38..efb139b 100644 --- a/src/modules/general/commands/giveaway.js +++ b/src/modules/general/commands/giveaway.js @@ -1,15 +1,12 @@ -const {RichEmbed} = require('discord.js'); -const {stripIndents} = require('common-tags'); const moment = require('moment'); const timestring = require('timestring'); - -const {Command} = require('../../../handler'); +const { Command } = require('../../../handler'); const Utils = require('../../../Utils.js'); -const {Giveaway} = require('../../Giveaway'); +const { Giveaway } = require('../../Giveaway'); module.exports = class extends Command { - constructor({client}) { + constructor({ client }) { super('giveaway', { aliases: ['ga'], info: @@ -21,7 +18,7 @@ module.exports = class extends Command { this.client = client; } - async run(message, args) { + run(message, args) { const gArgs = Utils.splitOnDivider(args.join(' '), '"'); if (gArgs.length < 2) { @@ -33,13 +30,16 @@ module.exports = class extends Command { const description = gArgs[2]; const giveaway = new Giveaway({ - time: moment().add(time).toDate().getTime(), + time: moment() + .add(time) + .toDate() + .getTime(), description, price, winners: args[args.length - 1], channelID: message.channel.id, - client: this.client + client: this.client, }); - await giveaway.start(); + return giveaway.start(); } }; diff --git a/src/modules/general/events/reactionAdd.js b/src/modules/general/events/reactionAdd.js index d882cab..7d6f2d6 100644 --- a/src/modules/general/events/reactionAdd.js +++ b/src/modules/general/events/reactionAdd.js @@ -1,5 +1,5 @@ -const {Event} = require('../../../handler'); -const {activeGiveaways} = require('../../Giveaway'); +const { Event } = require('../../../handler'); +const { activeGiveaways } = require('../../Giveaway'); module.exports = class extends Event { constructor() { @@ -12,7 +12,7 @@ module.exports = class extends Event { const message = reaction.message; if (activeGiveaways.has(message.id)) { const emoji = reaction.emoji; - if (emoji.name !== "🎉") return; + if (emoji.name !== '🎉') return; const giveaway = activeGiveaways.get(message.id); giveaway.enter(user.id);