Files
broccolini-bot/handlers/accountinfo.js
root 519788c633 Initial commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 08:22:19 -06:00

181 lines
5.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Account info command: look up website User by email or Discord ID,
* show ephemeral embed with option to send transcript to account info channel.
*/
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const { CONFIG } = require('../config');
const { mongoose } = require('../db-connection');
const User = mongoose.model('User');
const BUTTON_PREFIX = 'send_account_info_';
const MAX_CUSTOM_ID_LENGTH = 100;
function buildAccountInfoEmbed(user, requestedBy = null) {
const embed = new EmbedBuilder()
.setTitle('Account Info')
.setColor(CONFIG.EMBED_COLOR_INFO)
.setTimestamp();
embed.addFields({
name: 'Email',
value: user.email || '*not set*',
inline: true
});
embed.addFields({
name: 'Discord ID',
value: user.discordID ? `<@${user.discordID}>` : '*not set*',
inline: true
});
embed.addFields({
name: 'Customer ID',
value: user.customerId || '*not set*',
inline: true
});
const servers = user.servers || [];
const serverOrder = user.serverOrder || [];
const ordered = serverOrder.length
? serverOrder.map(id => servers.find(s => s._id && s._id.toString() === id) || servers[serverOrder.indexOf(id)]).filter(Boolean)
: servers;
if (ordered.length === 0) {
embed.addFields({
name: 'Servers',
value: '*No servers*',
inline: false
});
} else {
ordered.forEach((server, i) => {
const n = i + 1;
embed.addFields({
name: `Server ${n} Game`,
value: server.game || '*not set*',
inline: true
});
embed.addFields({
name: `Server ${n} IP`,
value: server.ip || '*not set*',
inline: true
});
embed.addFields({
name: `Server ${n} Port`,
value: server.serverPort != null ? String(server.serverPort) : '*not set*',
inline: true
});
});
}
if (requestedBy) {
embed.setFooter({ text: `Requested by ${requestedBy}` });
}
return embed;
}
async function handleAccountInfoCommand(interaction) {
const subcommand = interaction.options.getSubcommand();
let user = null;
if (subcommand === 'email') {
const email = (interaction.options.getString('email') || '').trim().toLowerCase();
if (!email) {
return interaction.reply({ content: 'Please provide an email.', ephemeral: true });
}
user = await User.findOne({ email }).lean();
} else if (subcommand === 'discord') {
const target = interaction.options.getUser('user');
if (!target) {
return interaction.reply({ content: 'Please provide a Discord user.', ephemeral: true });
}
user = await User.findOne({ discordID: target.id }).lean();
}
if (!user) {
return interaction.reply({
content: subcommand === 'email' ? 'No account found for that email.' : 'No account found for that Discord user/ID.',
ephemeral: true
});
}
const embed = buildAccountInfoEmbed(user, interaction.user.tag);
const components = [];
if (CONFIG.ACCOUNT_INFO_CHANNEL_ID) {
const safeEmail = (user.email || '').slice(0, 50);
const safeDiscordId = (user.discordID || '').slice(0, 50);
const customId = `${BUTTON_PREFIX}discord:${safeDiscordId}`;
if (customId.length <= MAX_CUSTOM_ID_LENGTH) {
components.push(
new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId(customId)
.setLabel('Send to account info channel')
.setStyle(ButtonStyle.Secondary)
)
);
}
}
await interaction.reply({
embeds: [embed],
components,
ephemeral: true
});
}
async function handleSendAccountInfoToChannel(interaction) {
if (!interaction.isButton() || !interaction.customId.startsWith(BUTTON_PREFIX)) return false;
const payload = interaction.customId.slice(BUTTON_PREFIX.length);
const [type, value] = payload.includes(':') ? payload.split(':') : [payload, ''];
let user = null;
if (type === 'email') {
const email = Buffer.from(value, 'base64').toString('utf8').toLowerCase();
user = await User.findOne({ email }).lean();
} else if (type === 'discord' && value) {
user = await User.findOne({ discordID: value }).lean();
}
if (!user) {
await interaction.update({ content: 'Account no longer found.', components: [] }).catch(() =>
interaction.followUp({ content: 'Account no longer found.', ephemeral: true })
);
return true;
}
if (!CONFIG.ACCOUNT_INFO_CHANNEL_ID) {
await interaction.update({ content: 'Account info channel is not configured.', components: [] }).catch(() =>
interaction.followUp({ content: 'Account info channel is not configured.', ephemeral: true })
);
return true;
}
const channel = await interaction.client.channels.fetch(CONFIG.ACCOUNT_INFO_CHANNEL_ID).catch(() => null);
if (!channel) {
await interaction.update({ content: 'Could not find account info channel.', components: [] }).catch(() =>
interaction.followUp({ content: 'Could not find account info channel.', ephemeral: true })
);
return true;
}
const embed = buildAccountInfoEmbed(user, `${interaction.user.tag} (from ticket)`);
await channel.send({ embeds: [embed] });
await interaction.update({
content: 'Account info sent to account transcript channel.',
components: []
}).catch(() =>
interaction.followUp({ content: 'Account info sent to account transcript channel.', ephemeral: true })
);
return true;
}
module.exports = {
buildAccountInfoEmbed,
handleAccountInfoCommand,
handleSendAccountInfoToChannel,
BUTTON_PREFIX
};