Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Button support #482

Open
wants to merge 30 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d1d5b08
intial
Nico105 Sep 12, 2022
66b36b7
fix
Nico105 Sep 18, 2022
82eb152
use discord enums for events
Nico105 Sep 18, 2022
5d0dbbc
add spaces for visibility
Nico105 Sep 18, 2022
cf130b5
properly handle leave and join
Nico105 Sep 18, 2022
05f82ae
typo
Nico105 Sep 18, 2022
40bd614
fix
Nico105 Sep 18, 2022
d75b283
jsdoc
Nico105 Sep 18, 2022
9035916
jsdoc
Nico105 Sep 18, 2022
9b2b39a
check for updated buttons
Nico105 Sep 25, 2022
044318d
add readme example
Nico105 Oct 3, 2022
dad94cd
improve example
Nico105 Oct 3, 2022
3e4fe69
reject link buttons
Nico105 Oct 3, 2022
5edd9e2
handle 1 button support
Nico105 Oct 3, 2022
f6abd6c
fix
Nico105 Oct 3, 2022
a9c79bc
Update src/Giveaway.js
Nico105 Oct 4, 2022
2288c94
fix reaction and button priority, hopefully?
Nico105 Oct 11, 2022
b1471ef
Merge branch 'feat/button-support' of https://github.com/Nico105/disc…
Nico105 Oct 11, 2022
e19c7b4
improve drop system
Nico105 Oct 12, 2022
d9eb6f5
Update src/Manager.js
Nico105 Nov 5, 2022
ebe5c4b
Merge 'upstream/develop' into feat/button-support
Nico105 Nov 5, 2022
9bffbff
default interaction replies
Nico105 Jan 6, 2023
24c7d75
formatting
Nico105 Jan 6, 2023
e945497
fix
Nico105 Jan 7, 2023
9939f95
refactor
Nico105 Jan 7, 2023
8e5c887
refactor and export event constants
Nico105 Feb 23, 2023
dcaf010
types and edit functionality
Nico105 Feb 23, 2023
62b5ec6
safe every entrant to the db
Nico105 Feb 24, 2023
e34ebb2
fix restart
Nico105 Feb 24, 2023
d6d5590
Merge remote-tracking branch 'upstream/develop' into feat/button-support
Nico105 Feb 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Discord Giveaways is a powerful [Node.js](https://nodejs.org) module that allows
- 📁 Support for all databases! (default is json)
- ⚙️ Very customizable! (prize, duration, winners, ignored permissions, bonus entries, etc...)
- 🚀 Super powerful: start, edit, reroll, end, delete and pause giveaways!
- 💥 Events: giveawayEnded, giveawayRerolled, giveawayDeleted, giveawayReactionAdded, giveawayReactionRemoved, endedGiveawayReactionAdded
- 🕸️ Support for shards!
- 💥 Events: giveawayEnded, giveawayRerolled, giveawayDeleted, giveawayMemberJoined, giveawayMemberLeft
- 🕸️ Support for buttons and shards!
- and much more!

## Installation
Expand Down Expand Up @@ -509,6 +509,38 @@ client.giveawaysManager.reroll(messageId, {
You can [access giveaway properties](https://github.com/Androz2091/discord-giveaways#access-giveaway-properties-in-messages) in these messages.
[Message options](https://github.com/Androz2091/discord-giveaways#message-options) are available in these messages.

## Buttons instead of reaction

```js
const Discord = require('discord.js');
const { GiveawaysManager } = require('discord-giveaways');
const manager = new GiveawaysManager(client, {
storage: './giveaways.json',
default: {
buttons: {
join: new Discord.ButtonBuilder()
.setLabel('Join')
.setStyle(Discord.ButtonStyle.Primary)
.setCustomId('join'),
leave: new Discord.ButtonBuilder()
.setLabel('Leave')
.setStyle(Discord.ButtonStyle.Secondary)
.setCustomId('leave')
}
}
});
```

- **options.default.buttons.join**: the button to join giveaways.
- **options.default.buttons.leave**: the button to leave giveaways.
^^^ If not set, the join-button doubles as the leave-button.
- **options.default.buttons.joinReply**: sent in the channel as the ephemeral interaction reply to the join-button.
^^^ If set to `null`, custom behaviour can be added via the [event](https://discord-giveaways.js.org/GiveawaysManager.html#event:giveawayJoined).
- **options.default.buttons.leaveReply**: sent in the channel as the ephemeral interaction reply to the leave-button.
^^^ If set to `null`, custom behaviour can be added via the [event](https://discord-giveaways.js.org/GiveawaysManager.html#event:giveawayLeft).

You can [access other giveaway properties](https://github.com/Androz2091/discord-giveaways#access-giveaway-properties-in-messages) in these properties.

## Custom Database

You can use your custom database to save giveaways, instead of the json files (the "database" by default for `discord-giveaways`).
Expand Down
7 changes: 7 additions & 0 deletions examples/custom-databases/mongoose.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ const giveawaySchema = new mongoose.Schema(
hostedBy: String,
winnerIds: { type: [String], default: undefined },
reaction: mongoose.Mixed,
buttons: {
join: mongoose.Mixed,
leave: mongoose.Mixed,
joinReply: mongoose.Mixed,
leaveReply: mongoose.Mixed
},
entrantIds: { type: [String], default: undefined },
botsCanWin: Boolean,
embedColor: mongoose.Mixed,
embedColorEnd: mongoose.Mixed,
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
exports.version = require('./package.json').version;
exports.GiveawaysManager = require('./src/Manager');
exports.Giveaway = require('./src/Giveaway');
exports.Events = require('./src/Events');
30 changes: 25 additions & 5 deletions src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ exports.GiveawayMessages = {
* @property {boolean} [replyToGiveaway] If the sent message should reply to the giveaway embed.
*/

/**
* @typedef {Object} ButtonsObject
*
* @property {Discord.JSONEncodable<Discord.APIButtonComponent>|Discord.APIButtonComponent} join The button to join the giveaway.
* @property {Discord.JSONEncodable<Discord.APIButtonComponent>|Discord.APIButtonComponent} [leave] The button to leave the giveaway.
* @property {?(string|MessageObject)} [joinReply] Sent in the channel as the ephemeral interaction reply to the join-button.
* @property {?(string|MessageObject)} [leaveReply] Sent in the channel as the ephemeral interaction reply to the leave-button.
*/

/**
* @typedef {Function} ExemptMembersFunction
*
Expand All @@ -76,6 +85,7 @@ exports.GiveawayMessages = {
* @property {Discord.ColorResolvable} [embedColor] The color of the giveaway embed when it is running.
* @property {Discord.ColorResolvable} [embedColorEnd] The color of the giveaway embed when it has ended.
* @property {Discord.EmojiIdentifierResolvable} [reaction] The reaction to participate in the giveaway.
* @property {ButtonsObject} [buttons] The buttons for the giveaway.
* @property {GiveawayMessages} [messages] The giveaway messages.
* @property {string} [thumbnail] The URL appearing as the thumbnail on the giveaway embed.
* @property {string} [image] The URL appearing as the image on the giveaway embed.
Expand Down Expand Up @@ -126,9 +136,9 @@ exports.LastChanceOptions = {
*
* @property {boolean} [isPaused=false] If the giveaway is paused.
* @property {string} [content='⚠️ **THIS GIVEAWAY IS PAUSED !** ⚠️'] The text of the embed when the giveaway is paused.
* @property {number} [unpauseAfter=null] The number of milliseconds, or a timestamp in milliseconds, after which the giveaway will automatically unpause.
* @property {?number} [unpauseAfter=null] The number of milliseconds, or a timestamp in milliseconds, after which the giveaway will automatically unpause.
* @property {Discord.ColorResolvable} [embedColor='#FFFF00'] The color of the embed when the giveaway is paused.
* @private @property {number} [durationAfterPause=null|giveaway.remainingTime] The remaining duration after the giveaway is unpaused.<br>⚠ This property gets set by the manager so that the pause system works properly. It is not recommended to set it manually!
* @private @property {?number} [durationAfterPause=null|giveaway.remainingTime] The remaining duration after the giveaway is unpaused.<br>⚠ This property gets set by the manager so that the pause system works properly. It is not recommended to set it manually!
* @property {string} [infiniteDurationText='`NEVER`'] The text that gets displayed next to "GiveawayMessages#drawing" in the paused embed, when there is no "unpauseAfter".
*/
exports.PauseOptions = {
Expand All @@ -145,16 +155,19 @@ exports.PauseOptions = {
* @typedef GiveawaysManagerOptions
*
* @property {string} [storage='./giveaways.json'] The storage path for the giveaways.
* @property {number} [forceUpdateEvery=null] Force the giveaway messages to be updated at a specific interval.
* @property {number} [endedGiveawaysLifetime=null] The number of milliseconds after which ended giveaways should get deleted from the DB.<br>⚠ Giveaways deleted from the DB cannot get rerolled anymore!
* @property {?number} [forceUpdateEvery=null] Force the giveaway messages to be updated at a specific interval.
* @property {?number} [endedGiveawaysLifetime=null] The number of milliseconds after which ended giveaways should get deleted from the DB.<br>⚠ Giveaways deleted from the DB cannot get rerolled anymore!
* @property {Object} [default] The default options for new giveaways.
* @property {boolean} [default.botsCanWin=false] If bots can win giveaways.
* @property {Discord.PermissionResolvable[]} [default.exemptPermissions=[]] Members with any of these permissions won't be able to win a giveaway.
* @property {ExemptMembersFunction} [default.exemptMembers] Function to filter members.<br>If true is returned, the member won't be able to win a giveaway.
* @property {Discord.ColorResolvable} [default.embedColor='#FF0000'] The color of the giveaway embeds when they are running.
* @property {Discord.ColorResolvable} [default.embedColorEnd='#000000'] The color of the giveaway embeds when they have ended.
* @property {Discord.EmojiIdentifierResolvable} [default.reaction='🎉'] The reaction to participate in giveaways.
* @property {?Discord.EmojiIdentifierResolvable} [default.reaction='🎉'] The reaction to participate in giveaways.
* @property {LastChanceOptions} [default.lastChance] The options for the last chance system.
* @property {?ButtonsObject} [default.buttons] The buttons for the giveaways.
* @property {?(string|MessageObject)} [default.buttons.joinReply='✅ joined'] Sent in the channel as the ephemeral interaction reply to the join-button.
* @property {?(string|MessageObject)} [default.buttons.leaveReply='✅ left'] Sent in the channel as the ephemeral interaction reply to the leave-button.
*/
exports.GiveawaysManagerOptions = {
storage: './giveaways.json',
Expand All @@ -167,6 +180,10 @@ exports.GiveawaysManagerOptions = {
embedColor: '#FF0000',
embedColorEnd: '#000000',
reaction: '🎉',
buttons: {
joinReply: '✅ joined',
leaveReply: '✅ left'
},
lastChance: {
enabled: false,
content: '⚠️ **LAST CHANCE TO ENTER !** ⚠️',
Expand Down Expand Up @@ -210,6 +227,7 @@ exports.GiveawayRerollOptions = {
* @property {BonusEntry[]} [newBonusEntries] The new BonusEntry objects.
* @property {ExemptMembersFunction} [newExemptMembers] The new filter function to exempt members from winning the giveaway.
* @property {LastChanceOptions} [newLastChance] The new options for the last chance system.<br>Will get merged with the existing object, if there.
* @property {ButtonsObject} [newButtons] The new buttons for the giveaway.
*/
exports.GiveawayEditOptions = {};

Expand All @@ -230,6 +248,7 @@ exports.GiveawayEditOptions = {};
* @property {Discord.Snowflake[]} [winnerIds] The winner Ids of the giveaway after it ended.
* @property {Discord.Snowflake} messageId The Id of the message.
* @property {Discord.EmojiIdentifierResolvable} [reaction] The reaction to participate in the giveaway.
* @property {ButtonsObject} [buttons] The buttons for the giveaway.
* @property {boolean} [botsCanWin] If bots can win the giveaway.
* @property {Discord.PermissionResolvable[]} [exemptPermissions] Members with any of these permissions will not be able to win the giveaway.
* @property {string} [exemptMembers] Filter function to exempt members from winning the giveaway.
Expand All @@ -242,5 +261,6 @@ exports.GiveawayEditOptions = {};
* @property {PauseOptions} [pauseOptions] The options for the pause system.
* @property {boolean} [isDrop] If the giveaway is a drop, or not.<br>Drop means that if the amount of valid entrants to the giveaway is the same as "winnerCount" then it immediately ends.
* @property {Discord.MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the giveaway messages content.
* @property {Snowflake[]} [entrantIds] The entrant ids for this giveaway, if buttons are used.
*/
exports.GiveawayData = {};
121 changes: 121 additions & 0 deletions src/Events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* @typedef {Object} Events
* @property {string} EndedGiveawayReactionAdded endedGiveawayReactionAdded
* @property {string} GiveawayDeleted giveawayDeleted'
* @property {string} GiveawayEnded giveawayEnded
* @property {string} GiveawayMemberJoined giveawayMemberJoined
* @property {string} GiveawayMemberLeft giveawayMemberLeft
* @property {string} GiveawayRerolled giveawayRerolled
*/

// JSDoc for IntelliSense purposes
/**
* @type {Events}
* @ignore
*/
module.exports = {
EndedGiveawayReactionAdded: 'endedGiveawayReactionAdded',
GiveawayDeleted: 'giveawayDeleted',
GiveawayEnded: 'giveawayEnded',
GiveawayMemberJoined: 'giveawayMemberJoined',
GiveawayMemberLeft: 'giveawayMemberLeft',
GiveawayRerolled: 'giveawayRerolled'
};

/**
* Emitted when someone reacted to an ended giveaway.
* @event GiveawaysManager#endedGiveawayReactionAdded
* @param {Giveaway} giveaway The giveaway instance
* @param {Discord.GuildMember} member The member who reacted to the ended giveaway
* @param {Discord.MessageReaction} reaction The reaction object
*
* @example
* // This can be used to prevent new participants when giveaways with reactions get rerolled
* manager.on('endedGiveawayReactionAdded', (giveaway, member, reaction) => {
* return reaction.users.remove(member.user);
* });
*/

/**
* Emitted when a giveaway was deleted.
* @event GiveawaysManager#giveawayDeleted
* @param {Giveaway} giveaway The giveaway instance
*
* @example
* // This can be used to add logs
* manager.on('giveawayDeleted', (giveaway) => {
* console.log('Giveaway with message Id ' + giveaway.messageId + ' was deleted.')
* });
*/

/**
* Emitted when a giveaway ended.
* @event GiveawaysManager#giveawayEnded
* @param {Giveaway} giveaway The giveaway instance
* @param {Discord.GuildMember[]} winners The giveaway winners
*
* @example
* // This can be used to add features such as a congratulatory message in DM
* manager.on('giveawayEnded', (giveaway, winners) => {
* winners.forEach((member) => {
* member.send('Congratulations, ' + member.user.username + ', you won: ' + giveaway.prize);
* });
* });
*/

/**
* Emitted when someone joined a giveaway.
* @event GiveawaysManager#giveawayMemberJoined
* @param {Giveaway} giveaway The giveaway instance
* @param {Discord.GuildMember} member The member who joined the giveaway
* @param {Discord.MessageReaction|Discord.ButtonInteraction} interaction The reaction to enter the giveaway
*
* @example
* // This can be used to add features such as giveaway requirements
* // Best used with the "exemptMembers" property of the giveaways
* manager.on('giveawayMemberJoined', (giveaway, member, reaction) => {
* if (!member.roles.cache.get('123456789')) {
* const index = giveaway.entrantIds.indexOf(member.id);
giveaway.entrantIds.splice(index, 1);
* member.send('You must have this role to participate in the giveaway: Staff');
* }
* });
* @example
* // This can be used to add features such as giveaway requirements
* // Best used with the "exemptMembers" property of the giveaways
* manager.on('giveawayMemberJoined', (giveaway, member, reaction) => {
* if (!member.roles.cache.get('123456789')) {
* reaction.users.remove(member.user);
* member.send('You must have this role to participate in the giveaway: Staff');
* }
* });
*/

/**
* Emitted when someone left a giveaway.
* @event GiveawaysManager#giveawayMemberLeft
* @param {Giveaway} giveaway The giveaway instance
* @param {Discord.GuildMember} member The member who remove their reaction giveaway
* @param {Discord.MessageReaction} reaction The reaction to enter the giveaway
*
* @example
* // This can be used to add features such as a leave message in DM
* manager.on('giveawayMemberLeft', (giveaway, member, interaction) => {
* return member.send('That\'s sad, you won\'t be able to win the super cookie!');
* });
*/

/**
* Emitted when a giveaway was rerolled.
* @event GiveawaysManager#giveawayRerolled
* @param {Giveaway} giveaway The giveaway instance
* @param {Discord.GuildMember[]} winners The winners of the giveaway
*
* @example
* // This can be used to add features such as a congratulatory message per DM
* manager.on('giveawayRerolled', (giveaway, winners) => {
* winners.forEach((member) => {
* member.send('Congratulations, ' + member.user.username + ', you won: ' + giveaway.prize);
* });
* });
*/
Loading