Thread: FnordCon 2
View Single Post
Old 05-05-2020, 01:49 PM   #15
Aleph
Administrator
 
Aleph's Avatar
 
Join Date: Aug 2006
Location: The Central Network
Default Re: FnordCon 2

If you attended the Virtual FnordCon, you probably dealt with, or at least saw, the PanelMod bot that I wrote to help manage questions. Some of you asked if I could post the code for this. I may throw up a github link later, once the many non-working commented-out bits are removed or implemented, but I can post the main script itself in text here for now. Keep in mind that there are better ways to do some of this, and if you're going to try to duplicate this in the wild, you should definitely sanitize your inputs. This is just what I could get running in a short time while learning the language. No warranties given, etc, etc.

There are steps involved of setting up a Discord bot and Node.js development that are readily found via your favorite search engine. Do those first.

There is also a config file referenced here that you don't upload to your code repository, because it has your identifying key for the Discord Bot integration. That file also has a string that you can set to be the prefix the bot looks for to know it should read the line as a command. For us, it was set to 'qq', so the commands were qqask and qqanswer, etc.

config.json
Code:
{
"prefix": "qq",
"token": "---REMOVED---"
}
index.js
Code:
// SETUP //

// require the filesystem module from Node
const fs = require('fs');

// require the discord.js module
const Discord = require('discord.js');

// get config options from config.js - Don't put the config file in repos!
const {prefix, token} = require('./config.json');

// create a new Discord client
const client = new Discord.Client();

// create Maps for the question queues
const queue = new Array();
//const approved = new MAP();
	var activeChannel = '';

// when the client is ready, run this code
// this event will only trigger one time after logging in
client.once('ready', () => {
	console.log('Ready!');
});

// dynamic command loader
client.on('message', message => {
	if (!message.content.startsWith(prefix) || message.author.bot) return;

	const args = message.content.slice(prefix.length).split(/ +/);
	const commandName = args.shift().toLowerCase();

	if (commandName === 'ping') {  //Test command
		message.channel.send('Pong.');

	} else if (commandName === 'ask') {  // ADD QUESTION TO QUEUE
		if (!(activeChannel)) { //Don't queue questions when a panel hasnt been started
			message.author.send('There is not currently a panel running to ask questions for.');
			return;
		}
    else if (message.channel.type !== 'dm') { //Only accept questions when DMed
			message.author.send('You need to ask questions in private message. Try again here. It\'s qqask *your question*');
			return;
		}
    const asktext = args.join(' ');
    const question = `<@${message.author.id}> asks: **${asktext}**`;
    queue.push(question);
		message.author.send('Question queued.  Moderators will send it to the channel when they are ready.');

  } else if (commandName ==='answer') { // PRINT QUESTION TO CHANNEL -- Moderator Only
		if (!(message.member.roles.cache.some(r=>["VIP", "Speakers", "Convention Staff", "Coding"].includes(r.name))))
		 {return "Not a moderator"};
		if ((activeChannel) && (message.channel !== activeChannel)) {  //Only answer in active channel
			message.channel.send(`I am still running a question queue in ${activeChannel.name}.`);
			return;
		}
		var answ = queue.shift();
		if (!answ) {answ = '**No questions queued.**'};
		activeChannel.send(`${answ}`);

	} else if (commandName ==='start') { // START PANEL -- Moderator Only
			if (!(message.member.roles.cache.some(r=>["VIP", "Speakers", "Convention Staff", "Coding"].includes(r.name))))
			 {return "Not a moderator"};
			if ((activeChannel) && (message.channel !== activeChannel)) {  //Don't start a queue if already active
				message.channel.send(`I am still running a question queue in ${activeChannel.name}.`);
				return;
			}
		  activeChannel = message.channel;
			console.log(`${message.author.username} is starting a panel in ${activeChannel.name}`);
			activeChannel.send(`Active Channel being set to ${activeChannel}`);
			qcounter = setInterval(() => {
				activeChannel.send(`There are ${queue.length} questions in the queue.`);
			},5*60*1000);
			activeChannel.send(`If you would like to ask a question in the panel, please send a direct message to <@${client.user.id}> that starts with: "qqask " (without the quotes).  It will queue your question.`);

	} else if (commandName ==='stop') { // STOP PANEL -- Moderator Only
			if (!(message.member.roles.cache.some(r=>["VIP", "Speakers", "Convention Staff", "Coding"].includes(r.name))))
			 {return "Not a moderator"};
			if ((activeChannel) && (message.channel !== activeChannel)) {  //Dont allow stop from a non-active channel
				message.channel.send(`I am still running a question queue in ${activeChannel.name}.`);
				return;
			}
			console.log(`${message.author.username} is ending the panel in ${activeChannel.name}`);
			activeChannel.send(`Ending panel.  The queue is being emptied of questions.`);
			queue.length = 0;
			clearInterval(qcounter);
			activeChannel = null;
	};
});


// Log API errors / unhandled rejections
process.on('unhandledRejection', error => {
	console.error('Unhandled promise rejection:', error);
});

// login to Discord with your app's token
client.login(token);
Aleph is offline   Reply With Quote