From b2ea634d8cc7d612570b147da993c75d2ba7c43d Mon Sep 17 00:00:00 2001 From: Luke Slater Date: Tue, 11 Dec 2012 16:04:52 +0000 Subject: [PATCH] Move all the modules to their own directories --- modules/admin/admin.js | 148 +++++++++++++++++++ modules/command/command.js | 104 +++++++++++++ modules/dice/dice.js | 105 +++++++++++++ modules/drama/drama.js | 96 ++++++++++++ modules/ignore/ignore.js | 81 ++++++++++ modules/js/js.js | 47 ++++++ modules/karma/karma.js | 8 + modules/kick/kick.js | 76 ++++++++++ modules/link/link.js | 52 +++++++ modules/poll/poll.js | 233 +++++++++++++++++++++++++++++ modules/puns/puns.js | 25 ++++ modules/quotes/quotes.js | 276 +++++++++++++++++++++++++++++++++++ modules/report/report.js | 52 +++++++ modules/spelling/spelling.js | 68 +++++++++ modules/web/web.js | 130 +++++++++++++++++ modules/youare/youare.js | 19 +++ 16 files changed, 1520 insertions(+) create mode 100644 modules/admin/admin.js create mode 100644 modules/command/command.js create mode 100644 modules/dice/dice.js create mode 100644 modules/drama/drama.js create mode 100644 modules/ignore/ignore.js create mode 100644 modules/js/js.js create mode 100644 modules/karma/karma.js create mode 100644 modules/kick/kick.js create mode 100644 modules/link/link.js create mode 100644 modules/poll/poll.js create mode 100644 modules/puns/puns.js create mode 100644 modules/quotes/quotes.js create mode 100644 modules/report/report.js create mode 100644 modules/spelling/spelling.js create mode 100644 modules/web/web.js create mode 100644 modules/youare/youare.js diff --git a/modules/admin/admin.js b/modules/admin/admin.js new file mode 100644 index 0000000..173e270 --- /dev/null +++ b/modules/admin/admin.js @@ -0,0 +1,148 @@ +/** + * Module Name: Admin + * Description: Set of commands which only one who is a DepressionBot + * administrator can run - as such, it has its own command execution listener. + */ +var fs = require('fs'); +var sys = require('sys') +var exec = require('child_process').exec; + +var admin = function(dbot) { + var commands = { + // Join a channel + 'join': function(event) { + var channel = event.params[1]; + if(event.allChannels.hasOwnProperty(channel)) { + event.reply("I'm already in that channel."); + } else { + dbot.instance.join(event, channel); + event.reply(dbot.t('join', {'channel': channel})); + } + }, + + // Leave a channel + 'part': function(event) { + var channel = event.params[1]; + if(!event.allChannels.hasOwnProperty(channel)) { + event.reply("I'm not in that channel."); + } else { + event.instance.part(event, channel); + event.reply(dbot.t('part', {'channel': channel})); + } + }, + + // Op admin caller in given channel + 'opme': function(event) { + var channel = event.params[1]; + + // If given channel isn't valid just op in current one. + if(!event.allChannels.hasOwnProperty(channel)) { + channel = event.channel.name; + } + dbot.instance.mode(event, channel, ' +o ' + event.user); + }, + + // Do a git pull and reload + 'greload': function(event) { + var child = exec("git pull", function (error, stdout, stderr) { + event.reply(dbot.t('gpull')); + commands.reload(event); + }.bind(this)); + }, + + // Reload DB, translations and modules. + 'reload': function(event) { + dbot.db = JSON.parse(fs.readFileSync('db.json', 'utf-8')); + dbot.strings = JSON.parse(fs.readFileSync('strings.json', 'utf-8')); + dbot.reloadModules(); + event.reply(dbot.t('reload')); + }, + + // Say something in a channel (TODO probably doesn't work.) + 'say': function(event) { + var channel = event.params[1]; + if(event.params[1] === "@") { + var channel = event.channel.name; + } + var message = event.params.slice(2).join(' '); + dbot.say(event.server, channel, message); + }, + + // Load new module + 'load': function(event) { + var moduleName = event.params[1]; + dbot.moduleNames.push(moduleName); + dbot.reloadModules(); + event.reply(dbot.t('load_module', {'moduleName': moduleName})); + }, + + // Unload a loaded module + 'unload': function(event) { + var moduleName = event.params[1]; + if(dbot.moduleNames.include(moduleName)) { + var cacheKey = require.resolve('../modules/' + moduleName); + delete require.cache[cacheKey]; + + var moduleIndex = dbot.moduleNames.indexOf(moduleName); + dbot.moduleNames.splice(moduleIndex, 1); + dbot.reloadModules(); + + event.reply(dbot.t('unload_module', {'moduleName': moduleName})); + } else { + event.reply(dbot.t('unload_error', {'moduleName': moduleName})); + } + }, + + // Ban user from command or * + 'ban': function(event) { + var username = event.params[1]; + var command = event.params[2]; + + if(!dbot.db.bans.hasOwnProperty(command)) { + dbot.db.bans[command] = [ ]; + } + dbot.db.bans[command].push(username); + event.reply(dbot.t('banned', {'user': username, 'command': command})); + }, + + // Unban a user from command or * + 'unban': function(event) { + var username = event.params[1]; + var command = event.params[2]; + if(dbot.db.bans.hasOwnProperty(command) && dbot.db.bans[command].include(username)) { + dbot.db.bans[command].splice(dbot.db.bans[command].indexOf(username), 1); + event.reply(dbot.t('unbanned', {'user': username, 'command': command})); + } else { + event.reply(dbot.t('unban_error', {'user': username})); + } + }, + + // Lock quote category so quotes can't be removed + 'lock': function(event) { + var category = event.params[1]; + dbot.db.locks.push(category); + event.reply(dbot.t('qlock', {'category': category})); + } + }; + + return { + 'name': 'admin', + 'ignorable': false, + + /** + * Run the appropriate admin command given the input (and user). + */ + 'listener': function(event) { + var commandName = event.params[0]; + if(commands.hasOwnProperty(commandName) && dbot.admin.include(event.user)) { + commands[commandName](event); + dbot.save(); + } + }, + 'on': 'PRIVMSG' + }; +}; + +exports.fetch = function(dbot) { + return admin(dbot); +}; diff --git a/modules/command/command.js b/modules/command/command.js new file mode 100644 index 0000000..ea3043d --- /dev/null +++ b/modules/command/command.js @@ -0,0 +1,104 @@ +/** + * Module Name: Command + * Description: An essential module which maps PRIVMSG input to an appropriate + * command and then runs that command, given the user isn't banned from or + * ignoring that command. + */ +var command = function(dbot) { + /** + * Is user banned from using command? + */ + var isBanned = function(user, command) { + var banned = false; + if(dbot.db.bans.hasOwnProperty(command)) { + if(dbot.db.bans[command].include(user) || dbot.db.bans['*'].include(user)) { + banned = true; + } + } + return banned; + }; + + /** + * Is user ignoring command? + */ + var isIgnoring = function(user, command) { + var module = dbot.commandMap[command]; + var ignoring = false; + if(dbot.db.ignores.hasOwnProperty(user) && dbot.db.ignores[user].include(module)) { + ignoring = true; + } + return ignoring; + }; + + /** + * Apply Regex to event message, store result. Return false if it doesn't + * apply. + */ + var applyRegex = function(commandName, event) { + var applies = false; + if(dbot.commands[commandName].hasOwnProperty('regex')) { + var cRegex = dbot.commands[commandName].regex; + var q = event.message.valMatch(cRegex[0], cRegex[1]); + if(q) { + applies = true; + event.input = q; + } + } else { + applies = true; + } + return applies; + }; + + return { + 'name': 'command', + 'ignorable': false, + + 'commands': { + '~usage': function(event) { + var commandName = event.params[1]; + console.log(commandName); + if(dbot.commands.hasOwnProperty(commandName)) { + event.reply('Usage for ' + commandName + ': ' + + dbot.commands[commandName].usage); + } else { + event.reply('No usage information for ' + commandName); + } + } + }, + + /** + * Run the appropriate command given the input. + */ + 'listener': function(event) { + var commandName = event.params[0]; + if(!dbot.commands.hasOwnProperty(commandName)) { + commandName = '~'; + } + + if(isBanned(event.user, commandName)) { + event.reply(dbot.t('command_ban', {'user': event.user})); + } else { + if(!isIgnoring(event.user, commandName)) { + if(applyRegex(commandName, event)) { + dbot.commands[commandName](event); + dbot.save(); + } else { + if(commandName !== '~') { + if(dbot.commands[commandName].hasOwnProperty('usage')){ + event.reply('Usage: ' + dbot.commands[commandName].usage); + } else { + event.reply(dbot.t('syntax_error')); + } + } + } + } + } + }, + 'on': 'PRIVMSG' + }; +}; + +exports.fetch = function(dbot) { + return command(dbot); +}; + diff --git a/modules/dice/dice.js b/modules/dice/dice.js new file mode 100644 index 0000000..172822b --- /dev/null +++ b/modules/dice/dice.js @@ -0,0 +1,105 @@ +var parseDiceSpec = function (specString) { + var rawSpec = specString.valMatch(/^([0-9]*)d(%|[0-9]*)(|[+-][0-9]+)$/i, 4); + if (rawSpec !== false) { + if (rawSpec[2] === "%") { + rawSpec[2] = 100; + } + return { + "count": parseInt(rawSpec[1] || 1), + "sides": parseInt(rawSpec[2] || 6), + "modifier": parseInt(rawSpec[3] || 0) + }; + } else { + return false; + } +}; + +var normalizeDiceSpec = function (specString) { + var diceSpec = parseDiceSpec(specString); + + if (diceSpec["sides"] > 10000) { + return false; + } + + if (diceSpec["count"] > 1000) { + return false; + } + + if (diceSpec["count"] > 1) { + var count = diceSpec["count"]; + } else { + var count = ""; + } + + if (diceSpec["sides"] === 100) { + var sides = "%"; + } else { + var sides = diceSpec["sides"]; + } + + if (diceSpec["modifier"] > 0) { + var modifier = "+" + diceSpec["modifier"]; + } else if (diceSpec["modifier"] < 0) { + var modifier = diceSpec["modifier"]; + } else { + var modifier = ""; + } + + return (count + "d" + sides + modifier); +}; + +var dice = function(dbot) { + var commands = { + '~roll': function (event) { + var rolls = []; + + if (event.params.length === 1) { + event.params.push("d6"); + } + + for (var i = 1; i < event.params.length; i++) { + var diceSpec = parseDiceSpec(event.params[i]); + if (diceSpec === false) { + rolls.push([event.params[i], false]); + } else { + rolls.push([normalizeDiceSpec(event.params[i]), [], diceSpec["modifier"]]); + for (var j = 0; j < diceSpec["count"] ; j++) { + rolls[rolls.length-1][1].push(Math.ceil(Math.random() * diceSpec["sides"])); + } + } + } + + for (var i = 0; i < rolls.length; i++) { + if (rolls[i][1] === false) { + event.reply(rolls[i][0] + ": invalid dice spec"); + } else { + if (rolls[i][1].length > 1) { + var total = " (total " + rolls[i][1].sum(); + if (rolls[i][2] != 0) { + if (rolls[i][2] > 0) { + total += " + "; + } else { + total += " - "; + } + total += Math.abs(rolls[i][2]) + " -> " + (rolls[i][1].sum() + rolls[i][2]); + } + total += ")" + } else { + var total = ""; + } + event.reply(rolls[i][0] + ": " + rolls[i][1].join(" ") + total); + } + } + } + }; + + return { + 'name': 'dice', + 'commands': commands, + 'ignorable': true + }; +} + +exports.fetch = function(dbot) { + return dice(dbot); +}; diff --git a/modules/drama/drama.js b/modules/drama/drama.js new file mode 100644 index 0000000..fc9aa3a --- /dev/null +++ b/modules/drama/drama.js @@ -0,0 +1,96 @@ +/** + * Module Name: Drama + * Description: Experimental, you probably don't want it. + */ +var brain = require('brain'); + +var drama = function(dbot) { + var dbot = dbot; + var last = {}; + var options = { + 'backend': { + 'type': 'Redis', + 'options': { + 'hostname': 'localhost', + 'port': 6379, + 'name': 'dbotdrama' + } + }, + + 'thresholds': { + 'drama': 3, + 'beinganasshole': 3, + 'sd': 3, // self depracating + 'normal': 1 + }, + + 'def': 'normal' + }; + var bayes = new brain.BayesianClassifier(options); + + var commands = { + '~train': function(event) { + if(dbot.admin.include(event.user)) { + bayes.train(last[event.params[1]][event.params[2]], event.params[3]); + event.reply('Last thing ' + event.params[2] + ' said in ' + + event.params[1] + ' (' + last[event.params[1]][event.params[2]] + ') classified as \'' + event.params[3] + '\''); + } + }, + + '~rtrain': function(event) { + if(dbot.admin.include(event.user)) { + var category = event.params[1]; + event.params.splice(0, 2); + var msg = event.params.join(' '); + bayes.train(msg, category); + event.reply('\'' + msg + '\' classified as \'' + category + '\''); + } + }, + + '~classify': function(event) { + event.params.splice(0, 1); + var msg = event.params.join(' '); + bayes.classify(msg, function(category) { + event.reply('Classified as: ' + category + '!'); + }.bind(this)); + } + } + + return { + 'name': 'drama', + 'ignorable': false, + 'commands': commands, + + 'listener': function(data) { + var category = bayes.classify(data.message, function(category) { + if(category !== 'normal') { + if(category === 'beinganasshole') { + if(dbot.db.drama.beinganasshole.hasOwnProperty(event.user)) { + dbot.db.drama.beinganasshole[event.user]++; + } else { + dbot.db.drama.beinganasshole[event.user] = 1; + } + } else if(category === 'sd') { + if(dbot.db.drama.sd.hasOwnProperty(event.user)) { + dbot.db.drama.sd[event.user]++; + } else { + dbot.db.drama.sd[event.user] = 1; + } + } + } + }.bind(this)); + + if(last.hasOwnProperty(event.channel)) { + last[event.channel][event.user] = data.message; + } else { + last[event.channel] = { }; + last[event.channel][event.user] = data.message; + } + }, + 'on': 'PRIVMSG' + }; +} + +exports.fetch = function(dbot) { + return drama(dbot); +}; diff --git a/modules/ignore/ignore.js b/modules/ignore/ignore.js new file mode 100644 index 0000000..b7330b7 --- /dev/null +++ b/modules/ignore/ignore.js @@ -0,0 +1,81 @@ +/** + * Module Name: Ignore + * Description: Handles commands in which users can choose to ignore listeners + * and commands from certain modules. It also populates the JSBot instance with + * this information, since that actually performs the ignorance. + */ +var ignore = function(dbot) { + var commands = { + '~ignore': function(event) { + var ignorableModules = []; + for(var i=0;i(.*)<\/title>/, 2); + if(title) { + event.reply(title[1]); + } else { + event.reply('no title found'); + } + } + }); + } + }; + + return { + 'name': 'link', + 'ignorable': true, + 'commands': commands, + + 'listener': function(event) { + var urlMatches = event.message.match(urlRegex); + if(urlMatches !== null) { + links[event.channel.name] = urlMatches[0]; + } + }, + 'on': 'PRIVMSG' + }; +}; + +exports.fetch = function(dbot) { + return link(dbot); +}; diff --git a/modules/poll/poll.js b/modules/poll/poll.js new file mode 100644 index 0000000..2b82282 --- /dev/null +++ b/modules/poll/poll.js @@ -0,0 +1,233 @@ +var poll = function(dbot) { + var polls = dbot.db.polls; + var commands = { + '~newpoll': function(event) { + var av = event.input[1] != undefined; + var name = event.input[2]; + var options = event.input[3].split(','); + var description = event.input[4]; + + if(name === undefined || name === 'help') { + event.reply(dbot.t('newpoll_usage')); + } else { + if(polls.hasOwnProperty(name)) { + event.reply(dbot.t('poll_exists', {'name': name})); + } else { + if(av) { + polls[name] = { + 'av': av, + 'name': name, + 'description': description, + 'owner': event.user, + 'votes': {}, + 'options': [] + }; + for(var i=0;i 0) { + altKey = key.replace(/ /g, '_'); + } + + if(key.charAt(0) !== '_') { // lol + if(quotes.hasOwnProperty(key)) { + event.reply(key + ': ' + interpolatedQuote(key)); + } else if(quotes.hasOwnProperty(altKey)) { + event.reply(altKey + ': ' + interpolatedQuote(altKey)); + } else { + event.reply(dbot.t('category_not_found', {'category': key})); + } + } + }, + + // Shows a list of the biggest categories + '~qstats': function(event) { + var qSizes = Object.prototype.sort(quotes, function(key, obj) { return obj[key].length }); + qSizes = qSizes.slice(qSizes.length - 10).reverse(); + + var qString = dbot.t('large_categories'); + for(var i=0;i 0) { + event.reply(dbot.t('prune', {'categories': pruned.join(", ")})); + } else { + event.reply(dbot.t('no_prune')); + } + } + }; + + commands['~'].regex = [/^~([\d\w\s-]*)/, 2]; + commands['~q'].regex = [/^~q ([\d\w\s-]*)/, 2]; + commands['~qsearch'].regex = [/^~qsearch ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3]; + commands['~rm'].regex = [/^~rm ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3]; + commands['~rmlast'].regex = [/^~rmlast ([\d\w\s-]*)/, 2]; + commands['~qadd'].regex = [/^~qadd ([\d\w\s-]+?)[ ]?=[ ]?(.+)$/, 3]; + + commands['~q'].usage = '~q [category]'; + commands['~qsearch'].usage = '~qsearch [category]=[search]'; + commands['~rm'].usage = '~rm [category]=[quote to delete]'; + commands['~rmlast'].usage = '~rmlast [category]' + commands['~qadd'].usage = '~qadd [category]=[content]'; + + return { + 'name': 'quotes', + 'ignorable': true, + 'commands': commands, + + 'onLoad': function() { + dbot.timers.addTimer(1000 * 60 * 3, function() { + rmAllowed = true; + }); + }, + + 'listener': function(event) { + if((dbot.db.ignores.hasOwnProperty(event) && + dbot.db.ignores[event.user].include(name)) == false) { + if(event.user == 'reality') { + var once = event.message.valMatch(/^I ([\d\w\s,'-]* once)/, 2); + } else { + var once = event.message.valMatch(/^reality ([\d\w\s,'-]* once)/, 2); + } + + if(once) { + if((dbot.db.bans.hasOwnProperty('~qadd') && + dbot.db.bans['~qadd'].include(event.user)) || + dbot.db.bans['*'].include(event.user)) { + event.reply(dbot.t('command_ban', {'user': event.user})); + } else { + if(!dbot.db.quoteArrs.hasOwnProperty('realityonce')) { + dbot.db.quoteArrs['realityonce'] = []; + } + if(dbot.db.quoteArrs['realityonce'].include('reality ' + once[1] + '.')) { + event.reply(event.user + ': reality has already done that once.'); + } else { + dbot.db.quoteArrs['realityonce'].push('reality ' + once[1] + '.'); + addStack.push('realityonce'); + rmAllowed = true; + event.reply('\'reality ' + once[1] + '.\' saved.'); + } + } + } + } + }, + + 'on': 'PRIVMSG' + }; +}; + +exports.fetch = function(dbot) { + return quotes(dbot); +}; diff --git a/modules/report/report.js b/modules/report/report.js new file mode 100644 index 0000000..f3f4c2f --- /dev/null +++ b/modules/report/report.js @@ -0,0 +1,52 @@ +var report = function(dbot) { + var commands = { + '~report': function(event) { + var channelName = event.input[1]; + var nick = event.input[2]; + var reason = event.input[3]; + + if(event.allChannels.hasOwnProperty(channelName)) { + var channel = event.allChannels[channelName]; + if(channel.nicks.hasOwnProperty(nick)) { + var ops = []; + for(var possibOps in channel.nicks) { + if(channel.nicks[possibOps].op == true) { + ops.push(possibOps); + } + } + + // Does the channel have an admin channel? + if(event.allChannels.hasOwnProperty('#' + channelName)) { + ops.push('#' + channelName); + } + + for(var i=0;i 0)) { + winner = candidates[i]; + winnerDistance = distance; + } + } + + if(winnerDistance < Math.ceil(winner.length * 1.33)) { + if(winner !== correction) { + var fix = last[event.channel.name][candidate].replace(winner, correction); + if (/^.ACTION/.test(fix)) { + fix = fix.replace(/^.ACTION/, '/me'); + } + last[event.channel.name][candidate] = fix; + var output = { + 'fix': fix, + 'correcter': event.user, + 'candidate': candidate + }; + output_callback(output); + } + } + } + + return { + 'name': 'spelling', + 'ignorable': true, + + 'listener': function(event) { + var q = event.message.valMatch(/^(?:\*\*?([\d\w\s']*)|([\d\w\s']*)\*\*?)$/, 3); + var otherQ = event.message.valMatch(/^([\d\w\s]*): (?:\*\*?([\d\w\s']*)|([\d\w\s']*)\*\*?)$/, 4); + if(q) { + correct(event, q[1] || q[2], event.user, function (e) { + event.reply(dbot.t('spelling_self', e)); + }); + } else if(otherQ) { + correct(event, otherQ[2] || otherQ[3], otherQ[1], function (e) { + event.reply(dbot.t('spelling_other', e)); + }); + } else { + if(last.hasOwnProperty(event.channel.name)) { + last[event.channel.name][event.user] = event.message; + } else { + last[event.channel.name] = { }; + last[event.channel.name][event.user] = event.message; + } + } + }, + 'on': 'PRIVMSG' + } +} + +exports.fetch = function(dbot) { + return spelling(dbot); +}; diff --git a/modules/web/web.js b/modules/web/web.js new file mode 100644 index 0000000..1be542a --- /dev/null +++ b/modules/web/web.js @@ -0,0 +1,130 @@ +var express = require('express'); + +var webInterface = function(dbot) { + var pub = 'public'; + var app = express.createServer(); + + app.use(express.compiler({ src: pub, enable: ['sass'] })); + app.use(express.static(pub)); + app.set('view engine', 'jade'); + + app.get('/', function(req, res) { + res.render('index', { 'name': dbot.name }); + }); + + app.get('/connections', function(req, res) { + var connections = Object.keys(dbot.instance.connections); + res.render('connections', { 'name': dbot.name, 'connections': connections }); + }); + + app.get('/channels/:connection', function(req, res) { + var connection = req.params.connection; + if(dbot.instance.connections.hasOwnProperty(connection)) { + var channels = Object.keys(dbot.instance.connections[connection].channels); + res.render('channels', { 'name': dbot.name, 'connection': connection, 'channels': channels}); + } else { + res.render('error', { 'name': dbot.name, 'message': 'No such connection.' }); + } + }); + + app.get('/users/:connection/:channel', function(req, res) { + var connection = req.params.connection; + var channel = '#' + req.params.channel; + var connections = dbot.instance.connections; + + if(connections.hasOwnProperty(connection) && + connections[connection].channels.hasOwnProperty(channel)) { + var nicks = Object.keys(connections[connection].channels[channel].nicks); + res.render('users', { 'name': dbot.name, 'connection': connection, + 'channel': channel, 'nicks': nicks }); + } else { + res.render('error', { 'name': dbot.name, 'message': 'No such connection or channel.' }); + } + }); + + app.get('/user/:connection/:channel/:user', function(req, res) { + var connection = req.params.connection; + var channel = '#' + req.params.channel; + var user = dbot.cleanNick(req.params.user); + + var quoteCount = 'no'; + if(dbot.db.quoteArrs.hasOwnProperty(user)) { + var quoteCount = dbot.db.quoteArrs[user].length; + } + + if(!dbot.db.kicks.hasOwnProperty(req.params.user)) { + var kicks = '0'; + } else { + var kicks = dbot.db.kicks[req.params.user]; + } + + if(!dbot.db.kickers.hasOwnProperty(req.params.user)) { + var kicked = '0'; + } else { + var kicked = dbot.db.kickers[req.params.user]; + } + + res.render('user', { 'name': dbot.name, 'user': req.params.user, + 'channel': channel, 'connection': connection, 'cleanUser': user, + 'quotecount': quoteCount, 'kicks': kicks, 'kicked': kicked }); + }); + + // Lists the quote categories + app.get('/quotes', function(req, res) { + res.render('quotelist', { 'name': dbot.name, 'quotelist': Object.keys(dbot.db.quoteArrs) }); + }); + + // Lists quotes in a category + app.get('/quotes/:key', function(req, res) { + var key = req.params.key.toLowerCase(); + if(dbot.db.quoteArrs.hasOwnProperty(key)) { + res.render('quotes', { 'name': dbot.name, 'quotes': dbot.db.quoteArrs[key], locals: { 'url_regex': RegExp.prototype.url_regex() } }); + } else { + res.render('error', { 'name': dbot.name, 'message': 'No quotes under that key.' }); + } + }); + + // Load random quote category page + app.get('/rq', function(req, res) { + var rCategory = Object.keys(dbot.db.quoteArrs).random(); + res.render('quotes', { 'name': dbot.name, 'quotes': dbot.db.quoteArrs[rCategory], locals: { 'url_regex': RegExp.prototype.url_regex() } }); + }); + + // Lists all of the polls + app.get('/polls', function(req, res) { + res.render('polllist', { 'name': dbot.name, 'polllist': Object.keys(dbot.db.polls) }); + }); + + // Shows the results of a poll + app.get('/polls/:key', function(req, res) { + var key = req.params.key.toLowerCase(); + if(dbot.db.polls.hasOwnProperty(key) && dbot.db.polls[key].hasOwnProperty('description')) { + // tally the votes + var totalVotes = 0; + for( var v in dbot.db.polls[key].votes ) { + var N = Number(dbot.db.polls[key].votes[v]); + if( !isNaN(N) ) { + totalVotes += N; + } + } + res.render('polls', { 'name': dbot.name, 'description': dbot.db.polls[key].description, 'votees': Object.keys(dbot.db.polls[key].votees), 'options': dbot.db.polls[key].votes, locals: { 'totalVotes': totalVotes, 'url_regex': RegExp.prototype.url_regex() } }); + } else { + res.render('error', { 'name': dbot.name, 'message': 'No polls under that key.' }); + } + }); + + app.listen(dbot.webPort); + + return { + 'name': 'web', + 'ignorable': false, + + 'onDestroy': function() { + app.close(); + } + }; +}; + +exports.fetch = function(dbot) { + return webInterface(dbot); +}; diff --git a/modules/youare/youare.js b/modules/youare/youare.js new file mode 100644 index 0000000..ddb25e0 --- /dev/null +++ b/modules/youare/youare.js @@ -0,0 +1,19 @@ +var youAre = function(dbot) { + return { + 'name': 'youare', + 'ignorable': false, + + 'listener': function(event) { + var key = event.message.valMatch(/(\bis\b|\bare\b)\s+([\w\s\d]*?)(\s+)?(,|\.|\band\b|$)/, 5); + + if(key && key[2] != "" && Number.prototype.chanceIn(1, 100) && event.user != 'aisbot') { + event.reply(event.user + ': You\'re ' + key[2] + '.'); + } + }, + 'on': 'PRIVMSG' + }; +}; + +exports.fetch = function(dbot) { + return youAre(dbot); +};