diff --git a/docs/commands/GENERAL.md b/docs/commands/GENERAL.md index 746c5bc..0f65597 100644 --- a/docs/commands/GENERAL.md +++ b/docs/commands/GENERAL.md @@ -14,6 +14,7 @@ - `/daily`/`?daily` - Gives you a daily reward of ARAs - `/pay `/`?pay ` - Give a user an amount of ARAs - `/balance`/`?balance` - Checks how many ARAs you have +- `/topbalances`/`?topbalances` - Displays the richest server members ## XP diff --git a/src/commands/economy/topbalances.ts b/src/commands/economy/topbalances.ts new file mode 100644 index 0000000..f2f8b0e --- /dev/null +++ b/src/commands/economy/topbalances.ts @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2023 Stefanie Merceron + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import { Command, RegisterBehavior } from '@sapphire/framework'; +import { Guild, GuildMember, Message, EmbedBuilder } from 'discord.js'; +import { getTopBalances } from '#utils/database/economy'; + +export class TopBalancesCommand extends Command { + public constructor(context: Command.Context, options: Command.Options) { + super(context, { + ...options, + name: 'topbalances', + aliases: ['topbal', 'leaderboard'], + description: 'Shows the top 5 largest balances on the server', + }); + } + + // Registers that this is a slash command + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand( + (builder) => builder.setName(this.name).setDescription(this.description), + { + behaviorWhenNotIdentical: RegisterBehavior.Overwrite, + }, + ); + } + + // Command run + public async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + const { guild } = interaction; + + if (guild === null) { + await interaction.reply({ + content: 'Could not find the guild!', + ephemeral: true, + }); + return; + } + + await interaction.deferReply(); + + const info = await this.showTopBalances(guild); + + await interaction.editReply({ + content: info.message, + embeds: info.embeds, + }); + } + + public async messageRun(message: Message) { + const { guild } = message; + + if (guild === null) { + await message.react('❌'); + await message.reply('Could not find the guild!'); + return; + } + + const info = await this.showTopBalances(guild); + + await message.reply({ + content: info.message, + embeds: info.embeds, + }); + if (!info.success) { + await message.react('❌'); + } + } + + private async showTopBalances(guild: Guild) { + const info = { + message: '', + embeds: [] as EmbedBuilder[], + success: false, + }; + + const embed = new EmbedBuilder() + .setColor('#cc802c') + .setTitle('Top Balances on the Server') + .setAuthor({ + name: 'ARA', + iconURL: + 'https://github.com/veganhacktivists/arabot/blob/main/docs/images/logo.png?raw=true', + }); + + const leaders = await getTopBalances(5); + const fetchMemberPromises: Promise[] = []; + + for (const leader of leaders) { + fetchMemberPromises.push( + guild.members.fetch(leader.userId).catch(() => null), + ); + } + + const members = await Promise.all(fetchMemberPromises); + + for (let i = 0; i < leaders.length; i += 1) { + const leader = leaders[i]; + const member = members[i]; + + // Server Members Display on The Leaderboard + if (member) { + embed.addFields( + { + name: i + 1 + '.', + value: + '[' + + member.displayName + + ']()', + inline: true, + }, + { + name: 'Balance', + value: leader.balance + " ARA's", + inline: true, + }, + { + name: '\u200b', + value: '\u200b', + inline: true, + }, + ); + } + } + info.success = true; + info.embeds.push(embed); + return info; + } +} diff --git a/src/utils/database/economy.ts b/src/utils/database/economy.ts index 666c0b6..fe6dd8f 100644 --- a/src/utils/database/economy.ts +++ b/src/utils/database/economy.ts @@ -128,3 +128,18 @@ export async function getLastDaily(userId: Snowflake) { return time; } + +export async function getTopBalances(count: number) { + const topBalances = await container.database.balance.findMany({ + select: { + userId: true, + balance: true, + }, + orderBy: { + balance: 'desc', + }, + take: count, + }); + + return topBalances; +} diff --git a/src/utils/gifs.ts b/src/utils/gifs.ts index 0694bb4..1f7a569 100644 --- a/src/utils/gifs.ts +++ b/src/utils/gifs.ts @@ -23,6 +23,24 @@ export const Kill = [ 'https://c.tenor.com/N1eC5_O9KiAAAAAd/justketh-goose-attack.gif', 'https://c.tenor.com/lSGhAaUU2iQAAAAC/honk-honk-am-goose-cute.gif', 'https://c.tenor.com/aM6ovLN3dtwAAAAC/cat-attack.gif', + // Thanks to Lithium (259318132936671233) <3 + 'https://c.tenor.com/rqwsMxkcw5AAAAAC/dog-bang.gif', + 'https://c.tenor.com/i9j5kg7dUV4AAAAC/toy-story-toy-story2.gif', + 'https://c.tenor.com/UGXBWgRuqlgAAAAC/penguin-chase.gif', + 'https://c.tenor.com/yOn0J1JGLMwAAAAd/blanket-attack.gif', + 'https://c.tenor.com/aZwgcwO6yvEAAAAd/dd.gif', + 'https://c.tenor.com/n51pqoBDBp4AAAAd/kill-you-chuckie.gif', + 'https://c.tenor.com/7XGED-yj1TwAAAAd/chonker-cat.gif', + 'https://c.tenor.com/coB4-k0N610AAAAd/cat-bite.gif', + 'https://c.tenor.com/MNt4by6XWVYAAAAd/flip-anime.gif', + 'https://c.tenor.com/Lyqfq7_vJnsAAAAC/kick-funny.gif', + 'https://c.tenor.com/5n9kC7DGb4oAAAAC/swadloon.gif', + 'https://c.tenor.com/NLcX8H3CzfkAAAAC/funny-epic.gif', + 'https://c.tenor.com/ZpKJzYJ-RhoAAAAd/jerk-penguins.gif', + 'https://c.tenor.com/g_kGVqKmxGoAAAAC/ffvii-ff7.gif', + 'https://c.tenor.com/GN48fNKNKGUAAAAC/tic-elder-sister-plastic-neesan.gif', + 'https://c.tenor.com/ulRnUvqttDEAAAAd/cat-tail-wagging.gif', + 'https://c.tenor.com/bB0ysXaYer8AAAAC/klee-genshin-impact.gif', ]; export const Poke = [