Initial databankerisation of profile [#331]

* Stats functionality disabled until completion of SamStudio8/dbot-stats#98
* Profile grid currently only works with dbType set to memory
* Merge user functionality temporarily disabled
This commit is contained in:
Sam Nicholls 2013-04-20 22:51:36 +01:00
parent bd2d0a8953
commit ab0a110a8e
8 changed files with 150 additions and 144 deletions

View File

@ -4,64 +4,77 @@ var api = function(dbot) {
return { return {
/** /**
* Create a profile for a new primary user on a given server. * Create a new profile for a given "databanked" user.
* If the server does not already exist, create it. * Typically only called as a hook to the new_user emit event.
* TODO(@samstudio8) Migrate to internalAPI
*/ */
"createProfile": function(server, primary){ "createProfile": function(user, callback){
var primaryLower = primary.toLowerCase(); if(user){
this.db.create('profiles', user.id, {
if(!_.has(this.profiles, server)){ 'id': user.id,
this.profiles[server] = {}; 'profile': dbot.config.profile.schema.profile,
'preferences': dbot.config.profile.schema.preferences
}, function(err, result){
if(err){
console.log(err);
} }
if(!_.has(this.profiles[server], primaryLower)){ });
this.profiles[server][primaryLower] = {
"profile": {},
"preferences": {}
};
this.profiles[server][primaryLower].profile.primary = primary;
}
// Ensure all profiles have the keys specified by config.json
//TODO(samstudio8) Currently only handles "top-level"
_.defaults(this.profiles[server][primaryLower].profile, this.config.schema.profile);
_.defaults(this.profiles[server][primaryLower].preferences, this.config.schema.preferences);
},
/**
* Given a server and "new" alias, resolve this alias to the user's
* new primary name and move profile data pertaining to the alias to
* the new primary name.
*/
'renameProfile': function(server, alias){
if(!_.has(this.profiles, server)) return;
var profiles = dbot.db.profiles[server];
if(_.has(profiles, alias)){
var primary = dbot.api.users.resolveUser(server, alias, true);
var primaryLower = primary.toLowerCase();
alias = alias.trim().toLowerCase();
profiles[primaryLower] = profiles[alias];
profiles[primaryLower].profile.primary = primary;
delete profiles[alias];
} }
}, },
/** //TODO(samstudio8) Merge Profiles
* Given a server and a primary username which has been converted to a 'mergeProfile': function(server, nick, callback){
* secondary alias find and remove the profile for the alias. console.log("mergeProfile not implemented");
*/ },
'mergeProfile': function(server, mergeFromPrimary){
if(!_.has(this.profiles, server)) return;
var profiles = dbot.db.profiles[server];
mergeFromPrimary = mergeFromPrimary.toLowerCase(); 'getProfile': function(server, nick, callback){
var mergeToPrimary = dbot.api.users.resolveUser(server, mergeFromPrimary, true).toLowerCase(); dbot.api.users.resolveUser(server, nick, function(user){
if(!_.has(profiles, mergeToPrimary) if(user){
|| !_.has(profiles, mergeFromPrimary)) return; this.db.read('profiles', user.id, function(err, profile){
callback(false, user, profile);
});
}
else{
callback(true, null, null);
}
}.bind(this));
},
// Remove the profile of the alias 'getAllProfiles': function(callback){
delete profiles[mergeFromPrimary]; var profiles = [];
this.db.scan('profiles', function(profile){
profiles.push(profile);
}, function(err){
if(!err){
callback(profiles);
}
else{
console.log(err);
}
});
},
'setProperty': function(server, nick, field, value, callback){
this.api.getProfile(server, nick, function(err, user, profile){
if(!err){
profile.profile[field] = value;
this.db.save('profiles', user.id, profile, function(err){
if(!err){
callback("Ok!");
}
});
}
}.bind(this));
},
'getProperty': function(server, nick, field, callback){
this.api.getProfile(server, nick, function(err, user, profile){
if(!err){
if(profile.profile[field]){
callback(profile.profile[field]);
}
}
}.bind(this));
}, },
} }
}; };

View File

@ -5,23 +5,10 @@ var commands = function(dbot){
"~getprop": function(event){ "~getprop": function(event){
if(event.params[1]){ if(event.params[1]){
var primary = dbot.api.users.resolveUser(event.server, event.user); if(_.has(this.config.schema.profile, event.params[1])){
var res = dbot.db.profiles[event.server][primary.toLowerCase()].profile[event.params[1]]; this.api.getProperty(event.server, event.user, event.params[1], function(reply){
if(res){ event.reply(reply);
event.reply(res); });
}
else{
event.reply("Nope.");
}
}
},
"~setprop": function(event){
if(event.input[1] && event.input[2]){
if(_.has(this.config.schema.profile, event.input[1])){
var primary = dbot.api.users.resolveUser(event.server, event.user);
dbot.db.profiles[event.server][primary.toLowerCase()].profile[event.input[1]] = event.input[2];
event.reply("Property set, maybe?");
} }
else{ else{
event.reply("Invalid property. Go home."); event.reply("Invalid property. Go home.");
@ -29,23 +16,18 @@ var commands = function(dbot){
} }
}, },
"~profile": function(event){ "~setprop": function(event){
if(event.params[1]){ if(event.input[1] && event.input[2]){
var primary = dbot.api.users.resolveUser(event.server, event.params[1]); if(_.has(this.config.schema.profile, event.input[1])){
if(_.has(dbot.db.profiles[event.server], primary.toLowerCase())){ this.api.setProperty(event.server, event.user, event.input[1], event.input[2], function(reply){
event.reply(dbot.api.web.getUrl("profile/"+event.server+"/"+primary.toLowerCase())); event.reply(reply);
});
} }
else{ else{
event.reply("No profile found for "+event.params[1]); event.reply("Invalid property. Go home.");
}
}
else{
event.message = '~profile ' + event.user;
event.action = 'PRIVMSG';
event.params = event.message.split(' ');
dbot.instance.emit(event);
} }
} }
},
}; };
commands['~setprop'].regex = [/~setprop ([^ ]+) (.+)/, 3]; commands['~setprop'].regex = [/~setprop ([^ ]+) (.+)/, 3];

View File

@ -1,6 +1,6 @@
{ {
"ignorable": false, "ignorable": false,
"dbKeys": [ "profiles" ], "dbType": "memory",
"help": "https://github.com/reality/depressionbot/blob/master/modules/profile/README.md", "help": "https://github.com/reality/depressionbot/blob/master/modules/profile/README.md",
"schema": { "schema": {
"profile": { "profile": {

View File

@ -5,48 +5,69 @@ var pages = function(dbot) {
return { return {
'/profile/:connection/:user': function(req, res) { '/profile/:connection/:user': function(req, res) {
var connection = req.params.connection; var connection = req.params.connection;
var user = dbot.cleanNick(req.params.user); var nick = req.params.user;
var primary = dbot.api.users.resolveUser(connection, user, true); dbot.api.users.resolveUser(connection, nick, function(user){
//var profile = dbot.api.profile.getProfile(primary); if(user){
var profile = dbot.db.profiles[connection][primary.toLowerCase()].profile; dbot.api.profile.getProfile(connection, user.primaryNick, function(err, user, profile){
var stats = dbot.api.stats.getUserChansStats(connection, primary.toLowerCase(), [ if(!err){
"lines", "words", "lincent", "wpl", "in_mentions"] var stats = [];
);
/*TODO(@samstudio8)
* stats functionality currently disabled as it has not been databanked
*/
//var stats = dbot.api.stats.getUserChansStats(connection, user.primaryNick, [
// "lines", "words", "lincent", "wpl", "in_mentions"]
//);
res.render('profile', { res.render('profile', {
'name': dbot.config.name, 'name': dbot.config.name,
'connection': connection, 'connection': connection,
'primary': primary, 'primary': user.primaryNick,
'profile': profile, 'profile': profile.profile,
'stats': stats.channels, 'stats': stats.channels,
}); });
}
else{
res.render('error', {
});
}
});
}
else{
res.render('not_found', {
});
}
});
}, },
'/profile/:connection': function(req, res) { '/profile/:connection': function(req, res) {
var connection = req.params.connection; dbot.api.profile.getAllProfiles(function(profiles){
var profiles = dbot.db.profiles[connection]; var thumbnails = [];
// TODO: Clean up
_.each(profiles, function(profile){ _.each(profiles, function(profile){
if(_.has(dbot.db.quoteArrs, profile.profile.primary) && !profile.profile.avatar) { var nick = dbot.api.users.getUser(profile.id, function(user){
var category = dbot.db.quoteArrs[profile.profile.primary]; if(user){
var avatar = _.find(category, function(quote) {
return quote.match(/(\.jpg|\.png|\.jpeg)$/i); /*TODO(@tmenari / @samstudio8)
* if username has a quote array and no avatar:
* search their quote array for a jpg, png, jpeg or gif
* set this as their new avatar
*/
if(profile.profile.avatar){
thumbnails.push({
"avatar": profile.profile.avatar,
"nick": user.primaryNick
}); });
if(avatar) profile.profile.avatar = avatar;
} }
}
});
}); });
var nicks = []; process.nextTick(function(){
for (var p in profiles) { thumbnails.sort(function(a, b) {
if (profiles.hasOwnProperty(p) && profiles[p].profile.avatar) { var x = a.nick.toLowerCase();
nicks.push(p); var y = b.nick.toLowerCase();
}
}
nicks.sort(function(a, b) {
var x = profiles[a].profile.primary.toLowerCase();
var y = profiles[b].profile.primary.toLowerCase();
if(x > y) return 1; if(x > y) return 1;
if(x < y) return -1; if(x < y) return -1;
return 0; return 0;
@ -54,9 +75,10 @@ var pages = function(dbot) {
res.render('profile_grid', { res.render('profile_grid', {
'name': dbot.config.name, 'name': dbot.config.name,
'connection': connection, 'connection': req.params.connection,
'nicks': nicks, 'thumbnails': thumbnails,
'profiles': profiles, });
});
}); });
} }
} }

View File

@ -2,27 +2,14 @@ var _ = require('underscore')._;
var profile = function(dbot) { var profile = function(dbot) {
this.profiles = dbot.db.profiles;
/**
* Iterate over known user profiles and ensure they contain all the
* required properties as defined in the configuation.
*/
this.onLoad = function(){ this.onLoad = function(){
var api = this.api; var api = this.api;
var schema = this.config.schema; var schema = this.config.schema;
// Ensure all known users have a profile
_.each(dbot.api.users.getAllUsers(), function(server, serverName){
_.each(server, function(primary, primaryi){
api.createProfile(serverName, primary);
});
});
dbot.save();
// Add API Hooks // Add API Hooks
dbot.api.command.addHook('~setaliasparent', this.api.renameProfile); dbot.api.command.addHook('~setaliasparent', this.api.renameProfile);
dbot.api.command.addHook('~mergeusers', this.api.mergeProfile); //TODO(@samstudio8) Profile Merging
//dbot.api.command.addHook('~mergeusers', this.api.mergeProfile);
dbot.api.event.addHook('new_user', this.api.createProfile); dbot.api.event.addHook('new_user', this.api.createProfile);
}; };
}; };

1
views/profile/error.jade Normal file
View File

@ -0,0 +1 @@
h1 Error

View File

@ -0,0 +1 @@
h1 Not Found

View File

@ -18,9 +18,9 @@ block content
a(href='../connections') &laquo; Connections a(href='../connections') &laquo; Connections
ul.thumbnails ul.thumbnails
each nick in nicks each thumbnail in thumbnails
li.span2 li.span2
a.thumbnail(href='/profile/'+connection+'/'+encodeURIComponent(nick)) a.thumbnail(href='/profile/'+connection+'/'+encodeURIComponent(thumbnail.nick))
div.imgwrap div.imgwrap
img(src="#{profiles[nick].profile.avatar}", alt="#{profiles[nick].profile.primary}'s photo") img(src="#{thumbnail.avatar}", alt="#{thumbnail.nick}'s photo")
span.nicks #{profiles[nick].profile.primary} span.nicks #{thumbnail.nick}