import discord, { CommandInteraction, CommandInteractionOptionResolver, SlashCommandBuilder, SlashCommandRoleOption, SlashCommandStringOption, SlashCommandIntegerOption, SlashCommandSubcommandBuilder, EmbedBuilder, InteractionResponse, SlashCommandSubcommandsOnlyBuilder, } from 'discord.js'; import {HydratedDocument} from 'mongoose'; import {Command} from '../../classes/command'; import {logger} from '../../logger'; import {config} from '../../config'; import {Guild, guildModel} from '../../models/Guild'; import {GiveawayMsg, giveawayMsgModel} from '../../models/GiveawayMsg'; type CIOR = CommandInteractionOptionResolver; async function add(interaction: CommandInteraction): Promise{ const message: string | null = (interaction.options as CIOR).getString('message'); if(!message) throw Error('message not exist'); const embed = new EmbedBuilder() .setTitle('New Giveaway') .setDescription(`@everyone\n${message}`); if(!interaction.guildId) throw Error('guildId not exist'); if(!interaction.channelId) throw Error('channelId not exist'); let msg: discord.Message = await (await interaction.reply({embeds: [embed]})).fetch(); await msg.react(config.giveaway.emoji); if(!interaction.guild || !interaction.guild.id) throw Error('guild not exist'); const guild: HydratedDocument | null = await guildModel.findOneAndUpdate( {id: interaction.guild.id}, {$set: {name: interaction.guild.name}}, {upsert: true, new: true} ); if(!guild) throw Error('guild not exist'); const giveawayMsg: HydratedDocument | null = await giveawayMsgModel.findOneAndUpdate( {guild: guild, messageId: msg.id, authorId: interaction.user.id}, {}, {upsert: true, new: true} ); if(!giveawayMsg) throw Error('giveawayMsg not exist'); await msg.edit({embeds: [new EmbedBuilder() .setColor(Math.floor(Math.random()*16777215)) .setTitle('Giveaway') .setDescription(message) .setFooter({text: `id: ${msg.id}`}) ]}); } async function pick(interaction: CommandInteraction): Promise{ const messageId: string | null = (interaction.options as CIOR).getString('message'); if(!messageId) throw Error('message not exist'); const num: number | null = (interaction.options as CIOR).getInteger('number'); if(!num) throw Error('number not exist'); const dbGiveawayMsg: HydratedDocument | null = await giveawayMsgModel.findOneAndDelete({ messageId: messageId, authorId: interaction.user.id }); if(!dbGiveawayMsg){ await interaction.reply({ content: logger.log(`Giveaway didn't exist or the author didn't match.`), ephemeral: true }); return; } for(let i = dbGiveawayMsg.userIds.length - 1; i > 0; i--){ let j = Math.floor(Math.random() * (i + 1)); [dbGiveawayMsg.userIds[i], dbGiveawayMsg.userIds[j]] = [dbGiveawayMsg.userIds[j], dbGiveawayMsg.userIds[i]]; } let content: string = '### Giveaway Result\n'; for(let i = 0; i < num; i++) content += `1. ${await interaction.client.users.fetch(dbGiveawayMsg.userIds[i])}\n`; content += `will obtain the prize for giveaway, id: ${dbGiveawayMsg.messageId}`; await interaction.reply({content: content}); } class Giveaway extends Command{ get name(){return 'giveaway';} get description(){return 'Setup a Giveaway message.';} async execute(interaction: CommandInteraction): Promise{ try{ const subcommand: string | null = (interaction.options as CIOR).getSubcommand(); switch(subcommand){ case 'add': await add(interaction); break; case 'pick': await pick(interaction); break; default: throw Error('subcommand not exist'); } }catch(err: unknown){ let message; if(err instanceof Error) message = err.message; else message = String(message); logger.error(`While executing "/giveaway", ${message}`); await interaction.reply({content: `While executing "/giveaway", ${message}`}); } } override build(): SlashCommandSubcommandsOnlyBuilder{ return new SlashCommandBuilder() .setName(this.name) .setDescription(this.description) .addSubcommand((subcommand: SlashCommandSubcommandBuilder) => subcommand .setName('add') .setDescription('Construct a giveaway') .addStringOption((option: SlashCommandStringOption) => option .setName('message') .setDescription('The message displayed with the giveaway message.') .setRequired(true) ) ) .addSubcommand((subcommand: SlashCommandSubcommandBuilder) => subcommand .setName('pick') .setDescription('Random pick a number of user in a giveaway') .addStringOption((option: SlashCommandStringOption) => option .setName('message') .setDescription('The message id of the giveaway (Shown in the footer)') .setRequired(true) ) .addIntegerOption((option: SlashCommandIntegerOption) => option .setName('number') .setDescription('The number of member to choose.') .setRequired(true) ) ) } }; export const command = new Giveaway();