diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js
index 79d1482860..c90461dcb1 100644
--- a/public/src/ajaxify.js
+++ b/public/src/ajaxify.js
@@ -198,7 +198,7 @@ var ajaxify = {};
function checkCallback() {
numLocations--;
- if (numLocations <= 0 && callback) {
+ if (numLocations < 0 && callback) {
callback();
}
}
diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js
index 6084daffaf..0369452758 100644
--- a/public/src/forum/topic.js
+++ b/public/src/forum/topic.js
@@ -3,7 +3,7 @@
/* globals define, app, templates, translator, socket, bootbox, config, ajaxify, RELATIVE_PATH */
-define(['composer', 'forum/pagination', 'forum/topic/fork'], function(composer, pagination, fork) {
+define(['composer', 'forum/pagination', 'forum/topic/threadTools'], function(composer, pagination, threadTools) {
var Topic = {},
infiniteLoaderActive = false,
scrollingToPost = false,
@@ -24,8 +24,7 @@ define(['composer', 'forum/pagination', 'forum/topic/fork'], function(composer,
});
Topic.init = function() {
- var expose_tools = templates.get('expose_tools'),
- tid = templates.get('topic_id'),
+ var tid = templates.get('topic_id'),
thread_state = {
locked: templates.get('locked'),
deleted: templates.get('deleted'),
@@ -68,145 +67,12 @@ define(['composer', 'forum/pagination', 'forum/topic/fork'], function(composer,
set_pinned_state(true);
}
- if (expose_tools === '1') {
- var moveThreadModal = $('#move_thread_modal');
- $('.thread-tools').removeClass('hide');
-
- // Add events to the thread tools
- $('.delete_thread').on('click', function(e) {
- if (thread_state.deleted !== '1') {
- bootbox.confirm('Are you sure you want to delete this thread?', function(confirm) {
- if (confirm) {
- socket.emit('topics.delete', tid);
- }
- });
- } else {
- bootbox.confirm('Are you sure you want to restore this thread?', function(confirm) {
- if (confirm) {
- socket.emit('topics.restore', tid);
- }
- });
- }
- return false;
- });
-
- $('.lock_thread').on('click', function(e) {
- if (thread_state.locked !== '1') {
- socket.emit('topics.lock', tid);
- } else {
- socket.emit('topics.unlock', tid);
- }
- return false;
- });
-
- $('.pin_thread').on('click', function(e) {
- if (thread_state.pinned !== '1') {
- socket.emit('topics.pin', tid);
- } else {
- socket.emit('topics.unpin', tid);
- }
- return false;
- });
-
- $('.move_thread').on('click', function(e) {
- moveThreadModal.modal('show');
- return false;
- });
-
- $('.markAsUnreadForAll').on('click', function() {
- var btn = $(this);
- socket.emit('topics.markAsUnreadForAll', tid, function(err) {
- if(err) {
- return app.alertError(err.message);
- }
- app.alertSuccess('[[topic:markAsUnreadForAll.success]]');
- btn.parents('.thread-tools.open').find('.dropdown-toggle').trigger('click');
- });
- return false;
- });
-
- moveThreadModal.on('shown.bs.modal', function() {
-
- var loadingEl = $('#categories-loading');
- if (loadingEl.length) {
- socket.emit('categories.get', function(err, data) {
-
- // Render categories
- var categoryEl,
- numCategories = data.categories.length,
- modalBody = moveThreadModal.find('.modal-body'),
- categoriesEl = modalBody.find('ul').eq(0).addClass('categories-list'),
- confirmDiv = $('#move-confirm'),
- confirmCat = confirmDiv.find('span').eq(0),
- commitEl = $('#move_thread_commit'),
- cancelEl = $('#move_thread_cancel'),
- x, info, targetCid, targetCatLabel;
-
- for (x = 0; x < numCategories; x++) {
- info = data.categories[x];
- categoryEl = $('
');
- categoryEl.css({background: info.bgColor, color: info.color || '#fff'})
- .addClass(info.disabled === '1' ? ' disabled' : '')
- .attr('data-cid', info.cid)
- .html(' ' + info.name);
-
- categoriesEl.append(categoryEl);
- }
- loadingEl.remove();
-
- categoriesEl.on('click', 'li[data-cid]', function(e) {
- var el = $(this);
- if (el.is('li')) {
- confirmCat.html(el.html());
- confirmDiv.css({display: 'block'});
- targetCid = el.attr('data-cid');
- targetCatLabel = el.html();
- commitEl.prop('disabled', false);
- }
- });
-
- commitEl.on('click', function() {
- if (!commitEl.prop('disabled') && targetCid) {
- commitEl.prop('disabled', true);
- cancelEl.fadeOut(250);
- moveThreadModal.find('.modal-header button').fadeOut(250);
- commitEl.html('Moving ');
-
- socket.emit('topics.move', {
- tid: tid,
- cid: targetCid
- }, function(err) {
- moveThreadModal.modal('hide');
- if(err) {
- return app.alert({
- 'alert_id': 'thread_move',
- type: 'danger',
- title: 'Unable to Move Topic',
- message: 'This topic could not be moved to ' + targetCatLabel + '.
Please try again later',
- timeout: 5000
- });
- }
-
- app.alert({
- 'alert_id': 'thread_move',
- type: 'success',
- title: 'Topic Successfully Moved',
- message: 'This topic has been successfully moved to ' + targetCatLabel,
- timeout: 5000
- });
- });
- }
- });
- });
- }
- });
-
- fork.init();
+ if (templates.get('expose_tools') === '1') {
+ threadTools.init(tid, thread_state);
}
fixDeleteStateForPosts();
-
socket.emit('topics.followCheck', tid, function(err, state) {
set_follow_state(state, false);
});
@@ -860,10 +726,9 @@ define(['composer', 'forum/pagination', 'forum/topic/fork'], function(composer,
$('.lock_thread').html(translated);
});
- $('.topic-main-buttons .post_reply').attr('disabled', locked).html(locked ? 'Locked ' : 'Reply');
-
$('#post-container .post_reply').html(locked ? 'Locked ' : 'Reply ');
$('#post-container').find('.quote, .edit, .delete').toggleClass('none', locked);
+ $('.topic-main-buttons .post_reply').attr('disabled', locked).html(locked ? 'Locked ' : 'Reply');
if (alert) {
app.alert({
diff --git a/public/src/forum/topic/move.js b/public/src/forum/topic/move.js
new file mode 100644
index 0000000000..2f92d44ad9
--- /dev/null
+++ b/public/src/forum/topic/move.js
@@ -0,0 +1,100 @@
+'use strict';
+
+/* globals define, app, socket */
+
+define(function() {
+
+ var Move = {};
+
+ Move.init = function(tid) {
+ var modal = $('#move_thread_modal'),
+ targetCid,
+ targetCategoryLabel;
+
+ $('.move_thread').on('click', function(e) {
+ modal.modal('show');
+ return false;
+ });
+
+ modal.on('shown.bs.modal', onMoveModalShown);
+
+ function onMoveModalShown() {
+ var loadingEl = $('#categories-loading');
+ if (!loadingEl.length) {
+ return;
+ }
+
+ socket.emit('categories.get', onCategoriesLoaded);
+ }
+
+ function onCategoriesLoaded(err, data) {
+ if (err) {
+ return app.alertError(err.message);
+ }
+
+ renderCategories(data.categories);
+
+ modal.find('.category-list').on('click', 'li[data-cid]', function(e) {
+ selectCategory($(this));
+ });
+
+ $('#move_thread_commit').on('click', onCommitClicked);
+ }
+
+ function selectCategory(category) {
+ modal.find('#confirm-category-name').html(category.html());
+ $('#move-confirm').css({display: 'block'});
+
+ targetCid = category.attr('data-cid');
+ targetCategoryLabel = category.html();
+ $('#move_thread_commit').prop('disabled', false);
+ }
+
+ function onCommitClicked() {
+ var commitEl = $('#move_thread_commit'),
+ cancelEl = $('#move_thread_cancel');
+
+ if (!commitEl.prop('disabled') && targetCid) {
+ commitEl.prop('disabled', true);
+ cancelEl.fadeOut(250);
+ modal.find('.modal-header button').fadeOut(250);
+ commitEl.html('Moving ');
+
+ moveTopic();
+ }
+ }
+
+ function moveTopic() {
+ socket.emit('topics.move', {
+ tid: tid,
+ cid: targetCid
+ }, function(err) {
+ modal.modal('hide');
+ if(err) {
+ return app.alertError('This topic could not be moved to ' + targetCategoryLabel + '.
Please try again later');
+ }
+
+ app.alertSuccess('This topic has been successfully moved to ' + targetCategoryLabel);
+ });
+ }
+
+ function renderCategories(categories) {
+ var categoriesEl = modal.find('.category-list'),
+ info;
+
+ for (var x = 0; x < categories.length; ++x) {
+ info = categories[x];
+ $('')
+ .css({background: info.bgColor, color: info.color || '#fff'})
+ .addClass(info.disabled === '1' ? ' disabled' : '')
+ .attr('data-cid', info.cid)
+ .html(' ' + info.name)
+ .appendTo(categoriesEl);
+ }
+
+ $('#categories-loading').remove();
+ }
+ };
+
+ return Move;
+});
\ No newline at end of file
diff --git a/public/src/forum/topic/threadTools.js b/public/src/forum/topic/threadTools.js
new file mode 100644
index 0000000000..75ba2f4e0e
--- /dev/null
+++ b/public/src/forum/topic/threadTools.js
@@ -0,0 +1,53 @@
+'use strict';
+
+/* globals define, app, translator, socket, bootbox */
+
+define(['forum/topic/fork', 'forum/topic/move'], function(fork, move) {
+
+ var ThreadTools = {};
+
+ ThreadTools.init = function(tid, threadState) {
+
+ $('.thread-tools').removeClass('hide');
+
+ $('.delete_thread').on('click', function(e) {
+ var command = threadState.deleted !== '1' ? 'delete' : 'restore';
+
+ bootbox.confirm('Are you sure you want to ' + command + ' this thread?', function(confirm) {
+ if (confirm) {
+ socket.emit('topics.' + command, tid);
+ }
+ });
+ return false;
+ });
+
+ $('.lock_thread').on('click', function(e) {
+ socket.emit(threadState.locked !== '1' ? 'topics.lock' : 'topics.unlock', tid);
+ return false;
+ });
+
+ $('.pin_thread').on('click', function(e) {
+ socket.emit(threadState.pinned !== '1' ? 'topics.pin' : 'topics.unpin', tid);
+ return false;
+ });
+
+ $('.markAsUnreadForAll').on('click', function() {
+ var btn = $(this);
+ socket.emit('topics.markAsUnreadForAll', tid, function(err) {
+ if(err) {
+ return app.alertError(err.message);
+ }
+ app.alertSuccess('[[topic:markAsUnreadForAll.success]]');
+ btn.parents('.thread-tools.open').find('.dropdown-toggle').trigger('click');
+ });
+ return false;
+ });
+
+ move.init(tid);
+
+ fork.init();
+ };
+
+
+ return ThreadTools;
+});
\ No newline at end of file
diff --git a/public/src/utils.js b/public/src/utils.js
index 44d348b096..34a4224762 100644
--- a/public/src/utils.js
+++ b/public/src/utils.js
@@ -126,18 +126,17 @@
return str;
},
- // from http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
+
isEmailValid: function(email) {
- // var re = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
- return email.indexOf('@') !== -1;
+ return typeof email === 'string' && email.length && email.indexOf('@') !== -1;
},
isUserNameValid: function(name) {
- return (name && name !== "" && (/^['"\s\-.*0-9\u00BF-\u1FFF\u2C00-\uD7FF\w]+$/.test(name)));
+ return (name && name !== '' && (/^['"\s\-.*0-9\u00BF-\u1FFF\u2C00-\uD7FF\w]+$/.test(name)));
},
isPasswordValid: function(password) {
- return password && password.indexOf(' ') === -1;
+ return typeof password === 'string' && password.length && password.indexOf(' ') === -1;
},
isNumber: function(n) {
diff --git a/src/categories.js b/src/categories.js
index e75ea055af..368f293794 100644
--- a/src/categories.js
+++ b/src/categories.js
@@ -10,6 +10,7 @@ var db = require('./database'),
plugins = require('./plugins'),
CategoryTools = require('./categoryTools'),
meta = require('./meta'),
+ emitter = require('./emitter'),
async = require('async'),
winston = require('winston'),
@@ -299,19 +300,24 @@ var db = require('./database'),
});
};
- Categories.onNewPostMade = function(uid, tid, pid, timestamp) {
- topics.getTopicFields(tid, ['cid', 'pinned'], function(err, topicData) {
+ Categories.onNewPostMade = function(postData) {
+ topics.getTopicFields(postData.tid, ['cid', 'pinned'], function(err, topicData) {
+ if (err) {
+ winston.error(err.message);
+ }
var cid = topicData.cid;
- db.sortedSetAdd('categories:recent_posts:cid:' + cid, timestamp, pid);
+ db.sortedSetAdd('categories:recent_posts:cid:' + cid, postData.timestamp, postData.pid);
if(parseInt(topicData.pinned, 10) === 0) {
- db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
+ db.sortedSetAdd('categories:' + cid + ':tid', postData.timestamp, postData.tid);
}
- Categories.addActiveUser(cid, uid, timestamp);
+ Categories.addActiveUser(cid, postData.uid, postData.timestamp);
});
};
+ emitter.on('event:newpost', Categories.onNewPostMade);
+
}(exports));
\ No newline at end of file
diff --git a/src/posts.js b/src/posts.js
index dff6af855d..63572d5104 100644
--- a/src/posts.js
+++ b/src/posts.js
@@ -9,6 +9,7 @@ var db = require('./database'),
categories = require('./categories'),
plugins = require('./plugins'),
meta = require('./meta'),
+ emitter = require('./emitter'),
async = require('async'),
path = require('path'),
@@ -68,9 +69,7 @@ var db = require('./database'),
db.incrObjectField('global', 'postCount');
- topics.onNewPostMade(tid, postData.pid, timestamp);
- categories.onNewPostMade(uid, tid, postData.pid, timestamp);
- user.onNewPostMade(uid, tid, postData.pid, timestamp);
+ emitter.emit('event:newpost', postData);
plugins.fireHook('filter:post.get', postData, next);
},
diff --git a/src/topics.js b/src/topics.js
index 032e3ce440..58399d7344 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -21,7 +21,8 @@ var async = require('async'),
notifications = require('./notifications'),
favourites = require('./favourites'),
meta = require('./meta'),
- Plugins = require('./plugins');
+ Plugins = require('./plugins'),
+ emitter = require('./emitter');
(function(Topics) {
@@ -1015,12 +1016,14 @@ var async = require('async'),
Topics.setTopicField(tid, 'lastposttime', timestamp);
};
- Topics.onNewPostMade = function(tid, pid, timestamp, callback) {
- Topics.increasePostCount(tid);
- Topics.updateTimestamp(tid, timestamp);
- Topics.addPostToTopic(tid, pid, timestamp, callback);
+ Topics.onNewPostMade = function(postData) {
+ Topics.increasePostCount(postData.tid);
+ Topics.updateTimestamp(postData.tid, postData.timestamp);
+ Topics.addPostToTopic(postData.tid, postData.pid, postData.timestamp);
};
+ emitter.on('event:newpost', Topics.onNewPostMade);
+
Topics.addPostToTopic = function(tid, pid, timestamp, callback) {
db.sortedSetAdd('tid:' + tid + ':posts', timestamp, pid, callback);
};
diff --git a/src/user.js b/src/user.js
index 89e88f490b..32bba3d6ce 100644
--- a/src/user.js
+++ b/src/user.js
@@ -15,6 +15,7 @@ var bcrypt = require('bcryptjs'),
groups = require('./groups'),
topics = require('./topics'),
events = require('./events'),
+ emitter = require('./emitter'),
Emailer = require('./emailer');
(function(User) {
@@ -23,6 +24,7 @@ var bcrypt = require('bcryptjs'),
User.notifications = require('./user/notifications');
User.reset = require('./user/reset');
+ require('./user/create')(User);
require('./user/follow')(User);
require('./user/profile')(User);
require('./user/admin')(User);
@@ -30,136 +32,6 @@ var bcrypt = require('bcryptjs'),
require('./user/settings')(User);
require('./user/search')(User);
- User.create = function(userData, callback) {
- userData = userData || {};
- userData.userslug = utils.slugify(userData.username);
-
- userData.username = userData.username.trim();
- if (userData.email !== undefined) {
- userData.email = userData.email.trim();
- userData.email = validator.escape(userData.email);
- }
-
- async.parallel([
- function(next) {
- if (userData.email) {
- next(!utils.isEmailValid(userData.email) ? new Error('Invalid Email!') : null);
- } else {
- next();
- }
- },
- function(next) {
- next((!utils.isUserNameValid(userData.username) || !userData.userslug) ? new Error('Invalid Username!') : null);
- },
- function(next) {
- if (userData.password) {
- next(!utils.isPasswordValid(userData.password) ? new Error('Invalid Password!') : null);
- } else {
- next();
- }
- },
- function(next) {
- User.exists(userData.userslug, function(err, exists) {
- if (err) {
- return next(err);
- }
- next(exists ? new Error('Username taken!') : null);
- });
- },
- function(next) {
- if (userData.email) {
- User.email.available(userData.email, function(err, available) {
- if (err) {
- return next(err);
- }
- next(!available ? new Error('Email taken!') : null);
- });
- } else {
- next();
- }
- },
- function(next) {
- plugins.fireHook('filter:user.create', userData, function(err, filteredUserData){
- next(err, utils.merge(userData, filteredUserData));
- });
- }
- ], function(err, results) {
- if (err) {
- return callback(err);
- }
- userData = results[results.length - 1];
-
- db.incrObjectField('global', 'nextUid', function(err, uid) {
- if(err) {
- return callback(err);
- }
-
- var gravatar = User.createGravatarURLFromEmail(userData.email);
- var timestamp = Date.now();
- var password = userData.password;
-
- userData = {
- 'uid': uid,
- 'username': userData.username,
- 'userslug': userData.userslug,
- 'fullname': '',
- 'location': '',
- 'birthday': '',
- 'website': '',
- 'email': userData.email || '',
- 'signature': '',
- 'joindate': timestamp,
- 'picture': gravatar,
- 'gravatarpicture': gravatar,
- 'uploadedpicture': '',
- 'profileviews': 0,
- 'reputation': 0,
- 'postcount': 0,
- 'lastposttime': 0,
- 'banned': 0,
- 'status': 'online'
- };
-
- db.setObject('user:' + uid, userData, function(err) {
-
- 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, uid);
- if (parseInt(uid, 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.joinByGroupName('registered-users', uid);
-
- if (password) {
- User.hashPassword(password, function(err, hash) {
- if(err) {
- return callback(err);
- }
-
- User.setUserField(uid, 'password', hash);
- callback(null, uid);
- });
- } else {
- callback(null, uid);
- }
- });
- });
- });
- };
User.getUserField = function(uid, field, callback) {
db.getObjectField('user:' + uid, field, callback);
@@ -328,7 +200,7 @@ var bcrypt = require('bcryptjs'),
User.hashPassword = function(password, callback) {
if (!password) {
- return callback(password);
+ return callback(null, password);
}
bcrypt.genSalt(nconf.get('bcrypt_rounds'), function(err, salt) {
@@ -339,16 +211,18 @@ var bcrypt = require('bcryptjs'),
});
};
- User.onNewPostMade = function(uid, tid, pid, timestamp) {
- User.addPostIdToUser(uid, pid, timestamp);
+ User.onNewPostMade = function(postData) {
+ User.addPostIdToUser(postData.uid, postData.pid, postData.timestamp);
- User.incrementUserFieldBy(uid, 'postcount', 1, function(err, newpostcount) {
- db.sortedSetAdd('users:postcount', newpostcount, uid);
+ User.incrementUserFieldBy(postData.uid, 'postcount', 1, function(err, newpostcount) {
+ db.sortedSetAdd('users:postcount', newpostcount, postData.uid);
});
- User.setUserField(uid, 'lastposttime', timestamp);
+ User.setUserField(postData.uid, 'lastposttime', postData.timestamp);
};
+ emitter.on('event:newpost', User.onNewPostMade);
+
User.addPostIdToUser = function(uid, pid, timestamp) {
db.sortedSetAdd('uid:' + uid + ':posts', timestamp, pid);
};
diff --git a/src/user/create.js b/src/user/create.js
new file mode 100644
index 0000000000..6e39ae047a
--- /dev/null
+++ b/src/user/create.js
@@ -0,0 +1,134 @@
+'use strict';
+
+var async = require('async'),
+ db = require('./../database'),
+ utils = require('./../../public/src/utils'),
+ validator = require('validator'),
+ plugins = require('./../plugins'),
+ groups = require('./../groups');
+
+module.exports = function(User) {
+
+ User.create = function(userData, callback) {
+ userData = userData || {};
+ userData.userslug = utils.slugify(userData.username);
+
+ userData.username = userData.username.trim();
+ if (userData.email !== undefined) {
+ userData.email = userData.email.trim();
+ userData.email = validator.escape(userData.email);
+ }
+
+ async.parallel([
+ function(next) {
+ next(!utils.isEmailValid(userData.email) ? new Error('Invalid Email!') : null);
+ },
+ function(next) {
+ next((!utils.isUserNameValid(userData.username) || !userData.userslug) ? new Error('Invalid Username!') : null);
+ },
+ function(next) {
+ next(!utils.isPasswordValid(userData.password) ? new Error('Invalid Password!') : null);
+ },
+ function(next) {
+ User.exists(userData.userslug, function(err, exists) {
+ if (err) {
+ return next(err);
+ }
+ next(exists ? new Error('Username taken!') : null);
+ });
+ },
+ function(next) {
+ if (userData.email) {
+ User.email.available(userData.email, function(err, available) {
+ if (err) {
+ return next(err);
+ }
+ next(!available ? new Error('Email taken!') : null);
+ });
+ } else {
+ next();
+ }
+ },
+ function(next) {
+ plugins.fireHook('filter:user.create', userData, function(err, filteredUserData){
+ next(err, utils.merge(userData, filteredUserData));
+ });
+ }
+ ], function(err, results) {
+ if (err) {
+ return callback(err);
+ }
+ userData = results[results.length - 1];
+
+ db.incrObjectField('global', 'nextUid', function(err, uid) {
+ if(err) {
+ return callback(err);
+ }
+
+ var gravatar = User.createGravatarURLFromEmail(userData.email);
+ var timestamp = Date.now();
+ var password = userData.password;
+
+ userData = {
+ 'uid': uid,
+ 'username': userData.username,
+ 'userslug': userData.userslug,
+ 'fullname': '',
+ 'location': '',
+ 'birthday': '',
+ 'website': '',
+ 'email': userData.email || '',
+ 'signature': '',
+ 'joindate': timestamp,
+ 'picture': gravatar,
+ 'gravatarpicture': gravatar,
+ 'uploadedpicture': '',
+ 'profileviews': 0,
+ 'reputation': 0,
+ 'postcount': 0,
+ 'lastposttime': 0,
+ 'banned': 0,
+ 'status': 'online'
+ };
+
+ db.setObject('user:' + uid, userData, function(err) {
+
+ 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, uid);
+ if (parseInt(uid, 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.joinByGroupName('registered-users', uid);
+
+ if (password) {
+ User.hashPassword(password, function(err, hash) {
+ if(err) {
+ return callback(err);
+ }
+
+ User.setUserField(uid, 'password', hash);
+ callback(null, uid);
+ });
+ } else {
+ callback(null, uid);
+ }
+ });
+ });
+ });
+ };
+};
\ No newline at end of file