3
0
mirror of https://github.com/reality/dbot.git synced 2024-12-24 03:33:07 +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')._,
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);
} 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();
});
}
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;
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);
}
}
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) {
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) {
// Retrive a user record given its ID
'getUser': function(id, callback) {
this.db.read('users', id, function(err, result) {
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 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);
callback(null, result);
} 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')._,
moment = require('moment-timezone');
var _ = require('underscore')._;
var commands = function(dbot) {
var commands = {
this.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 {
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(nick === user.primaryNick) {
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('alias', {
'alias': nick,
'user': user.primaryNick
}));
}
});
} else {
event.reply(dbot.t('unknown_alias', { 'alias': nick }));
}
}.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];
this.api.resolveUser(event.server, alias, function(user) {
if(user) {
user.aliases = _.without(user.aliases, alias);
user.mobile = _.without(user.mobile, alias);
this.db.save('users', user.id, user, function(err) {
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': 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));
});
}
};
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';
return commands;
this.commands['~setaliasparent'].access = 'moderator';
this.commands['~addalias'].access = 'moderator';
this.commands['~rmalias'].access = 'moderator';
this.commands['~mergeusers'].access = 'moderator';
};
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
* 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', [ event.rUser, event.newNick ]);
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) {
var id = alias + '.' + server;
this.db.del('user_aliases', id, function(err) {
callback(err);
});
},
if(!channel.op) channel.op = [];
if(!channel.voice) channel.voice = [];
// 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);
}
});
},
if(staff.op) {
channel.op.push(user.id);
} else if(staff.voice) {
channel.voice.push(user.id);
}
// 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.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 ]);
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));
}.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;
// Update current nick
this.internalAPI.updateCurrentNick(event.rUser, event.newNick, function(){});
if(!isKnown) {
event.rUser.aliases.push(event.newNick);
// 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(){});
}
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);
this.on = ['NICK'];
/*** Pre-emit ***/
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
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));
// 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 {
done(null);
}
}.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);
if(user.currentNick !== event.user) {
this.internalAPI.updateCurrentNick(user, 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);
});
} 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();
}
}.bind(this));
};
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) {
event.rUser = user;
if(event.channel) {
checkChannelUsers(function() {
callback();
});
} else {
callback();
}
}.bind(this));
}.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();
callback(null);
}
}.bind(this));
};
};
exports.fetch = function(dbot) {
return new users(dbot);
});
}.bind(this);
};