3
0
mirror of https://github.com/reality/dbot.git synced 2024-12-24 19:52:36 +01:00

replace users with new modules

This commit is contained in:
reality 2014-09-04 09:36:57 +00:00
parent be07c36294
commit 0a4240f3db
6 changed files with 226 additions and 843 deletions

View File

@ -1,172 +1,65 @@
var _ = require('underscore')._, var _ = require('underscore')._;
uuid = require('node-uuid'),
databank = require('databank');
var api = function(dbot) { var api = function(dbot) {
var escapeRegexen = function(str) { this.api = {
return (str+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); // Retrieve a user record given a server and nickname
}; 'resolveUser': function(server, nick, callback) {
var id = nick + '.' + server;
var api = { this.api.getUser(id, function(err, result) {
// Return a user record given a primary nick or an alias if(!err) {
'resolveUser': function(server, nick, callback, lc) { callback(null, result);
var user = false; } else {
if(lc) nick = nick.toLowerCase(); this.db.read('user_aliases', id, function(err, result) {
if(_.has(this.userCache[server], nick)) { if(!err) {
this.api.getUser(this.userCache[server][nick], callback); this.api.getUser(result.user, callback);
} else { } else {
this.db.search('users', { 'server': server }, function(result) { callback(true, null);
if(lc) {
result.primaryNick = result.primaryNick.toLowerCase();
_.each(result.aliases, function(v, k) {
result.aliases[k] = v.toLowerCase();
});
}
if(result.primaryNick == nick || _.include(result.aliases, nick)) {
user = result;
}
}.bind(this), function(err) {
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;
} }
} }.bind(this));
callback(user);
}.bind(this));
}
},
// 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)); }.bind(this));
}, },
'getChannel': function(uuid, callback) { // Retrive a user record given its ID
this.db.read('channel_users', uuid, function(err, channel) { 'getUser': function(id, callback) {
if(err) channel = false; this.db.read('users', id, function(err, result) {
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) { if(!err) {
callback(users); callback(null, result);
}
});
},
'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 isOnline = _.any(onlineNicks, function(nick) {
nick = nick.name;
return _.include(possiNicks, nick);
}, this);
callback(isOnline);
}
});
},
'isKnownUser': function(server, nick, callback) {
this.api.resolveUser(server, nick, function(isKnown) {
if(isKnown == false) {
callback(false);
} else { } else {
callback(true); callback(true, null);
}
});
},
// 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);
}
});
},
// Retrieve a channel record given a server and a channel name
'resolveChannel': function(server, channel, callback) {
var id = channel + '.' + server;
this.api.getChannel(id, callback);
},
// Retrieve a channel record given its ID
'getChannel': function(id, callback) {
this.db.read('channels', id, function(err, result) {
if(!err) {
callback(null, result);
} else {
callback(true, null);
} }
}); });
} }
}; };
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' ];
return api;
};
exports.fetch = function(dbot) {
return api(dbot);
}; };

View File

@ -1,216 +1,109 @@
var _ = require('underscore')._, var _ = require('underscore')._;
moment = require('moment-timezone');
var commands = function(dbot) { var commands = function(dbot) {
var commands = { this.commands = {
'~alias': function(event) { '~alias': function(event) {
var nick = event.params[1].trim() || event.user; var nick = event.params[1] || event.user;
this.api.resolveUser(event.server, nick, function(user) { this.api.resolveUser(event.server, nick, function(err, user) {
if(user) { if(user) {
if(nick == user.primaryNick) { this.api.getUserAliases(user.id, function(err, aliases) {
var aliases = _.first(user.aliases, 10); var including = _.first(aliases, 10).join(', ');
var including = 'including: ' + aliases.join(', ') + '.';
if(user.aliases.length != 0) { if(nick === user.primaryNick) {
event.reply(dbot.t('primary', { if(aliases.length === 0) {
'user': nick, event.reply(dbot.t('primary_no_alias', {
'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 {
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', {
'user': user.primaryNick, '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 {
} else { event.reply(dbot.t('alias', {
event.reply(dbot.t('alias_exists', { 'alias': alias })); 'alias': nick,
} 'user': user.primaryNick
}));
}
});
} else { } else {
event.reply(dbot.t('unknown_alias', { 'alias': nick })); event.reply(dbot.t('unknown_alias', { 'alias': nick }));
} }
}.bind(this)); }.bind(this));
}, },
'~removealias': function(event) { '~addalias': function(event) {
var nick = event.params[1],
alias = event.params[2];
this.api.resolveUser(event.server, nick, function(err, user) {
if(user) {
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('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];
this.api.resolveUser(event.server, newPrimary, function(user) {
if(user) {
if(user.primaryNick !== newPrimary) {
this.internalAPI.reparentUser(user, newPrimary, function() {
event.reply(dbot.t('aliasparentset', {
'newParent': newPrimary,
'newAlias': user.primaryNick
}));
});
} else {
event.reply(dbot.t('already_primary', { 'user': newPrimary }));
}
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
});
},
'~rmalias': function(event) {
var alias = event.params[1]; var alias = event.params[1];
this.api.resolveUser(event.server, alias, function(user) { this.api.resolveUser(event.server, alias, function(err, user) {
if(user) { if(user) { // Retrieving user record via alias proves existence of alias record
user.aliases = _.without(user.aliases, alias); this.internalAPI.removeAlias(event.server, alias, function(err) {
user.mobile = _.without(user.mobile, alias);
this.db.save('users', user.id, user, function(err) {
event.reply(dbot.t('alias_removed', { event.reply(dbot.t('alias_removed', {
'primary': user.primaryNick, 'primary': user.primaryNick,
'alias': alias 'alias': alias
})); }));
}); });
} else { } else {
event.reply(dbot.t('unknown_alias', { 'alias': alias })); 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', {
'newParent': newPrimary,
'newAlias': newAlias
}));
dbot.api.event.emit('~setaliasparent', {
'server': event.server,
'alias': newAlias
});
}
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': newPrimary }));
}
}.bind(this));
},
'~mergeusers': function(event) {
var primaryUser = event.params[1];
var secondaryUser = event.params[2];
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
}));
dbot.api.event.emit('~mergeusers', [
event.server,
oldUser,
user
]);
}
}.bind(this));
}
}.bind(this));
} else {
event.reply(dbot.t('unprimary_error', { 'nick': secondaryUser }));
}
}.bind(this));
} else {
event.reply(dbot.t('unprimary_error', { 'nick': primaryUser }));
}
}.bind(this));
} }
}; };
this.commands['~setaliasparent'].access = 'moderator';
commands['~alias'].regex = [/^alias ([\d\w[\]{}^|\\`_-]+?)/, 2]; this.commands['~addalias'].access = 'moderator';
commands['~time'].regex = [/^time ([\d\w[\]{}^|\\`_-]+?)/, 2]; this.commands['~rmalias'].access = 'moderator';
commands['~setaliasparent'].regex = [/^setaliasparent ([\d\w[\]{}^|\\`_-]+?)/, 2]; this.commands['~mergeusers'].access = 'moderator';
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';
return commands;
}; };
exports.fetch = function(dbot) { exports.fetch = function(dbot) {

View File

@ -1,65 +0,0 @@
var _ = require('underscore')._;
var api = function(dbot) {
this.api = {
// 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.read('user_aliases', id, function(err, result) {
if(!err) {
this.api.getUser(result.user, callback);
} else {
callback(true, null);
}
}.bind(this));
}
}.bind(this));
},
// 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);
}
});
},
// 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);
}
});
},
// Retrieve a channel record given a server and a channel name
'resolveChannel': function(server, channel, callback) {
var id = channel + '.' + server;
this.api.getChannel(id, callback);
},
// Retrieve a channel record given its ID
'getChannel': function(id, callback) {
this.db.read('channels', id, function(err, result) {
if(!err) {
callback(null, result);
} else {
callback(true, null);
}
});
}
};
};

View File

@ -1,111 +0,0 @@
var _ = require('underscore')._;
var commands = function(dbot) {
this.commands = {
'~alias': function(event) {
var nick = event.params[1] || event.user;
this.api.resolveUser(event.server, nick, function(err, user) {
if(user) {
this.api.getUserAliases(user.id, function(err, aliases) {
var including = _.first(aliases, 10).join(', ');
if(nick === user.primaryNick) {
if(aliases.length === 0) {
event.reply(dbot.t('primary_no_alias', {
'user': user.primaryNick,
'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', {
'alias': nick,
'user': user.primaryNick
}));
}
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
}.bind(this));
},
'~addalias': function(event) {
var nick = event.params[1],
alias = event.params[2];
this.api.resolveUser(event.server, nick, function(err, user) {
if(user) {
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('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];
this.api.resolveUser(event.server, newPrimary, function(user) {
if(user) {
if(user.primaryNick !== newPrimary) {
this.internalAPI.reparentUser(user, newPrimary, function() {
event.reply(dbot.t('aliasparentset', {
'newParent': newPrimary,
'newAlias': user.primaryNick
}));
});
} else {
event.reply(dbot.t('already_primary', { 'user': newPrimary }));
}
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
});
},
'~rmalias': function(event) {
var alias = event.params[1];
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
}));
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
});
}
};
this.commands['~setaliasparent'].access = 'moderator';
this.commands['~addalias'].access = 'moderator';
this.commands['~rmalias'].access = 'moderator';
this.commands['~mergeusers'].access = 'moderator';
};
exports.fetch = function(dbot) {
return commands(dbot);
};

View File

@ -1,142 +0,0 @@
/**
* Name: Users
* Description: Track known users
*/
var _ = require('underscore')._;
var users = function(dbot) {
/*** Internal API ***/
this.internalAPI = {
// Create new user record
'createUser': function(server, nick, callback) {
var id = nick + '.' + server;
this.db.create('users', id, {
'id': id,
'server': server,
'primaryNick': nick,
'currentNick': nick
}, function(err, result) {
if(!err) {
dbot.api.event.emit('new_user', [ result ]);
callback(null, result);
} else {
callback(true, null);
}
});
},
// Add new user alias
'createAlias': function(alias, user, callback) {
var id = alias + '.' + user.server;
this.db.create('user_aliases', id, {
'id': id,
'alias': alias,
'user': user.id
}, function(err, result) {
if(!err) {
dbot.api.event.emit('new_user_alias', [ event.rUser, event.newNick ]);
callback(null, result);
} else {
callback(true, null);
}
});
},
// Remove an alias record
'removeAlias': function(server, alias) {
var id = alias + '.' + server;
this.db.del('user_aliases', id, function(err) {
callback(err);
});
},
// 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);
}
});
},
// Merge two user records and aliases
'mergeUsers': function(oldUser, newUser, callback) {
this.db.search('user_aliases', { 'user': oldUser.id }, function(alias) {
alias.user = newUser.id;
this.db.save('user_aliases', alias.id, alias, function(){});
}.bind(this), function(){});
this.db.del('users', oldUser.id, function(err) {
if(!err) {
dbot.api.event.emit('merged_users', [
oldUser,
newUser
]);
callback(null);
} else {
callback(true);
}
});
},
// 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));
}
};
/*** Listener ***/
// Track nick changes
this.listener = function(event) {
// Update current nick
this.internalAPI.updateCurrentNick(event.rUser, event.newNick, function(){});
// Add new alias record if nick is not already claimed
this.api.resolveUser(event.server, event.newNick, function(err, user) {
if(!user) {
this.internalAPI.createAlias(event.newNick, event.rUser, function(){});
}
}.bind(this));
}.bind(this);
this.on = ['NICK'];
/*** Pre-emit ***/
this.onLoad = function() {
// Create non-existing users and update current nicks
var checkUser = function(done) {
this.api.resolveUser(event.server, event.user, function(err, user) {
if(!user) {
this.internalAPI.createUser(event.server, event.user, done);
} else {
if(user.currentNick !== event.user) {
this.internalAPI.updateCurrentNick(user, event.user, done);
} else {
done(null, user);
}
}
}.bind(this));
};
dbot.instance.addPreEmitHook(function(event, callback) {
if(event.user && _.include(['JOIN', 'PRIVMSG'], event.action)) {
checkUser(function(err, user) {
event.rUser = user;
callback(null);
});
} else {
callback(null);
}
});
}.bind(this);
};

View File

@ -2,226 +2,141 @@
* Name: Users * Name: Users
* Description: Track known users * Description: Track known users
*/ */
var _ = require('underscore')._, var _ = require('underscore')._;
uuid = require('node-uuid'),
async = require('async');
var users = function(dbot) { 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 ***/ /*** Internal API ***/
this.internalAPI = { this.internalAPI = {
// Create new user record
'createUser': function(server, nick, callback) { 'createUser': function(server, nick, callback) {
var id = uuid.v4(); var id = nick + '.' + server;
this.db.create('users', id, { this.db.create('users', id, {
'id': id, 'id': id,
'primaryNick': nick,
'currentNick': nick,
'server': server, 'server': server,
'channels': [], 'primaryNick': nick,
'aliases': [], 'currentNick': nick
'mobile': []
}, function(err, result) { }, function(err, result) {
if(!err) { if(!err) {
dbot.api.event.emit('new_user', [ result ]); dbot.api.event.emit('new_user', [ result ]);
callback(result); callback(null, result);
} else {
callback(true, null);
} }
}); });
}.bind(this), },
'createChannel': function(server, name, callback) { // Add new user alias
var id = uuid.v4(); 'createAlias': function(alias, user, callback) {
this.db.create('channel_users', id, { var id = alias + '.' + user.server;
this.db.create('user_aliases', id, {
'id': id, 'id': id,
'server': server, 'alias': alias,
'name': name, 'user': user.id
'users': [],
'op': [],
'voice': []
}, function(err, result) { }, function(err, result) {
if(!err) { if(!err) {
dbot.api.event.emit('new_channel', [ result ]); dbot.api.event.emit('new_user_alias', [ event.rUser, event.newNick ]);
callback(result); callback(null, result);
} else {
callback(true, null);
} }
}); });
}.bind(this), },
'addChannelUser': function(channel, user, staff, callback) { // Remove an alias record
if(!_.include(channel.users, user.id)) { 'removeAlias': function(server, alias) {
channel.users.push(user.id); var id = alias + '.' + server;
} this.db.del('user_aliases', id, function(err) {
if(!_.include(user.channels, channel.id)) { callback(err);
user.channels.push(channel.id); });
} },
if(!channel.op) channel.op = []; // Update current nick of user record
if(!channel.voice) channel.voice = []; '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);
}
});
},
if(staff.op) { // Merge two user records and aliases
channel.op.push(user.id); 'mergeUsers': function(oldUser, newUser, callback) {
} else if(staff.voice) { this.db.search('user_aliases', { 'user': oldUser.id }, function(alias) {
channel.voice.push(user.id); alias.user = newUser.id;
} this.db.save('user_aliases', alias.id, alias, function(){});
}.bind(this), function(){});
this.db.save('users', user.id, user, function(err) { this.db.del('users', oldUser.id, function(err) {
this.db.save('channel_users', channel.id, channel, function(err) { if(!err) {
dbot.api.event.emit('new_channel_user', [ user, channel ]); dbot.api.event.emit('merged_users', [
oldUser,
newUser
]);
callback(null);
} else {
callback(true);
}
});
},
// 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); callback(err);
}); });
}.bind(this)); }.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.listener = function(event) {
this.api.isKnownUser(event.server, event.newNick, function(isKnown) { // Update current nick
event.rUser.currentNick = event.newNick; this.internalAPI.updateCurrentNick(event.rUser, event.newNick, function(){});
if(!isKnown) { // Add new alias record if nick is not already claimed
event.rUser.aliases.push(event.newNick); this.api.resolveUser(event.server, event.newNick, function(err, user) {
if(!user) {
this.internalAPI.createAlias(event.newNick, event.rUser, 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 ]);
}
dbot.api.event.emit('new_current_nick', [ event.rUser, event.user ]);
});
}.bind(this)); }.bind(this));
}.bind(this); }.bind(this);
this.on = ['NICK']; this.on = ['NICK'];
/*** Pre-emit ***/
this.onLoad = function() { this.onLoad = function() {
dbot.instance.addPreEmitHook(function(event, callback) { // Create non-existing users and update current nicks
// 1. Attempt to resolve channel var checkUser = function(done) {
// 2. Create channel if it doesn't exist this.api.resolveUser(event.server, event.user, function(err, user) {
// 3. Attempt to resolve user if(!user) {
// 4. Create user if it doesn't exist this.internalAPI.createUser(event.server, event.user, done);
// 5. Make sure channel objects are up to date
// 6. Update staff channel lists
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 { } else {
done(null); if(user.currentNick !== event.user) {
} this.internalAPI.updateCurrentNick(user, event.user, done);
}.bind(this);
var checkUser = function(done) {
this.api.resolveUser(event.server, event.user, function(user) {
if(!user) {
this.internalAPI.createUser(event.server, event.user, done);
} else { } else {
if(event.user !== user.currentNick) { done(null, user);
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);
});
} else {
done(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();
} }
}.bind(this));
};
if(!_.has(event.channel, 'nicks') || !_.has(event.channel.nicks, event.rUser.currentNick)) { dbot.instance.addPreEmitHook(function(event, callback) {
return done(); if(event.user && _.include(['JOIN', 'PRIVMSG'], event.action)) {
} checkUser(function(err, user) {
var cUser = event.channel.nicks[event.rUser.currentNick]; event.rUser = user;
callback(null);
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) {
event.rUser = user;
if(event.channel) {
checkChannelUsers(function() {
callback();
});
} else {
callback();
}
}.bind(this));
}.bind(this));
} else { } else {
callback(); callback(null);
} }
}.bind(this)); });
}; }.bind(this);
};
exports.fetch = function(dbot) {
return new users(dbot);
}; };