From bc8a4fa143e3e7da394ed57f34ec203f98951211 Mon Sep 17 00:00:00 2001 From: Pfych Date: Sat, 18 Sep 2021 13:49:43 +1000 Subject: [PATCH] Tidied select code --- bot/.eslintrc.json | 5 +- bot/src/config.ts | 4 +- .../selectMenu/handleIsSelectMenu.ts | 12 +-- bot/src/profile/buildProfileEmbed.ts | 98 +++++++++++-------- bot/src/profile/fetch.ts | 9 +- bot/src/utils/utils.ts | 35 +++++++ 6 files changed, 105 insertions(+), 58 deletions(-) create mode 100644 bot/src/utils/utils.ts diff --git a/bot/.eslintrc.json b/bot/.eslintrc.json index 5cb359029..56c038c78 100644 --- a/bot/.eslintrc.json +++ b/bot/.eslintrc.json @@ -18,7 +18,10 @@ "rules": { "indent": [ "error", - "tab" + "tab", + { + "SwitchCase": 1 + } ], "linebreak-style": [ "error", diff --git a/bot/src/config.ts b/bot/src/config.ts index 85fc38e06..86bf3e1c4 100644 --- a/bot/src/config.ts +++ b/bot/src/config.ts @@ -1,5 +1,4 @@ /** @TODO Potentially re-work this to only run on PROD env, handy for DEV env! **/ -/** @deprecated replace with database call & cache */ export const allowedChannels = ["876321394005254214"]; export enum LoggerLayers { @@ -10,5 +9,6 @@ export enum LoggerLayers { botConfigSetup = "botConfigSetup", tachiFetch = "tachiFetch", profile = "profile", - selectInteractionHandler = "selectInteractionHandler" + selectInteractionHandler = "selectInteractionHandler", + buildProfileEmbed = "buildProfileEmbed" } diff --git a/bot/src/interactionHandlers/selectMenu/handleIsSelectMenu.ts b/bot/src/interactionHandlers/selectMenu/handleIsSelectMenu.ts index 08201f8d9..0f35e745b 100644 --- a/bot/src/interactionHandlers/selectMenu/handleIsSelectMenu.ts +++ b/bot/src/interactionHandlers/selectMenu/handleIsSelectMenu.ts @@ -1,9 +1,8 @@ import { Interaction } from "discord.js"; -import { UserGameStats } from "tachi-common"; import { LoggerLayers } from "../../config"; import { buildProfileIntractable } from "../../profile/buildProfileEmbed"; -import { TachiServerV1Get } from "../../utils/fetch-tachi"; import { createLayeredLogger } from "../../utils/logger"; +import { stringToSimpleGameType } from "../../utils/utils"; const logger = createLayeredLogger(LoggerLayers.selectInteractionHandler); @@ -12,12 +11,9 @@ export const handleIsSelectMenu = async (interaction: Interaction): Promise(`/users/${userId}/game-stats`))?.body; - if (userData) { - await interaction.update(buildProfileIntractable(userData, userId, interaction.values[0])); - } else { - throw new Error("Failed to re-fetch user data! This is a bad sign!"); - } + await interaction.update( + await buildProfileIntractable(userId, stringToSimpleGameType(interaction.values[0])) + ); } return; } catch (e) { diff --git a/bot/src/profile/buildProfileEmbed.ts b/bot/src/profile/buildProfileEmbed.ts index 68c836b39..9eadf151f 100644 --- a/bot/src/profile/buildProfileEmbed.ts +++ b/bot/src/profile/buildProfileEmbed.ts @@ -1,9 +1,29 @@ import { InteractionReplyOptions, MessageActionRow, MessageEmbed, MessagePayload, MessageSelectMenu } from "discord.js"; -import { FormatGame, Game, Playtypes, UserGameStats } from "tachi-common"; +import { Game, UserGameStats } from "tachi-common"; import { IDStrings, UGSRatingsLookup } from "tachi-common/js/types"; import { find } from "lodash"; +import { LoggerLayers } from "../config"; +import { TachiServerV1Get } from "../utils/fetch-tachi"; +import { createLayeredLogger } from "../utils/logger"; +import { formatGameWrapper, prettyRatingString, SimpleGameType, simpleGameTypeToString } from "../utils/utils"; -export const buildProfileEmbed = (data: UserGameStats[], game?: string): MessageEmbed => { +const logger = createLayeredLogger(LoggerLayers.buildProfileEmbed); + +const pullRatings = ( + ratings: Partial> +): string[] => { + const allRatings: string[] = []; + const RatingKeys = Object.keys(ratings); + + RatingKeys.map((rating) => { + const ratingValue: number = ratings[rating] || 0; + allRatings.push(`${prettyRatingString(rating)}: ${Math.round((ratingValue + Number.EPSILON) * 100) / 100}`); + }); + + return allRatings; +}; + +export const buildProfileEmbed = (data: UserGameStats[], game?: SimpleGameType): MessageEmbed => { const embed = new MessageEmbed().setColor("#cc527a"); /** @TODO FETCH USERS ACTUAL DETAILS */ @@ -13,27 +33,14 @@ export const buildProfileEmbed = (data: UserGameStats[], game?: string): Message embed.setThumbnail("https://cdn.mos.cms.futurecdn.net/mrArzwHcNuQbRwbEmuiwdJ.jpg"); if (game) { - const specificData: UserGameStats | undefined = find(data, (item) => game === `${item.game}:${item.playtype}`); - if (!specificData) { - throw new Error(`Could not get ratings for requested game: ${game}`); + const specificData: UserGameStats | undefined = find( + data, + (item) => simpleGameTypeToString(game) === `${item.game}:${item.playtype}` + ); + if (specificData) { + embed.addField(`Stats for: ${formatGameWrapper(game)}`, `${pullRatings(specificData.ratings).join("\n")}`); } else { - const ratings: string[] = []; - Object.keys(specificData.ratings).map((rating) => { - /** @TODO MAKE THIS ITS OWN FUNCTION THIS IS FILTHY */ - ratings.push( - `${rating}: ${ - Math.round( - (specificData.ratings[rating as UGSRatingsLookup[IDStrings]] || 0 + Number.EPSILON) * 100 - ) / 100 - }` - ); - }); - - /** @TODO DONT SPLIT THE STRING HERE HOLY SHIT */ - embed.addField( - `Stats for: ${FormatGame(game.split(":")[0] as Game, game.split(":")[1] as Playtypes[never])}`, - `${ratings.join("\n")}` - ); + throw new Error(`Could not get ratings for requested game: ${game}`); } } else { embed.addField("Select a game to see stats", "\u200B"); @@ -42,24 +49,35 @@ export const buildProfileEmbed = (data: UserGameStats[], game?: string): Message return embed; }; -export const buildProfileIntractable = ( - data: UserGameStats[], +export const buildProfileIntractable = async ( userId: string, - game?: string -): InteractionReplyOptions | MessagePayload => { - const dropdown = new MessageActionRow().addComponents( - new MessageSelectMenu() - .setCustomId(`SelectGameForProfile:${userId}`) - .setPlaceholder("Browse By Game") - .addOptions( - data.map((game) => { - return { - label: `${FormatGame(game.game, game.playtype)}`, - value: `${game.game}:${game.playtype}` - }; - }) - ) - ); + game?: SimpleGameType +): Promise => { + try { + const data = (await TachiServerV1Get(`/users/${userId}/game-stats`))?.body; + logger.verbose(data); - return { embeds: [buildProfileEmbed(data, game)], components: [dropdown] }; + if (data) { + const dropdown = new MessageActionRow().addComponents( + new MessageSelectMenu() + .setCustomId(`SelectGameForProfile:${userId}`) + .setPlaceholder("Browse By Game") + .addOptions( + data.map((game) => { + return { + label: `${formatGameWrapper(game)}`, + value: `${game.game}:${game.playtype}` + }; + }) + ) + ); + + return { embeds: [buildProfileEmbed(data, game)], components: [dropdown] }; + } else { + throw new Error(`No data found for user ${userId}`); + } + } catch (e) { + logger.error("Unable to build profile interactable"); + throw new Error("Unable to build profile interactable"); + } }; diff --git a/bot/src/profile/fetch.ts b/bot/src/profile/fetch.ts index c10c23779..64de84302 100644 --- a/bot/src/profile/fetch.ts +++ b/bot/src/profile/fetch.ts @@ -1,9 +1,7 @@ import { CommandInteraction } from "discord.js"; import { LoggerLayers } from "../config"; import { BotConfig } from "../setup"; -import { TachiServerV1Get } from "../utils/fetch-tachi"; import { createLayeredLogger } from "../utils/logger"; -import { UserGameStats } from "tachi-common"; import { buildProfileIntractable } from "./buildProfileEmbed"; const logger = createLayeredLogger(LoggerLayers.profile); @@ -13,11 +11,8 @@ export const getProfileByName = async (interaction: CommandInteraction): Promise const userId = interaction.options.getString("user", false) || "TODO FALLBACK TO SELF"; logger.info(`Fetching user ${userId}`); - const userData = (await TachiServerV1Get(`/users/${userId}/game-stats`))?.body; - logger.verbose(userData); - - if (userData) { - await interaction.reply(buildProfileIntractable(userData, userId)); + if (userId) { + await interaction.reply(await buildProfileIntractable(userId)); } else { await interaction.reply("No user data found for user"); } diff --git a/bot/src/utils/utils.ts b/bot/src/utils/utils.ts new file mode 100644 index 000000000..b9e0b70e3 --- /dev/null +++ b/bot/src/utils/utils.ts @@ -0,0 +1,35 @@ +import { FormatGame, Game, Playtypes } from "tachi-common"; +import { IDStrings, UGSRatingsLookup } from "tachi-common/js/types"; + +export interface SimpleGameType { + game: T; + playtype: Playtypes[T]; +} + +export const simpleGameTypeToString = (game: SimpleGameType): IDStrings => + `${game.game}:${game.playtype}`; + +export const stringToSimpleGameType = (game: string): SimpleGameType => { + return { game: game.split(":")[0], playtype: game.split(":")[1] }; +}; + +export const formatGameWrapper = (game: SimpleGameType): string => FormatGame(game.game, game.playtype); + +export const prettyRatingString = (rating: UGSRatingsLookup[I]): string => { + switch (rating) { + case "ktRating": + return "Kamai Rating"; + case "ktLampRating": + return "Kamai Lamp Rating"; + case "sieglinde": + return "???"; + case "VF6": + return "Volforce"; + case "BPI": + return "BPI"; + case "MFCP": + return "???"; + default: + return "Skill"; + } +};