Skip to content

Commit 531c6a2

Browse files
committed
fix(remindverify): assign correct user ID to verification button
Previously, the verification reminder DM button used the ID of the admin who triggered `/remindverify`, causing unverified users to see "⚠️ This verification button is not for you." This update sets the button’s customId to the target member’s user ID, ensuring that each reminder button works correctly for its recipient.
1 parent ab73df7 commit 531c6a2

File tree

2 files changed

+8
-94
lines changed

2 files changed

+8
-94
lines changed

src/bot.js

Lines changed: 7 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ async function writeServiceAccountKey() {
7575
}
7676

7777
/**
78-
* Main Discord Bot class with improved error handling and interaction management.
78+
* Main Discord Bot class
7979
*/
8080
class PulchowkBot {
8181
constructor(token, dbInstance) {
@@ -123,7 +123,7 @@ class PulchowkBot {
123123
this.spamWarnings = new Map();
124124
this.voiceStates = new Map();
125125
this.rateLimitMap = new Map();
126-
this.interactionStates = new Map(); // Track interaction states
126+
this.interactionStates = new Map();
127127

128128
this._initializeCommands();
129129
this._registerEventListeners();
@@ -177,7 +177,7 @@ class PulchowkBot {
177177
}
178178

179179
/**
180-
* Registers all Discord.js event listeners with improved error handling.
180+
* Registers all Discord.js event listeners
181181
* @private
182182
*/
183183
_registerEventListeners() {
@@ -199,17 +199,13 @@ class PulchowkBot {
199199
this.debugConfig.log('Error during bot initialization:', 'client', null, error, 'error');
200200
}
201201
});
202-
203-
// Core event handlers with error wrapping
204202
this.client.on(Events.InteractionCreate, this._safeEventHandler('InteractionCreate', this._onInteractionCreate.bind(this)));
205203
this.client.on(Events.VoiceStateUpdate, this._safeEventHandler('VoiceStateUpdate', this._onVoiceStateUpdate.bind(this)));
206204
this.client.on(Events.MessageCreate, this._safeEventHandler('MessageCreate', this._onMessageCreate.bind(this)));
207205
this.client.on(Events.GuildMemberAdd, this._safeEventHandler('GuildMemberAdd', this._onGuildMemberAdd.bind(this)));
208206
this.client.on(Events.GuildMemberRemove, this._safeEventHandler('GuildMemberRemove', this._onGuildMemberRemove.bind(this)));
209207
this.client.on(Events.MessageReactionAdd, this._safeEventHandler('MessageReactionAdd', this._onMessageReactionAdd.bind(this)));
210208
this.client.on(Events.MessageReactionRemove, this._safeEventHandler('MessageReactionRemove', this._onMessageReactionRemove.bind(this)));
211-
212-
// Error handling
213209
this.client.on(Events.Error, error => this.debugConfig.log('Discord.js Client Error:', 'client', null, error, 'error'));
214210
this.client.on(Events.ShardDisconnect, (event, id) => this.debugConfig.log(`Shard ${id} Disconnected:`, 'client', { event }, null, 'warn'));
215211
this.client.on(Events.ShardReconnecting, (id) => this.debugConfig.log(`Shard ${id} Reconnecting...`, 'client', null, null, 'info'));
@@ -219,7 +215,7 @@ class PulchowkBot {
219215
}
220216

221217
/**
222-
* Wraps event handlers with error handling to prevent crashes.
218+
* Wraps event handlers
223219
* @private
224220
*/
225221
_safeEventHandler(eventName, handler) {
@@ -290,12 +286,8 @@ class PulchowkBot {
290286
});
291287
}
292288

293-
// ===================================================================================
294-
// == IMPROVED INTERACTION HANDLING ==================================================
295-
// ===================================================================================
296-
297289
/**
298-
* Enhanced interaction handler with comprehensive error handling.
290+
* Enhanced interaction handler
299291
*/
300292
async _onInteractionCreate(interaction) {
301293
const startTime = Date.now();
@@ -729,7 +721,6 @@ class PulchowkBot {
729721
errorCode: error.code
730722
}, error, 'error');
731723

732-
// Handle specific error cases
733724
if (error.code === 10062) {
734725
this.debugConfig.log('Interaction expired', 'interaction', { user: interaction.user?.tag }, null, 'warn');
735726
return;
@@ -739,8 +730,6 @@ class PulchowkBot {
739730
this.debugConfig.log('Interaction already acknowledged', 'interaction', { user: interaction.user?.tag }, null, 'warn');
740731
return;
741732
}
742-
743-
// Last resort attempt
744733
if (!interaction.replied) {
745734
try {
746735
await interaction.followUp({
@@ -824,8 +813,6 @@ class PulchowkBot {
824813
*/
825814
async _handleInteractionError(interaction, error, context = {}) {
826815
const duration = Date.now() - (context.startTime || Date.now());
827-
828-
// Classify error types
829816
let errorType = 'unknown';
830817
if (error.code === 10062) errorType = 'expired';
831818
else if (error.code === 40060) errorType = 'already_acknowledged';
@@ -839,13 +826,9 @@ class PulchowkBot {
839826
errorCode: error.code,
840827
errorType
841828
}, error, 'error');
842-
843-
// Don't respond to expired or acknowledged interactions
844829
if (error.code === 10062 || error.code === 40060) {
845830
return;
846831
}
847-
848-
// Only send error response if not already handled
849832
if (!interaction.replied && !interaction.deferred) {
850833
await this._safeErrorReply(interaction, '⚠️ An unexpected error occurred. Please try again later.');
851834
}
@@ -859,17 +842,12 @@ class PulchowkBot {
859842
const key = `${userId}:${action}`;
860843
const now = Date.now();
861844
const userActions = this.rateLimitMap.get(key) || [];
862-
863845
const recentActions = userActions.filter(time => now - time < window);
864-
865846
if (recentActions.length >= limit) {
866847
return true;
867848
}
868-
869849
recentActions.push(now);
870850
this.rateLimitMap.set(key, recentActions);
871-
872-
// Cleanup occasionally
873851
if (Math.random() < 0.01) {
874852
this._cleanupRateLimitMap();
875853
}
@@ -883,8 +861,7 @@ class PulchowkBot {
883861
*/
884862
_cleanupRateLimitMap() {
885863
const now = Date.now();
886-
const maxAge = 300000; // 5 minutes
887-
864+
const maxAge = 300000;
888865
for (const [key, actions] of this.rateLimitMap.entries()) {
889866
const recentActions = actions.filter(time => now - time < maxAge);
890867
if (recentActions.length === 0) {
@@ -911,11 +888,6 @@ class PulchowkBot {
911888
);
912889
});
913890
}
914-
915-
// ===================================================================================
916-
// == CORE EVENT HANDLERS ============================================================
917-
// ===================================================================================
918-
919891
/**
920892
* Enhanced voice state update handler.
921893
* @private
@@ -928,8 +900,6 @@ class PulchowkBot {
928900
const userLeft = oldState.channelId && !newState.channelId;
929901
const userMoved = oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId;
930902
const userJoined = !oldState.channelId && newState.channelId;
931-
932-
// Handle leaving/moving
933903
if (userLeft || userMoved) {
934904
const session = this.voiceStates.get(userId);
935905
if (session) {
@@ -955,8 +925,6 @@ class PulchowkBot {
955925
this.client.db.run(`DELETE FROM active_voice_sessions WHERE user_id = ? AND guild_id = ?`, [userId, guildId]);
956926
}
957927
}
958-
959-
// Handle joining/moving
960928
if (userJoined || userMoved) {
961929
this.voiceStates.set(userId, {
962930
guildId,
@@ -1010,8 +978,6 @@ class PulchowkBot {
1010978
try {
1011979
const userAvatar = member.user.displayAvatarURL({ dynamic: true, size: 128 });
1012980
const VERIFIED_ROLE_ID = process.env.VERIFIED_ROLE_ID;
1013-
1014-
// Check if previously verified
1015981
const verifiedRow = await new Promise((resolve, reject) => {
1016982
this.client.db.get(
1017983
`SELECT user_id FROM verified_users WHERE user_id = ? AND guild_id = ?`,
@@ -1027,7 +993,6 @@ class PulchowkBot {
1027993
let dmComponents = [];
1028994

1029995
if (verifiedRow) {
1030-
// Previously verified - restore role
1031996
if (VERIFIED_ROLE_ID) {
1032997
const verifiedRole = member.guild.roles.cache.get(VERIFIED_ROLE_ID);
1033998
if (verifiedRole) {
@@ -1047,7 +1012,6 @@ class PulchowkBot {
10471012
.setThumbnail(userAvatar)
10481013
.setTimestamp();
10491014
} else {
1050-
// New user - needs verification
10511015
const verifyButton = new ButtonBuilder()
10521016
.setCustomId(`verify_start_button_${member.user.id}`)
10531017
.setLabel('Verify Your Account')
@@ -1062,16 +1026,12 @@ class PulchowkBot {
10621026
.setThumbnail(userAvatar)
10631027
.setTimestamp();
10641028
}
1065-
1066-
// Send welcome DM
10671029
try {
10681030
await member.send({ embeds: [dmEmbed], components: dmComponents });
10691031
this.debugConfig.log(`Sent welcome DM to ${member.user.tag}`, 'event');
10701032
} catch (dmErr) {
10711033
this.debugConfig.log('Could not send welcome DM', 'event', { user: member.user.tag }, dmErr, 'warn');
10721034
}
1073-
1074-
// Send public welcome message
10751035
const guildConfig = await new Promise((resolve) => {
10761036
this.client.db.get(
10771037
`SELECT welcome_channel_id, welcome_message_content FROM guild_configs WHERE guild_id = ?`,
@@ -1153,7 +1113,6 @@ class PulchowkBot {
11531113
if (user.bot || !reaction.message.guild) return;
11541114

11551115
try {
1156-
// Reaction roles
11571116
const reactionRole = await new Promise((resolve) => {
11581117
this.client.db.get(
11591118
`SELECT role_id FROM reaction_roles WHERE guild_id = ? AND message_id = ? AND emoji = ?`,
@@ -1170,8 +1129,6 @@ class PulchowkBot {
11701129
await member.roles.add(role, 'Reaction role assignment');
11711130
}
11721131
}
1173-
1174-
// Suggestion voting
11751132
const SUGGESTIONS_CHANNEL_ID = process.env.SUGGESTIONS_CHANNEL_ID;
11761133
if (reaction.message.channel.id === SUGGESTIONS_CHANNEL_ID && ['👍', '👎'].includes(reaction.emoji.name)) {
11771134
await this._updateSuggestionVotes(reaction.message);
@@ -1198,7 +1155,6 @@ class PulchowkBot {
11981155
if (user.bot || !reaction.message.guild) return;
11991156

12001157
try {
1201-
// Reaction roles
12021158
const reactionRole = await new Promise((resolve) => {
12031159
this.client.db.get(
12041160
`SELECT role_id FROM reaction_roles WHERE guild_id = ? AND message_id = ? AND emoji = ?`,
@@ -1215,8 +1171,6 @@ class PulchowkBot {
12151171
await member.roles.remove(role, 'Reaction role removal');
12161172
}
12171173
}
1218-
1219-
// Suggestion voting
12201174
const SUGGESTIONS_CHANNEL_ID = process.env.SUGGESTIONS_CHANNEL_ID;
12211175
if (reaction.message.channel.id === SUGGESTIONS_CHANNEL_ID && ['👍', '👎'].includes(reaction.emoji.name)) {
12221176
await this._updateSuggestionVotes(reaction.message);
@@ -1318,13 +1272,9 @@ class PulchowkBot {
13181272
if (userData.count > message_limit) {
13191273
this.spamWarnings.set(userId, (this.spamWarnings.get(userId) || 0) + 1);
13201274
const currentWarnings = this.spamWarnings.get(userId);
1321-
1322-
// Delete spam messages
13231275
if (message.channel.permissionsFor(this.client.user).has(PermissionsBitField.Flags.ManageMessages)) {
13241276
await message.channel.bulkDelete(Math.min(userData.count, 100), true);
13251277
}
1326-
1327-
// Apply moderation
13281278
if (currentWarnings >= ban_threshold && message.member?.bannable) {
13291279
await message.member.ban({ reason: `Anti-spam: ${currentWarnings} warnings.` });
13301280
await message.channel.send(`🚨 ${message.author.tag} has been banned for repeated spamming.`);
@@ -1436,7 +1386,6 @@ class PulchowkBot {
14361386
}
14371387
);
14381388
});
1439-
14401389
const suggestionsChannel = this.client.channels.cache.get(process.env.SUGGESTIONS_CHANNEL_ID);
14411390
const message = await suggestionsChannel?.messages.fetch(suggestionRow.message_id).catch(() => null);
14421391

@@ -1447,7 +1396,6 @@ class PulchowkBot {
14471396

14481397
await message.edit({ embeds: [updatedEmbed], components: [] });
14491398
}
1450-
14511399
await this._safeReply(interaction, {
14521400
content: `✅ Suggestion \`${suggestionId}\` has been denied.`,
14531401
flags: MessageFlags.Ephemeral
@@ -1474,11 +1422,9 @@ class PulchowkBot {
14741422
}
14751423
);
14761424
});
1477-
14781425
if (!suggestionRow) {
14791426
return this._safeErrorReply(interaction, `⚠️ Suggestion with ID \`${suggestionId}\` not found.`);
14801427
}
1481-
14821428
await new Promise((resolve, reject) => {
14831429
this.client.db.run(
14841430
`DELETE FROM suggestions WHERE id = ?`,
@@ -1489,14 +1435,12 @@ class PulchowkBot {
14891435
}
14901436
);
14911437
});
1492-
14931438
const suggestionsChannel = this.client.channels.cache.get(process.env.SUGGESTIONS_CHANNEL_ID);
14941439
const message = await suggestionsChannel?.messages.fetch(suggestionRow.message_id).catch(() => null);
14951440

14961441
if (message) {
14971442
await message.delete(`Deleted by ${interaction.user.tag}. Reason: ${reason}`);
14981443
}
1499-
15001444
await this._safeReply(interaction, {
15011445
content: `✅ Suggestion \`${suggestionId}\` has been deleted.`,
15021446
flags: MessageFlags.Ephemeral
@@ -1507,10 +1451,6 @@ class PulchowkBot {
15071451
}
15081452
}
15091453

1510-
// ===================================================================================
1511-
// == SCHEDULED JOBS ==================================================================
1512-
// ===================================================================================
1513-
15141454
/**
15151455
* Sets up all scheduled jobs with better error handling.
15161456
* @private
@@ -1748,9 +1688,7 @@ class PulchowkBot {
17481688
}
17491689
);
17501690
});
1751-
17521691
if (birthdays.length === 0) continue;
1753-
17541692
const birthdayUsers = [];
17551693
for (const birthday of birthdays) {
17561694
try {
@@ -1780,7 +1718,7 @@ class PulchowkBot {
17801718
}
17811719

17821720
/**
1783-
* Starts the bot with enhanced error handling.
1721+
* Starts the bot
17841722
*/
17851723
async start() {
17861724
this.debugConfig.log('Starting bot...', 'init');
@@ -1803,58 +1741,40 @@ class PulchowkBot {
18031741
this.debugConfig.log('Initiating bot shutdown...', 'shutdown');
18041742

18051743
try {
1806-
// Clear all scheduled jobs
18071744
schedule.gracefulShutdown();
1808-
1809-
// Close database connection
18101745
if (this.client.db) {
18111746
this.client.db.close();
18121747
}
1813-
1814-
// Destroy Discord client
18151748
this.client.destroy();
1816-
18171749
this.debugConfig.log('Bot shutdown completed', 'shutdown', null, null, 'success');
18181750
} catch (error) {
18191751
this.debugConfig.log('Error during shutdown', 'shutdown', null, error, 'error');
18201752
}
18211753
}
18221754
}
18231755

1824-
// ===================================================================================
1825-
// == MAIN INITIALIZATION ============================================================
1826-
// ===================================================================================
1827-
18281756
async function main() {
18291757
try {
18301758
debugConfig.log('Initializing application...', 'init');
1831-
18321759
const requiredEnvVars = ['BOT_TOKEN', 'CLIENT_ID'];
18331760
const missing = requiredEnvVars.filter(varName => !process.env[varName]);
1834-
18351761
if (missing.length > 0) {
18361762
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
18371763
}
1838-
18391764
const database = await initializeDatabase();
18401765
debugConfig.log('Database initialized successfully', 'init');
1841-
18421766
const bot = new PulchowkBot(process.env.BOT_TOKEN, database);
1843-
18441767
process.on('SIGINT', async () => {
18451768
debugConfig.log('Received SIGINT signal, shutting down gracefully...', 'shutdown');
18461769
await bot.shutdown();
18471770
process.exit(0);
18481771
});
1849-
18501772
process.on('SIGTERM', async () => {
18511773
debugConfig.log('Received SIGTERM signal, shutting down gracefully...', 'shutdown');
18521774
await bot.shutdown();
18531775
process.exit(0);
18541776
});
1855-
18561777
await bot.start();
1857-
18581778
} catch (error) {
18591779
debugConfig.log('Critical application error', 'init', null, error, 'error');
18601780
console.error('Application failed to start:', error);

0 commit comments

Comments
 (0)