diff --git a/src/discord/bot.ts b/src/discord/bot.ts index 350042f..0172cb8 100644 --- a/src/discord/bot.ts +++ b/src/discord/bot.ts @@ -1,6 +1,7 @@ import type { Client } from "discord.js"; import type { AppConfig } from "../config"; import { createDb } from "../db"; +import { logger } from "../logger"; import { BoosterRoleService } from "../services/boosterRoleService"; import { DrizzleBoosterRoleStore } from "../services/drizzleBoosterRoleStore"; import { DiscordRoleRepository } from "../services/discordRoleRepository"; @@ -33,9 +34,12 @@ export function attachBotHandlers(client: Client, config: AppConfig): void { const hadBooster = oldMember.roles.cache.has(eligibilityRoleId); const hasBooster = newMember.roles.cache.has(eligibilityRoleId); if (!hadBooster && hasBooster && config.boosterGreetingChannelId) { - await sendBoostGreeting(newMember, config.boosterGreetingChannelId).catch((err) => { - logger.error("Failed to send boost greeting", { error: String(err), userId: newMember.id }); - }); + const channel = newMember.guild.channels.cache.get(config.boosterGreetingChannelId); + if (channel && "send" in channel) { + await sendBoostGreeting(channel as { send(input: { content: string }): Promise }, newMember.id, config.boosterGreetingChannelId).catch((err) => { + logger.error("Failed to send boost greeting", { error: String(err), userId: newMember.id }); + }); + } } // Handle boost loss (existing behaviour) diff --git a/src/discord/events/boostGreeting.test.ts b/src/discord/events/boostGreeting.test.ts new file mode 100644 index 0000000..c727a9b --- /dev/null +++ b/src/discord/events/boostGreeting.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, test } from "bun:test"; +import { sendBoostGreeting } from "./boostGreeting"; + +describe("sendBoostGreeting", () => { + test("sends boost greeting to the given channel", async () => { + const sent: string[] = []; + const channel = { + send: async (input: { content: string }): Promise => { + sent.push(input.content); + }, + }; + + await sendBoostGreeting(channel, "user-123", "channel-456"); + + expect(sent.length).toBe(1); + expect(sent[0]).toContain("Thank you for boosting"); + expect(sent[0]).toContain("<@user-123>"); + expect(sent[0]).toContain("/booster-role claim"); + expect(sent[0]).toContain("<#channel-456>"); + }); + + test("handles different user and channel IDs", async () => { + const sent: string[] = []; + const channel = { + send: async (input: { content: string }): Promise => { + sent.push(input.content); + }, + }; + + await sendBoostGreeting(channel, "other-user", "other-channel"); + + expect(sent[0]).toContain("<@other-user>"); + expect(sent[0]).toContain("<#other-channel>"); + }); +}); diff --git a/src/discord/events/boostGreeting.ts b/src/discord/events/boostGreeting.ts index 107604a..88ff1b2 100644 --- a/src/discord/events/boostGreeting.ts +++ b/src/discord/events/boostGreeting.ts @@ -1,50 +1,19 @@ import { logger } from "../../logger"; -type GuildTextChannel = { - send(input: { content: string }): Promise; -}; - -type GuildMemberLike = { - id: string; - user?: { id: string }; - guild: { - id: string; - channels: { - cache: { - get(channelId: string): GuildTextChannel | undefined; - }; - }; - }; -}; - /** - * Sends a welcome message to the configured greeting channel. - * Call this after confirming the member newly gained the booster eligibility role. + * Sends a welcome message via the given channel when a member newly + * acquires the booster eligibility role (i.e. just boosted the server). */ export async function sendBoostGreeting( - member: GuildMemberLike, + channel: { send(input: { content: string }): Promise }, + userId: string, greetingChannelId: string, ): Promise { - const channel = member.guild.channels.cache.get(greetingChannelId); - - if (!channel) { - logger.warn("Boost greeting channel not found", { - channelId: greetingChannelId, - guildId: member.guild.id, - }); - return; - } - - const mention = member.user?.id ?? member.id; const message = - `🎉 Thank you for boosting <@${mention}>! ` + + `🎉 Thank you for boosting <@${userId}>! ` + `You can now claim a custom role using \`/booster-role claim\` in <#${greetingChannelId}>.`; await channel.send({ content: message }); - logger.info("Boost greeting sent", { - userId: member.id, - guildId: member.guild.id, - channelId: greetingChannelId, - }); + logger.info("Boost greeting sent", { userId, channelId: greetingChannelId }); }