You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nodebb/src/user.js

467 lines
12 KiB
JavaScript

11 years ago
'use strict';
10 years ago
var async = require('async'),
nconf = require('nconf'),
gravatar = require('gravatar'),
11 years ago
plugins = require('./plugins'),
11 years ago
db = require('./database'),
meta = require('./meta'),
11 years ago
groups = require('./groups'),
11 years ago
Password = require('./password');
11 years ago
(function(User) {
11 years ago
User.email = require('./user/email');
User.notifications = require('./user/notifications');
User.reset = require('./user/reset');
11 years ago
require('./user/auth')(User);
require('./user/create')(User);
require('./user/follow')(User);
require('./user/profile')(User);
require('./user/admin')(User);
require('./user/delete')(User);
require('./user/settings')(User);
require('./user/search')(User);
require('./user/jobs')(User);
User.getUserField = function(uid, field, callback) {
User.getUserFields(uid, [field], function(err, user) {
callback(err, user ? user[field] : null);
});
};
User.getUserFields = function(uid, fields, callback) {
User.getMultipleUserFields([uid], fields, function(err, users) {
callback(err, users ? users[0] : null);
});
};
User.getMultipleUserFields = function(uids, fields, callback) {
var fieldsToRemove = [];
function addField(field) {
if (fields.indexOf(field) === -1) {
fields.push(field);
fieldsToRemove.push(field);
}
}
if (!Array.isArray(uids) || !uids.length) {
return callback(null, []);
}
var keys = uids.map(function(uid) {
return 'user:' + uid;
});
addField('uid');
if (fields.indexOf('picture') !== -1) {
addField('email');
addField('gravatarpicture');
addField('uploadedpicture');
}
db.getObjectsFields(keys, fields, function(err, users) {
if (err) {
return callback(err);
}
11 years ago
modifyUserData(users, fieldsToRemove, callback);
});
};
User.getUserData = function(uid, callback) {
User.getUsersData([uid], function(err, users) {
callback(err, users ? users[0] : null);
});
};
User.getUsersData = function(uids, callback) {
if (!Array.isArray(uids) || !uids.length) {
return callback(null, []);
}
var keys = uids.map(function(uid) {
return 'user:' + uid;
});
db.getObjects(keys, function(err, users) {
if (err) {
11 years ago
return callback(err);
}
11 years ago
modifyUserData(users, [], callback);
});
};
11 years ago
function modifyUserData(users, fieldsToRemove, callback) {
users.forEach(function(user) {
if (!user) {
return;
}
if (user.password) {
user.password = undefined;
}
if (!parseInt(user.uid, 10)) {
10 years ago
user.uid = 0;
user.username = '[[global:guest]]';
user.userslug = '';
10 years ago
user.picture = User.createGravatarURLFromEmail('');
}
if (user.picture) {
if (user.picture === user.uploadedpicture) {
user.picture = user.picture.indexOf('http') === -1 ? nconf.get('relative_path') + user.picture : user.picture;
} else {
user.picture = User.createGravatarURLFromEmail(user.email);
}
}
for(var i=0; i<fieldsToRemove.length; ++i) {
user[fieldsToRemove[i]] = undefined;
}
});
11 years ago
plugins.fireHook('filter:users.get', users, callback);
}
User.updateLastOnlineTime = function(uid, callback) {
11 years ago
callback = callback || function() {};
10 years ago
User.getUserFields(uid, ['status', 'lastonline'], function(err, userData) {
if(err || userData.status === 'offline' || Date.now() - parseInt(userData.lastonline, 10) < 300000) {
11 years ago
return callback(err);
}
11 years ago
User.setUserField(uid, 'lastonline', Date.now(), callback);
});
};
User.isReadyToPost = function(uid, callback) {
11 years ago
if (parseInt(uid, 10) === 0) {
return callback();
}
async.parallel({
userData: function(next) {
User.getUserFields(uid, ['banned', 'lastposttime', 'joindate', 'email', 'email:confirmed', 'reputation'], next);
},
exists: function(next) {
db.exists('user:' + uid, next);
},
isAdmin: function(next) {
User.isAdministrator(uid, next);
}
}, function(err, results) {
if (err) {
return callback(err);
}
if (!results.exists) {
return callback(new Error('[[error:no-user]]'));
}
if (results.isAdmin) {
return callback();
}
var userData = results.userData;
if (parseInt(userData.banned, 10) === 1) {
return callback(new Error('[[error:user-banned]]'));
}
if (userData.email && parseInt(meta.config.requireEmailConfirmation, 10) === 1 && parseInt(userData['email:confirmed'], 10) !== 1) {
return callback(new Error('[[error:email-not-confirmed]]'));
}
var now = Date.now();
if (now - parseInt(userData.joindate, 10) < parseInt(meta.config.initialPostDelay, 10) * 1000) {
return callback(new Error('[[error:user-too-new, ' + meta.config.initialPostDelay + ']]'));
}
var lastposttime = userData.lastposttime || 0;
if (parseInt(meta.config.newbiePostDelay, 10) > 0 && parseInt(meta.config.newbiePostDelayThreshold, 10) > parseInt(userData.reputation, 10) && now - parseInt(lastposttime, 10) < parseInt(meta.config.newbiePostDelay, 10) * 1000) {
return callback(new Error('[[error:too-many-posts-newbie, ' + meta.config.postDelay + ', ' + meta.config.newbiePostDelayThreshold + ']]'));
} else if (now - parseInt(lastposttime, 10) < parseInt(meta.config.postDelay, 10) * 1000) {
return callback(new Error('[[error:too-many-posts, ' + meta.config.postDelay + ']]'));
}
callback();
});
11 years ago
};
User.setUserField = function(uid, field, value, callback) {
plugins.fireHook('action:user.set', field, value, 'set');
11 years ago
db.setObjectField('user:' + uid, field, value, callback);
};
11 years ago
User.setUserFields = function(uid, data, callback) {
for (var field in data) {
if (data.hasOwnProperty(field)) {
plugins.fireHook('action:user.set', field, data[field], 'set');
}
}
11 years ago
db.setObject('user:' + uid, data, callback);
};
12 years ago
User.incrementUserFieldBy = function(uid, field, value, callback) {
db.incrObjectFieldBy('user:' + uid, field, value, function(err, value) {
plugins.fireHook('action:user.set', field, value, 'increment');
if (typeof callback === 'function') {
callback(err, value);
}
});
};
User.decrementUserFieldBy = function(uid, field, value, callback) {
db.incrObjectFieldBy('user:' + uid, field, -value, function(err, value) {
plugins.fireHook('action:user.set', field, value, 'decrement');
if (typeof callback === 'function') {
callback(err, value);
}
});
};
11 years ago
User.getUsersFromSet = function(set, start, stop, callback) {
async.waterfall([
function(next) {
if (set === 'users:online') {
var uids = require('./socket.io').getConnectedClients();
next(null, uids.slice(start, stop + 1));
} else {
db.getSortedSetRevRange(set, start, stop, next);
}
11 years ago
},
function(uids, next) {
User.getUsers(uids, next);
}
], callback);
};
User.getUsers = function(uids, callback) {
async.parallel({
userData: function(next) {
10 years ago
User.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'banned', 'postcount', 'reputation', 'email:confirmed'], next);
},
isAdmin: function(next) {
User.isAdministrator(uids, next);
},
isOnline: function(next) {
require('./socket.io').isUsersOnline(uids, next);
}
}, function(err, results) {
11 years ago
if (err) {
return callback(err);
}
11 years ago
results.userData.forEach(function(user, index) {
if (!user) {
return;
}
user.status = !user.status ? 'online' : user.status;
user.status = !results.isOnline[index] ? 'offline' : user.status;
user.administrator = results.isAdmin[index];
user.banned = parseInt(user.banned, 10) === 1;
10 years ago
user['email:confirmed'] = parseInt(user['email:confirmed'], 10) === 1;
});
callback(err, results.userData);
11 years ago
});
};
User.createGravatarURLFromEmail = function(email) {
var customGravatarDefaultImage = meta.config.customGravatarDefaultImage;
if (customGravatarDefaultImage && customGravatarDefaultImage.indexOf('http') === -1) {
customGravatarDefaultImage = nconf.get('url') + meta.config.customGravatarDefaultImage;
}
12 years ago
var options = {
11 years ago
size: parseInt(meta.config.profileImageDimension, 10) || 128,
11 years ago
default: customGravatarDefaultImage || meta.config.defaultGravatarImage || 'identicon',
12 years ago
rating: 'pg'
11 years ago
};
if (!email) {
12 years ago
email = '';
}
12 years ago
11 years ago
return gravatar.url(email, options, true);
};
User.hashPassword = function(password, callback) {
if (!password) {
return callback(null, password);
}
11 years ago
Password.hash(nconf.get('bcrypt_rounds'), password, callback);
11 years ago
};
10 years ago
User.onNewPostMade = function(postData, callback) {
async.parallel([
function(next) {
User.addPostIdToUser(postData.uid, postData.pid, postData.timestamp, next);
},
function(next) {
User.incrementUserPostCountBy(postData.uid, 1, next);
},
function(next) {
User.setUserField(postData.uid, 'lastposttime', postData.timestamp, next);
}
], callback);
};
11 years ago
User.incrementUserPostCountBy = function(uid, value, callback) {
11 years ago
callback = callback || function() {};
11 years ago
User.incrementUserFieldBy(uid, 'postcount', value, function(err, newpostcount) {
if (err) {
11 years ago
return callback(err);
11 years ago
}
db.sortedSetAdd('users:postcount', newpostcount, uid, callback);
});
};
User.addPostIdToUser = function(uid, pid, timestamp, callback) {
db.sortedSetAdd('uid:' + uid + ':posts', timestamp, pid, callback);
};
User.addTopicIdToUser = function(uid, tid, timestamp, callback) {
db.sortedSetAdd('uid:' + uid + ':topics', timestamp, tid, callback);
};
11 years ago
User.getPostIds = function(uid, start, stop, callback) {
db.getSortedSetRevRange('uid:' + uid + ':posts', start, stop, function(err, pids) {
callback(err, Array.isArray(pids) ? pids : []);
});
};
User.exists = function(userslug, callback) {
User.getUidByUserslug(userslug, function(err, exists) {
11 years ago
callback(err, !! exists);
});
};
User.count = function(callback) {
db.getObjectField('global', 'userCount', function(err, count) {
callback(err, count ? count : 0);
});
};
User.getUidByUsername = function(username, callback) {
11 years ago
db.getObjectField('username:uid', username, callback);
};
User.getUidByUserslug = function(userslug, callback) {
11 years ago
db.getObjectField('userslug:uid', userslug, callback);
};
User.getUsernamesByUids = function(uids, callback) {
User.getMultipleUserFields(uids, ['username'], function(err, users) {
if (err) {
return callback(err);
}
users = users.map(function(user) {
return user.username;
});
callback(null, users);
});
};
User.getUsernameByUserslug = function(slug, callback) {
async.waterfall([
function(next) {
User.getUidByUserslug(slug, next);
},
function(uid, next) {
User.getUserField(uid, 'username', next);
}
], callback);
};
User.getUidByEmail = function(email, callback) {
db.getObjectField('email:uid', email.toLowerCase(), callback);
};
11 years ago
User.getUsernameByEmail = function(email, callback) {
db.getObjectField('email:uid', email.toLowerCase(), function(err, uid) {
if (err) {
return callback(err);
}
11 years ago
User.getUserField(uid, 'username', callback);
});
};
User.isModerator = function(uid, cid, callback) {
if (Array.isArray(cid)) {
if (!parseInt(uid, 10)) {
return callback(null, cid.map(function() {return false;}));
}
var uniqueCids = cid.filter(function(cid, index, array) {
return array.indexOf(cid) === index;
});
var groupNames = uniqueCids.map(function(cid) {
return 'cid:' + cid + ':privileges:mods';
});
groups.isMemberOfGroups(uid, groupNames, function(err, isMembers) {
if (err) {
return callback(err);
}
var map = {};
uniqueCids.forEach(function(cid, index) {
map[cid] = isMembers[index];
});
callback(null, cid.map(function(cid) {
return map[cid];
}));
});
} else {
if (Array.isArray(uid)) {
groups.isMembers(uid, 'cid:' + cid + ':privileges:mods', callback);
} else {
groups.isMember(uid, 'cid:' + cid + ':privileges:mods', callback);
}
}
};
User.isAdministrator = function(uid, callback) {
if (Array.isArray(uid)) {
groups.isMembers(uid, 'administrators', callback);
} else {
groups.isMember(uid, 'administrators', callback);
}
};
11 years ago
User.getIgnoredCategories = function(uid, callback) {
db.getSortedSetRange('uid:' + uid + ':ignored:cids', 0, -1, callback);
};
User.ignoreCategory = function(uid, cid, callback) {
11 years ago
if (!uid) {
return callback();
}
11 years ago
db.sortedSetAdd('uid:' + uid + ':ignored:cids', Date.now(), cid, callback);
};
User.watchCategory = function(uid, cid, callback) {
11 years ago
if (!uid) {
return callback();
}
11 years ago
db.sortedSetRemove('uid:' + uid + ':ignored:cids', cid, callback);
};
11 years ago
}(exports));