Skip to content

Conversation

@GalvinPython
Copy link
Owner

This PR just adds guild events into the database and bot. Merging into the refactor/database branch because well.. it updates the database

@GalvinPython GalvinPython added this to the 2.0.0 milestone Jul 18, 2025
@GalvinPython GalvinPython requested a review from Copilot July 18, 2025 14:00
@GalvinPython GalvinPython self-assigned this Jul 18, 2025
@GalvinPython GalvinPython added enhancement New feature or request component: bot labels Jul 18, 2025
@GalvinPython GalvinPython moved this to In review in Feedr Jul 18, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements guild event handling for a Discord bot by adding database tracking for guild joins/leaves and synchronization logic for guilds that changed while the bot was offline. The implementation includes real-time event handlers and a startup reconciliation process.

  • Adds Discord guild event handlers for GuildCreate and GuildDelete events with database integration
  • Implements startup synchronization to detect and update guilds that were added/removed while offline
  • Extends the database schema with a memberCount field and adds helper functions for guild management

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/utils/discord/updateGuildsOnStartup.ts Startup reconciliation logic to sync guild state between Discord cache and database
src/index.ts Integration of startup guild synchronization into bot initialization
src/events/guildDelete.ts Event handler for when the bot leaves a guild
src/events/guildCreate.ts Event handler for when the bot joins a new guild
src/db/schema.ts Database schema update adding memberCount field
src/db/discord.ts Helper functions for adding and removing guilds from database tracking

Comment on lines 40 to 77
missingGuilds.forEach(async (guild) => {
console.log(`Removing guild from tracking: ${guild.guildId}`);
const result = await db
.update(dbDiscordTable)
.set({ isInServer: false })
.where(eq(dbDiscordTable.guildId, guild.guildId))
.returning();

if (result) {
console.log(
`Successfully removed guild ${guild.guildId} from tracking.`,
);
} else {
console.error(
`Failed to remove guild ${guild.guildId} from tracking.`,
);
}
});

newGuilds.forEach(async (guildId) => {
console.log(`Adding new guild to tracking: ${guildId}`);
const result = await db
.insert(dbDiscordTable)
.values({
guildId,
allowedPublicSharing: false,
feedrUpdatesChannelId: null,
isInServer: true,
memberCount: 0,
})
.returning();

if (result) {
console.log(`Successfully added guild ${guildId} to tracking.`);
} else {
console.error(`Failed to add guild ${guildId} to tracking.`);
}
});
Copy link

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using forEach with async callbacks can lead to unhandled promise rejections and doesn't properly handle errors. Use Promise.all with map or a for...of loop instead.

Suggested change
missingGuilds.forEach(async (guild) => {
console.log(`Removing guild from tracking: ${guild.guildId}`);
const result = await db
.update(dbDiscordTable)
.set({ isInServer: false })
.where(eq(dbDiscordTable.guildId, guild.guildId))
.returning();
if (result) {
console.log(
`Successfully removed guild ${guild.guildId} from tracking.`,
);
} else {
console.error(
`Failed to remove guild ${guild.guildId} from tracking.`,
);
}
});
newGuilds.forEach(async (guildId) => {
console.log(`Adding new guild to tracking: ${guildId}`);
const result = await db
.insert(dbDiscordTable)
.values({
guildId,
allowedPublicSharing: false,
feedrUpdatesChannelId: null,
isInServer: true,
memberCount: 0,
})
.returning();
if (result) {
console.log(`Successfully added guild ${guildId} to tracking.`);
} else {
console.error(`Failed to add guild ${guildId} to tracking.`);
}
});
for (const guild of missingGuilds) {
try {
console.log(`Removing guild from tracking: ${guild.guildId}`);
const result = await db
.update(dbDiscordTable)
.set({ isInServer: false })
.where(eq(dbDiscordTable.guildId, guild.guildId))
.returning();
if (result) {
console.log(
`Successfully removed guild ${guild.guildId} from tracking.`,
);
} else {
console.error(
`Failed to remove guild ${guild.guildId} from tracking.`,
);
}
} catch (error) {
console.error(
`Error while removing guild ${guild.guildId} from tracking:`,
error,
);
}
}
for (const guildId of newGuilds) {
try {
console.log(`Adding new guild to tracking: ${guildId}`);
const result = await db
.insert(dbDiscordTable)
.values({
guildId,
allowedPublicSharing: false,
feedrUpdatesChannelId: null,
isInServer: true,
memberCount: 0,
})
.returning();
if (result) {
console.log(`Successfully added guild ${guildId} to tracking.`);
} else {
console.error(`Failed to add guild ${guildId} to tracking.`);
}
} catch (error) {
console.error(
`Error while adding guild ${guildId} to tracking:`,
error,
);
}
}

Copilot uses AI. Check for mistakes.
.where(eq(dbDiscordTable.guildId, guild.guildId))
.returning();

if (result) {
Copy link

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition if (result) is incorrect. Database update operations return an array, which is always truthy even when empty. Check result.length > 0 instead.

Suggested change
if (result) {
if (result.length > 0) {

Copilot uses AI. Check for mistakes.
})
.returning();

if (result) {
Copy link

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition if (result) is incorrect. Database insert operations return an array, which is always truthy even when empty. Check result.length > 0 instead.

Suggested change
if (result) {
if (result.length > 0) {

Copilot uses AI. Check for mistakes.
console.log("Waiting for guilds to load...");
currentGuilds = client.guilds.cache.map((guild) => guild.id);
if (currentGuilds.length === 0) {
await new Promise((resolve) => setTimeout(resolve, 10000));
Copy link

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The 10-second timeout is a magic number. Consider extracting this to a named constant like GUILD_LOAD_RETRY_INTERVAL for better maintainability.

Suggested change
await new Promise((resolve) => setTimeout(resolve, 10000));
await new Promise((resolve) => setTimeout(resolve, GUILD_LOAD_RETRY_INTERVAL));

Copilot uses AI. Check for mistakes.
GalvinPython and others added 3 commits July 18, 2025 15:46
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@GalvinPython GalvinPython merged commit 175abe2 into refactor/database Jul 18, 2025
1 check passed
@github-project-automation github-project-automation bot moved this from In review to Done in Feedr Jul 18, 2025
@GalvinPython GalvinPython deleted the feat/guild-events branch July 18, 2025 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: bot enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants