diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 13d704eed..c59b37b6f 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -49,21 +49,21 @@ export default { ) .addStringOption((option) => option - .setName('ign') + .setName('name') .setDescription('The username you use in Blitz') .setRequired(true), ), execute(interaction) { - const ign = interaction.options.getString('ign')!; + const name = interaction.options.getString('name')!; const server = interaction.options.getString('server') as BlitzServer; const clan = interaction.options.getString('clan') as keyof typeof CLANS; - getBlitzAccount(interaction, ign, server, async (account) => { + getBlitzAccount(interaction, name, server, async (account) => { getBlitzStarsAccount( interaction, account.account_id, - ign, + name, async (data) => { const issues: string[] = []; diff --git a/src/commands/inactive.ts b/src/commands/inactive.ts index 417216258..ba58200b1 100644 --- a/src/commands/inactive.ts +++ b/src/commands/inactive.ts @@ -2,28 +2,36 @@ import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; import fetch from 'node-fetch'; import { CommandRegistry } from '../behaviors/interactionCreate.js'; import { NEGATIVE_COLOR, POSITIVE_COLOR } from '../constants/colors.js'; +import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; import { ClanDetails } from '../types/clanDetails.js'; import { PlayerPersonalData } from '../types/playerPersonalData.js'; -import { CLANS } from './eligible.js'; +import getClan from '../utilities/getClan.js'; const DEFAULT_THRESHOLD = 7; export default { inProduction: true, inDevelopment: false, - inPublic: false, + inPublic: true, command: new SlashCommandBuilder() .setName('inactive') .setDescription('Lists all inactive players') .addStringOption((option) => option - .setName('clan') - .setDescription('The Skilled clan you are checking') + .setName('server') + .setDescription('The Blitz server you are in') + .setRequired(true) .addChoices( - { name: CLANS.sklld.name, value: 'sklld' }, - { name: CLANS.smri.name, value: 'smri' }, - ) + { name: BLITZ_SERVERS.com, value: 'com' }, + { name: BLITZ_SERVERS.eu, value: 'eu' }, + { name: BLITZ_SERVERS.asia, value: 'asia' }, + ), + ) + .addStringOption((option) => + option + .setName('name') + .setDescription('The clan name or tag you are checking') .setRequired(true), ) .addNumberOption((option) => @@ -36,63 +44,64 @@ export default { ), async execute(interaction) { - 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 ClanDetails; - const clan = clanData.data[CLANS[clanName].id]; - const memberIds = clan.members_ids; - const playerPersonalData = (await ( - await fetch( - `https://api.wotblitz.com/wotb/account/info/?application_id=${ - process.env.WARGAMING_APPLICATION_ID - }&account_id=${memberIds.join(',')}`, - ) - ).json()) as PlayerPersonalData; + const name = interaction.options.getString('name')!; + const server = interaction.options.getString('server') as BlitzServer; - const inactiveInfo = memberIds - .map((memberId) => { - const member = playerPersonalData.data[memberId]; - const inactiveDays = (time - member.last_battle_time) / 60 / 60 / 24; + getClan(interaction, name, server, async (clan) => { + const threshold = + interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD; + const time = new Date().getTime() / 1000; + const clanData = (await ( + await fetch( + `https://api.wotblitz.com/wotb/clans/info/?application_id=${process.env.WARGAMING_APPLICATION_ID}&clan_id=${clan.clan_id}`, + ) + ).json()) as ClanDetails; + const memberIds = clanData.data[clan.clan_id].members_ids; + const playerPersonalData = (await ( + await fetch( + `https://api.wotblitz.com/wotb/account/info/?application_id=${ + process.env.WARGAMING_APPLICATION_ID + }&account_id=${memberIds.join(',')}`, + ) + ).json()) as PlayerPersonalData; - return [member.nickname, inactiveDays] as const; - }) - .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 inactiveInfo = memberIds + .map((memberId) => { + const member = playerPersonalData.data[memberId]; + const inactiveDays = (time - member.last_battle_time) / 60 / 60 / 24; + + return [member.nickname, inactiveDays] as const; + }) + .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 + ? `${clan.name}'s inactive members` + : `No inactive members in ${clan.name}`, + ) + .setDescription( + hasInactiveMembers + ? `Players that exceed the threshold of ${threshold} days:\n\n${inactiveInfo.join( + '\n', + )}` + : `No players exceed the threshold of ${threshold} days.`, + ), + ], }); - 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 ${clan.name} for ${threshold} days`, + ); }); - - console.log( - `Displaying inactive members in ${CLANS[clanName].name} for ${threshold} days`, - ); }, } satisfies CommandRegistry; diff --git a/src/commands/stats.ts b/src/commands/stats.ts index 052ecefe8..6b16b0bbc 100644 --- a/src/commands/stats.ts +++ b/src/commands/stats.ts @@ -9,7 +9,7 @@ import poweredByBlitzStars from '../utilities/poweredByBlitzStars.js'; export default { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: new SlashCommandBuilder() @@ -39,24 +39,24 @@ export default { ) .addStringOption((option) => option - .setName('ign') + .setName('name') .setDescription('The username you use in Blitz') .setRequired(true), ), execute(interaction) { - const ign = interaction.options.getString('ign')!; + const name = interaction.options.getString('name')!; const server = interaction.options.getString('server') as BlitzServer; const period = interaction.options.getString('period')! as | '30' | '90' | 'career'; - getBlitzAccount(interaction, ign, server, async (account) => { + getBlitzAccount(interaction, name, server, async (account) => { getBlitzStarsAccount( interaction, account.account_id, - ign, + name, async (data) => { { const stats = diff --git a/src/commands/tanks.ts b/src/commands/tanks.ts index 631dfb888..1334c7552 100644 --- a/src/commands/tanks.ts +++ b/src/commands/tanks.ts @@ -28,7 +28,7 @@ export default { ) .addStringOption((option) => option - .setName('ign') + .setName('name') .setDescription('The username you use in Blitz') .setRequired(true), ) @@ -43,10 +43,10 @@ export default { execute(interaction) { const server = interaction.options.getString('server') as BlitzServer; - const ign = interaction.options.getString('ign')!; + const name = interaction.options.getString('name')!; const tier = Math.round(interaction.options.getNumber('tier')!); - getBlitzAccount(interaction, ign, server, async (account) => { + getBlitzAccount(interaction, name, server, async (account) => { const tankStats = (await ( await fetch( `https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${process.env.WARGAMING_APPLICATION_ID}&account_id=${account.account_id}`, diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 3223443d1..c681e35d8 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -28,16 +28,16 @@ export default { ) .addStringOption((option) => option - .setName('ign') + .setName('name') .setDescription('The username you use in Blitz') .setRequired(true), ), execute(interaction) { - const ign = interaction.options.getString('ign')!; + const name = interaction.options.getString('name')!; const server = interaction.options.getString('server') as BlitzServer; - getBlitzAccount(interaction, ign, server, async (account) => { + getBlitzAccount(interaction, name, server, async (account) => { // good match const clanData = (await fetch( `https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${process.env.WARGAMING_APPLICATION_ID}&account_id=${account.account_id}&extra=clan`, @@ -51,7 +51,7 @@ export default { ); member - ?.setNickname(`${ign}${clanTag}`) + ?.setNickname(`${name}${clanTag}`) .then(async () => { await member.roles.remove(discord.verify_role); await member.roles.add(discord.peasant_role); @@ -61,13 +61,13 @@ export default { .setColor(POSITIVE_COLOR) .setTitle(`${interaction.user.username} is verified`) .setDescription( - `The user is now verified as ${ign}${clanTag}`, + `The user is now verified as ${name}${clanTag}`, ), ], }); console.log( - `${interaction.user.username} verified as ${ign}${clanTag}`, + `${interaction.user.username} verified as ${name}${clanTag}`, ); }) .catch(async () => { @@ -83,7 +83,7 @@ export default { }); console.warn( - `${interaction.user.username} failed to verify as ${ign}${clanTag}`, + `${interaction.user.username} failed to verify as ${name}${clanTag}`, ); }); } diff --git a/src/types/clanDetails.ts b/src/types/clanDetails.ts index 7d52db452..333b35674 100644 --- a/src/types/clanDetails.ts +++ b/src/types/clanDetails.ts @@ -1,34 +1,34 @@ import { WargamingResponse } from './wargamingResponse.js'; -export interface ClanDetails extends WargamingResponse { - data: { - [accountId: 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; - }; +export interface ClanDetailsData { + 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; +} + +export interface ClanDetails extends WargamingResponse { + data: { [accountId: number]: ClanDetailsData }; } diff --git a/src/types/clanList.ts b/src/types/clanList.ts new file mode 100644 index 000000000..c35572f56 --- /dev/null +++ b/src/types/clanList.ts @@ -0,0 +1,13 @@ +import { WargamingResponse } from './wargamingResponse.js'; + +export interface Clan { + members_count: number; + created_at: number; + clan_id: number; + tag: string; + name: string; +} + +export interface ClanList extends WargamingResponse { + data: Clan[]; +} diff --git a/src/utilities/getBlitzAccount.ts b/src/utilities/getBlitzAccount.ts index d4437494c..d74f26195 100644 --- a/src/utilities/getBlitzAccount.ts +++ b/src/utilities/getBlitzAccount.ts @@ -10,19 +10,19 @@ import { Player, Players } from '../types/players.js'; export default async function getBlitzAccount( interaction: ChatInputCommandInteraction, - ign: string, + name: string, server: BlitzServer, callback: (account: Player) => void, ) { const serverName = BLITZ_SERVERS[server]; const players = (await fetch( - `https://api.wotblitz.${server}/wotb/account/list/?application_id=${process.env.WARGAMING_APPLICATION_ID}&search=${ign}`, + `https://api.wotblitz.${server}/wotb/account/list/?application_id=${process.env.WARGAMING_APPLICATION_ID}&search=${name}`, ).then((response) => response.json())) as Players; if ( players.status === 'ok' && players.data.length > 0 && - players.data[0].nickname === ign + players.data[0].nickname === name ) { callback(players.data[0]); } else { @@ -33,7 +33,7 @@ export default async function getBlitzAccount( .setColor(NEGATIVE_COLOR) .setTitle(`Account not found`) .setDescription( - `I couldn't find "${ign}" in the ${serverName} server. I found ${ + `I couldn't find "${name}" in the ${serverName} server. I found ${ players?.data ? players.data.length < 100 ? players.data.length diff --git a/src/utilities/getBlitzStarsAccount.ts b/src/utilities/getBlitzStarsAccount.ts index bc27438d9..ab34b236a 100644 --- a/src/utilities/getBlitzStarsAccount.ts +++ b/src/utilities/getBlitzStarsAccount.ts @@ -10,7 +10,7 @@ import { PlayerStatistics } from '../types/statistics.js'; export default async function getBlitzStarsAccount( interaction: ChatInputCommandInteraction, accountId: number, - ign: string, + name: string, callback: (account: PlayerStatistics) => void, ) { function notTracked() { @@ -18,7 +18,7 @@ export default async function getBlitzStarsAccount( embeds: [ new EmbedBuilder() .setTitle('No data to display') - .setDescription(`${ign} is not tracked by BlitzStars.`) + .setDescription(`${name} is not tracked by BlitzStars.`) .setColor(NEGATIVE_COLOR), ], }); diff --git a/src/utilities/getClan.ts b/src/utilities/getClan.ts new file mode 100644 index 000000000..af1600600 --- /dev/null +++ b/src/utilities/getClan.ts @@ -0,0 +1,52 @@ +import { + CacheType, + ChatInputCommandInteraction, + EmbedBuilder, +} from 'discord.js'; +import fetch from 'node-fetch'; +import { NEGATIVE_COLOR } from '../constants/colors.js'; +import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js'; +import { Clan, ClanList } from '../types/clanList.js'; + +export default async function getClan( + interaction: ChatInputCommandInteraction, + name: string, + server: BlitzServer, + callback: (account: Clan) => void, +) { + const serverName = BLITZ_SERVERS[server]; + + const clans = (await fetch( + `https://api.wotblitz.${server}/wotb/clans/list/?application_id=${process.env.WARGAMING_APPLICATION_ID}&search=${name}`, + ).then((response) => response.json())) as ClanList; + + if ( + clans.status === 'ok' && + clans.data.length > 0 && + (clans.data[0].name === name || clans.data[0].tag === name.toUpperCase()) + ) { + callback(clans.data[0]); + } else { + // no exact match + interaction.reply({ + embeds: [ + new EmbedBuilder() + .setColor(NEGATIVE_COLOR) + .setTitle(`Clan not found`) + .setDescription( + `I couldn't find "${name}" in the ${serverName} server. I found ${ + clans?.data + ? clans.data.length < 100 + ? clans.data.length + : 'over 100' + : 0 + } similarly spelled clan${clans?.data?.length !== 1 ? 's' : ''}. ${ + clans?.data && clans.data.length > 0 + ? `Did you mean "${clans.data[0].name}" or "${clans.data[0].tag}"? ` + : '' + }Re-run the command, don't make typos, and capitalize correctly.`, + ), + ], + }); + } +}