3
0
mirror of https://github.com/reality/dbot.git synced 2024-11-23 20:39:25 +01:00

Merge pull request #627 from reality/betterusers

merge new users into master
This commit is contained in:
Luke Slater 2014-10-27 16:41:40 +00:00
commit 81b352c306
39 changed files with 835 additions and 802 deletions

152
modules/atheme/atheme.js Normal file
View File

@ -0,0 +1,152 @@
/**
* Module Name: atheme
* Description: atheme mode references & retrieve channel flags
*/
var _ = require('underscore')._,
async = require('async');
var atheme = function(dbot) {
this.flagStack = {};
this.hostStack = {};
this.api = {
'getChannelFlags': function(server, channel, callback) {
if(!_.has(this.flagStack, server)) this.flagStack[server] = {};
if(_.has(this.flagStack[server], channel)) { // Already an active flag call
this.flagStack[server][channel].callbacks.push(callback);
} else {
this.flagStack[server][channel] = {
'flags': {},
'callbacks': [ callback ]
};
}
dbot.say(server, 'chanserv', 'FLAGS ' + channel);
setTimeout(function() { // Delete callback if no response
if(_.has(this.flagStack[server], channel)) {
_.each(this.flagStack[server][channel].callbacks, function(callback) {
callback(true, null);
});
delete this.flagStack[server][channel];
}
}.bind(this), 20000);
},
'getVHosts': function(server, mask, callback) {
if(!_.has(this.hostStack, server)) this.hostStack[server] = {};
if(_.has(this.hostStack[server], mask)) { // Already an active host call
this.hostStack[server][channel].callbacks.push(callback);
} else {
this.hostStack[server][mask] = {
'users': [],
'callbacks': [ callback ]
};
}
dbot.say(server, 'hostserv', 'LISTVHOST ' + mask);
setTimeout(function() { // Delete callback if no response
if(_.has(this.hostStack[server], mask)) {
_.each(this.hostStack[server][mask].callbacks, function(callback) {
callback(true, null);
});
delete this.hostStack[server][mask];
}
}.bind(this), 5000);
}
};
this.commands = {
'~chanserv': function(event) {
if(_.has(this.config.chanserv, event.input[1])) {
event.reply('ChanServ flag ' + event.input[1] + ': ' + this.config.chanserv[event.input[1]]);
} else {
event.reply('I don\'t know anything about ' + event.input[1]);
}
},
'~chanmode': function(event) {
if(_.has(this.config.chanmodes, event.input[1])) {
event.reply('Channel Mode ' + event.input[1] + ': ' + this.config.chanmodes[event.input[1]]);
} else {
event.reply('I don\'t know anything about ' + event.input[1]);
}
}
};
this.commands['~chanserv'].regex = [/^chanserv (\+.)/, 2];
this.commands['~chanmode'].regex = [/^chanmode (\+.)/, 2];
this.listener = function(event) {
if(event.action === 'NOTICE') {
if(event.user === 'ChanServ') {
var flags = event.params.match(/(\d+)\s+([^ ]+)\s+(\+\w+)\s+\((\#[\w\.]+)\)/),
end = event.params.match(/end of \u0002(\#[\w\.]+)\u0002 flags listing/i);
if(flags && _.has(this.flagStack[event.server], flags[4])) {
this.flagStack[event.server][flags[4]].flags[flags[2]] = flags[3];
} else if(end) {
if(_.has(this.flagStack[event.server], end[1])) {
// Parse wildcard hostmasks to nicks
var allFlags = this.flagStack[event.server][end[1]].flags,
hostMasks = {};
_.each(allFlags, function(f, u) { // TODO: combine to one loop
if(u.indexOf('*!*@') !== -1) {
hostMasks[u] = f;
delete allFlags[u];
}
});
async.each(_.keys(hostMasks), function(hostMask, done) {
this.api.getVHosts(event.server, hostMask.split('@')[1], function(err, users) {
_.each(users, function(user) {
allFlags[user] = hostMasks[hostMask];
});
done();
});
}.bind(this), function() {
console.log('DONE');
_.each(this.flagStack[event.server][end[1]].callbacks, function(callback) {
callback(null, this.flagStack[event.server][end[1]].flags);
}.bind(this));
delete this.flagStack[event.server][end[1]];
}.bind(this));
}
}
} else if(event.user === 'HostServ') {
_.each(this.hostStack[event.server], function(el, mask) {
if(event.params.match(mask)) {
var user = event.params.match(/- ([^ ]+)/),
end = event.params.match(/matches for pattern/);
if(user) {
this.hostStack[event.server][mask].users.push(user[1]);
} else if(end) {
_.each(this.hostStack[event.server][mask].callbacks, function(callback) {
callback(null, this.hostStack[event.server][mask].users);
}, this);
delete this.hostStack[event.server][mask];
}
}
}, this);
}
} else { // PRIVMSG
console.log(event.message);
var akill = event.message.match(/([^ ]+) AKILL:ADD: ([^ ]+) \(reason: (.+)(\) )\(duration: ([^,)]+)/);
if(event.channel == '#services' && akill) {
console.log(akill);
var channel = dbot.config.servers[event.server].admin_channel;
dbot.api.users.getUser(akill[1] + '.' + event.server, function(err, user) {
dbot.api.report.notify('ban', 'tripsit', user, channel, dbot.t('akill', {
'host': akill[2],
'reason': akill[3],
'duration': akill[5]
}));
});
}
}
}.bind(this);
this.on = ['NOTICE', 'PRIVMSG'];
};
exports.fetch = function(dbot) {
return new atheme(dbot);
};

View File

@ -0,0 +1,5 @@
{
"akill": {
"en": "{host} has been AKilled for {duration} due to \"{reason}\""
}
}

View File

@ -1,31 +0,0 @@
/**
* Module Name: charybdis
* Description: charybdis and atheme mode references
*/
var _ = require('underscore')._;
var charybdis = function(dbot) {
this.commands = {
'~chanserv': function(event) {
if(_.has(this.config.chanserv, event.input[1])) {
event.reply('ChanServ flag ' + event.input[1] + ': ' + this.config.chanserv[event.input[1]]);
} else {
event.reply('I don\'t know anything about ' + event.input[1]);
}
},
'~chanmode': function(event) {
if(_.has(this.config.chanmodes, event.input[1])) {
event.reply('Channel Mode ' + event.input[1] + ': ' + this.config.chanmodes[event.input[1]]);
} else {
event.reply('I don\'t know anything about ' + event.input[1]);
}
}
};
this.commands['~chanserv'].regex = [/^chanserv (\+.)/, 2]
this.commands['~chanmode'].regex = [/^chanmode (\+.)/, 2]
};
exports.fetch = function(dbot) {
return new charybdis(dbot);
};

View File

@ -2,7 +2,7 @@ var _ = require('underscore')._,
request = require('request');
var commands = function(dbot) {
return {
var commands = {
'usage': function(event) {
var commandName = event.params[1];
if(_.has(dbot.usage, commandName)) {
@ -60,6 +60,9 @@ var commands = function(dbot) {
}
}
};
commands['usage'].regex = [/usage ([^ ]+)/, 2];
return commands;
};
exports.fetch = function(dbot) {

View File

@ -0,0 +1,6 @@
{
"~md5": "~md5 [text]",
"~sha1": "~sha1 [text]",
"~sha256": "~sha256 [text]",
"~aes": "~aes \"[text]\" \"[key]\""
}

View File

@ -16,7 +16,7 @@ var ignore = function(dbot) {
this.api.getUserIgnores(user, function(err, ignores) {
var isImpeded = false;
if(!err && ignores) {
if(_.has(dbot.commands, item)) {
if(_.has(dbot.commands, item) && !_.include(ignores[by], item)) {
item = dbot.commands[item].module;
}
if(_.include(ignores[by], item)) {
@ -273,7 +273,7 @@ var ignore = function(dbot) {
dbot.instance.clearIgnores();
this.db.scan('ignores', function(ignores) {
dbot.api.users.getUser(ignores.id, function(user) {
dbot.api.users.getUser(ignores.id, function(err, user) {
if(user) {
_.each(ignores.ignores, function(module) {
dbot.instance.ignoreTag(user.currentNick, module);

View File

@ -28,7 +28,7 @@ var commands = function(dbot) {
this.api.voice(server, quietee, channel);
}
dbot.api.users.resolveUser(server, dbot.config.name, function(user) {
dbot.api.users.resolveUser(server, dbot.config.name, function(err, user) {
dbot.api.report.notify('unquiet', server, user, channel,
dbot.t('unquiet_notify', {
'unquieter': dbot.config.name,

View File

@ -15,7 +15,7 @@ var lastfm = function(dbot) {
'getLastFM': function(server, nick, callback) {
dbot.api.profile.getProfile(server, nick, function(err, user, profile) {
if(user) {
if(profile && _.has(profile.profile, 'lastfm')) {
if(profile && _.has(profile.profile, 'lastfm') && _.isString(profile.profile.lastfm)) {
callback(user, profile.profile.lastfm.toLowerCase());
} else {
callback(user, null);
@ -187,7 +187,7 @@ var lastfm = function(dbot) {
.value();
async.each(scrobbliest, function(item, done) {
dbot.api.users.getUser(item.user, function(user) {
dbot.api.users.getUser(item.user, function(err, user) {
item.user = user;
done();
});
@ -327,9 +327,9 @@ var lastfm = function(dbot) {
async.each(tastiest, function(pair, done) {
if(!_.isObject(pair.p1)) { // fix this
dbot.api.users.getUser(pair.p1, function(user) {
dbot.api.users.getUser(pair.p1, function(err, user) {
pair.p1 = user;
dbot.api.users.getUser(pair.p2, function(user) {
dbot.api.users.getUser(pair.p2, function(err, user) {
pair.p2 = user;
done();
});

View File

@ -0,0 +1,5 @@
{
"outputPrefix": "\u00033weed\u000f",
"app_key": "",
"app_id": ""
}

47
modules/leafly/leafly.js Normal file
View File

@ -0,0 +1,47 @@
/**
* Module name: Leafly
* Description: Information from leafly
*/
var _ = require('underscore')._,
request = require('request');
var leafly = function(dbot) {
var ApiRoot = 'http://data.leafly.com/';
this.commands = {
'~strain': function(event) {
request.post(ApiRoot + 'strains', {
'headers': {
'app_key': this.config.app_key,
'app_id': this.config.app_id
},
'body': {
'page': 0,
'take': 1,
'sort': 'rating',
'search': event.input[1]
},
'json': true
}, function(error, response, body) {
if(_.isObject(body) && _.has(body, 'Strains') && body.Strains.length > 0) {
var strain = body.Strains[0],
flavours = _.pluck(strain.Flavors, 'Name').join(', ');
event.reply(dbot.t('strain', {
'name': strain.Name,
'flavours': flavours,
'link': strain.permalink
}));
} else {
event.reply(dbot.t('no_strains'));
}
}.bind(this));
}
};
this.commands['~strain'].regex = [/^strain (.+)$/, 2];
};
exports.fetch = function(dbot) {
return new leafly(dbot);
};

View File

@ -0,0 +1,8 @@
{
"strain": {
"en": "{name} tastes of {flavours} - {link}"
},
"no_strains": {
"en": "No strains found :("
}
}

View File

@ -15,7 +15,7 @@ var pages = function(dbot) {
var voterNicks = [];
async.each(_.keys(poll.votees), function(id, done) {
dbot.api.users.getUser(id, function(user) {
dbot.api.users.getUser(id, function(err, user) {
voterNicks.push(user.primaryNick);
done();
});

View File

@ -9,16 +9,13 @@ var api = function(dbot) {
* TODO(@samstudio8) Migrate to internalAPI
*/
"createProfile": function(user, callback){
if(!callback) callback = function(){};
if(user){
this.db.create('profiles', user.id, {
'id': user.id,
'profile': this.config.schema.profile,
'preferences': this.config.schema.preferences
}, function(err, result){
if(err){
console.log(err);
}
});
}, callback);
}
},
@ -28,15 +25,21 @@ var api = function(dbot) {
},
'getProfile': function(server, nick, callback){
dbot.api.users.resolveUser(server, nick, function(user){
dbot.api.users.resolveUser(server, nick, function(err, user){
if(user){
this.db.read('profiles', user.id, function(err, profile){
if(!err){
if(profile) {
callback(false, user, profile);
} else {
this.api.createProfile(user, function(err, profile) {
callback(null, user, profile);
});
}
} else {
callback(true, user, null);
}
});
}.bind(this));
}
else{
callback(true, null, null);
@ -44,10 +47,16 @@ var api = function(dbot) {
}.bind(this));
},
'getProfileByUUID': function(uuid, callback){
this.db.read('profiles', uuid, function(err, profile){
'getProfileByUser': function(user, callback){
this.db.read('profiles', user.id, function(err, profile){
if(profile) {
callback(profile);
} else {
this.api.createProfile(user, function(err, profile) {
callback(profile);
});
}
}.bind(this));
},
'getAllProfiles': function(callback){

View File

@ -7,7 +7,7 @@ var pages = function(dbot) {
var connection = req.params.connection;
var nick = req.params.user;
dbot.api.users.resolveUser(connection, nick, function(user){
dbot.api.users.resolveUser(connection, nick, function(err, user){
if(user){
dbot.api.profile.getProfile(connection, user.primaryNick, function(err, user, profile){
if(!err){
@ -45,7 +45,7 @@ var pages = function(dbot) {
dbot.api.profile.getAllProfiles(function(profiles){
var thumbnails = [];
_.each(profiles, function(profile){
var nick = dbot.api.users.getUser(profile.id, function(user){
var nick = dbot.api.users.getUser(profile.id, function(err, user){
if(user){
/*TODO(@tmenari / @samstudio8)

View File

@ -5,30 +5,16 @@ var profile = function(dbot) {
this.onLoad = function(){
var schema = this.config.schema;
// Ensure all users have a profile
dbot.api.users.getAllUsers(function(users){
if(users){
_.each(users, function(user){
this.api.getProfileByUUID(user.id, function(err, uuid, profile){
// If function returns an error and uuid, create a new profile
if(err && uuid){
this.api.createProfile(user);
}
}.bind(this));
}.bind(this));
}
}.bind(this));
// Add API Hooks
dbot.api.event.addHook('new_user', this.api.createProfile);
dbot.instance.addPreEmitHook(function(event, callback) {
if(!event.rUser) return callback();
this.api.getProfileByUUID(event.rUser.id, function(uProfile) {
this.api.getProfileByUser(event.rUser, function(uProfile) {
if(uProfile) {
event.rProfile = uProfile.profile;
callback();
}
callback();
}.bind(this));
}.bind(this));

View File

@ -14,11 +14,18 @@ var commands = function(dbot) {
this.api.addQuote(key, quote, event.user, function(newCount) {
if(newCount) {
dbot.api.event.emit('~qadd', [ key, quote ]);
if(_.has(dbot.modules, 'web')) {
event.reply(dbot.t('quote_saved', {
'category': key,
'count': newCount,
'link': dbot.api.web.getUrl('quotes/' + encodeURIComponent(key))
}));
} else {
event.reply(dbot.t('quote_saved', {
'category': key,
'count': newCount
}));
}
} else {
event.reply(dbot.t('quote_exists'));
}
@ -103,11 +110,18 @@ var commands = function(dbot) {
removedQuote;
var quoteRemoved = function(err) {
this.internalAPI.resetRemoveTimer(event, key, removedQuote);
if(_.has(dbot.modules, 'web')) {
event.reply(dbot.t('removed_from', {
'quote': removedQuote,
'category': key,
'link': dbot.api.web.getUrl('quotes/' + encodeURIComponent(key))
}));
} else {
event.reply(dbot.t('removed_from', {
'quote': removedQuote,
'category': key
}));
}
}.bind(this);
this.db.search('quote_category', { 'name': key }, function(result) {
@ -137,11 +151,18 @@ var commands = function(dbot) {
category = false;
var quoteRemoved = function(err) {
this.internalAPI.resetRemoveTimer(event, key, quote);
if(_.has(dbot.modules, 'web')) {
event.reply(dbot.t('removed_from', {
'category': key,
'quote': quote,
'link': dbot.api.web.getUrl('quotes/' + encodeURIComponent(key))
}));
} else {
event.reply(dbot.t('removed_from', {
'category': key,
'quote': quote
}));
}
}.bind(this);
this.db.search('quote_category', { 'name': key }, function(result) {

View File

@ -16,11 +16,14 @@ var quotes = function(dbot) {
if(quoteRefs) {
var ref = this.internalAPI.cleanRef(quoteRefs[0].replace(/^~~/,'').replace(/~~$/,'').trim());
if(ref === '-nicks-') {
dbot.api.users.getRandomChannelUser(server, channel, function(user) {
quote = quote.replace('~~' + ref + '~~', user);
if(_.has(dbot.instance.connections[server].channels, channel)) {
var nicks =
_.keys(dbot.instance.connections[server].channels[channel].nicks);
var randomUser = nicks[_.random(0, nicks.length -1)];
quote = quote.replace('~~' + ref + '~~', randomUser);
this.internalAPI.interpolatedQuote(server, channel,
username, key, quote, callback);
}.bind(this));
}
} else if(ref === '-nick-') {
quote = quote.replace('~~' + ref + '~~', username);
this.internalAPI.interpolatedQuote(server, channel,

View File

@ -1,6 +1,6 @@
{
"category_not_found": {
"en": "Nobody loves {category}",
"en": "Everyone is rather ambivalent towards the matter of {category}",
"es": "Nadie ama a {category}",
"na'vi": "{category} yawne ke lu kawturu.",
"cy": "Does neb yn caru {category}",

View File

@ -1,5 +1,5 @@
{
"stream": "http://tripsit.fm:8000",
"announce": [ { "server": "tripsit", "name": "#tripbot" } ],
"stream": "http://radio.tripsit.me:8000/tripradio",
"announce": [ { "server": "tripsit", "name": "#drugs" } ],
"outputPrefix": "\u00033radio\u000f"
}

View File

@ -21,6 +21,7 @@ var radio = function(dbot) {
stream.on('response', function(res) {
this.data = res.headers;
if(res.headers['icy-name']) {
_.each(this.config.announce, function(a) {
dbot.say(a.server, a.name, dbot.t('now_online', {
'name': res.headers['icy-name'],
@ -28,11 +29,12 @@ var radio = function(dbot) {
'url': res.headers['icy-url']
}));
});
}
}.bind(this));
stream.on('metadata', function(metadata) {
var title = icecast.parseMetadata(metadata).StreamTitle;
if(title != 'undefined') { // sowwy jesus
if(!_.isUndefined(title) && this.data['icy-name']) { // sowwy jesus
_.each(this.config.announce, function(a) {
dbot.say(a.server, a.name, dbot.t('now_playing', {
'name': this.data['icy-name'],
@ -54,7 +56,7 @@ var radio = function(dbot) {
var dj = this.data['icy-description'],
song = event.input[1];
dbot.api.users.resolveUser(event.server, dj, function(user) {
dbot.api.users.resolveUser(event.server, dj, function(err, user) {
if(user) {
dbot.say(event.server, user.currentNick, dbot.t('radio_request',{
'user': event.user,

View File

@ -23,6 +23,66 @@ var api = function(dbot) {
dbot.api.event.emit('new_notify', [ notify, user.primaryNick ]);
});
var channel = dbot.instance.connections[server].channels[cName];
if(_.has(dbot.modules, 'atheme')) {
dbot.api.atheme.getChannelFlags(server, cName, function(err, flags) {
var ops = _.map(flags, function(f, k) {
var staff = (f.indexOf('O') !== -1);
if(this.config.notifyVoice && !staff) {
staff = (f.indexOf('V') !== -1);
}
if(staff) {
return k;
}
}.bind(this));
ops = _.without(ops, undefined);
console.log(ops);
this.db.read('nunsubs', cName + '.' + server, function(err, nunsubs) {
if(nunsubs) {
_.each(nunsubs.users, function(user) {
var uPart = user.split('.')[0];
if(_.include(ops, uPart)) {
console.log('removing ' + uPart);
ops = _.without(ops, uPart);
}
});
}
var offlineOps = {};
async.each(ops, function(op, done) {
dbot.api.users.isOnline(server, cName, op, function(err, user, online) {
if(!err && !online) offlineOps[op] = user;
if(user.currentNick !== op) {
ops = _.without(ops, op);
ops.push(user.currentNick);
}
done();
});
}, function() {
// Queue notifies for offline ops
_.each(offlineOps, function(op) {
if(!this.pending[op.id]) this.pending[op.id] = [];
this.pending[op.id].push({
'time': new Date().getTime(),
'channel': cName,
'user': user.id,
'message': message
});
this.pNotify[op.id] = true;
}, this);
// Send notifies to online ops
ops = _.difference(ops, _.keys(offlineOps));
message = this.internalAPI.formatNotify(type, server,
user, cName, message);
this.internalAPI.notify(server, ops, message);
if(_.has(this.config.chan_redirs, cName)) {
dbot.say(server, this.config.chan_redirs[cName], message);
}
}.bind(this));
}.bind(this));
}.bind(this));
} else {
var channel = dbot.instance.connections[server].channels[cName];
var ops = _.filter(channel.nicks, function(user) {
if(this.config.notifyVoice) {
@ -38,32 +98,15 @@ var api = function(dbot) {
var perOps = channel.op;
if(this.config.notifyVoice) perOps = _.union(perOps, channel.voice);
this.db.read('nunsubs', channel.id, function(err, nunsubs) {
this.db.read('nunsubs', cName + '.' + server, function(err, nunsubs) {
async.eachSeries(ops, function(nick, next) {
dbot.api.users.resolveUser(server, nick, function(user) {
if(!_.include(user.mobile, user.currentNick)) {
perOps = _.without(perOps, user.id);
}
if(nunsubs && _.include(nunsubs.users, user.id)) {
ops = _.without(ops, user.currentNick);
}
next();
});
}, function() {
offlineUsers = perOps;
if(!_.include(this.config.noMissingChans, cName)) {
_.each(offlineUsers, function(id) {
if(!this.pending[id]) this.pending[id] = [];
this.pending[id].push({
'time': new Date().getTime(),
'channel': cName,
'user': user.primaryNick,
'message': message
});
this.pNotify[id] = true;
}.bind(this));
}
message = this.internalAPI.formatNotify(type, server,
user, cName, message);
this.internalAPI.notify(server, ops, message);
@ -74,6 +117,7 @@ var api = function(dbot) {
}.bind(this));
}
}.bind(this));
}
},
'notifyUsers': function(server, users, message) {

View File

@ -75,9 +75,10 @@ var commands = function(dbot) {
},
'~report': function(event) {
var channelName = (event.input[1].trim() || event.channel),
var channelName = (event.input[1] || event.channel.toString()),
nick = event.input[2],
reason = event.input[3].trim();
channelName = channelName.trim();
if(channelName == event.user) {
channelName = dbot.config.servers[event.server].admin_channel;
@ -85,7 +86,7 @@ var commands = function(dbot) {
if(reason.charAt(reason.length - 1) != '.') reason += '.';
dbot.api.users.resolveUser(event.server, nick, function(reportee) {
dbot.api.users.resolveUser(event.server, nick, function(err, reportee) {
if(_.has(event.allChannels, channelName)) {
if(reportee) {
this.api.notify('report', event.server, event.rUser,
@ -114,7 +115,7 @@ var commands = function(dbot) {
if(_.has(event.allChannels, channelName)) {
if(this.config.firstHost) {
var first = message.split(' ')[0];
dbot.api.users.resolveUser(event.server, first, function(user) {
dbot.api.users.resolveUser(event.server, first, function(err, user) {
if(user && _.include(this.config.host_lookup, channelName)) {
dbot.api.nickserv.getUserHost(event.server, first, function(host) {
message = message.replace(first, first + ' [' + host + ']');
@ -138,21 +139,21 @@ var commands = function(dbot) {
},
'~nunsub': function(event) {
var cName = event.input[1];
var cName = event.input[1],
cId = event.input[1] + '.' + event.server;
dbot.api.users.resolveChannel(event.server, cName, function(channel) {
if(channel) {
this.db.read('nunsubs', channel.id, function(err, nunsubs) {
if(_.has(dbot.instance.connections[event.server].channels, cName)) {
this.db.read('nunsubs', cId, function(err, nunsubs) {
if(!nunsubs) {
var nunsubs = {
'id': channel.id,
'id': cId,
'users': []
}
}
if(!_.include(nunsubs, event.rUser.id)) {
nunsubs.users.push(event.rUser.id);
this.db.save('nunsubs', channel.id, nunsubs, function() {
this.db.save('nunsubs', cId, nunsubs, function() {
var reply = dbot.t('nunsubbed', { 'cName': cName })
if(_.has(this.config.chan_redirs, cName)) {
reply += dbot.t('n_also_found', { 'afaName' : this.config.chan_redirs[cName] });
@ -166,18 +167,17 @@ var commands = function(dbot) {
} else {
event.reply('Channel not known.');
}
}.bind(this));
},
'~ununsub': function(event) {
var cName = event.input[1];
var cName = event.input[1],
cId = event.input[1] + '.' + event.server;
dbot.api.users.resolveChannel(event.server, cName, function(channel) {
if(channel) {
this.db.read('nunsubs', channel.id, function(err, nunsubs) {
if(_.has(dbot.instance.connections[event.server].channels, cName)) {
this.db.read('nunsubs', cId, function(err, nunsubs) {
if(!_.isUndefined(nunsubs) && _.include(nunsubs.users, event.rUser.id)) {
nunsubs.users = _.without(nunsubs.users, event.rUser.id);
this.db.save('nunsubs', channel.id, nunsubs, function() {
this.db.save('nunsubs', cId, nunsubs, function() {
event.reply(dbot.t('ununsubbed', { 'cName': cName }));
});
} else {
@ -187,7 +187,6 @@ var commands = function(dbot) {
} else {
event.reply('Channel not known.');
}
}.bind(this));
}
};
commands['~report'].regex = /^report (#[^ ]+ )?([^ ]+) (.*)$/;

View File

@ -33,7 +33,7 @@ var pages = function(dbot) {
});
async.eachSeries(userCount, function(userCount, next) {
dbot.api.users.getUser(userCount.id, function(user) {
dbot.api.users.getUser(userCount.id, function(err, user) {
if(user) {
userCount['name'] = user.primaryNick;
users.push(userCount);
@ -72,7 +72,7 @@ var pages = function(dbot) {
});
}.bind(this), function() {
async.each(notifications, function(notify, done) {
dbot.api.users.getUser(notify.user, function(user) {
dbot.api.users.getUser(notify.user, function(err, user) {
if(user) notify.user = user.primaryNick;
done();
});
@ -138,7 +138,7 @@ var pages = function(dbot) {
var pNickCache = {};
async.eachSeries(notifies, function(notify, next) {
if(!_.has(pNickCache, notify.user)) {
dbot.api.users.getUser(notify.user, function(user) {
dbot.api.users.getUser(notify.user, function(err, user) {
pNickCache[notify.user] = user.primaryNick;
notify.user = user.primaryNick;
next();
@ -163,7 +163,7 @@ var pages = function(dbot) {
} else {
var username = req.params.item;
dbot.api.users.resolveUser(server, username, function(user) {
dbot.api.users.resolveUser(server, username, function(err, user) {
this.db.search('notifies', {
'user': user.id
}, function(notify) {

View File

@ -10,6 +10,7 @@ var report = function(dbot) {
this.internalAPI = {
'notify': function(server, users, message) {
async.eachSeries(users, function(nick, next) {
console.log('sending msg to ' + nick);
setTimeout(function() {
dbot.say(server, nick, message);
next();

View File

@ -5,18 +5,25 @@ var _ = require('underscore')._,
var commands = function(dbot) {
var commands = {
'~words': function(event) {
var getWords = function(user) {
this.api.getUserStats(user.id, function(uStats) {
var id = event.rUser.primaryNick + '.' + event.server,
user = event.rUser.currentNick,
cId = event.channel + '.' + event.server;
if(event.params[1]) {
id = event.params[1] + '.' + event.server;
user = event.params[1];
}
this.api.getUserStats(id, function(uStats) {
if(uStats) {
var output = dbot.t('sstats_uwords', {
'user': user.primaryNick,
'user': user,
'words': uStats.words,
'curses': uStats.curses,
'capitals': uStats.capitals,
'date': moment(uStats.creation).format('DD/MM/YYYY')
});
if(event.rChannel && _.has(uStats.channels, event.rChannel.id)) {
ucStats = uStats.channels[event.rChannel.id];
if(_.has(uStats.channels, cId)) {
ucStats = uStats.channels[cId];
output += dbot.t('sstats_ucwords', {
'channel': event.channel,
'words': ucStats.words,
@ -29,22 +36,10 @@ var commands = function(dbot) {
event.reply(dbot.t('sstats_noustats'));
}
});
}.bind(this);
if(event.params[1]) {
dbot.api.users.resolveUser(event.server, event.params[1], function(user) {
if(user) {
getWords(user);
} else {
event.reply(dbot.t('sstats_unknown_user'));
}
});
} else {
getWords(event.rUser);
}
},
'~lines': function(event) {
var cId = event.channel + '.' + event.server;
var getLines = function(user) {
this.api.getUserStats(user.id, function(uStats) {
if(uStats) {
@ -53,10 +48,10 @@ var commands = function(dbot) {
'lines': uStats.lines,
'date': moment(uStats.creation).format('DD/MM/YYYY')
});
if(event.rChannel && _.has(uStats.channels, event.rChannel.id)) {
if(_.has(uStats.channels, cId)) {
output += dbot.t('sstats_uclines', {
'channel': event.channel,
'lines': uStats.channels[event.rChannel.id].lines
'lines': uStats.channels[cId].lines
});
}
event.reply(output);
@ -160,7 +155,7 @@ var commands = function(dbot) {
},
'~last': function(event) {
dbot.api.users.resolveUser(event.server, event.params[1], function(user) {
dbot.api.users.resolveUser(event.server, event.params[1], function(err, user) {
if(user) {
this.api.getUserStats(user.id, function(uStats) {
if(uStats && uStats.last) {
@ -218,7 +213,7 @@ var commands = function(dbot) {
.value();
async.eachSeries(pCounts, function(pCount, next) {
dbot.api.users.getUser(pCount[0], function(user) {
dbot.api.users.getUser(pCount[0], function(err, user) {
pCount[0] = user.primaryNick; next();
});
}, function() {

View File

@ -20,7 +20,10 @@ var sstats = function(dbot) {
// repetition
'highscore': function(key, property, callback) {
var pList = {},
pPointer = property;
if(!_.isArray(pPointer)) {
pPointer = property.split('.');
}
this.db.scan(key, function(item) {
var id = item.id;
@ -44,7 +47,7 @@ var sstats = function(dbot) {
.value();
async.eachSeries(pCounts, function(pCount, next) {
dbot.api.users.getUser(pCount[0], function(user) {
dbot.api.users.getUser(pCount[0], function(err, user) {
pCount[0] = user.primaryNick; next();
});
}, function() {
@ -54,14 +57,9 @@ var sstats = function(dbot) {
}.bind(this),
'channelHighscore': function(key, server, channel, property, callback) {
dbot.api.users.resolveChannel(server, channel, function(channel) {
if(channel) {
var newProperty = 'channels.' + channel.id + '.' + property;
var cId = channel + '.' + server;
var newProperty = ['channels', cId, property];
this.internalAPI.highscore(key, newProperty, callback);
} else {
callback(null);
}
}.bind(this));
}.bind(this),
'formatHighscore': function(string, pCounts) {
@ -78,6 +76,7 @@ var sstats = function(dbot) {
event.uStats.lines++;
var message = event.message.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g, "");
var cId = event.channel + '.' + event.server;
var words = message.split(' '),
wCount = words.length,
capitals = 0,
@ -98,18 +97,18 @@ var sstats = function(dbot) {
event.cStats.capitals += capitals;
event.cStats.curses += curses;
if(!_.has(event.uStats.channels, event.rChannel.id)) {
event.uStats.channels[event.rChannel.id] = {
if(!_.has(event.uStats.channels, cId)) {
event.uStats.channels[cId] = {
'lines': 1,
'words': wCount,
'capitals': capitals,
'curses': curses
};
} else {
event.uStats.channels[event.rChannel.id].lines++;
event.uStats.channels[event.rChannel.id].words += wCount;
event.uStats.channels[event.rChannel.id].capitals += capitals;
event.uStats.channels[event.rChannel.id].curses += curses;
event.uStats.channels[cId].lines++;
event.uStats.channels[cId].words += wCount;
event.uStats.channels[cId].capitals += capitals;
event.uStats.channels[cId].curses += curses;
}
// Look for tracked words.
@ -124,9 +123,9 @@ var sstats = function(dbot) {
this.api.getTrackedWord(word, function(tWord) {
if(tWord) {
tWord.total += count;
if(!_.has(tWord.channels, event.rChannel.id)) tWord.channels[event.rChannel.id] = 0;
if(!_.has(tWord.channels, cId)) tWord.channels[cId] = 0;
if(!_.has(tWord.users, event.rUser.id)) tWord.users[event.rUser.id] = 0;
tWord.channels[event.rChannel.id] += count;
tWord.channels[cId] += count;
tWord.users[event.rUser.id] += count;
this.db.save('tracked_words', word, tWord, function() {});
}
@ -158,13 +157,14 @@ var sstats = function(dbot) {
// Preload channel stats
dbot.instance.addPreEmitHook(function(event, callback) {
if(!event.rChannel) return callback();
this.api.getChannelStats(event.rChannel.id, function(cStats) {
if(!event.channel) return callback();
var id = event.channel + '.' + event.server;
this.api.getChannelStats(id, function(cStats) {
if(cStats) {
event.cStats = cStats;
callback();
} else {
this.api.createChannelStats(event.rChannel.id, function(cStats) {
this.api.createChannelStats(id, function(cStats) {
event.cStats = cStats;
callback();
});

View File

@ -14,7 +14,9 @@ var udp = function(dbot) {
dbot.say(this.config.server, this.config.channel, message);
}
}.bind(this));
this.onLoad = function() {
server.bind(this.config.port);
}.bind(this);
};
exports.fetch = function(dbot) {

View File

@ -1,168 +1,73 @@
var _ = require('underscore')._,
uuid = require('node-uuid'),
databank = require('databank');
var _ = require('underscore')._;
var api = function(dbot) {
var escapeRegexen = function(str) {
return (str+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
};
var api = {
// Return a user record given a primary nick or an alias
'resolveUser': function(server, nick, callback, lc) {
var user = false;
if(lc) nick = nick.toLowerCase();
if(_.has(this.userCache[server], nick)) {
this.api.getUser(this.userCache[server][nick], callback);
// Retrieve a user record given a server and nickname
'resolveUser': function(server, nick, callback) {
var id = nick + '.' + server;
this.api.getUser(id, function(err, result) {
if(!err) {
callback(null, result);
} else {
this.db.search('users', { 'server': server }, function(result) {
if(lc) {
result.primaryNick = result.primaryNick.toLowerCase();
_.each(result.aliases, function(v, k) {
result.aliases[k] = v.toLowerCase();
});
this.db.read('user_aliases', id, function(err, result) {
if(!err) {
this.api.getUser(result.user, callback);
} else {
callback(true, null);
}
}.bind(this));
}
}.bind(this));
},
if(result.primaryNick == nick || _.include(result.aliases, nick)) {
user = result;
// Retrive a user record given its ID
'getUser': function(id, callback) {
this.db.read('users', id, function(err, result) {
if(!err) {
callback(null, result);
} else {
callback(true, null);
}
}.bind(this), function(err) {
});
},
// Retrieve user aliases given a user ID
'getUserAliases': function(id, callback) {
var aliases = [];
this.db.search('user_aliases', { 'user': id }, function(result) {
aliases.push(result.alias);
}, function(err) {
if(!err) {
callback(null, aliases);
} else {
callback(true, null);
}
});
},
// Check if a nick is online under a given alias
'isOnline': function(server, channel, nick, callback) {
this.api.resolveUser(server, nick, function(err, user) {
if(user) {
if(!_.has(this.userCache[server], nick)) {
this.userCache[server][nick] = user.id;
} else if(this.userCache[server][nick] !== user.id) {
this.userCache[server][nick] = user.id;
}
}
callback(user);
}.bind(this));
}
},
this.api.getUserAliases(user.id, function(err, aliases) {
aliases.push(nick);
// Return many user records given primary nicks of aliases
'resolveUsers': function(server, nicks, callback) {
var users = [];
this.db.search('users', { 'server': server }, function(result) {
var pNicks = result.aliases.slice(0).unshift(result.primaryNick);
for(var i=0;i<pNicks.length;i++) {
var n = _.indexOf(nicks, pNicks[i]);
if(n != -1) {
users.push(result);
nicks = _.without(nicks, nicks[n]);
break;
}
}
}, function(err) {
if(!err) {
callback(users, nicks);
}
});
},
// Return a user record given a UUID
'getUser': function(uuid, callback) {
this.db.read('users', uuid, function(err, user) {
if(err) user = false;
callback(user);
});
},
'resolveChannel': function(server, channelName, callback) {
if(_.has(this.chanCache[server], channelName)) {
return this.api.getChannel(this.chanCache[server][channelName], callback);
}
var channel = false;
this.db.search('channel_users', {
'server': server,
'name': channelName
}, function(result) {
channel = result;
}, function(err) {
if(!err) {
this.chanCache[server][channelName] = channel.id;
callback(channel);
}
}.bind(this));
},
'getChannel': function(uuid, callback) {
this.db.read('channel_users', uuid, function(err, channel) {
if(err) channel = false;
callback(channel);
});
},
'getRandomChannelUser': function(server, cName, callback) {
if(_.has(dbot.instance.connections[server].channels, cName)) {
var nicks = _.keys(dbot.instance.connections[server].channels[cName].nicks);
var randomUser = nicks[_.random(0, nicks.length -1)]
callback(randomUser);
} else {
callback(false);
}
},
'getAllUsers': function(callback) {
var users = [];
this.db.scan('users', function(user) {
users.push(user);
}, function(err) {
if(!err) {
callback(users);
}
});
},
'getAllChannels': function(callback) {
var channels = [];
this.db.scan('channel_users', function(channel) {
channels.push(channel);
}, function(err) {
if(!err) {
callback(channels);
}
});
},
'isOnline': function(server, nick, channel, callback) {
this.api.resolveUser(server, nick, function(user) {
var possiNicks = [user].concat(user.aliases);
if(_.has(dbot.instance.connections[server].channels, channel)) {
var onlineNicks = dbot.instance.connections[server].channels[channel].nicks;
var onlineNicks = _.keys(dbot.instance.connections[server].channels[channel].nicks);
var isOnline = _.any(onlineNicks, function(nick) {
nick = nick.name;
return _.include(possiNicks, nick);
return _.include(aliases, nick);
}, this);
callback(isOnline);
}
callback(null, user, isOnline);
});
},
'isKnownUser': function(server, nick, callback) {
this.api.resolveUser(server, nick, function(isKnown) {
if(isKnown == false) {
callback(false);
} else {
callback(true);
callback(true, null, null);
}
});
}.bind(this));
}
};
api['resolveUser'].external = true;
api['resolveUser'].extMap = [ 'server', 'nick', 'callback' ];
api['getChannel'].external = true;
api['getChannel'].extMap = [ 'server', 'channel', 'callback' ];
api['getAllUsers'].external = true;
api['getAllUsers'].extMap = [ 'callback' ];
api['getAllChannels'].external = true;
api['getAllChannels'].extMap = [ 'callback' ];
api['getUserAliases'].external = true;
api['getUserAliases'].extMap = [ 'id', 'callback' ];
return api;
};

View File

@ -1,214 +1,133 @@
var _ = require('underscore')._,
moment = require('moment-timezone');
var _ = require('underscore')._;
var commands = function(dbot) {
var commands = {
'~alias': function(event) {
var nick = event.params[1].trim() || event.user;
this.api.resolveUser(event.server, nick, function(user) {
var nick = event.params[1] || event.user;
this.api.resolveUser(event.server, nick, function(err, user) {
if(user) {
if(nick == user.primaryNick) {
var aliases = _.first(user.aliases, 10);
var including = 'including: ' + aliases.join(', ') + '.';
this.api.getUserAliases(user.id, function(err, aliases) {
var including = _.first(aliases, 10).join(', ');
if(user.aliases.length != 0) {
event.reply(dbot.t('primary', {
'user': nick,
'currentNick': user.currentNick,
'count': user.aliases.length,
}) + including);
} else {
event.reply(dbot.t('primary', {
'user': nick,
'currentNick': user.currentNick,
'count': user.aliases.length
}).slice(0, -2) + ".");
}
} else {
if(nick !== user.primaryNick) {
event.reply(dbot.t('alias', {
'alias': nick,
'user': user.primaryNick
}));
}
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
});
},
'~timezone': function(event) {
if(event.params[1]) {
try {
moment().tz(event.params[1]);
} catch(err) {
return event.reply('Invalid timezone. See http://momentjs.com/timezone/');
}
event.rUser.timezone = event.params[1];
this.db.save('users', event.rUser.id, event.rUser, function() {
event.reply('Timezone updated.');
});
} else {
event.reply('Current timezone: ' + event.rUser.timezone);
}
},
'~time': function(event) {
var nick = event.params[1].trim();
this.api.resolveUser(event.server, nick, function(user) {
if(user) {
if(user.timezone) {
var fDate = moment.tz(user.timezone).format('MMMM Do YYYY HH:mm:ss');
event.reply('The time for ' + user.primaryNick + ' is: ' + fDate);
} else {
event.reply(user.primaryNick + ' doesn\'t have a timezone set. They can do this with ~timezone.');
}
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
});
},
'~setmobilealias': function(event) {
if(_.include(event.rUser.aliases, event.params[1])) {
if(!_.has(event.rUser, 'mobile')) event.rUser.mobile = [];
if(!_.include(event.rUser.mobile, event.params[1])) {
event.rUser.mobile.push(event.params[1]);
this.db.save('users', event.rUser.id, event.rUser, function(err) {
event.reply(dbot.t('added_mobile_alias', { 'alias': event.params[1] }));
});
} else {
event.reply(dbot.t('already_mobile', { 'alias': event.params[1] }));
}
} else {
event.reply(dbot.t('unknown_alias', { 'alias': event.params[1] }));
}
},
'~addalias': function(event) {
var nick = event.input[1],
alias = event.input[2];
this.api.resolveUser(event.server, nick, function(user) {
if(user) {
if(!_.include(user.aliases, alias)) {
user.aliases.push(alias);
this.db.save('users', user.id, user, function(err) {
if(!err) {
event.reply(dbot.t('alias_added', {
if(aliases.length === 0) {
event.reply(dbot.t('primary_no_alias', {
'user': user.primaryNick,
'alias': alias
'currentNick': user.currentNick
}));
} else {
event.reply(dbot.t('primary', {
'user': user.primaryNick,
'currentNick': user.currentNick,
'count': aliases.length,
'including': including
}));
}
});
} else {
event.reply(dbot.t('alias_exists', { 'alias': alias }));
}
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
}.bind(this));
},
'~removealias': function(event) {
var alias = event.params[1];
'~addalias': function(event) {
var nick = event.params[1],
alias = event.params[2];
this.api.resolveUser(event.server, alias, function(user) {
this.api.resolveUser(event.server, nick, function(err, user) {
if(user) {
user.aliases = _.without(user.aliases, alias);
user.mobile = _.without(user.mobile, alias);
this.db.save('users', user.id, user, function(err) {
event.reply(dbot.t('alias_removed', {
'primary': user.primaryNick,
this.api.resolveUser(event.server, alias, function(err, aUser) {
if(!aUser) {
this.internalAPI.createAlias(alias, user, function(err) {
event.reply(dbot.t('alias_added', {
'user': user.primaryNick,
'alias': alias
}));
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': alias }));
event.reply(dbot.t('alias_exists', {
'alias': alias,
'user': aUser.primaryNick
}));
}
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
}.bind(this));
},
'~setaliasparent': function(event) {
var newPrimary = event.params[1].trim();
this.api.resolveUser(event.server, newPrimary, function(user) {
if(user && user.primaryNick != newPrimary) {
var newAlias = user.primaryNick;
user.primaryNick = newPrimary;
user.aliases = _.without(user.aliases, newPrimary);
user.aliases.push(newAlias);
this.db.save('users', user.id, user, function(err) {
if(!err) {
event.reply(dbot.t('aliasparentset', {
var newPrimary = event.params[1];
this.api.resolveUser(event.server, newPrimary, function(err, user) {
if(user) {
if(user.primaryNick !== newPrimary) {
this.internalAPI.reparentUser(user, newPrimary, function() {
event.reply(dbot.t('alias_parent_set', {
'newParent': newPrimary,
'newAlias': newAlias
'newAlias': user.primaryNick
}));
dbot.api.event.emit('~setaliasparent', {
'server': event.server,
'alias': newAlias
});
} else {
event.reply(dbot.t('already_primary', { 'user': newPrimary }));
}
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': newPrimary }));
}
}.bind(this));
},
'~mergeusers': function(event) {
var primaryUser = event.params[1];
var secondaryUser = event.params[2];
'~rmalias': function(event) {
var alias = event.params[1];
this.api.resolveUser(event.server, primaryUser, function(user) {
if(user) {
this.api.resolveUser(event.server, secondaryUser, function(oldUser) {
if(oldUser) {
user.aliases.push(oldUser.primaryNick);
user.aliases = _.union(user.aliases, oldUser.aliases);
this.internalAPI.mergeChannelUsers(oldUser, user);
this.db.del('users', oldUser.id, function(err) {
if(!err) {
this.db.save('user_redirs', oldUser.id, user.id, function() {});
this.db.save('users', user.id, user, function(err) {
if(!err) {
if(_.has(this.userCache, event.server) && _.has(this.userCache[event.server], oldUser.currentNick)) {
delete this.userCache[event.server][oldUser.currentNick];
}
event.reply(dbot.t('merged_users', {
'old_user': secondaryUser,
'new_user': primaryUser
this.api.resolveUser(event.server, alias, function(err, user) {
if(user) { // Retrieving user record via alias proves existence of alias record
this.internalAPI.removeAlias(event.server, alias, function(err) {
event.reply(dbot.t('alias_removed', {
'primary': user.primaryNick,
'alias': alias
}));
dbot.api.event.emit('~mergeusers', [
event.server,
oldUser,
user
]);
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
}.bind(this));
},
'~mergeusers': function(event) {
var oldNick = event.params[1],
newNick = event.params[2];
this.api.resolveUser(event.server, oldNick, function(err, oldUser) {
if(oldUser) {
this.api.resolveUser(event.server, newNick, function(err, newUser) {
if(newUser && newUser.id !== oldUser.id) {
this.internalAPI.mergeUsers(oldUser, newUser, function() {
event.reply(dbot.t('merged_users', {
'old_user': oldNick,
'new_user': newNick
}));
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': newNick }));
}
}.bind(this));
} else {
event.reply(dbot.t('unprimary_error', { 'nick': secondaryUser }));
}
}.bind(this));
} else {
event.reply(dbot.t('unprimary_error', { 'nick': primaryUser }));
event.reply(dbot.t('unknown_alias', { 'alias': oldNick }));
}
}.bind(this));
}
};
commands['~alias'].regex = [/^alias ([\d\w[\]{}^|\\`_-]+?)/, 2];
commands['~time'].regex = [/^time ([\d\w[\]{}^|\\`_-]+?)/, 2];
commands['~setaliasparent'].regex = [/^setaliasparent ([\d\w[\]{}^|\\`_-]+?)/, 2];
commands['~mergeusers'].regex = [/^mergeusers ([\d\w[\]{}^|\\`_-]+?)\s*?([\d\w[\]{}^|\\`_-]+?)/, 3];
commands['~addalias'].regex = [/^addalias ([\d\w[\]{}^|\\`_-]+?) ([\d\w[\]{}^|\\`_-]+?)$/, 3];
commands['~setaliasparent'].access = 'moderator';
commands['~mergeusers'].access = 'moderator';
commands['~addalias'].access = 'moderator';
commands['~removealias'].access = 'moderator';
commands['~rmalias'].access = 'moderator';
commands['~mergeusers'].access = 'moderator';
return commands;
};

View File

@ -8,22 +8,23 @@
"fr": "{alias} est un alias de {user}",
"it": "{alias} è un alias di {user}"
},
"added_mobile_alias": {
"en": "{alias} added as a mobile alias.",
"de": "{alias} als mobiler Benutzer hinzugefügt."
},
"already_mobile": {
"en": "{alias} is already a mobile alias.",
"de": "{alias} ist bereits ein mobiler Benutzer."
},
"primary": {
"en": "{user} (currently {currentNick}) is a primary user with {count} aliases, ",
"na'vi": "{user} ({currentNick}) lu txin ulte {count}a stxo lu poru, ",
"nl": "{user} ({currentNick}) is een primaire gebruiker met {count} aliassen, ",
"en": "{user} (currently {currentNick}) is a primary user with {count} aliases, including {including}.",
"na'vi": "{user} ({currentNick}) lu txin ulte {count}a stxo lu poru, {including}",
"nl": "{user} ({currentNick}) is een primaire gebruiker met {count} aliassen, {including}",
"cy": "Mae {user} ({currentNick}) yn ddefnyddiwr gynradd gyda {count} enwau eraill, ",
"de": "{user} ({currentNick}) ist ein Benutzer mit {count} Nicknamen, ",
"fr": "{user} (actuellement {currentNick}) est un utilisateur primaire avec {count} alias, ",
"it": "{user} (attualmente {currentNick}) è un utente primario con {count} alias, "
"de": "{user} ({currentNick}) ist ein Benutzer mit {count} Nicknamen, {including}",
"fr": "{user} (actuellement {currentNick}) est un utilisateur primaire avec {count} alias, {including}",
"it": "{user} (attualmente {currentNick}) è un utente primario con{count} alias, {including}"
},
"primary_no_alias": {
"en": "{user} (currently {currentNick}) is a primary user.",
"na'vi": "{user} ({currentNick}) lu txin ulte",
"nl": "{user} ({currentNick}) is een primaire gebruiker",
"cy": "Mae {user} ({currentNick}) yn ddefnyddiwr gynradd",
"de": "{user} ({currentNick}) ist ein Benutzer",
"fr": "{user} (actuellement {currentNick}) est un utilisateur primaire",
"it": "{user} (attualmente {currentNick}) è un utente primario"
},
"unknown_alias": {
"en": "{alias} does not currently exist as an alias or known user.",
@ -39,7 +40,7 @@
"de": "Alias {alias} von {primary} entfernt.",
"it": "Tolto alias {alias} da {primary}."
},
"aliasparentset": {
"alias_parent_set": {
"en": "{newParent} is now the parent user, and {newAlias} is an alias.",
"na'vi": "{newParent} lu sa'sem set ulte {newAlias} lu stxo set nìteng.",
"cy": "Mae {newParent} ydy defnyddiwr rhiant nawr, a {alias} ydy enw arall.",
@ -48,15 +49,6 @@
"fr": "{newParent} est maintenant le même utilisateur parent, et {newAlias} est un alias.",
"it": "{newParent} è adesso l' utente genitore e {newAlias} è un alias."
},
"unprimary_error": {
"en": "{nick} isn't recorded as a primary user.",
"na'vi": "fo sute txin ke lu.",
"cy": "Nid yw un o'r defnyddwyr hynny yn cael ei gofnodi ar hyn o bryd fel defnyddiwr gynradd.",
"nl": "Een van deze gebruikers is nog niet bekend als een primaire gebruiker.",
"de": "Einer dieser Benutzer ist nicht als Hauptbenutzer gespeichert.",
"fr": "{nick} n'est pas enregistré en tant qu'utilisateur primaire.",
"it": "{nick} non è registrato come utente principale."
},
"merged_users": {
"en": "{old_user} and their aliases have been merged into {new_user}.",
"na'vi": "{old_user} ulte stxo alahe {new_user} lu set.",

View File

@ -2,224 +2,153 @@
* Name: Users
* Description: Track known users
*/
var _ = require('underscore')._,
uuid = require('node-uuid'),
async = require('async');
var _ = require('underscore')._;
var users = function(dbot) {
this.userCache = {};
_.each(dbot.config.servers, function(v, k) {
this.userCache[k] = {};
}.bind(this));
this.chanCache = {};
_.each(dbot.config.servers, function(v, k) {
this.chanCache[k] = {};
}.bind(this));
/*** Internal API ***/
this.internalAPI = {
// Create new user record
'createUser': function(server, nick, callback) {
var id = uuid.v4();
var id = nick + '.' + server;
this.db.create('users', id, {
'id': id,
'primaryNick': nick,
'currentNick': nick,
'server': server,
'channels': [],
'aliases': [],
'mobile': []
'primaryNick': nick,
'currentNick': nick
}, function(err, result) {
if(!err) {
dbot.api.event.emit('new_user', [ result ]);
callback(result);
callback(null, result);
} else {
callback(true, null);
}
});
}.bind(this),
'createChannel': function(server, name, callback) {
var id = uuid.v4();
this.db.create('channel_users', id, {
// Add new user alias
'createAlias': function(alias, user, callback) {
var id = alias + '.' + user.server;
this.db.create('user_aliases', id, {
'id': id,
'server': server,
'name': name,
'users': [],
'op': [],
'voice': []
'alias': alias,
'user': user.id
}, function(err, result) {
if(!err) {
dbot.api.event.emit('new_channel', [ result ]);
callback(result);
dbot.api.event.emit('new_user_alias', [ result, alias ]);
callback(null, result);
} else {
callback(true, null);
}
});
}.bind(this),
'addChannelUser': function(channel, user, staff, callback) {
if(!_.include(channel.users, user.id)) {
channel.users.push(user.id);
}
if(!_.include(user.channels, channel.id)) {
user.channels.push(channel.id);
}
// Remove an alias record
'removeAlias': function(server, alias, callback) {
var id = alias + '.' + server;
this.db.del('user_aliases', id, function(err) {
callback(err);
});
}.bind(this),
if(!channel.op) channel.op = [];
if(!channel.voice) channel.voice = [];
if(staff.op) {
channel.op.push(user.id);
} else if(staff.voice) {
channel.voice.push(user.id);
// Update current nick of user record
'updateCurrentNick': function(user, newNick, callback) {
user.currentNick = newNick;
this.db.save('users', user.id, user, function(err, result) {
if(!err) {
dbot.api.event.emit('new_current_nick', [ user, newNick ]);
callback(null, result);
} else {
callback(true, null);
}
});
}.bind(this),
this.db.save('users', user.id, user, function(err) {
this.db.save('channel_users', channel.id, channel, function(err) {
dbot.api.event.emit('new_channel_user', [ user, channel ]);
// Merge two user records and aliases
'mergeUsers': function(oldUser, newUser, callback) {
this.db.search('user_aliases', { 'user': oldUser.id }, function(alias) {
if(alias.alias === newUser.primaryNick) {
this.db.del('user_aliases', alias.id, function(){});
} else {
alias.user = newUser.id;
this.db.save('user_aliases', alias.id, alias, function(){});
}
}.bind(this), function(){
this.internalAPI.createAlias(oldUser.primaryNick, newUser, function(){});
}.bind(this));
this.db.del('users', oldUser.id, function(err) {
if(!err) {
dbot.api.event.emit('merged_users', [
oldUser,
newUser
]);
callback(null);
} else {
callback(true);
}
});
}.bind(this),
// Set a new nick as the parent for a user (so just recreate and merge)
'reparentUser': function(user, newPrimary, callback) {
this.internalAPI.createUser(user.server, newPrimary, function(err, newUser) {
this.internalAPI.mergeUsers(user, newUser, function(err) {
callback(err);
});
}.bind(this));
}.bind(this),
'mergeChannelUsers': function(oldUser, newUser) {
newUser.channels = _.union(oldUser.channels, newUser.channels);
_.each(newUser.channels, function(uuid) {
this.api.getChannel(uuid, function(channel) {
if(_.include(channel.users, oldUser.id)) {
channel.users = _.without(channel.users, oldUser.id);
}
if(!_.include(channel.users, newUser.id)) {
channel.users.push(newUser.id);
}
this.db.save('channel_users', channel.id, channel, function(err) {
if(err) {
// QQ
}
});
}.bind(this));
}, this);
}.bind(this)
};
/*** Listener ***/
// Track nick changes
this.listener = function(event) {
this.api.isKnownUser(event.server, event.newNick, function(isKnown) {
event.rUser.currentNick = event.newNick;
if(!isKnown) {
event.rUser.aliases.push(event.newNick);
// Update current nick
this.api.resolveUser(event.server, event.user, function(err, user) {
if(user) {
this.api.resolveUser(event.server, event.newNick, function(err, eUser) {
if(!eUser) {
this.internalAPI.createAlias(event.newNick, user, function(){});
this.internalAPI.updateCurrentNick(user, event.newNick, function(){});
} else if(user.id === eUser.id) {
this.internalAPI.updateCurrentNick(user, event.newNick, function(){});
}
this.db.save('users', event.rUser.id, event.rUser, function(err) {
if(!isKnown) {
dbot.api.event.emit('new_user_alias', [ event.rUser, event.newNick ]);
}.bind(this));
}
dbot.api.event.emit('new_current_nick', [ event.rUser, event.user ]);
});
}.bind(this));
}.bind(this);
this.on = ['NICK'];
this.onLoad = function() {
dbot.instance.addPreEmitHook(function(event, callback) {
// 1. Attempt to resolve channel
// 2. Create channel if it doesn't exist
// 3. Attempt to resolve user
// 4. Create user if it doesn't exist
// 5. Make sure channel objects are up to date
// 6. Update staff channel lists
/*** Pre-emit ***/
var checkChannel = function(done) {
if(event.channel) {
this.api.resolveChannel(event.server, event.channel.name, function(channel) {
if(!channel) {
this.internalAPI.createChannel(event.server, event.channel.name, done);
} else {
done(channel);
}
}.bind(this));
} else {
done(null);
}
}.bind(this);
var checkUser = function(done) {
this.api.resolveUser(event.server, event.user, function(user) {
this.onLoad = function() {
// Create non-existing users and update current nicks
var checkUser = function(event, done) {
this.api.resolveUser(event.server, event.user, function(err, user) {
if(!user) {
this.internalAPI.createUser(event.server, event.user, done);
} else {
if(event.user !== user.currentNick) {
var oldNick = user.currentNick;
user.currentNick = event.user;
this.db.save('users', user.id, user, function() {
dbot.api.event.emit('new_current_nick', [ user, oldNick ]);
done(user);
});
if(user.currentNick !== event.user) {
this.internalAPI.updateCurrentNick(user, event.user, done);
} else {
done(user);
done(null, user);
}
}
}.bind(this));
}.bind(this);
var checkChannelUsers = function(done) {
var needsUpdating = false;
if(!_.include(event.rUser.channels, event.rChannel.id)) {
event.rUser.channels.push(event.rChannel.id);
event.rChannel.users.push(event.rUser.id);
dbot.api.event.emit('new_channel_user', [ event.rUser, event.rChannel ]);
// since it's not in event.channel yet we have to do this here
this.db.save('users', event.rUser.id, event.rUser, function() {
this.db.save('channel_users', event.rChannel.id, event.rChannel, function() {});
}.bind(this));
return done();
}
if(!_.has(event.channel, 'nicks') || !_.has(event.channel.nicks, event.rUser.currentNick)) {
return done();
}
var cUser = event.channel.nicks[event.rUser.currentNick];
if(!_.include(event.rChannel.op, event.rUser.id) && cUser.op) {
event.rChannel.op.push(event.rUser.id);
needsUpdating = true;
} else if(!_.include(event.rChannel.voice, event.rUser.id) && cUser.voice) {
event.rChannel.voice.push(event.rUser.id);
needsUpdating = true;
} else if(_.include(event.rChannel.op, event.rUser.id) && !cUser.op) {
event.rChannel.op = _.without(event.rChannel.op, event.rUser.id);
needsUpdating = true;
} else if(_.include(event.rChannel.voice, event.rUser.id) && !cUser.voice) {
event.rChannel.voice = _.without(event.rChannel.voice, event.rUser.id);
needsUpdating = true;
}
if(needsUpdating) {
this.db.save('users', event.rUser.id, event.rUser, function() {
this.db.save('channel_users', event.rChannel.id, event.rChannel, done);
}.bind(this));
} else {
done();
}
}.bind(this);
if(event.user && _.include(['JOIN', 'MODE', 'NICK', 'PRIVMSG'], event.action)) {
checkChannel(function(channel) {
event.rChannel = channel;
checkUser(function(user) {
dbot.instance.addPreEmitHook(function(event, callback) {
if(event.user && _.include(['JOIN', 'PRIVMSG'], event.action)) {
checkUser(event, function(err, user) {
event.rUser = user;
if(event.channel) {
checkChannelUsers(function() {
callback();
callback(null);
});
} else {
callback();
callback(null);
}
}.bind(this));
}.bind(this));
} else {
callback();
}
}.bind(this));
};
});
}.bind(this);
};
exports.fetch = function(dbot) {

View File

@ -10,6 +10,7 @@ var pages = function(dbot) {
'name': dbot.config.name,
'servers': _.keys(dbot.config.servers)
});
console.log('YE');
},
'/warning/:server': function(req, res) {
@ -21,8 +22,12 @@ var pages = function(dbot) {
if(!_.include(userIds, warning.warnee)) userIds.push(warning.warnee);
}, function(err) {
async.eachSeries(userIds, function(id, callback) {
dbot.api.users.getUser(id, function(user) {
dbot.api.users.getUser(id, function(err, user) {
if(user) {
userNicks.push(user.primaryNick);
} else {
userNicks.push(id);
}
callback(false);
});
}, function(err) {
@ -38,23 +43,23 @@ var pages = function(dbot) {
'/warning/:server/:uid': function(req, res) {
var server = req.params.server,
user = req.params.uid;
console.log('YE YE');
dbot.api.users.resolveUser(server, user, function(user) {
dbot.api.users.resolveUser(server, user, function(err, user) {
var warnings = [];
if(user) {
this.db.search('warnings', {
'server': server,
'warnee': user.id
}, function(warning) {
warnings.push(warning);
}, function(err) {
console.log(warnings);
async.eachSeries(warnings, function(warning, callback) {
dbot.api.users.getUser(warning.warner, function(user) {
dbot.api.users.getUser(warning.warner, function(err, user) {
warning.warner = user.primaryNick;
callback(false);
});
}, function(err) {
console.log(warnings);
res.render('warnings', {
'name': dbot.config.name,
'server': server,
@ -62,6 +67,7 @@ var pages = function(dbot) {
});
});
});
}
}.bind(this));
}
};

View File

@ -6,7 +6,7 @@ var warning = function(dbot) {
'warn': function(server, warner, user, reason, channel, callback) {
var adminChannel = dbot.config.servers[server].admin_channel || channel.name;
dbot.api.users.resolveUser(server, user, function(warnee) {
dbot.api.users.resolveUser(server, user, function(err, warnee) {
if(warnee) {
var id = uuid.v4();
this.db.save('warnings', id, {
@ -52,7 +52,7 @@ var warning = function(dbot) {
'~rmwarning': function(event) {
var warning = null;
dbot.api.users.resolveUser(event.server, event.input[1], function(warnee) {
dbot.api.users.resolveUser(event.server, event.input[1], function(err, warnee) {
if(warnee) {
this.db.search('warnings', { 'warnee': warnee.id, 'reason': event.input[2] }, function(result) {
warning = result;
@ -75,7 +75,7 @@ var warning = function(dbot) {
var warnee = event.params[1],
server = event.server;
dbot.api.users.resolveUser(server, warnee, function(warnee) {
dbot.api.users.resolveUser(server, warnee, function(err, warnee) {
var warnings = 0;
this.db.search('warnings', {
'server': server,

View File

@ -1,3 +1,5 @@
var _ = require('underscore')._;
var api = function(dbot) {
return {
'getUrl': function(path) {
@ -46,7 +48,7 @@ var api = function(dbot) {
}
}
if(_.include(allowedUsers, req.user.primaryNick)) {
if(_.include(accessNeeded(), req.user.primaryNick)) {
return next();
} else {
res.redirect('/');
@ -54,7 +56,8 @@ var api = function(dbot) {
} else {
res.render('login', {
'message': 'You need to log in to access this module.',
'redirect': req.originalUrl
'redirect': req.originalUrl,
'routes': dbot.modules.web.indexLinks
});
}
} else {

View File

@ -4,6 +4,10 @@ var express = require('express'),
flash = require('connect-flash'),
_ = require('underscore')._,
fs = require('fs'),
cookieParser = require('cookie-parser'),
bodyParser = require('body-parser'),
expressSession = require('express-session'),
methodOverride = require('method-override'),
LocalStrategy = require('passport-local').Strategy;
var webInterface = function(dbot) {
@ -14,22 +18,34 @@ var webInterface = function(dbot) {
this.app.use(express.static(this.pub));
this.app.set('view engine', 'jade');
this.app.use(express.cookieParser());
this.app.use(express.bodyParser());
this.app.use(express.methodOverride());
this.app.use(express.session({ 'secret': 'wat' }));
this.app.use(cookieParser());
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ 'extended': true }));
this.app.use(methodOverride());
this.app.use(expressSession({ 'secret': 'wat' }));
this.app.use(flash());
this.app.use(passport.initialize());
this.app.use(passport.session());
this.app.use(this.app.router);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
dbot.api.users.getUser(id, function(user) {
dbot.api.users.getUser(id, function(err, user) {
// Get user access level. Sigh.
if(user) {
user.access = 'user';
if(_.include(dbot.config.admins, user.primaryNick)) {
user.access = 'admin';
} else if(_.include(dbot.config.moderators, user.primaryNick)) {
user.access = 'moderator';
} else if(_.include(dbot.config.power_users, user.primaryNick)) {
user.access = 'power_user';
}
}
console.log(user);
done(null, user);
});
});
@ -46,7 +62,7 @@ var webInterface = function(dbot) {
'Please provide a valid server (Servers: ' +
_.keys(dbot.config.servers).join(', ') + ')' });
dbot.api.users.resolveUser(server, username, function(user) {
dbot.api.users.resolveUser(server, username, function(err, user) {
if(user) {
this.api.getWebUser(user.id, function(webUser) {
if(webUser) {
@ -72,9 +88,10 @@ var webInterface = function(dbot) {
for(var p in pages) {
if(_.has(pages, p)) {
var func = pages[p],
mod = func.module;
mod = func.module,
type = func.type || 'get';
this.app.get(p, this.api.hasAccess, (function(req, resp) {
this.app[type](p, this.api.hasAccess, (function(req, resp) {
// Crazy shim to seperate module views.
var shim = Object.create(resp);
shim.render = (function(view, one, two) {
@ -95,8 +112,7 @@ var webInterface = function(dbot) {
this.onLoad = function() {
this.reloadPages();
var routes = _.pluck(dbot.modules.web.app.routes.get, 'path'),
var routes = _.pluck(_.without(_.pluck(this.app._router.stack, 'route'), undefined), 'path'),
moduleNames = _.keys(dbot.modules);
_.each(moduleNames, function(moduleName) {
@ -120,13 +136,15 @@ var webInterface = function(dbot) {
this.app.get('/login', function(req, res) {
res.render('login', {
'user': req.user,
'message': req.flash('error')
});
'message': req.flash('error'),
'routes': this.indexLinks
});
}.bind(this));
this.app.post('/login', passport.authenticate('local', {
'failureRedirect': '/login',
'failureFlash': true
'failureFlash': true,
'routes': this.indexLinks
}), function(req, res) {
if(req.body.redirect) {
res.redirect(req.body.redirect);

15
run.js
View File

@ -45,12 +45,9 @@ var DBot = function() {
this.config.admin, function(event) {
var server = this.config.servers[event.server];
async.eachSeries(server.channels, function(channel, next) {
setTimeout(function() {
_.each(server.channels, function(channel) {
this.instance.join(event, channel);
next();
}.bind(this), 5000);
}.bind(this));
}, this);
}.bind(this), server.nickserv, server.password);
}, this);
@ -329,6 +326,14 @@ DBot.prototype.reloadModules = function() {
this.commands[cName.substring(1)] = command;
}
}, this);
_.each(this.usage, function(command, cName) {
if(cName.charAt(0) == '~') {
delete this.usage[cName];
this.usage[cName.substring(1)] = command;
}
}, this);
}.bind(this));
this.save();

View File

@ -1,4 +1,4 @@
!!! 5
doctype html
html(lang='en')
head
meta(charset='utf-8')
@ -6,6 +6,4 @@ html(lang='en')
title #{name} web interface
body
div.container
blink [
span.flash(style='color: #'+colour+';') #{text}
]
blink [ span.flash(style='color: #'+colour+';') #{text} span ]

View File

@ -3,6 +3,7 @@ html(lang='en')
head
meta(charset='utf-8')
script(type="text/javascript", src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js")
script(type="text/javascript", src="/fs_edit.js")
link(rel="stylesheet", type="text/css", href="http://fonts.googleapis.com/css?family=Source+Sans+Pro")
link(rel="stylesheet", type="text/css", href="/bootstrap/css/bootstrap.min.css")
link(rel='stylesheet', type='text/css', href='/styles.css')