Source

commands/a_boothing/e-room-directory.js

const PermissionCommand = require('../../classes/permission-command');
const { Message, MessageEmbed, Role, Collection} = require('discord.js');
const { deleteMessage } = require('../../discord-services');
const BotGuildModel = require('../../classes/bot-guild');
const winston = require('winston');
const { StringPrompt, RolePrompt, SpecialPrompt } = require('advanced-discord.js-prompts');

/**
 * Shows an embed with a link used for activities happening outside discord. Initial intent was to be used for 
 * sponsor booths. A specified role can open and close the rooms as they want. When rooms open, a specified role is notified.
 * @category Commands
 * @subcategory Boothing
 * @extends PermissionCommand
 * @guildonly
 */
class ERoomDirectory extends PermissionCommand {
    constructor(client) {
        super(client, {
            name: 'e-room-directory',
            group: 'a_boothing',
            memberName: 'keep track of booths',
            description: 'Sends embeds to booth directory to notify hackers of booth statuses',
            guildOnly: true,
        },
        {
            role: PermissionCommand.FLAGS.STAFF_ROLE,
            roleMessage: 'This command can only be ran by staff!',
        });
    }

    /**
     * Sends an embed same channel with the sponsor's name and link to their Zoom boothing room. The embed has 2 states: Open and Closed. 
     * In the Closed state the embed will be red and say the booth is closed, which is the default, and the bot will react to the embed with 
     * a door emoji at the beginning. In the Open state the embed will be green and say the booth is open. Any time a staff or sponsor clicks 
     * on that emoji, the embed changes to the other state. When a booth goes from Closed to Open, it will also notify a role (specified by 
     * the user) that it is open.
     * 
     * @param {Message} message - messaged that called this command
     * @param {BotGuildModel} botGuild
     */
    async runCommand(botGuild, message) {

        // helpful vars
        let channel = message.channel;
        let userId = message.author.id;

        try {
            var sponsorName = await StringPrompt.single({prompt: 'What is the room name?', channel, userId, cancelable: true});
            sponsorName = sponsorName.content;

            var link = await StringPrompt.single({prompt: 'What is the room link? We will add no words to it! (ex. <Room Name> is Currently Open).', channel, userId, cancelable: true});
            link = link.content;

            //ask user for role and save its id in the role variable
            var role = (await RolePrompt.single({prompt: 'What role will get pinged when the rooms open?', channel, userId})).id;
        } catch (error) {
            channel.send('<@' + userId + '> Command was canceled due to prompt being canceled.').then(msg => msg.delete({timeout: 5000}));
            return;
        }

        /**
         * prompt for roles that can open/close the room
         * @type {Collection<String, Role>}
         */
        var roomRoles;
        try {
            roomRoles = await RolePrompt.multi({ prompt: 'What other roles can open/close the room? (Apart form staff).', channel, userId, cancelable: true });
        } catch (error) {
            // do nothing as this is fine
            winston.loggers.get(message.guild.id).warning(`Got an error: ${error} but I let it go since we expected it from the prompt.`, { event: 'E-Room-Directory Command' });
        }
        // add staff role
        roomRoles.set(botGuild.roleIDs.staffRole, message.guild.roles.resolve(botGuild.roleIDs.staffRole));

        // prompt user for emoji to use
        let emoji = await SpecialPrompt.singleEmoji({prompt: 'What emoji do you want to use to open/close the room?', channel, userId});
    
        //variable to keep track of state (Open vs Closed)
        var closed = true;
        //embed for closed state
        const embed = new MessageEmbed()
            .setColor('#FF0000')
            .setTitle(sponsorName + ' is Currently Closed')
            .setDescription('Room link: ' + link);
        
        //send closed embed at beginning (default is Closed)
        channel.send(embed).then((msg) => {
            msg.pin();
            msg.react(emoji);

            //only listen for the door react from users that have one of the roles in the room roles collection
            const emojiFilter = (reaction, user) => {
                let member = message.guild.member(user);
                return !user.bot && reaction.emoji.name === emoji.name && roomRoles.some(role => member.roles.cache.has(role.id));
            };
            const emojiCollector = msg.createReactionCollector(emojiFilter);
            
            var announcementMsg;

            emojiCollector.on('collect', async (reaction, user) => {
                reaction.users.remove(user);
                if (closed) {
                    //embed for open state
                    const openEmbed = new MessageEmbed()
                        .setColor('#008000')
                        .setTitle(sponsorName + ' \'s Booth is Currently Open')
                        .setDescription('Please visit this Zoom link to join: ' + link);
                    //change to open state embed if closed is true
                    msg.edit(openEmbed);
                    closed = false;
                    //notify people of the given role that booth is open and delete notification after 5 mins
                    announcementMsg = await channel.send('<@&' + role + '> ' + sponsorName + ' \'s booth has just opened!');
                    announcementMsg.delete({timeout: 300 * 1000});
                } else {
                    //change to closed state embed if closed is false
                    msg.edit(embed);
                    closed = true;
                    deleteMessage(announcementMsg);
                }
            });
        });
    }
}
module.exports = ERoomDirectory;