Files
NodeBB/src/user/data.js

267 lines
7.7 KiB
JavaScript
Raw Normal View History

2015-09-25 17:08:00 -04:00
'use strict';
2017-03-02 16:11:11 +03:00
var async = require('async');
2015-09-25 17:08:00 -04:00
var validator = require('validator');
var nconf = require('nconf');
var winston = require('winston');
var _ = require('lodash');
2015-09-25 17:08:00 -04:00
var db = require('../database');
2017-05-27 23:32:55 -04:00
var meta = require('../meta');
2015-09-25 17:08:00 -04:00
var plugins = require('../plugins');
var utils = require('../utils');
2015-09-25 17:08:00 -04:00
const intFields = [
'uid', 'postcount', 'topiccount', 'reputation', 'profileviews',
2018-10-25 17:02:59 -04:00
'banned', 'banned:expire', 'email:confirmed', 'joindate', 'lastonline', 'lastqueuetime',
'lastposttime', 'followingCount', 'followerCount',
];
2018-10-20 17:07:32 -04:00
module.exports = function (User) {
2017-11-08 14:06:52 -05:00
var iconBackgrounds = [
'#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3',
'#009688', '#1b5e20', '#33691e', '#827717', '#e65100', '#ff5722',
'#795548', '#607d8b',
];
var fieldWhitelist = [
'uid', 'username', 'userslug', 'email', 'email:confirmed', 'joindate',
'lastonline', 'picture', 'fullname', 'location', 'birthday', 'website',
'aboutme', 'signature', 'uploadedpicture', 'profileviews', 'reputation',
'postcount', 'topiccount', 'lastposttime', 'banned', 'banned:expire',
'status', 'flags', 'followerCount', 'followingCount', 'cover:url',
'cover:position', 'groupTitle',
];
User.getUsersFields = function (uids, fields, callback) {
2017-05-03 15:30:42 -04:00
if (!Array.isArray(uids) || !uids.length) {
return callback(null, []);
}
2018-10-20 17:07:32 -04:00
uids = uids.map(uid => (isNaN(uid) ? 0 : uid));
2017-06-01 16:17:03 -04:00
2015-09-25 17:08:00 -04:00
var fieldsToRemove = [];
function addField(field) {
if (!fields.includes(field)) {
2015-09-25 17:08:00 -04:00
fields.push(field);
fieldsToRemove.push(field);
}
}
if (fields.length && !fields.includes('uid')) {
2015-09-25 17:08:00 -04:00
fields.push('uid');
}
if (fields.includes('picture')) {
2015-09-25 17:08:00 -04:00
addField('uploadedpicture');
}
if (fields.includes('status')) {
addField('lastonline');
}
var uniqueUids = _.uniq(uids);
2017-05-03 15:30:42 -04:00
2017-03-02 16:11:11 +03:00
async.waterfall([
function (next) {
2017-11-08 14:06:52 -05:00
plugins.fireHook('filter:user.whitelistFields', { uids: uids, whitelist: fieldWhitelist.slice() }, next);
},
function (results, next) {
2017-06-01 16:17:03 -04:00
if (fields.length) {
2018-10-20 17:07:32 -04:00
const whitelistSet = new Set(results.whitelist);
2017-11-08 14:06:52 -05:00
fields = fields.filter(function (field) {
2018-10-20 17:07:32 -04:00
var isFieldWhitelisted = field && whitelistSet.has(field);
if (!isFieldWhitelisted) {
winston.verbose('[user/getUsersFields] ' + field + ' removed because it is not whitelisted, see `filter:user.whitelistFields`');
}
return isFieldWhitelisted;
2017-11-08 14:06:52 -05:00
});
2017-06-01 16:17:03 -04:00
} else {
2017-11-08 14:06:52 -05:00
fields = results.whitelist;
2017-06-01 16:17:03 -04:00
}
2017-11-08 14:06:52 -05:00
db.getObjectsFields(uidsToUserKeys(uniqueUids), fields, next);
2017-03-02 16:11:11 +03:00
},
function (users, next) {
2017-05-03 15:30:42 -04:00
users = uidsToUsers(uids, uniqueUids, users);
2018-10-25 19:58:01 -04:00
modifyUserData(users, fields, fieldsToRemove, next);
2017-03-02 16:11:11 +03:00
},
], callback);
2015-09-25 17:08:00 -04:00
};
2018-10-20 17:07:32 -04:00
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.getUsersFields([uid], fields, function (err, users) {
callback(err, users ? users[0] : null);
});
};
User.getUserData = function (uid, callback) {
User.getUsersData([uid], function (err, users) {
2015-09-25 17:08:00 -04:00
callback(err, users ? users[0] : null);
});
};
User.getUsersData = function (uids, callback) {
2017-06-01 16:17:03 -04:00
User.getUsersFields(uids, [], callback);
2015-09-25 17:08:00 -04:00
};
2017-05-03 15:30:42 -04:00
function uidsToUsers(uids, uniqueUids, usersData) {
2018-10-20 16:10:02 -04:00
var uidToUser = uniqueUids.reduce(function (memo, cur, idx) {
memo[cur] = usersData[idx];
2017-05-03 15:30:42 -04:00
return memo;
}, {});
var users = uids.map(function (uid) {
2018-10-20 16:10:02 -04:00
const returnPayload = uidToUser[uid];
2018-07-26 14:36:25 -04:00
if (uid > 0 && !returnPayload.uid) {
returnPayload.oldUid = parseInt(uid, 10);
}
2018-10-20 16:10:02 -04:00
return returnPayload;
2017-05-03 15:30:42 -04:00
});
return users;
}
function uidsToUserKeys(uids) {
2018-10-20 16:10:02 -04:00
return uids.map(uid => 'user:' + uid);
2017-05-03 15:30:42 -04:00
}
2018-10-25 19:58:01 -04:00
function modifyUserData(users, requestedFields, fieldsToRemove, callback) {
users.forEach(function (user) {
2015-09-25 17:08:00 -04:00
if (!user) {
return;
}
2018-10-20 17:07:32 -04:00
2018-10-25 19:58:01 -04:00
db.parseIntFields(user, intFields, requestedFields);
2018-10-20 17:07:32 -04:00
2018-04-05 16:46:32 -04:00
if (user.hasOwnProperty('groupTitle')) {
parseGroupTitle(user);
}
2016-08-11 08:41:34 +03:00
if (user.hasOwnProperty('username')) {
user.username = validator.escape(user.username ? user.username.toString() : '');
}
2015-09-25 17:08:00 -04:00
if (!parseInt(user.uid, 10)) {
user.uid = 0;
2018-07-26 14:36:25 -04:00
user.username = (user.hasOwnProperty('oldUid') && parseInt(user.oldUid, 10)) ? '[[global:former_user]]' : '[[global:guest]]';
2015-09-25 17:08:00 -04:00
user.userslug = '';
2017-05-27 23:32:55 -04:00
user.picture = User.getDefaultAvatar();
user['icon:text'] = '?';
user['icon:bgColor'] = '#aaa';
2015-09-25 17:08:00 -04:00
}
2015-09-27 12:57:21 -04:00
if (user.picture && user.picture === user.uploadedpicture) {
user.uploadedpicture = user.picture.startsWith('http') ? user.picture : nconf.get('relative_path') + user.picture;
user.picture = user.uploadedpicture;
2015-10-07 03:06:32 -04:00
} else if (user.uploadedpicture) {
user.uploadedpicture = user.uploadedpicture.startsWith('http') ? user.uploadedpicture : nconf.get('relative_path') + user.uploadedpicture;
2015-09-25 17:08:00 -04:00
}
2017-05-27 23:32:55 -04:00
if (meta.config.defaultAvatar && !user.picture) {
user.picture = User.getDefaultAvatar();
}
2015-09-25 17:08:00 -04:00
2018-10-25 17:02:59 -04:00
if (user.hasOwnProperty('status') && user.lastonline) {
user.status = User.getStatus(user);
}
for (var i = 0; i < fieldsToRemove.length; i += 1) {
2015-09-25 17:08:00 -04:00
user[fieldsToRemove[i]] = undefined;
}
// User Icons
2017-05-27 23:32:55 -04:00
if (user.hasOwnProperty('picture') && user.username && parseInt(user.uid, 10) && !meta.config.defaultAvatar) {
user['icon:text'] = (user.username[0] || '').toUpperCase();
user['icon:bgColor'] = iconBackgrounds[Array.prototype.reduce.call(user.username, function (cur, next) {
return cur + next.charCodeAt();
}, 0) % iconBackgrounds.length];
}
2016-10-07 17:35:24 +03:00
if (user.hasOwnProperty('joindate')) {
user.joindateISO = utils.toISOString(user.joindate);
}
if (user.hasOwnProperty('lastonline')) {
user.lastonlineISO = utils.toISOString(user.lastonline) || user.joindateISO;
}
2017-08-01 14:09:55 -04:00
if (user.hasOwnProperty('banned:expire')) {
2018-10-25 17:02:59 -04:00
user.banned_until = user['banned:expire'];
2017-08-01 14:09:55 -04:00
user.banned_until_readable = user.banned_until ? new Date(user.banned_until).toString() : 'Not Banned';
}
2015-09-25 17:08:00 -04:00
});
plugins.fireHook('filter:users.get', users, callback);
}
2018-04-05 16:46:32 -04:00
function parseGroupTitle(user) {
try {
user.groupTitleArray = JSON.parse(user.groupTitle);
} catch (err) {
user.groupTitleArray = [user.groupTitle];
}
if (!Array.isArray(user.groupTitleArray)) {
user.groupTitleArray = [user.groupTitleArray];
}
if (!meta.config.allowMultipleBadges) {
2018-04-05 16:46:32 -04:00
user.groupTitleArray = [user.groupTitleArray[0]];
}
}
2017-05-27 23:32:55 -04:00
User.getDefaultAvatar = function () {
if (!meta.config.defaultAvatar) {
return '';
}
return meta.config.defaultAvatar.startsWith('http') ? meta.config.defaultAvatar : nconf.get('relative_path') + meta.config.defaultAvatar;
};
User.setUserField = function (uid, field, value, callback) {
2018-10-20 17:07:32 -04:00
User.setUserFields(uid, { [field]: value }, callback);
2015-09-25 17:08:00 -04:00
};
User.setUserFields = function (uid, data, callback) {
callback = callback || function () {};
2017-03-02 16:11:11 +03:00
async.waterfall([
function (next) {
db.setObject('user:' + uid, data, next);
},
function (next) {
for (var field in data) {
if (data.hasOwnProperty(field)) {
plugins.fireHook('action:user.set', { uid: uid, field: field, value: data[field], type: 'set' });
}
2015-09-25 17:08:00 -04:00
}
2017-03-02 16:11:11 +03:00
next();
},
], callback);
2015-09-25 17:08:00 -04:00
};
User.incrementUserFieldBy = function (uid, field, value, callback) {
2017-03-02 16:11:11 +03:00
incrDecrUserFieldBy(uid, field, value, 'increment', callback);
2015-09-25 17:08:00 -04:00
};
User.decrementUserFieldBy = function (uid, field, value, callback) {
2017-03-02 16:11:11 +03:00
incrDecrUserFieldBy(uid, field, -value, 'decrement', callback);
2015-09-25 17:08:00 -04:00
};
2017-03-02 16:11:11 +03:00
function incrDecrUserFieldBy(uid, field, value, type, callback) {
callback = callback || function () {};
async.waterfall([
function (next) {
db.incrObjectFieldBy('user:' + uid, field, value, next);
},
function (value, next) {
plugins.fireHook('action:user.set', { uid: uid, field: field, value: value, type: type });
next(null, value);
},
], callback);
}
};