Integrates Supabase for persistent storage of federation mappings and active tickets, along with adding new commands for announcements, audit logs, and polls. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 110a0afc-77c3-48ac-afca-8e969438dafc Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/hHBt1No Replit-Helium-Checkpoint-Created: true
111 lines
3.7 KiB
JavaScript
111 lines
3.7 KiB
JavaScript
const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js');
|
|
|
|
module.exports = {
|
|
data: new SlashCommandBuilder()
|
|
.setName('announce')
|
|
.setDescription('Send an announcement to all realms')
|
|
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
|
.addStringOption(option =>
|
|
option.setName('title')
|
|
.setDescription('Announcement title')
|
|
.setRequired(true)
|
|
.setMaxLength(256)
|
|
)
|
|
.addStringOption(option =>
|
|
option.setName('message')
|
|
.setDescription('Announcement message')
|
|
.setRequired(true)
|
|
.setMaxLength(2000)
|
|
)
|
|
.addStringOption(option =>
|
|
option.setName('color')
|
|
.setDescription('Embed color')
|
|
.setRequired(false)
|
|
.addChoices(
|
|
{ name: 'Purple (Default)', value: '7c3aed' },
|
|
{ name: 'Green (Success)', value: '00ff00' },
|
|
{ name: 'Red (Alert)', value: 'ff0000' },
|
|
{ name: 'Blue (Info)', value: '3b82f6' },
|
|
{ name: 'Yellow (Warning)', value: 'fbbf24' }
|
|
)
|
|
)
|
|
.addBooleanOption(option =>
|
|
option.setName('ping')
|
|
.setDescription('Ping @everyone with this announcement')
|
|
.setRequired(false)
|
|
),
|
|
|
|
async execute(interaction, supabase, client) {
|
|
await interaction.deferReply({ ephemeral: true });
|
|
|
|
const title = interaction.options.getString('title');
|
|
const message = interaction.options.getString('message');
|
|
const color = parseInt(interaction.options.getString('color') || '7c3aed', 16);
|
|
const ping = interaction.options.getBoolean('ping') || false;
|
|
|
|
const embed = new EmbedBuilder()
|
|
.setColor(color)
|
|
.setTitle(title)
|
|
.setDescription(message)
|
|
.setFooter({ text: `Announced by ${interaction.user.tag}` })
|
|
.setTimestamp();
|
|
|
|
const results = [];
|
|
const REALM_GUILDS = client.REALM_GUILDS;
|
|
|
|
for (const [realm, guildId] of Object.entries(REALM_GUILDS)) {
|
|
if (!guildId) continue;
|
|
|
|
const guild = client.guilds.cache.get(guildId);
|
|
if (!guild) {
|
|
results.push({ realm, status: 'offline' });
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
const announcementChannel = guild.channels.cache.find(
|
|
c => c.isTextBased() && !c.isThread() && !c.isVoiceBased() &&
|
|
(c.name.includes('announcement') || c.name.includes('general'))
|
|
);
|
|
|
|
if (announcementChannel && announcementChannel.isTextBased()) {
|
|
const content = ping ? '@everyone' : null;
|
|
await announcementChannel.send({ content, embeds: [embed] });
|
|
results.push({ realm, status: 'sent', channel: announcementChannel.name });
|
|
} else {
|
|
results.push({ realm, status: 'no_channel' });
|
|
}
|
|
} catch (error) {
|
|
console.error(`Announce error for ${realm}:`, error);
|
|
results.push({ realm, status: 'error', error: error.message });
|
|
}
|
|
}
|
|
|
|
if (supabase) {
|
|
try {
|
|
await supabase.from('audit_logs').insert({
|
|
action: 'announce',
|
|
user_id: interaction.user.id,
|
|
username: interaction.user.tag,
|
|
guild_id: interaction.guildId,
|
|
details: { title, message, results },
|
|
});
|
|
} catch (e) {
|
|
console.warn('Failed to log announcement:', e.message);
|
|
}
|
|
}
|
|
|
|
const resultText = results.map(r => {
|
|
const emoji = r.status === 'sent' ? '✅' : r.status === 'offline' ? '⚫' : '❌';
|
|
return `${emoji} **${r.realm}**: ${r.status}${r.channel ? ` (#${r.channel})` : ''}`;
|
|
}).join('\n');
|
|
|
|
const resultEmbed = new EmbedBuilder()
|
|
.setColor(0x7c3aed)
|
|
.setTitle('Announcement Results')
|
|
.setDescription(resultText || 'No realms configured')
|
|
.setTimestamp();
|
|
|
|
await interaction.editReply({ embeds: [resultEmbed] });
|
|
},
|
|
};
|