blob: f94fb24aca16180378f2dfe6d85670490fa6f144 [file] [log] [blame]
pineafan63fc5e22022-08-04 22:04:10 +01001import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
Skyler Grey75ea9172022-08-06 10:22:23 +01002import Discord, {
3 CommandInteraction,
4 GuildMember,
TheCodedProf21c08592022-09-13 14:14:43 -04005 ActionRowBuilder,
TheCodedProf21c08592022-09-13 14:14:43 -04006 ButtonBuilder,
Skyler Grey75ea9172022-08-06 10:22:23 +01007 MessageComponentInteraction,
PineaFanc729e762023-01-02 22:11:34 +00008 ButtonStyle,
9 PermissionResolvable,
10 APISelectMenuOption,
11 StringSelectMenuBuilder
Skyler Grey75ea9172022-08-06 10:22:23 +010012} from "discord.js";
PineaFan100df682023-01-02 13:26:08 +000013import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
pineafan4edb7762022-06-26 19:21:04 +010014import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
pineafan377794f2022-04-18 19:01:01 +010015import getEmojiByName from "../../utils/getEmojiByName.js";
16import generateKeyValueList from "../../utils/generateKeyValueList.js";
pineafan34369e62022-05-18 16:52:37 +010017import createPageIndicator from "../../utils/createPageIndicator.js";
pineafan63fc5e22022-08-04 22:04:10 +010018import client from "../../utils/client.js";
pineafan4f164f32022-02-26 22:07:12 +000019
20const command = (builder: SlashCommandSubcommandBuilder) =>
21 builder
pineafan63fc5e22022-08-04 22:04:10 +010022 .setName("about")
23 .setDescription("Shows info about a user")
Skyler Grey75ea9172022-08-06 10:22:23 +010024 .addUserOption((option) =>
Skyler Grey11236ba2022-08-08 21:13:33 +010025 option.setName("user").setDescription("The user to get info about | Default: Yourself")
Skyler Grey75ea9172022-08-06 10:22:23 +010026 );
pineafanea063042022-05-19 19:08:44 +010027
28class Embed {
PineaFanc729e762023-01-02 22:11:34 +000029 embed: EmojiEmbed = new EmojiEmbed();
30 title: string = "";
pineafan63fc5e22022-08-04 22:04:10 +010031 description = "";
32 pageId = 0;
PineaFanc729e762023-01-02 22:11:34 +000033
34 setEmbed(embed: EmojiEmbed) {
Skyler Grey75ea9172022-08-06 10:22:23 +010035 this.embed = embed;
36 return this;
37 }
38 setTitle(title: string) {
39 this.title = title;
40 return this;
41 }
42 setDescription(description: string) {
43 this.description = description;
44 return this;
45 }
46 setPageId(pageId: number) {
47 this.pageId = pageId;
48 return this;
49 }
pineafanea063042022-05-19 19:08:44 +010050}
51
Skyler Grey1a67e182022-08-04 23:05:44 +010052const callback = async (interaction: CommandInteraction): Promise<void> => {
PineaFanc729e762023-01-02 22:11:34 +000053 const guild = interaction.guild!;
Skyler Grey11236ba2022-08-08 21:13:33 +010054 const member = (interaction.options.getMember("user") ?? interaction.member) as Discord.GuildMember;
PineaFanc729e762023-01-02 22:11:34 +000055 await userAbout(guild, member, interaction);
56}
57
58async function userAbout(guild: Discord.Guild, member: Discord.GuildMember, interaction: Discord.CommandInteraction | Discord.ContextMenuCommandInteraction) {
59 await member.user.fetch()
60 await member.fetch()
61 await interaction.reply({
62 embeds: LoadingEmbed,
63 fetchReply: true,
64 ephemeral: true
65 });
66 const { renderUser, renderDelta } = client.logger;
pineafan63fc5e22022-08-04 22:04:10 +010067 const flags: string[] = [];
Skyler Grey75ea9172022-08-06 10:22:23 +010068 if (
69 [
70 "438733159748599813", // Pinea
71 "317731855317336067", // Mini
72 "261900651230003201", // Coded
73 "511655498676699136" // Zan
74 ].includes(member.user.id)
75 ) {
76 flags.push("NUCLEUSDEVELOPER");
77 }
78 if (
79 (await client.guilds.cache.get("684492926528651336")?.members.fetch())
Skyler Grey11236ba2022-08-08 21:13:33 +010080 ?.filter((m: GuildMember) => m.roles.cache.has("760896837866749972"))
Skyler Grey75ea9172022-08-06 10:22:23 +010081 ?.map((m: GuildMember) => m.id)
82 .includes(member.user.id)
83 ) {
84 flags.push("CLICKSDEVELOPER");
85 }
PineaFanc729e762023-01-02 22:11:34 +000086 if (member.user.flags) { member.user.flags.toArray().map((flag) => { flags.push(flag.toString()); }); }
87 if (member.user.bot) { flags.push("BOT"); }
pineafan377794f2022-04-18 19:01:01 +010088 // Check if they are boosting the server
PineaFanc729e762023-01-02 22:11:34 +000089 if (member.premiumSince) { flags.push("BOOSTER"); }
90 const nameReplacements: Record<string, string> = {
Skyler Grey75ea9172022-08-06 10:22:23 +010091 NUCLEUSDEVELOPER: "**Nucleus Developer**",
92 CLICKSDEVELOPER: "Clicks Developer",
Skyler Grey75ea9172022-08-06 10:22:23 +010093 BOT: "Bot",
PineaFanc729e762023-01-02 22:11:34 +000094 BOOSTER: "Server Booster",
95 HypeSquadOnlineHouse1: "Hypesquad Bravery",
96 HypeSquadOnlineHouse2: "Hypesquad Brilliance",
97 HypeSquadOnlineHouse3: "Hypesquad Balance",
98 Hypesquad: "Hypesquad Events",
99 PremiumEarlySupporter: "Early Supporter",
100 BugHunterLevel1: "Bug Hunter Level 1",
101 BugHunterLevel2: "Bug Hunter Level 2",
102 Partner: "Partnered Server Owner",
103 Staff: "Discord Staff",
104 VerifiedDeveloper: "Verified Bot Developer"
105 // ActiveDeveloper
106 // CertifiedModerator
107 // Quarantined https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags#Quarantined
108 // Spammer https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags#Spammer
109 // VerifiedBot
pineafan63fc5e22022-08-04 22:04:10 +0100110 };
PineaFanc729e762023-01-02 22:11:34 +0000111 const members = await guild.members.fetch();
pineafan63fc5e22022-08-04 22:04:10 +0100112 const membersArray = [...members.values()];
Skyler Greyc634e2b2022-08-06 17:50:48 +0100113 membersArray.sort((a, b) => {
114 if (a.joinedTimestamp === null) return 1;
115 if (b.joinedTimestamp === null) return -1;
116 return a.joinedTimestamp - b.joinedTimestamp;
117 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100118 const joinPos = membersArray.findIndex((m) => m.id === member.user.id);
pineafan377794f2022-04-18 19:01:01 +0100119
PineaFanc729e762023-01-02 22:11:34 +0000120 const roles = member.roles.cache.filter((r) => r.id !== guild.id).sort();
pineafan377794f2022-04-18 19:01:01 +0100121 let s = "";
122 let count = 0;
pineafan63fc5e22022-08-04 22:04:10 +0100123 let ended = false;
Skyler Greyc634e2b2022-08-06 17:50:48 +0100124 for (const roleId in roles) {
125 const string = `<@&${roleId}>, `;
Skyler Grey75ea9172022-08-06 10:22:23 +0100126 if (s.length + string.length > 1000) {
pineafan63fc5e22022-08-04 22:04:10 +0100127 ended = true;
128 s += `and ${roles.size - count} more`;
Skyler Greyc634e2b2022-08-06 17:50:48 +0100129 break;
pineafan63fc5e22022-08-04 22:04:10 +0100130 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100131 count++;
pineafan377794f2022-04-18 19:01:01 +0100132 s += string;
Skyler Greyc634e2b2022-08-06 17:50:48 +0100133 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100134 if (s.length > 0 && !ended) s = s.slice(0, -2);
pineafan377794f2022-04-18 19:01:01 +0100135
pineafan63fc5e22022-08-04 22:04:10 +0100136 let perms = "";
PineaFanc729e762023-01-02 22:11:34 +0000137 const permsArray: Record<string, string> = {
138 Administrator: "Administrator",
139 ManageGuild: "Manage Server",
140 ManageRoles: "Manage Roles",
141 ManageChannels: "Manage Channels",
142 KickMembers: "Kick Members",
143 BanMembers: "Ban Members",
144 ModerateMembers: "Moderate Members",
145 ManageNicknames: "Manage Nicknames",
146 ManageWebhooks: "Manage Webhooks",
147 ManageMessages: "Manage Messages",
148 ViewAuditLog: "View Audit Log",
149 MentionEveryone: "Mention Everyone"
pineafan63fc5e22022-08-04 22:04:10 +0100150 };
Skyler Grey75ea9172022-08-06 10:22:23 +0100151 Object.keys(permsArray).map((perm) => {
PineaFanc729e762023-01-02 22:11:34 +0000152 const hasPerm = member.permissions.has(perm as PermissionResolvable);
Skyler Grey11236ba2022-08-08 21:13:33 +0100153 perms += `${getEmojiByName("CONTROL." + (hasPerm ? "TICK" : "CROSS"))} ${permsArray[perm]}\n`;
pineafan63fc5e22022-08-04 22:04:10 +0100154 });
pineafan377794f2022-04-18 19:01:01 +0100155
pineafanea063042022-05-19 19:08:44 +0100156 let selectPaneOpen = false;
157
pineafan63fc5e22022-08-04 22:04:10 +0100158 const embeds = [
pineafanea063042022-05-19 19:08:44 +0100159 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100160 .setEmbed(
161 new EmojiEmbed()
162 .setTitle("User Info: General")
163 .setStatus("Success")
164 .setEmoji("MEMBER.JOIN")
165 .setDescription(
PineaFanc729e762023-01-02 22:11:34 +0000166 flags.map((flag) => {
167 if (nameReplacements[flag]) {
168 const emoji = getEmojiByName(`BADGES.${flag}`)
169 if (emoji) return (emoji + " " + nameReplacements[flag] + "\n");
170 else return nameReplacements[flag] + "\n";
171 }
172 }).join("") + "\n" +
173 generateKeyValueList({
174 member: renderUser(member.user),
175 nickname: member.nickname ?? "*None set*",
176 id: `\`${member.id}\``,
177 "joined the server": renderDelta(member.joinedTimestamp!),
178 "joined discord": renderDelta(member.user.createdTimestamp),
179 "boost status": member.premiumSince
180 ? `Started boosting ${renderDelta(member.premiumSinceTimestamp!)}`
181 : "*Not boosting*",
182 "join position": `${joinPos + 1}`
183 })
Skyler Grey75ea9172022-08-06 10:22:23 +0100184 )
PineaFanc729e762023-01-02 22:11:34 +0000185 .setThumbnail(member.user.displayAvatarURL())
Skyler Grey75ea9172022-08-06 10:22:23 +0100186 )
187 .setTitle("General")
188 .setDescription("General information about the user")
189 .setPageId(0),
pineafanea063042022-05-19 19:08:44 +0100190 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100191 .setEmbed(
192 new EmojiEmbed()
193 .setTitle("User Info: Roles")
194 .setStatus("Success")
195 .setEmoji("GUILD.ROLES.CREATE")
196 .setDescription(
197 generateKeyValueList({
198 member: renderUser(member.user),
199 id: `\`${member.id}\``,
PineaFanc729e762023-01-02 22:11:34 +0000200 roles: `${member.roles.cache.size - 1}` // FIXME
Skyler Grey75ea9172022-08-06 10:22:23 +0100201 }) +
202 "\n" +
203 (s.length > 0 ? s : "*None*") +
204 "\n"
205 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100206 )
207 .setTitle("Roles")
208 .setDescription("Roles the user has")
209 .setPageId(1),
pineafanea063042022-05-19 19:08:44 +0100210 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100211 .setEmbed(
212 new EmojiEmbed()
213 .setTitle("User Info: Key Permissions")
214 .setStatus("Success")
215 .setEmoji("GUILD.ROLES.CREATE")
216 .setDescription(
217 generateKeyValueList({
218 member: renderUser(member.user),
219 id: `\`${member.id}\``
220 }) +
221 "\n" +
222 perms
223 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100224 )
225 .setTitle("Key Permissions")
226 .setDescription("Key permissions the user has")
227 .setPageId(2)
pineafan63fc5e22022-08-04 22:04:10 +0100228 ];
PineaFanc729e762023-01-02 22:11:34 +0000229 if (member.user.bannerURL() ) { embeds[0]!.embed.setImage(member.user.bannerURL()!); }
pineafan63fc5e22022-08-04 22:04:10 +0100230 let page = 0;
Skyler Greyad002172022-08-16 18:48:26 +0100231 let timedOut = false;
PineaFanc729e762023-01-02 22:11:34 +0000232 for (const embed of embeds) {
233 embed.embed.setDescription(embed.embed.description + "\n" + createPageIndicator(embeds.length, embed.pageId));
234 }
Skyler Greyad002172022-08-16 18:48:26 +0100235 while (!timedOut) {
PineaFanc729e762023-01-02 22:11:34 +0000236 const em = embeds[page]!.embed;
237
238 let selectPane: ActionRowBuilder<ButtonBuilder | StringSelectMenuBuilder>[] = [];
pineafanea063042022-05-19 19:08:44 +0100239
240 if (selectPaneOpen) {
PineaFanc729e762023-01-02 22:11:34 +0000241 const options: APISelectMenuOption[] = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 embeds.forEach((embed) => {
Skyler Greyad002172022-08-16 18:48:26 +0100243 options.push({
244 label: embed.title,
245 value: embed.pageId.toString(),
246 description: embed.description || ""
247 });
pineafan63fc5e22022-08-04 22:04:10 +0100248 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100249 selectPane = [
PineaFanc729e762023-01-02 22:11:34 +0000250 new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
251 new Discord.StringSelectMenuBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100252 .addOptions(options)
253 .setCustomId("page")
254 .setMaxValues(1)
255 .setPlaceholder("Choose a page...")
PineaFanc729e762023-01-02 22:11:34 +0000256 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100257 ];
pineafanea063042022-05-19 19:08:44 +0100258 }
PineaFanc729e762023-01-02 22:11:34 +0000259 const m = await interaction.editReply({
pineafan34369e62022-05-18 16:52:37 +0100260 embeds: [em],
Skyler Grey75ea9172022-08-06 10:22:23 +0100261 components: selectPane.concat([
PineaFanc729e762023-01-02 22:11:34 +0000262 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -0400263 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100264 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400265 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100266 .setCustomId("left")
267 .setDisabled(page === 0),
TheCodedProf21c08592022-09-13 14:14:43 -0400268 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100269 .setEmoji(getEmojiByName("CONTROL.MENU", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400270 .setStyle(selectPaneOpen ? ButtonStyle.Primary : ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100271 .setCustomId("select")
272 .setDisabled(false),
TheCodedProf21c08592022-09-13 14:14:43 -0400273 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100274 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
275 .setCustomId("right")
TheCodedProf21c08592022-09-13 14:14:43 -0400276 .setStyle(ButtonStyle.Secondary)
Skyler Greyad002172022-08-16 18:48:26 +0100277 .setDisabled(page === embeds.length - 1)
Skyler Grey75ea9172022-08-06 10:22:23 +0100278 ])
279 ])
pineafan63fc5e22022-08-04 22:04:10 +0100280 });
Skyler Grey1a67e182022-08-04 23:05:44 +0100281 let i: MessageComponentInteraction;
pineafan377794f2022-04-18 19:01:01 +0100282 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100283 i = await m.awaitMessageComponent({ time: 300000 });
284 } catch {
Skyler Greyad002172022-08-16 18:48:26 +0100285 timedOut = true;
286 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100287 }
pineafan63fc5e22022-08-04 22:04:10 +0100288 i.deferUpdate();
PineaFanc729e762023-01-02 22:11:34 +0000289 if (i.customId === "left") {
pineafan377794f2022-04-18 19:01:01 +0100290 if (page > 0) page--;
pineafanea063042022-05-19 19:08:44 +0100291 selectPaneOpen = false;
PineaFanc729e762023-01-02 22:11:34 +0000292 } else if (i.customId === "right") {
pineafan377794f2022-04-18 19:01:01 +0100293 if (page < embeds.length - 1) page++;
pineafanea063042022-05-19 19:08:44 +0100294 selectPaneOpen = false;
PineaFanc729e762023-01-02 22:11:34 +0000295 } else if (i.customId === "select") {
pineafanea063042022-05-19 19:08:44 +0100296 selectPaneOpen = !selectPaneOpen;
PineaFanc729e762023-01-02 22:11:34 +0000297 } else if (i.customId === "page" && i.isStringSelectMenu()) {
298 page = parseInt(i.values[0]!);
pineafanea063042022-05-19 19:08:44 +0100299 selectPaneOpen = false;
pineafan377794f2022-04-18 19:01:01 +0100300 }
301 }
PineaFanc729e762023-01-02 22:11:34 +0000302 const em = embeds[page]!.embed;
303 em.setDescription(em.description + " | Message closed");
Skyler Grey75ea9172022-08-06 10:22:23 +0100304 await interaction.editReply({
305 embeds: [em],
Skyler Greyad002172022-08-16 18:48:26 +0100306 components: []
Skyler Grey75ea9172022-08-06 10:22:23 +0100307 });
pineafan63fc5e22022-08-04 22:04:10 +0100308};
pineafan4f164f32022-02-26 22:07:12 +0000309
Skyler Grey1a67e182022-08-04 23:05:44 +0100310const check = () => {
pineafan4f164f32022-02-26 22:07:12 +0000311 return true;
pineafan63fc5e22022-08-04 22:04:10 +0100312};
pineafan4f164f32022-02-26 22:07:12 +0000313
314export { command };
315export { callback };
Skyler Grey1a67e182022-08-04 23:05:44 +0100316export { check };
PineaFanc729e762023-01-02 22:11:34 +0000317export { userAbout };