diff --git a/config.json.sample b/config.json.sample index 1f1501e..be6de54 100644 --- a/config.json.sample +++ b/config.json.sample @@ -13,7 +13,7 @@ }, "admins": [ "batman" ], "moderators": [ "whatever" ], - "moduleNames": [ "ignore", "admin", "command", "dice", "js", "kick", "quotes", "spelling", "youare", "stats", "users" ], + "moduleNames": [ "ignore", "admin", "command", "dice", "js", "kick", "quotes", "spelling", "youare", "stats", "users", "link" ], "language": "en", "debugMode": true, "version": "Depressionbot IRC bot 0.4-dev - Lovingly crafted by The DepressionBot Foundation (a charity arm of the Official Aberystwyth Open Source International Development League)." diff --git a/install.sh b/install.sh index 8a8d85d..d175afb 100755 --- a/install.sh +++ b/install.sh @@ -3,6 +3,17 @@ cat LICENCE git submodule init git submodule update +if [ ! -e /usr/bin/node ] && [ ! -e /usr/local/bin/node ]; +then + echo 'node.js is not installed. Please install it before running install.sh.' + exit 1 +fi +if [ ! -e /usr/bin/npm ] && [ ! -e /usr/local/bin/npm ]; +then + echo 'npm is not installed. Please install it before running install.sh' + exit 1 +fi + npm install underscore request sandbox express moment jade@0.25 cd public/ diff --git a/modules/admin/commands.js b/modules/admin/commands.js index c648760..b272d8f 100644 --- a/modules/admin/commands.js +++ b/modules/admin/commands.js @@ -23,10 +23,10 @@ var commands = function(dbot) { return false; } } - } + } var currentOption; - if(configKey.length != 1) { + if(configKey && configKey.length != 1) { configKey = _.last(configKey); if(_.has(userConfigPath, configKey) && !_.isUndefined(userConfigPath[configKey])) { currentOption = userConfigPath[configKey]; @@ -173,8 +173,10 @@ var commands = function(dbot) { var moduleName = event.params[1]; if(_.include(moduleNames, moduleName)) { var moduleDir = '../' + moduleName + '/'; - var cacheKey = require.resolve(moduleDir + moduleName); - delete require.cache[cacheKey]; + try { + var cacheKey = require.resolve(moduleDir + moduleName); + delete require.cache[cacheKey]; + } catch(err) { } dbot.config.moduleNames = _.without(dbot.config.moduleNames, moduleName); dbot.reloadModules(); @@ -184,32 +186,6 @@ var commands = function(dbot) { } }, - // Ban user from command or * - 'ban': function(event) { - var username = event.params[1]; - var command = event.params[2]; - - if(!_.has(dbot.db.bans, 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(_.has(dbot.db.bans, command) && _.include(dbot.db.bans[command], username)) { - _.reject(dbot.db.bans[command], function(bans) { - return bans == username; - }, this); - event.reply(dbot.t('unbanned', {'user': username, 'command': command})); - } else { - event.reply(dbot.t('unban_error', {'user': username})); - } - }, - /*** Config options ***/ 'setconfig': function(event) { @@ -291,19 +267,15 @@ var commands = function(dbot) { } }; - commands['greload'].access = 'admin'; - commands['reload'].access = 'admin'; - commands['unload'].access = 'admin'; - commands['load'].access = 'admin'; - commands['version'].access = 'admin'; - commands['setconfig'].access = 'admin'; + _.each(commands, function(command) { + command.access = 'admin'; + }); + commands['showconfig'].access = 'moderator'; commands['join'].access = 'moderator'; commands['part'].access = 'moderator'; commands['opme'].access = 'moderator'; commands['say'].access = 'moderator'; - commands['ban'].access = 'moderator'; - commands['unban'].access = 'moderator'; return commands; }; diff --git a/modules/admin/config.json b/modules/admin/config.json index 009fb85..f87d4b9 100644 --- a/modules/admin/config.json +++ b/modules/admin/config.json @@ -1,6 +1,5 @@ { "ignorable": false, - "dbKeys": [ "bans" ], "dependencies": [ "command" ], "help": "http://github.com/reality/depressionbot/blob/master/modules/admin/README.md" } diff --git a/modules/command/api.js b/modules/command/api.js index 51202e9..dd19b9e 100644 --- a/modules/command/api.js +++ b/modules/command/api.js @@ -4,8 +4,10 @@ var api = function(dbot) { return { 'isBanned': function(user, command) { var banned = false; - if(_.has(dbot.db.bans, command)) { - if(_.include(dbot.db.bans[command], user) || _.include(dbot.db.bans['*'], user)) { + if(_.has(dbot.db.bans, user)) { + if(_.include(dbot.db.bans[user], command) || + _.include(dbot.db.bans[user], dbot.commands[command].module) || + _.include(dbot.db.bans[user], '*')) { banned = true; } } @@ -39,7 +41,8 @@ var api = function(dbot) { 'isIgnoring': function(item, command) { var module = dbot.commands[command].module; return (_.has(dbot.db.ignores, item) && - _.include(dbot.db.ignores[item], module)); + (_.include(dbot.db.ignores[item], module) || + _.include(dbot.db.ignores[item], '*'))); }, /** diff --git a/modules/command/commands.js b/modules/command/commands.js index 96ac77a..68d7a28 100644 --- a/modules/command/commands.js +++ b/modules/command/commands.js @@ -18,8 +18,27 @@ var commands = function(dbot) { '~help': function(event) { var moduleName = event.params[1]; + if(!moduleName) { + helpfulModules = _.filter(dbot.modules, function(element, index, array) { + return _.has(dbot.config[element], 'help'); + }); + + event.reply(dbot.t('usage', { + 'command': '~help', + 'usage': '~help [module]' + })); + event.reply(dbot.t('loaded_modules_with_help', { + 'modules': helpfulModules.join(', ') + })); + return; + } + if(!_.has(dbot.modules, moduleName)) { - var moduleName = dbot.commands[moduleName].module; + if(_.has(dbot.commands, moduleName)) { + var moduleName = dbot.commands[moduleName].module; + } else { + var moduleName = undefined; + } } if(moduleName && _.has(dbot.config[moduleName], 'help')) { diff --git a/modules/command/config.json b/modules/command/config.json index f7de9b5..bace93b 100644 --- a/modules/command/config.json +++ b/modules/command/config.json @@ -1,5 +1,5 @@ { "ignorable": false, "help": "http://github.com/reality/depressionbot/blob/master/modules/command/README.md", - "dbKeys": [ "ignores" ] + "dbKeys": [ "ignores", "bans" ] } diff --git a/modules/command/strings.json b/modules/command/strings.json index 676532e..341aae2 100644 --- a/modules/command/strings.json +++ b/modules/command/strings.json @@ -26,5 +26,8 @@ "no_help": { "en": "No help found for {module}.", "na'vi": "Fì{module}ìri oel ke tsun run srungit" + }, + "loaded_modules_with_help": { + "en": "Loaded modules with help information: {modules}." } } diff --git a/modules/command/usage.json b/modules/command/usage.json new file mode 100644 index 0000000..8aaf80e --- /dev/null +++ b/modules/command/usage.json @@ -0,0 +1,4 @@ +{ + "~usage": "~usage [command]", + "~help": "~help [module]" +} diff --git a/modules/dns/README.md b/modules/dns/README.md new file mode 100644 index 0000000..f730352 --- /dev/null +++ b/modules/dns/README.md @@ -0,0 +1,17 @@ +## DNS + +Performs and reports upon basic DNS functions. + +### Description + +This module utilises the domain name system to discover basic information about +domain names and IP addresses. + +### Commands + +#### ~lookup [domain name] +Looks up the specified domain name in the domain name system. If a match is found, +the first corresponding A or AAAA record is displayed. +#### ~rdns [IP address] +Looks up the specified IP address in the domain name system. If a match is found, +the first corresponding rDNS domain name is displayed. diff --git a/modules/dns/dns.js b/modules/dns/dns.js new file mode 100644 index 0000000..e061d83 --- /dev/null +++ b/modules/dns/dns.js @@ -0,0 +1,37 @@ +/** + * Module Name: DNS + * Description: Performs and reports on basic DNS functions. + */ +var dnsmod = require('dns'); + +var dns = function(dbot) { + var commands = { + '~lookup': function(event) { + domain = event.params[1]; + dnsmod.lookup(domain, function (error, addr) { + if (error) { + event.reply(dbot.t("lookup-error",{"domain": domain, "code": error.code})); + } else { + event.reply(dbot.t("lookup",{"domain": domain, "address": addr})); + } + }); + }, + '~rdns': function(event) { + ip = event.params[1]; + dnsmod.reverse(ip, function (error, domain) { + if (error) { + event.reply(dbot.t("rdns-error",{"domain": domain, "ip": ip, "error": error.code})); + } else { + event.reply(dbot.t("rdns",{"domain": domain, "ip": ip})); + } + }); + } + }; + this.commands = commands; + + this.on = 'PRIVMSG'; +}; + +exports.fetch = function(dbot) { + return new dns(dbot); +}; diff --git a/modules/dns/strings.json b/modules/dns/strings.json new file mode 100644 index 0000000..f8c69bc --- /dev/null +++ b/modules/dns/strings.json @@ -0,0 +1,14 @@ +{ + "lookup-error": { + "en": "{domain} is \u000303AVAILABLE! \u000314({code})" + }, + "lookup": { + "en": "{domain} is \u000305TAKEN! \u000314({address})" + }, + "rdns": { + "en": "{ip} \u2192 {domain}" + }, + "rdns-error": { + "en": "Unable to lookup {ip}. \u000314({error})" + } +} diff --git a/modules/finger/README.md b/modules/finger/README.md deleted file mode 100644 index 549e850..0000000 --- a/modules/finger/README.md +++ /dev/null @@ -1,13 +0,0 @@ -## Finger - -Retrieves user information from a remote server. - -### Description -Uses the ``finger`` command to retrieve limited information on users. - - -### Commands -###~finger [username] -Returns the real name of the user specified. -### Dependencies -* ``npm install request`` diff --git a/modules/finger/finger.js b/modules/finger/finger.js deleted file mode 100644 index f0a2e34..0000000 --- a/modules/finger/finger.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Module Name: Finger - * Description: Returns the name of users via the Finger protocol - */ -var request = require('request'), - _ = require('underscore')._, - exec = require('child_process').exec; - -var finger = function(dbot) { - var commands = { - '~finger': function(event) { - var username = event.params[1]; - exec("finger -s " + username + "@central.aber.ac.uk",function(error,stdout,stderr){ - stdout = stdout.replace(/(\r\n|\n|\r)/gm,""); - name = stdout.search("Name:"); - stdout = stdout.substring(name); - ret = stdout.search("Dir"); - stdout = stdout.substring(6,ret); - if (stdout == "Welcom") { - event.reply(dbot.t("nonexistent",{user: username})); - } else { - event.reply(dbot.t("name",{user: username, name: stdout})); - } - }); - } - }; - this.commands = commands; - - this.on = 'PRIVMSG'; -}; - -exports.fetch = function(dbot) { - return new finger(dbot); -}; diff --git a/modules/finger/strings.json b/modules/finger/strings.json deleted file mode 100644 index 710e0f5..0000000 --- a/modules/finger/strings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": { - "en": "{user} is {name}." - }, - "nonexistent": { - "en": "{user} not found." - } -} diff --git a/modules/ignore/config.json b/modules/ignore/config.json index fa1961a..14e12c2 100644 --- a/modules/ignore/config.json +++ b/modules/ignore/config.json @@ -1,6 +1,6 @@ { "ignorable": false, "dependencies": [ "command" ], - "dbKeys": [ "ignores" ], + "dbKeys": [ "ignores", "bans" ], "help": "http://github.com/reality/depressionbot/blob/master/modules/ignore/README.md" } diff --git a/modules/ignore/ignore.js b/modules/ignore/ignore.js index 9fa9eac..3e3d974 100644 --- a/modules/ignore/ignore.js +++ b/modules/ignore/ignore.js @@ -24,7 +24,7 @@ var ignore = function(dbot) { 'modules': ignorableModules.join(', ') })); } else { - if(_.include(ignorableModules, module)) { + if(module == '*' || _.include(ignorableModules, module)) { if(_.has(dbot.db.ignores, event.user) && _.include(dbot.db.ignores[event.user], module)) { event.reply(dbot.t('already_ignoring', { 'user': event.user })); } else { @@ -72,12 +72,72 @@ var ignore = function(dbot) { } }, + '~ban': function(event) { + var user = event.params[1]; + var module = event.params[2]; + + if(_.isUndefined(user) || _.isUndefined(module)) { + event.reply(dbot.t('ban_usage', {'user': event.user})); + return; + } + + if(module == '*' || _.include(dbot.config.moduleNames, module) || _.include(dbot.commands, module)) { + if(_.has(dbot.db.bans, user) && _.include(dbot.db.bans[user], module)) { + event.reply(dbot.t('already_banned', { + 'user': event.user, + 'banned': user + })); + return; + } + + if(_.has(dbot.db.bans, event.params[1])) { + dbot.db.bans[event.params[1]].push(module); + } else { + dbot.db.bans[event.params[1]] = [module]; + } + + event.reply(dbot.t('banned_success', { + 'user': event.user, + 'banned': user, + 'module': module + })); + } else { + event.reply(dbot.t('invalid_ban', {'user': event.user})); + } + }, + + '~unban': function(event) { + var bannedModules = []; + + var user = event.params[1]; + var module = event.params[2]; + + if(_.isUndefined(user) || _.isUndefined(module)) { + event.reply(dbot.t('unban_usage', {'user': event.user})); + } else { + if(_.has(dbot.db.bans, user) && _.include(dbot.db.bans[user], module)) { + dbot.db.bans[user].splice(dbot.db.bans[user].indexOf(module), 1); + + event.reply(dbot.t('unbanned_success', { + 'user': event.user, + 'banned': user, + 'module': module + })); + } else { + event.reply(dbot.t('invalid_unban', { + 'user': event.user, + 'banned': user + })); + } + } + }, + '~ignorechannel': function(event) { var channel = ((event.params[1] == '@') ? event.channel.name : event.params[1]); var module = event.params[2]; // Ignoring the value of 'ignorable' at the moment - if(_.include(dbot.config.moduleNames, module)) { + if(module == '*' || _.include(dbot.config.moduleNames, module)) { if(!_.has(dbot.db.ignores, channel)) dbot.db.ignores[channel] = []; if(!_.include(dbot.db.ignores[channel], module)) { dbot.db.ignores[channel].push(module); @@ -118,6 +178,8 @@ var ignore = function(dbot) { } }; + commands['~ban'].access = 'moderator'; + commands['~unban'].access = 'moderator'; commands['~ignorechannel'].access = 'moderator'; commands['~unignorechannel'].access = 'moderator'; diff --git a/modules/ignore/strings.json b/modules/ignore/strings.json index 8202cb0..0badd2a 100644 --- a/modules/ignore/strings.json +++ b/modules/ignore/strings.json @@ -41,6 +41,27 @@ "na'vi": "{user}: Nga terìng mikyun {module}ne set", "cy": "{user}: Ddim yn anwybyddu {module} bellach" }, + "ban_usage": { + "en": "{user}: Usage: ~ban [user] [module/command]. Use * for all modules and commands." + }, + "already_banned": { + "en": "{user}: {banned} is already banned from that module." + }, + "banned_success": { + "en": "{user}: {banned} is now banned from {module}." + }, + "invalid_ban": { + "en": "{user}: That isn't a valid module name." + }, + "unban_usage": { + "en": "{user}: Usage: ~unban [user] [module]." + }, + "invalid_unban": { + "en": "{user}: {banned} is not banned from that module or it doesn't exist." + }, + "unbanned_success": { + "en": "{user}: {banned} is no longer banned from {module}." + }, "ignoring_channel": { "en": "Now ignoring {module} in {channel}", "na'vi": "Oe ke stayawm {module}ur mì {channel}" diff --git a/modules/link/link.js b/modules/link/link.js index 2d9c994..e07c178 100644 --- a/modules/link/link.js +++ b/modules/link/link.js @@ -16,7 +16,7 @@ var link = function(dbot) { body = body.replace(/(\r\n|\n\r|\n)/gm, " "); var title = body.valMatch(/(.*)<\/title>/, 2); if(title && title.length < 140) { - event.reply(ent.decode(title[1])); + event.reply(ent.decode(title[1]).trim()); } } }); diff --git a/modules/quotes/commands.js b/modules/quotes/commands.js index c1abaee..5fc8324 100644 --- a/modules/quotes/commands.js +++ b/modules/quotes/commands.js @@ -7,6 +7,32 @@ var commands = function(dbot) { var quotes = dbot.db.quoteArrs; var commands = { + /*** Quote Addition ***/ + + // Add a quote to a category + '~qadd': function(event) { + var key = event.input[1].toLowerCase(); + var quote = event.input[2]; + + this.db.indexOf('quote_category', key, quote, function(err, index) { + if(index == null || index == -1) { + this.db.append('quote_category', key, quote, function(err, newCount) { + this.rmAllowed = true; + dbot.api.event.emit('~qadd', { + 'key': key, + 'text': quote + }); + event.reply(dbot.t('quote_saved', { + 'category': key, + 'count': newCount + })); + }.bind(this)); + } else { + event.reply(dbot.t('quote_exists')); + } + }.bind(this)); + }, + /*** Quote Retrieval ***/ // Alternative ~q syntax @@ -27,6 +53,15 @@ var commands = function(dbot) { }); }, + '~rq': function(event) { + if(_.keys(quotes).length > 0) { + var category = _.keys(quotes)[_.random(0, _.size(quotes) -1)]; + event.reply(category + ': ' + this.internalAPI.interpolatedQuote(event.server, event.channel.name, category)); + } else { + event.reply(dbot.t('no_results')); + } + }, + /*** Quote Removal ***/ // Show number of quotes in removal cache @@ -145,7 +180,6 @@ var commands = function(dbot) { }, // Search a given category for some text. - // TODO fix '~qsearch': function(event) { var haystack = event.input[1].trim().toLowerCase(); var needle = event.input[2]; @@ -171,7 +205,8 @@ var commands = function(dbot) { } }.bind(this)); }, - + + // Count quotes in a given category or total quotes overall '~qcount': function(event) { var input = event.message.valMatch(/^~qcount ([\d\w\s-]*)/, 2); if(input) { // Give quote count for named category @@ -198,51 +233,28 @@ var commands = function(dbot) { } }, - '~qadd': function(event) { - var key = event.input[1].toLowerCase(); - var quote = event.input[2]; - - this.db.indexOf('quote_category', key, quote, function(err, index) { - if(index == null || index == -1) { - this.db.append('quote_category', key, quote, function(err, newCount) { - this.rmAllowed = true; - dbot.api.event.emit('~qadd', { - 'key': key, - 'text': quote - }); - event.reply(dbot.t('quote_saved', { - 'category': key, - 'count': newCount - })); - }.bind(this)); - } else { - event.reply(dbot.t('quote_exists')); - } - }.bind(this)); - }, - - '~rq': function(event) { - var category = _.keys(quotes)[_.random(0, _.size(quotes) -1)]; - event.reply(category + ': ' + this.internalAPI.interpolatedQuote(event.server, event.channel.name, category)); - }, - + // Link to quote web page '~link': function(event) { var key = event.input[1].toLowerCase(); this.db.read('quote_category', key, function(err, category) { if(!err) { - event.reply(dbot.t('quote_link', { - 'category': key, - 'url': dbot.t('url', { - 'host': dbot.config.web.webHost, - 'port': dbot.config.web.webPort, - 'path': 'quotes/' + key - }) - })); + if(_.has(dbot.config, 'web') && _.has(dbot.config.web, 'webHost') + event.reply(dbot.t('quote_link', { + 'category': key, + 'url': dbot.t('url', { + 'host': dbot.config.web.webHost, + 'port': dbot.config.web.webPort, + 'path': 'quotes/' + encodeURIComponent(key) + }) + })); + } else { + event.reply(dbot.t('web_not_configured')); + } } else if(err == NoSuchThingError) { event.reply(dbot.t('category_not_found', { 'category': key })); } }); - }, + } }; commands['~'].regex = [/^~([\d\w\s-]*)/, 2]; @@ -250,7 +262,7 @@ var commands = function(dbot) { 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['~qadd'].regex = [/^~qadd ([\d\w-]+[\d\w\s-]*)[ ]?=[ ]?(.+)$/, 3]; commands['~link'].regex = [/^~link ([\d\w\s-]*)/, 2]; commands['~rmconfirm'].access = 'moderator'; diff --git a/modules/quotes/strings.json b/modules/quotes/strings.json index 5c3d3d3..2622f68 100644 --- a/modules/quotes/strings.json +++ b/modules/quotes/strings.json @@ -126,5 +126,8 @@ "rm_cache_limit": { "en": "Attention: Too many quotes removed, rmCache must be cleared or reinstated manually with ~rmconfirm or ~rmdeny.", "na'vi": "Oel zerok 'upxareti apxay set, sweylu txo nga 'aivku upxareti ìlä ~rmconfirm fu ~rmdeny." + }, + "web_not_configured": { + "en": "Cannot link to category. Web module is either not loaded or misconfigured." } } diff --git a/modules/users/api.js b/modules/users/api.js index 4d13814..635f748 100644 --- a/modules/users/api.js +++ b/modules/users/api.js @@ -1,4 +1,9 @@ -var _ = require('underscore')._; +var _ = require('underscore')._, + uuid = require('node-uuid'); + databank = require('databank'), + AlreadyExistsError = databank.AlreadyExistsError, + NoSuchThingError = databank.NoSuchThingError, + NotImplementedError = databank.NotImplementedError; var api = function(dbot) { var escapeRegexen = function(str) { @@ -6,113 +11,113 @@ var api = function(dbot) { }; var api = { - 'resolveUser': function(server, nick, useLowerCase) { - var user = nick; + 'resolveUser': function(server, nick, callback) { if(this.api.isPrimaryUser(nick)) { - return user; + callback(nick); } else { + var user = false; this.db.search('user', { 'server': server }, function(user) { if(_.include(user.aliases, nick)) user = user.primaryNick; - }.bind(this), function(err) { - if(err instanceof NotImplementedError) { - // QQ + }, function(err) { + if(!err) { + callback(user); } }); - return user; - } - - /** TODO: Re-add lowercase support - if(!useLowerCase) { - if(!_.include(knownUsers.users, nick) && _.has(knownUsers.aliases, nick)) { - user = knownUsers.aliases[nick]; - } - } else { - // this is retarded - user = user.toLowerCase(); - var toMatch = new RegExp("^" + escapeRegexen(user) + "$", "i"); - - var resolvedUser = _.find(knownUsers.users, function(nick) { - return nick.match(toMatch) !== null; - }, this); - - if(!resolvedUser) { - resolvedUser = _.find(knownUsers.aliases, function(nick, alias) { - if(alias.match(toMatch) !== null) return nick; - }, this); - if(!_.isUndefined(resolvedUser)) user = resolvedUser; - } - else{ - user = resolvedUser; - } - } - return user; - **/ - }, - - 'getRandomChannelUser': function(server, channel) { - this.db.get('channel_users', { '' }) - var channelUsers = this.getServerUsers(server).channelUsers[channel]; - if(!_.isUndefined(channelUsers)) { - return channelUsers[_.random(0, channelUsers.length - 1)]; - } else { - return false; } }, - 'getServerUsers': function(server) { + 'getRandomChannelUser': function(server, channel, callback) { + var channel; + this.db.search('channel_users', { + 'server': server, + 'channel': channel + }, function(result) { + channel = result; + }, function(err) { + if(!err) { + if(!_.isUndefined(channel.users)) { + callback(channel.users[_.random(0, channel.users.length - 1)]); + } else { + callback(false); + } + } + }); + }, + + 'getServerUsers': function(server, callback) { var users = []; - this.db.search('user', { 'server': server }, function(user) { - users.push(user.primaryNick); - }.bind(this), function(err) { - if(err instanceof NotImplementedError) { - // QQ + this.db.search('users', { 'server': server }, function(user) { + users.push(user); + }, function(err) { + if(!err) { + callback(users); } }); - - return users; }, - 'getAllUsers': function() { - return _.reduce(dbot.db.knownUsers, function(memo, server, name) { - memo[name] = server.users; - return memo; - }, {}, this); + 'getAllUsers': function(callback) { + var users = []; + this.db.scan('users', function(user) { + users.push(user); + }, function(err) { + if(!err) { + callback(users); + } + }); }, - 'isKnownUser': function(server, nick) { - var knownUsers = this.getServerUsers(server); - return (_.include(knownUsers.users, nick) || _.has(knownUsers.aliases, nick)); + 'isKnownUser': function(server, nick, callback) { + this.api.resolveUser(server, nick, function(isKnown) { + if(isKnown == false) { + callback(false); + } else { + callback(true); + } + }); }, - 'isPrimaryUser': function(server, nick) { - var knownUsers = this.getServerUsers(server); - return _.include(knownUsers.users, nick); + 'isPrimaryUser': function(server, nick, callback) { + var isPrimaryUser = false; + this.db.search('users', { + 'server': server, + 'primaryNick': nick + }, function(user) { + isPrimaryUser = true; + }, function(err) { + if(!err) { + callback(isPrimaryUser); + } + }); }, - 'getAliases': function(server, nick) { - var knownUsers = this.getServerUsers(server); - return _.chain(knownUsers.aliases) - .keys() - .filter(function(user) { - return knownUsers.aliases[user] == nick; - }, this) - .value(); + 'getAliases': function(server, nick, callback) { + var aliases; + this.db.search('users', { + 'server': server, + 'primaryNick': nick + }, function(result) { + aliases = result.aliases; + }, function(err) { + callback(aliases); + }); }, - 'isOnline': function(server, user, channel, useLowerCase) { + 'isOnline': function(server, user, channel, callback) { var user = this.api.resolveUser(server, user, useLowerCase); var possiNicks = [user].concat(this.api.getAliases(server, user)); if(!_.has(dbot.instance.connections[server].channels, channel)) return false; var onlineNicks = dbot.instance.connections[server].channels[channel].nicks; - return _.any(onlineNicks, function(nick) { + var isOnline = _.any(onlineNicks, function(nick) { nick = nick.name; return _.include(possiNicks, nick); }, this); + + callback(isOnline); }, - 'isChannelUser': function(server, user, channel, useLowerCase) { + 'isChannelUser': function(server, user, channel) { var knownUsers = this.getServerUsers(server); var user = this.api.resolveUser(server, user, useLowerCase); diff --git a/modules/users/commands.js b/modules/users/commands.js index ed1d561..57452c1 100644 --- a/modules/users/commands.js +++ b/modules/users/commands.js @@ -12,12 +12,8 @@ var commands = function(dbot) { if(aliasCount != 0) { var aliases = _.first(aliases, 10); - var including = 'including: '; - for(var i=0;i<aliases.length;i++) { - including += aliases[i] + ', '; - } - including = including.slice(0, -2) + '.'; - + var including = 'including: ' + aliases.join(', ') + '.'; + event.reply(dbot.t('primary', { 'user': alias, 'count': aliasCount @@ -26,7 +22,7 @@ var commands = function(dbot) { event.reply(dbot.t('primary', { 'user': alias, 'count': aliasCount - })); + }).slice(0, -2) + "."); } } else if(_.has(knownUsers.aliases, alias)) { event.reply(dbot.t('alias', { @@ -100,7 +96,11 @@ var commands = function(dbot) { return false; } }; - + + commands['~alias'].regex = [/^~alias ([\d\w[\]{}^|\\`_-]+?)/, 2]; + commands['~setaliasparent'].regex = [/^~setaliasparent ([\d\w[\]{}^|\\`_-]+?)/, 2]; + commands['~mergeusers'].regex = [/^~mergeusers ([\d\w[\]{}^|\\`_-]+?)\s*?([\d\w[\]{}^|\\`_-]+?)/, 3]; + commands['~setaliasparent'].access = 'moderator'; commands['~mergeusers'].access = 'moderator'; diff --git a/modules/users/config.json b/modules/users/config.json index 866deb7..07f200d 100644 --- a/modules/users/config.json +++ b/modules/users/config.json @@ -2,5 +2,6 @@ "ignorable": false, "dependencies": [ "command", "event" ], "dbKeys": [ "knownUsers" ], - "help": "https://github.com/reality/depressionbot/blob/master/modules/users/README.md" + "help": "https://github.com/reality/depressionbot/blob/master/modules/users/README.md", + "dbType": "memory" } diff --git a/modules/users/usage.json b/modules/users/usage.json new file mode 100644 index 0000000..203bd4d --- /dev/null +++ b/modules/users/usage.json @@ -0,0 +1,5 @@ +{ + "~alias": "~alias [nick]", + "~setaliasparent": "~setaliasparent [nick]", + "~mergeusers": "~mergeusers [primary] [secondary]" +} diff --git a/modules/users/users.js b/modules/users/users.js index 69bf4c4..5e713de 100644 --- a/modules/users/users.js +++ b/modules/users/users.js @@ -35,10 +35,10 @@ var users = function(dbot) { }; this.listener = function(event) { - var knownUsers = this.getServerUsers(event.server); + /*var knownUsers = this.getServerUsers(event.server); var nick = event.user; - if(event.action == 'JOIN') { + if(event.action == 'JOIN' && nick != dbot.config.name) { if(!_.has(knownUsers.channelUsers, event.channel.name)) { knownUsers.channelUsers[event.channel.name] = []; } @@ -55,17 +55,17 @@ var users = function(dbot) { channelUsers.push(nick); } } else if(event.action == 'NICK') { - var newNick = event.params.substr(1); + var newNick = event.newNick; if(!this.api.isKnownUser(newNick)) { knownUsers.aliases[newNick] = this.api.resolveUser(event.server, event.user); dbot.api.event.emit('nick_change', [ event.server, newNick ]); } - } + }*/ }.bind(this); this.on = ['JOIN', 'NICK']; this.onLoad = function() { - // Trigger updateNickLists to stat current users in channel + /* Trigger updateNickLists to stat current users in channel dbot.instance.addListener('366', 'users', function(event) { var knownUsers = this.getServerUsers(event.server); if(!_.has(knownUsers.channelUsers, event.channel.name)) { @@ -90,7 +90,7 @@ var users = function(dbot) { var connections = dbot.instance.connections; _.each(connections, function(connection) { connection.updateNickLists(); - }); + });*/ }; }; diff --git a/modules/web/config.json b/modules/web/config.json index 47a0b3a..981e0f7 100644 --- a/modules/web/config.json +++ b/modules/web/config.json @@ -1,5 +1,4 @@ { - "ignorable": false, "webHost": "localhost", - "webPort": 9001 + "webPort": 8080 } diff --git a/run.js b/run.js index 7ec03fa..855b18f 100644 --- a/run.js +++ b/run.js @@ -90,16 +90,17 @@ DBot.prototype.say = function(server, channel, message) { // Format given stored string in config language DBot.prototype.t = function(string, formatData) { - var formattedString; + var formattedString = 'String not found. Something has gone screwy. Maybe.'; + if(_.has(this.strings, string)) { var lang = this.config.language; if(!_.has(this.strings[string], lang)) { lang = "en"; } - formattedString = this.strings[string][lang].format(formatData); - } else { - formattedString = 'String not found. Something has gone screwy. Maybe.'; + if(_.has(this.strings[string], lang)) { + formattedString = this.strings[string][lang].format(formatData); + } } return formattedString; @@ -157,10 +158,16 @@ DBot.prototype.reloadModules = function() { this.instance.removeListeners(); - moduleNames.each(function(name) { + _.each(moduleNames, function(name) { + this.status[name] = true; var moduleDir = './modules/' + name + '/'; - var cacheKey = require.resolve(moduleDir + name); - delete require.cache[cacheKey]; + try { + var cacheKey = require.resolve(moduleDir + name); + delete require.cache[cacheKey]; + } catch(err) { + this.status[name] = 'Error loading module: ' + err + ' ' + err.stack.split('\n')[2].trim(); + return; + } try { var webKey = require.resolve(moduleDir + 'web'); @@ -170,8 +177,6 @@ DBot.prototype.reloadModules = function() { delete require.cache[webKey]; } - this.status[name] = true; - try { // Load the module config data var config = {}; @@ -304,6 +309,7 @@ DBot.prototype.reloadModules = function() { module.onLoad(); } catch(err) { this.status[name] = 'Error in onLoad: ' + err + ' ' + err.stack.split('\n')[1].trim(); + console.log('MODULE ONLOAD ERROR (' + name + '): ' + err ); } } }, this);