From 02a03b4d685fb22e9bf8243ce2a39c025dc5f978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:42:15 -0600 Subject: [PATCH] feat: advanced PSAs --- src/core/blitz/getRatingsInfo.ts | 4 +- src/core/blitzkrieg/patientFetch.ts | 13 ++++- src/core/discord/psa.ts | 26 +++++++-- .../handlers/chatInputCommand.ts | 56 ++++++++++++++++++- 4 files changed, 87 insertions(+), 12 deletions(-) diff --git a/src/core/blitz/getRatingsInfo.ts b/src/core/blitz/getRatingsInfo.ts index 15dc750f2..6c77df9f7 100644 --- a/src/core/blitz/getRatingsInfo.ts +++ b/src/core/blitz/getRatingsInfo.ts @@ -1,15 +1,17 @@ import { RatingsInfo } from '../../commands/ratings'; import { Region } from '../../constants/regions'; import { context } from '../blitzkrieg/context'; +import { patientFetch } from '../blitzkrieg/patientFetch'; import regionToRegionSubdomain from './regionToRegionSubdomain'; export default async function getRatingsInfo(region: Region) { - const response = await fetch( + const response = await patientFetch( context === 'website' ? `/api/${region}/ratings/current/info` : `https://${regionToRegionSubdomain( region, )}.wotblitz.com/en/api/rating-leaderboards/season/`, + undefined, { cache: 'no-store' }, ); diff --git a/src/core/blitzkrieg/patientFetch.ts b/src/core/blitzkrieg/patientFetch.ts index 4a8d17121..ebb4e1f71 100644 --- a/src/core/blitzkrieg/patientFetch.ts +++ b/src/core/blitzkrieg/patientFetch.ts @@ -1,11 +1,18 @@ -export async function patientFetch(url: string, timeout = 1000) { +export async function patientFetch( + url: string, + timeout = 1000, + options?: Partial<{ cache: 'no-store' }>, +) { let patientResponse: Response; while (patientResponse! === undefined) { try { - patientResponse = await fetch(url); + patientResponse = await fetch(url, options); } catch (error) { - console.warn(`Failed to fetch ${url}; retrying in ${timeout}ms...`); + console.warn( + `Failed to fetch ${url}; retrying in ${timeout}ms...`, + error, + ); await new Promise((resolve) => setTimeout(resolve, timeout)); } } diff --git a/src/core/discord/psa.ts b/src/core/discord/psa.ts index 06441f663..7fd6fff7c 100644 --- a/src/core/discord/psa.ts +++ b/src/core/discord/psa.ts @@ -1,13 +1,29 @@ -export interface PSAData { - title: string; - description: string; -} +export type PSAData = { + secret?: boolean; + links?: { + title: string; + url: string; + }[]; +} & ( + | { + type: 'image'; + image: string; + title?: string; + } + | { + type: 'embed'; + title: string; + description: string; + } +); export interface PSA { data: PSAData | null; } -export const psa: PSA = { data: null }; +export const psa: PSA = { + data: null, +}; fetch( 'https://gist.githubusercontent.com/tresabhi/ed4b136f08856e615212e573aabe1968/raw', diff --git a/src/events/interactionCreate/handlers/chatInputCommand.ts b/src/events/interactionCreate/handlers/chatInputCommand.ts index fbad9dc6b..471d08248 100644 --- a/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -1,13 +1,16 @@ import { ActionRowBuilder, + AttachmentBuilder, ButtonBuilder, ButtonStyle, CacheType, ChatInputCommandInteraction, + InteractionReplyOptions, } from 'discord.js'; import { commands } from '..'; import discord from '../../../../discord.json' assert { type: 'json' }; import { UserError } from '../../../core/blitzkrieg/userError'; +import buttonLink from '../../../core/discord/buttonLink'; import embedNegative from '../../../core/discord/embedNegative'; import embedWarning from '../../../core/discord/embedWarning'; import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable'; @@ -40,12 +43,59 @@ export default async function handleChatInputCommand( const reply = await normalizeInteractionReturnable(returnable!); - if (psa.data) { - if (!reply.embeds) reply.embeds = []; - reply.embeds.push(embedWarning(psa.data.title, psa.data.description)); + if (psa.data && !psa.data.secret) { + if (psa.data.type === 'embed') { + if (!reply.embeds) reply.embeds = []; + reply.embeds.push(embedWarning(psa.data.title, psa.data.description)); + } else { + if (!reply.files) reply.files = []; + reply.files.push(new AttachmentBuilder(psa.data.image)); + reply.content = reply.content ?? psa.data.title; + } + + if (psa.data.links) { + if (!reply.components?.[0]) { + reply.components = [new ActionRowBuilder()]; + } + + (reply.components[0] as ActionRowBuilder).addComponents( + psa.data.links.map(({ title, url }) => buttonLink(url, title)), + ); + } } await interaction.editReply(reply); + + if (psa.data && psa.data.secret) { + const followUp: InteractionReplyOptions = { + ephemeral: true, + }; + + if (psa.data.type === 'embed') { + if (!followUp.embeds) followUp.embeds = []; + followUp.embeds.push( + embedWarning(psa.data.title, psa.data.description), + ); + } else { + if (!followUp.files) followUp.files = []; + followUp.files.push(new AttachmentBuilder(psa.data.image)); + followUp.content = followUp.content ?? psa.data.title; + } + + if (psa.data.links) { + if (!followUp.components?.[0]) { + followUp.components = [new ActionRowBuilder()]; + } + + ( + followUp.components[0] as ActionRowBuilder + ).addComponents( + psa.data.links.map(({ title, url }) => buttonLink(url, title)), + ); + } + + interaction.followUp(followUp); + } } catch (error) { const components = [ new ActionRowBuilder().addComponents(