diff --git a/src/user/create.js b/src/user/create.js index 6340b67f64..84f90dba3a 100644 --- a/src/user/create.js +++ b/src/user/create.js @@ -13,37 +13,142 @@ var async = require('async'), module.exports = function(User) { User.create = function(data, callback) { - var gravatar = User.createGravatarURLFromEmail(data.email); - var timestamp = Date.now(); - var password = data.password; - var userData = { - 'username': data.username.trim(), - 'email': data.email, - 'joindate': timestamp, - 'picture': gravatar, - 'gravatarpicture': gravatar, - 'fullname': '', - 'location': '', - 'birthday': '', - 'website': '', - 'signature': '', - 'uploadedpicture': '', - 'profileviews': 0, - 'reputation': 0, - 'postcount': 0, - 'lastposttime': 0, - 'banned': 0, - 'status': 'online' - }; - - userData.userslug = utils.slugify(userData.username); - - if (userData.email !== undefined) { - userData.email = userData.email.trim(); - userData.email = validator.escape(userData.email); + data.username = data.username.trim(); + data.userslug = utils.slugify(data.username); + if (data.email !== undefined) { + data.email = validator.escape(data.email.trim()); } + isDataValid(data, function(err) { + if (err) { + return callback(err); + } + var gravatar = User.createGravatarURLFromEmail(data.email); + var timestamp = Date.now(); + + var userData = { + 'username': data.username.trim(), + 'userslug': data.userslug, + 'email': data.email, + 'joindate': timestamp, + 'picture': gravatar, + 'gravatarpicture': gravatar, + 'fullname': '', + 'location': '', + 'birthday': '', + 'website': '', + 'signature': '', + 'uploadedpicture': '', + 'profileviews': 0, + 'reputation': 0, + 'postcount': 0, + 'lastposttime': 0, + 'banned': 0, + 'status': 'online' + }; + + async.parallel({ + renamedUsername: function(next) { + renameUsername(userData, next); + }, + customFields: function(next) { + plugins.fireHook('filter:user.custom_fields', [], next); + }, + userData: function(next) { + plugins.fireHook('filter:user.create', userData, next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + + var customData = {}; + results.customFields.forEach(function(customField) { + if (data[customField]) { + customData[customField] = data[customField]; + } + }); + + userData = utils.merge(results.userData, customData); + + var userNameChanged = !!results.renamedUsername; + + if (userNameChanged) { + userData.username = results.renamedUsername; + userData.userslug = utils.slugify(results.renamedUsername); + } + + async.waterfall([ + function(next) { + db.incrObjectField('global', 'nextUid', next); + }, + function(uid, next) { + userData.uid = uid; + db.setObject('user:' + uid, userData, next); + } + ], function(err) { + if (err) { + return callback(err); + } + + async.parallel([ + function(next) { + db.incrObjectField('global', 'userCount', next); + }, + function(next) { + db.setObjectField('username:uid', userData.username, userData.uid, next); + }, + function(next) { + db.setObjectField('userslug:uid', userData.userslug, userData.uid, next); + }, + function(next) { + db.sortedSetAdd('users:joindate', timestamp, userData.uid, next); + }, + function(next) { + db.sortedSetsAdd(['users:postcount', 'users:reputation'], 0, userData.uid, next); + }, + function(next) { + groups.join('registered-users', userData.uid, next); + }, + function(next) { + if (userData.email !== undefined) { + db.setObjectField('email:uid', userData.email.toLowerCase(), userData.uid, next); + if (parseInt(userData.uid, 10) !== 1 && parseInt(meta.config.requireEmailConfirmation, 10) === 1) { + User.email.verify(userData.uid, userData.email); + } + } else { + next(); + } + }, + function(next) { + if (!data.password) { + return next(); + } + User.hashPassword(data.password, function(err, hash) { + if (err) { + return next(err); + } + + User.setUserField(userData.uid, 'password', hash, next); + }); + } + ], function(err) { + if (err) { + return callback(err); + } + if (userNameChanged) { + User.notifications.sendNameChangeNotification(userData.uid, userData.username); + } + plugins.fireHook('action:user.create', userData); + callback(null, userData.uid); + }); + }); + }); + }); + }; + + function isDataValid(userData, callback) { async.parallel({ emailValid: function(next) { if (userData.email) { @@ -56,40 +161,12 @@ module.exports = function(User) { next((!utils.isUserNameValid(userData.username) || !userData.userslug) ? new Error('[[error:invalid-username]]') : null); }, passwordValid: function(next) { - if (password) { - next(!utils.isPasswordValid(password) ? new Error('[[error:invalid-password]]') : null); + if (userData.password) { + next(!utils.isPasswordValid(userData.password) ? new Error('[[error:invalid-password]]') : null); } else { next(); } }, - renamedUsername: function(next) { - meta.userOrGroupExists(userData.userslug, function(err, exists) { - if (err) { - return next(err); - } - - if (exists) { - var newUsername = ''; - async.forever(function(next) { - newUsername = userData.username + (Math.floor(Math.random() * 255) + 1); - User.exists(newUsername, function(err, exists) { - if (err) { - return callback(err); - } - if (!exists) { - next(newUsername); - } else { - next(); - } - }); - }, function(username) { - next(null, username); - }); - } else { - next(); - } - }); - }, emailAvailable: function(next) { if (userData.email) { User.email.available(userData.email, function(err, available) { @@ -101,92 +178,33 @@ module.exports = function(User) { } else { next(); } - }, - customFields: function(next) { - plugins.fireHook('filter:user.custom_fields', [], next); - }, - userData: function(next) { - plugins.fireHook('filter:user.create', userData, next); } - }, function(err, results) { - if (err) { + }, callback); + } + + function renameUsername(userData, callback) { + meta.userOrGroupExists(userData.userslug, function(err, exists) { + if (err || !exists) { return callback(err); } - var customData = {}; - results.customFields.forEach(function(customField) { - if (data[customField]) { - customData[customField] = data[customField]; - } - }); - - userData = utils.merge(results.userData, customData); - - var userNameChanged = !!results.renamedUsername; - - if (userNameChanged) { - userData.username = results.renamedUsername; - userData.userslug = utils.slugify(results.renamedUsername); - } - - db.incrObjectField('global', 'nextUid', function(err, uid) { - if (err) { - return callback(err); - } - - userData.uid = uid; - - db.setObject('user:' + uid, userData, function(err) { + var newUsername = ''; + async.forever(function(next) { + newUsername = userData.username + (Math.floor(Math.random() * 255) + 1); + User.exists(newUsername, function(err, exists) { if (err) { return callback(err); } - - db.setObjectField('username:uid', userData.username, uid); - db.setObjectField('userslug:uid', userData.userslug, uid); - - if (userData.email !== undefined) { - db.setObjectField('email:uid', userData.email.toLowerCase(), uid); - if (parseInt(uid, 10) !== 1 && parseInt(meta.config.requireEmailConfirmation, 10) === 1) { - User.email.verify(uid, userData.email); - } - } - - plugins.fireHook('action:user.create', userData); - db.incrObjectField('global', 'userCount'); - - db.sortedSetAdd('users:joindate', timestamp, uid); - db.sortedSetAdd('users:postcount', 0, uid); - db.sortedSetAdd('users:reputation', 0, uid); - - groups.join('registered-users', uid); - - if (userNameChanged) { - notifications.create({ - bodyShort: '[[user:username_taken_workaround, ' + userData.username + ']]', - image: 'brand:logo', - nid: 'username_taken:' + uid, - datetime: Date.now() - }, function(err, notification) { - if (!err && notification) { - notifications.push(notification, uid); - } - }); - } - - if (password) { - User.hashPassword(password, function(err, hash) { - if(err) { - return callback(err); - } - - User.setUserField(uid, 'password', hash); - callback(null, uid); - }); + if (!exists) { + next(newUsername); } else { - callback(null, uid); + next(); } }); + }, function(username) { + callback(null, username); }); }); - }; + } + }; diff --git a/src/user/notifications.js b/src/user/notifications.js index afffcb58e9..7b356b8f88 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -280,6 +280,19 @@ var async = require('async'), }); }; + UserNotifications.sendNameChangeNotification = function(uid, username) { + notifications.create({ + bodyShort: '[[user:username_taken_workaround, ' + username + ']]', + image: 'brand:logo', + nid: 'username_taken:' + uid, + datetime: Date.now() + }, function(err, notification) { + if (!err && notification) { + notifications.push(notification, uid); + } + }); + }; + UserNotifications.pushCount = function(uid) { var websockets = require('./../socket.io'); UserNotifications.getUnreadCount(uid, function(err, count) {