diff --git a/packages/bot/src/commands/notifications.ts b/packages/bot/src/commands/notifications.ts index 48ae895..fb040e9 100644 --- a/packages/bot/src/commands/notifications.ts +++ b/packages/bot/src/commands/notifications.ts @@ -9,7 +9,7 @@ import { StringSelectMenuOptionBuilder, } from "@discordjs/builders"; import { storeComponents } from "../util/components"; -import { ButtonStyle, MessageFlags } from "discord-api-types/v10"; +import { ButtonStyle, ChannelType, MessageFlags } from "discord-api-types/v10"; import { transformLocalizations, uni } from "../util/l10n"; import { colors } from "../util/colors"; import { InteractionContext } from "../interactions"; @@ -44,14 +44,24 @@ const s = transformLocalizations({ deactivate: "Deactivate", channel: "Channel", preview: "Preview", + previewDescription: + "Sent 6 hours before game time. Shows location, tickets, & records", threads: "Threads", + threadsDescription: "Public chat thread under the preview or start message", hype: "Hype messages", start: "Game start", + startDescription: "First period started", periods: "Periods", + periodsDescription: "Any period started", goals: "Goals", + goalsDescription: "A goal was scored by either team", penalties: "Penalties", + penaltiesDescription: "Either team was penalized", end: "Game end", + endDescription: "Last period ended", final: "Game final", + finalDescription: + "Final score posted online. Stats shouldn't change after this", }, fr: { settings: "Paramètres de notification", @@ -97,10 +107,30 @@ const getComponents = async ( ctx: InteractionContext, league: League, channelId: string, + channelType: ChannelType, sendConfig?: NotificationSendConfig, teamIds?: string[], active?: boolean, ) => { + const allFeatures = [ + "preview", + "threads", + "start", + "periods", + "goals", + "end", + "final", + ] as const; + const features = allFeatures; + // I was going to do this in order to allow announcement channels but I decided + // against it because the type can be swapped with the same channel ID, rendering + // thread creation suddenly broken. The only workaround as far as I know would be + // to get every channel every time to make sure it hasn't changed, which is wasteful. + // Keeping this snippet for posterity in case I try again. + // .filter( + // (f) => !(channelType === ChannelType.GuildAnnouncement && f === "threads"), + // ); + return [ new ActionRowBuilder().addComponents( await storeComponents(ctx.env.KV, [ @@ -133,6 +163,7 @@ const getComponents = async ( componentOnce: true, league, channelId, + channelType, }, ]), ), @@ -140,24 +171,13 @@ const getComponents = async ( await storeComponents(ctx.env.KV, [ new StringSelectMenuBuilder() .setPlaceholder(s(ctx, "selectFeatures")) - .setMaxValues(7) + .setMaxValues(features.length) .addOptions( - ( - [ - "preview", - "threads", - // "hype", - "start", - "periods", - "goals", - // "penalties", - "end", - "final", - ] as const - ).map( + features.map( (feature) => new StringSelectMenuOptionBuilder({ label: s(ctx, feature), + description: s(ctx, `${feature}Description`), value: feature, default: sendConfig ? sendConfig[feature] : false, }), @@ -169,6 +189,7 @@ const getComponents = async ( componentOnce: true, league, channelId, + channelType, }, ]), ), @@ -184,6 +205,7 @@ const getComponents = async ( componentOnce: true, league, channelId, + channelType, }, ]), ), @@ -217,6 +239,7 @@ export const notificationsCallback: ChatInputAppCommandCallback = async ( ctx, league, channel.id, + channel.type, settings?.sendConfig, settings?.teamIds, settings?.active ?? undefined, @@ -243,6 +266,7 @@ export const selectNotificationTeamCallback: SelectMenuCallback = async ( const state = ctx.state as MinimumKVComponentState & { league: League; channelId: string; + channelType: ChannelType; }; const teamIds = ctx.interaction.data.values; @@ -269,6 +293,7 @@ export const selectNotificationTeamCallback: SelectMenuCallback = async ( ctx, state.league, state.channelId, + state.channelType, settings?.sendConfig, teamIds, ), @@ -281,6 +306,7 @@ export const selectNotificationFeaturesCallback: SelectMenuCallback = async ( const state = ctx.state as MinimumKVComponentState & { league: League; channelId: string; + channelType: ChannelType; }; const featureValues = ctx.interaction.data .values as (keyof NotificationSendConfig)[]; @@ -330,6 +356,7 @@ export const selectNotificationFeaturesCallback: SelectMenuCallback = async ( ctx, state.league, state.channelId, + state.channelType, settings.sendConfig, settings.teamIds, ), @@ -342,6 +369,7 @@ export const toggleNotificationActiveButtonCallback: ButtonCallback = async ( const state = ctx.state as MinimumKVComponentState & { league: League; channelId: string; + channelType: ChannelType; }; const db = getDb(ctx.env.DB); const settings = await db.query.notifications.findFirst({ @@ -380,6 +408,7 @@ export const toggleNotificationActiveButtonCallback: ButtonCallback = async ( ctx, state.league, state.channelId, + state.channelType, settings?.sendConfig, settings?.teamIds, active, diff --git a/packages/bot/src/cron.ts b/packages/bot/src/cron.ts index 3100f12..6604648 100644 --- a/packages/bot/src/cron.ts +++ b/packages/bot/src/cron.ts @@ -17,6 +17,7 @@ import { Goal, Penalty, Period, + Periods, PlayerInfo, ScorebarMatch, } from "hockeytech"; @@ -560,6 +561,12 @@ export const checkPosts = async ( const getSummary = async () => (await client.getGameSummary(Number(game.ID))).GC.Gamesummary; + const score = [Number(game.VisitorGoals), Number(game.HomeGoals)]; + const totalScore = score[0] + score[1]; + const totalPriorScore = dbGame + ? dbGame.lastKnownAwayGoals + dbGame.lastKnownHomeGoals + : 0; + const periodChannels = filterConfigChannels( channelConfigs, (c) => c.periods, @@ -580,6 +587,7 @@ export const checkPosts = async ( if ( dbGame?.lastKnownPeriodId !== game.Period && periodChannels.length !== 0 + // (game.Period === "1" ? totalScore === 0 : true) ) { if (!summary) summary = await getSummary(); const period = @@ -588,13 +596,13 @@ export const checkPosts = async ( Object.keys(summary.periods)[ Object.keys(summary.periods).length - 1 ], - ) as 1 | 2 | 3 + ) as keyof Periods ]; for (const channelId of [ ...periodChannels, ...(game.Period === "1" ? startChannels : []), - ]) { + ].filter((c, i, a) => a.indexOf(c) === i)) { ctx.waitUntil( logErrors( (async () => { @@ -603,7 +611,9 @@ export const checkPosts = async ( { body: { content: `**${period?.long_name} Period Starting - ${game.VisitorCode} @ ${game.HomeCode}**`, - embeds: [getHtStatusEmbed(env, summary)], + embeds: [ + getHtStatusEmbed(env, summary, game.GameStatus), + ], }, }, )) as APIMessage; @@ -657,12 +667,6 @@ export const checkPosts = async ( } } - const score = [Number(game.VisitorGoals), Number(game.HomeGoals)]; - const totalScore = score[0] + score[1]; - const totalPriorScore = dbGame - ? dbGame.lastKnownAwayGoals + dbGame.lastKnownHomeGoals - : 0; - if (totalScore > totalPriorScore && goalChannels.length !== 0) { if (!summary) summary = await getSummary(); @@ -862,7 +866,6 @@ export const checkPosts = async ( }); } if (postedFinalIds.length !== 0) { - console.log(`Inserting ${postedFinalIds.length} final records`) await db .insert(games) .values( diff --git a/packages/bot/src/db/schema.ts b/packages/bot/src/db/schema.ts index b0bad30..f9920e0 100644 --- a/packages/bot/src/db/schema.ts +++ b/packages/bot/src/db/schema.ts @@ -22,6 +22,7 @@ export const notifications = sqliteTable( id: integer("id").primaryKey({ autoIncrement: true }), league: text("league").$type().notNull(), channelId: snowflake("channelId").notNull(), + // channelType: integer("channelType").notNull().$type().default(ChannelType.GuildText), teamIds: text("teamIds", { mode: "json" }) .$type() .notNull()