Skip to content

Release #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Feb 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions bot/baseCommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class BaseCommand {
constructor(
command, example, title,
description, action, responseType = 'reply',
adminOnly = false, showWithHelp = true, allowInDM = false,
) {
this.command = command;
this.example = example;
this.title = title;
this.description = description;
this.showWithHelp = showWithHelp;
this.allowInDM = allowInDM;
this.adminOnly = adminOnly;
this.responseType = responseType;
this.action = action;
}
}
module.exports = BaseCommand;
70 changes: 70 additions & 0 deletions bot/baseController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const util = require('apex-util');
const { isAdmin } = require('./botUtils.js');

class BaseController {
constructor(message) {
// Add middleware to saved message
this.message = BaseController.messageMiddleware(message);
this.commands = [];
}

// Add extra information to message object
static messageMiddleware(message) {
// Creates an empty object container
const messageContainer = {};
// Tokenizes the message by space characters, adds to container
messageContainer.parsed = message.content.split(' ');
// Adds message object to container
return Object.assign(message, messageContainer);
}

onSuccess(commandResponse, command) {
if (commandResponse !== null) {
// Determine how to respond to message
if (command.responseType === 'reply') {
return this.message.reply(commandResponse);
} else if (command.responseType === 'dm') {
return this.message.author.send(commandResponse);
}
}
// Fail safe
return false;
}

onError(errorMessage = 'I Broke... Beep...Boop...Beep') {
return this.message.reply(errorMessage);
}

// Execute the command's functionality
run() {
// Loop through each command and map to key
util.log('Looping through controller commands', 0);
Object.keys(this.commands).map((key) => {
// If command matches message
if (this.message.parsed[0].toLowerCase() === this.commands[key].command.toLowerCase()) {
util.log('Matching command found', this.commands[key].command, 2);

// If user messages the bot a channel-only command
if (!this.commands[key].allowInDM && !this.message.guild) {
return this.onError('Please don\'t use this command directly. Instead use it in a channel on a server. :beers:');
}

// If non-admin enters admin command
if (this.commands[key].adminOnly && !isAdmin(this.message.member)) {
return this.onError('You don\'t have permissions to run this command.');
}

// Execute command's action
const commandResponse = this.commands[key].action();
// Handle if command responds or breaks
if (commandResponse) {
this.onSuccess(commandResponse, this.commands[key]);
} else {
this.onError();
}
}
return this.commands[key];
});
}
}
module.exports = BaseController;
32 changes: 32 additions & 0 deletions bot/botUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
exports.generateCode = (n) => {
// Workaround method for Math.pow() and ** operator
const pow = (base, exp) => {
let result = 1;
for (let i = 0; i < exp; i += 1) {
result *= base;
}
return result;
};
const add = 1;
let max = 12 - add;
let min = 0;
if (n > max) {
return this.generateCode(max) + this.generateCode(n - max);
}
max = pow(10, n + add);
min = max / 10;
const number = Math.floor(Math.random() * (max - (min + 1))) + min;
return ('' + number).substring(add);
};

// Checks if person is an admin user, use GuildMember object
exports.isAdmin = (member) => {
const adminRoles = [
'Admin', 'Armada Officers', 'Armada Officer', 'Fleet Officer',
'Moderator', 'Tester',
];
if (adminRoles.some(role => member.roles.find('name', role))) {
return true;
}
return false;
};
61 changes: 34 additions & 27 deletions bot/client.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,58 @@
const Discord = require('discord.js');
const util = require('apex-util');
const { isAdmin } = require('./botUtils.js');

// If Production server default Debug mode to Production Setting
// If production server, set default debug mode to production setting
if (process.env.NODE_ENV === 'production' && !process.env.DEBUG_MODE) process.env.DEBUG_MODE = 0;

const client = new Discord.Client();

// Pre Load Controllers
const ctrls = require('./controllers')();
// Pre-load controllers
const controllers = require('./controllers')();

// Alert when ready
client.on('ready', () => {
util.log('Bot Online and Ready!', 0);
util.log('Bot Online and Ready', 0);
});

// Listen for messages
client.on('message', (message) => {
// Check for ! Prefix on message to ensure it is a command
// Check for ! prefix on message to ensure it is a command
if (message.content.charAt(0) === '!') {
util.log('!Cmd Message Received', message.content, 0);
util.log('Command message received', message.content, 0);

const ctrlResponses = [];
// Build basic help string
let helpString = 'v1.4.0 Discovered Commands:\n\n\t**<> - Required Item\t\t[] - Optional Item**';

// Process message against every controller
Object.keys(ctrls).forEach((ctrlKey) => {
if (ctrlKey) {
// initialize the controller
const ctrlInstance = ctrls[ctrlKey]();

// Determine the method names of each controller
const controllerMethodKeys = Object.keys(ctrlInstance);
util.log('Methods found in controller', controllerMethodKeys, 3);

// For each method on each controller
Object.keys(controllerMethodKeys).forEach((controllerMethodKey) => {
const methodName = controllerMethodKeys[controllerMethodKey];
const method = ctrlInstance[methodName];

util.log('Looping Through Each Method within each Controller', method, 4);

// Pass the message to each method of each controller
ctrlResponses.push(method(message));
Object.keys(controllers).forEach((key) => {
// Instantiate the controller
const controllerInstance = new controllers[key](message);
util.log('Controller instance', controllerInstance, 5);
// Runs commands after constructor is called
controllerInstance.run();

// Loop through commands if help command and add to string
if (message.content.toLowerCase() === '!help') {
Object.keys(controllerInstance.commands).forEach((commandKey) => {
const commandInstance = controllerInstance.commands[commandKey];
// Check if command should be shown in help menu
if (commandInstance.showWithHelp) {
if (commandInstance.adminOnly && isAdmin(message.member)) {
helpString += `\n\n \`${commandInstance.example}\` **- Admin Only** \n\t ${commandInstance.description}`;
} else if (commandInstance.adminOnly && !isAdmin(message.member)) {
helpString += '';
} else {
helpString += `\n\n \`${commandInstance.example}\` \n\t ${commandInstance.description}`;
}
}
});
}
});

// TODO: Improve help message
// If help command called, display string
if (message.content.toLowerCase() === '!help') {
message.reply('v1.3.2 Discovered Commands: \n `!roles` \n\t List all Armada Roles \n\n `!addRole` RoleName \n\t Adds yourself to a role and the related text/voice rooms. \n\n `!removeRole` RoleName \n\t Removes a role from yourself. \n\n `!addAllRoles` \n\t Add all roles to yourself. \n\n `!removeAllRoles` \n\t Remove all roles from yourself. \n\n `!verify emailAddress@student.fullsail.com` \n\t Self verify that you are a Full Sail Student / Alumni via your Full Sail email account.');
message.reply(helpString);
}
}
});
Expand Down
71 changes: 71 additions & 0 deletions bot/controllers/channels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const BaseController = require('../baseController.js');
const Command = require('../baseCommand.js');
const util = require('apex-util');

class ChannelController extends BaseController {
constructor(message) {
super(message);
const controller = this;
this.commands = [
new Command(
'!channels',
'!channels',
'List All Channels',
'List all available Armada channels.',
this.channelsAction.bind(controller),
'dm',
),
new Command(
'!announce',
'!announce <channel_name>,[channel_name] <message>',
'Announce To Channels',
'Broadcast to multiple channels. Channels are case-sensitive.',
this.announceAction.bind(controller),
'reply',
true,
),
];
}

channelsAction() {
const { message } = this;
const channels = [];
message.guild.channels.map(channel => channels.push(channel.name));
return 'List of all Armada Channels: \n\n' + channels.join('\n');
}

announceAction() {
const { message } = this;
const channels = message.parsed[1].split(',');
util.log('Multiple Channels Parsing', channels, 4);

channels.map((channel) => {
const targetChannel = message.guild.channels.find('name', channel);
const sender = message.author.username;
util.log('Asking API for Channel', targetChannel, 4);

if (targetChannel === null) {
return '"' + channel + '" is not a known channel. Try `!channels` to get a list of all Channels (They are case-sensitive)';
}

// Set parsed value to 2 for message.
let msgParsedIndex = 2;
let preparedMessage = '';

// Loop through/join user message by space until end.
while (msgParsedIndex < message.parsed.length) {
// Add spaces after first word
if (msgParsedIndex !== 2) {
preparedMessage += ' ';
}
preparedMessage += message.parsed[msgParsedIndex];
msgParsedIndex += 1;
}
return targetChannel.send(sender + ' has an announcment: ```' + preparedMessage + '```');
});

return 'Broadcast sent!';
}
}

module.exports = ChannelController;
19 changes: 9 additions & 10 deletions bot/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ const fs = require('fs');
const util = require('apex-util');

module.exports = () => {
const ctrls = [];
const controllers = [];
const targetPath = './bot/controllers';
const exts = ['js'];
const validExtensions = ['js'];

// const file = 'roles.js';
// Auto-load controller files
fs.readdirSync(targetPath).forEach((file) => {
// Skip Self Recursive Loading
// Skip self-recursive loading
if (file === 'index.js') return false;

// Split File name on "."
Expand All @@ -18,14 +18,13 @@ module.exports = () => {
const currentExt = splitFile[splitFile.length - 1];

// Check if extension is on approved array
if (exts.includes(currentExt)) {
ctrls.push(require(`./${file}`));
// import/no-dynamic-require
if (validExtensions.includes(currentExt)) {
// Add controller to list
controllers.push(require(`./${file}`));
}

return true;
});

util.log('Return Controllers loaded within the target path of ' + targetPath, ctrls, 3);
return ctrls;
util.log('Controllers found within target path' + targetPath, controllers, 3);
return controllers;
};
Loading