From 6cd135f7d467dc262f212a7bf971b6105a50a55f Mon Sep 17 00:00:00 2001 From: tresabhi Date: Sun, 23 Apr 2023 23:23:55 +0000 Subject: [PATCH] feat: inactive command --- src/commands/eligible.ts | 26 ++++++---- src/commands/inactive.ts | 96 +++++++++++++++++++++++++++++++++++++ src/types/accountInfo.ts | 57 ++++++++++++++++++++++ src/types/clanInfo.ts | 32 +++++++++++++ src/utilities/blitzLinks.ts | 8 +++- 5 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 src/commands/inactive.ts create mode 100644 src/types/accountInfo.ts create mode 100644 src/types/clanInfo.ts diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 781134054..0d9cd5860 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -12,8 +12,14 @@ import getBlitzStarsAccount from '../utilities/getBlitzStarsAccount.js'; import poweredByBlitzStars from '../utilities/poweredByBlitzStars.js'; export const CLANS = { - sklld: 'Skilled', - smri: 'Samurai', + sklld: { + name: 'Skilled', + id: 71559, + }, + smri: { + name: 'Samurai', + id: 91244, + }, }; export async function execute( @@ -90,15 +96,17 @@ export async function execute( new EmbedBuilder() .setTitle( `${data.nickname} is ${eligible ? '' : 'not '}eligible for ${ - CLANS[clan] + CLANS[clan].name }`, ) .setColor(eligible ? POSITIVE_COLOR : NEGATIVE_COLOR) .setDescription( `${ eligible - ? `${data.nickname} meets all the requirements set for ${CLANS[clan]}.` - : `${data.nickname}'s shortcomings for ${CLANS[clan]} (${ + ? `${data.nickname} meets all the requirements set for ${CLANS[clan].name}.` + : `${data.nickname}'s shortcomings for ${ + CLANS[clan].name + } (${ clan === 'sklld' ? '30 days stats' : 'career stats' }):\n\n${issues.join('\n')}` }\n\n${blitzLinks(data)}`, @@ -107,7 +115,9 @@ export async function execute( ], }); - console.log(`Showing ${data.nickname}'s eligibility for ${CLANS[clan]}`); + console.log( + `Showing ${data.nickname}'s eligibility for ${CLANS[clan].name}`, + ); }); }); } @@ -120,8 +130,8 @@ export const data = new SlashCommandBuilder() .setName('clan') .setDescription('The Skilled clan you are checking') .addChoices( - { name: CLANS.sklld, value: 'sklld' }, - { name: CLANS.smri, value: 'smri' }, + { name: CLANS.sklld.name, value: 'sklld' }, + { name: CLANS.smri.name, value: 'smri' }, ) .setRequired(true), ) diff --git a/src/commands/inactive.ts b/src/commands/inactive.ts new file mode 100644 index 000000000..83ede074a --- /dev/null +++ b/src/commands/inactive.ts @@ -0,0 +1,96 @@ +import { + CacheType, + ChatInputCommandInteraction, + EmbedBuilder, + SlashCommandBuilder, +} from 'discord.js'; +import fetch from 'node-fetch'; +import { NEGATIVE_COLOR, POSITIVE_COLOR } from '../constants/colors.js'; +import { AccountInfo } from '../types/accountInfo.js'; +import { ClanInfo } from '../types/clanInfo.js'; +import { CLANS } from './eligible.js'; + +const DEFAULT_THRESHOLD = 7; + +export async function execute( + interaction: ChatInputCommandInteraction, +) { + const threshold = + interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD; + const time = new Date().getTime() / 1000; + const clanName = interaction.options.getString('clan') as keyof typeof CLANS; + const clanData = (await ( + await fetch( + `https://api.wotblitz.com/wotb/clans/info/?application_id=${process.env.WARGAMING_APPLICATION_ID}&clan_id=${CLANS[clanName].id}`, + ) + ).json()) as ClanInfo; + const clan = clanData.data[CLANS[clanName].id]; + const memberIds = clan.members_ids; + const accountInfo = (await ( + await fetch( + `https://api.wotblitz.com/wotb/account/info/?application_id=${ + process.env.WARGAMING_APPLICATION_ID + }&account_id=${memberIds.join(',')}`, + ) + ).json()) as AccountInfo; + + const inactiveInfo = memberIds + .map((memberId) => { + const member = accountInfo.data[memberId]; + const inactiveDays = (time - member.last_battle_time) / 60 / 60 / 24; + + return [member.nickname, inactiveDays] as [string, number]; + }) + .filter(([, inactiveDays]) => inactiveDays >= threshold) + .sort((a, b) => b[1] - a[1]) + .map(([nickname, inactiveDays]) => { + const days = Math.floor(inactiveDays); + return `**${nickname}**: ${days} day${days === 1 ? '' : 's'}`; + }); + const hasInactiveMembers = inactiveInfo.length > 0; + + await interaction.reply({ + embeds: [ + new EmbedBuilder() + .setColor(hasInactiveMembers ? NEGATIVE_COLOR : POSITIVE_COLOR) + .setTitle( + hasInactiveMembers + ? `${CLANS[clanName].name}'s inactive members` + : `No inactive members in ${CLANS[clanName].name}`, + ) + .setDescription( + hasInactiveMembers + ? `Players that exceed the threshold of ${threshold} days:\n\n${inactiveInfo.join( + '\n', + )}` + : `No players exceed the threshold of ${threshold} days.`, + ), + ], + }); + + console.log( + `Displaying inactive members in ${CLANS[clanName].name} for ${threshold} days`, + ); +} + +export const data = new SlashCommandBuilder() + .setName('inactive') + .setDescription('Lists all inactive players') + .addStringOption((option) => + option + .setName('clan') + .setDescription('The Skilled clan you are checking') + .addChoices( + { name: CLANS.sklld.name, value: 'sklld' }, + { name: CLANS.smri.name, value: 'smri' }, + ) + .setRequired(true), + ) + .addNumberOption((option) => + option + .setName('threshold') + .setDescription( + `The number of days inactive (default: ${DEFAULT_THRESHOLD})`, + ) + .setMinValue(0), + ); diff --git a/src/types/accountInfo.ts b/src/types/accountInfo.ts new file mode 100644 index 000000000..5c25b1c1b --- /dev/null +++ b/src/types/accountInfo.ts @@ -0,0 +1,57 @@ +export interface AccountInfo { + data: { + [key: number]: { + statistics: { + clan: { + spotted: number; + max_frags_tank_id: number; + hits: number; + frags: number; + max_xp: number; + max_xp_tank_id: number; + wins: number; + losses: number; + capture_points: number; + battles: number; + damage_dealt: number; + damage_received: number; + max_frags: number; + shots: number; + frags8p: number; + xp: number; + win_and_survived: number; + survived_battles: number; + dropped_capture_points: number; + }; + all: { + spotted: number; + max_frags_tank_id: number; + hits: number; + frags: number; + max_xp: number; + max_xp_tank_id: number; + wins: number; + losses: number; + capture_points: number; + battles: number; + damage_dealt: number; + damage_received: number; + max_frags: number; + shots: number; + frags8p: number; + xp: number; + win_and_survived: number; + survived_battles: number; + dropped_capture_points: number; + }; + frags: null; + }; + account_id: number; + created_at: number; + updated_at: number; + private: null; + last_battle_time: number; + nickname: string; + }; + }; +} diff --git a/src/types/clanInfo.ts b/src/types/clanInfo.ts new file mode 100644 index 000000000..ea798643e --- /dev/null +++ b/src/types/clanInfo.ts @@ -0,0 +1,32 @@ +export interface ClanInfo { + data: { + [key: number]: { + recruiting_options: { + vehicles_level: number; + wins_ratio: number; + average_battles_per_day: number; + battles: number; + average_damage: number; + }; + members_count: number; + name: string; + creator_name: string; + clan_id: number; + created_at: number; + updated_at: number; + leader_name: string; + members_ids: number[]; + recruiting_policy: string; + tag: string; + is_clan_disbanded: boolean; + old_name: string; + emblem_set_id: number; + creator_id: number; + motto: string; + renamed_at: number; + old_tag: null; + leader_id: number; + description: string; + }; + }; +} diff --git a/src/utilities/blitzLinks.ts b/src/utilities/blitzLinks.ts index 18c79373a..4462e1310 100644 --- a/src/utilities/blitzLinks.ts +++ b/src/utilities/blitzLinks.ts @@ -1,5 +1,9 @@ import { PlayerStatistics } from '../types/statistics.js'; -export default function blitzLinks(data: PlayerStatistics) { - return `[View full stats](https://www.blitzstars.com/player/${data.region}/${data.nickname}) • [Support BlitzStars](https://www.blitzstars.com/supporters)`; +export default function blitzLinks(data?: PlayerStatistics) { + return `${ + data + ? `[View full stats](https://www.blitzstars.com/player/${data.region}/${data.nickname}) • ` + : '' + }[Support BlitzStars](https://www.blitzstars.com/supporters)`; }