psychobunny 11 years ago
commit 79bacfe164

@ -29,8 +29,8 @@ define(['forum/accountheader', 'uploader'], function(header, uploader) {
return app.alertError(err.message);
}
if (!data || !data.success) {
return app.alertError('There was an error updating your profile! ' + err.message);
if (!data) {
return app.alertError('There was an error updating your profile!');
}
app.alertSuccess('Your profile has been updated successfully!');

@ -1,151 +1,162 @@
define(function() {
var Register = {};
'use strict';
Register.init = function() {
var username = $('#username'),
password = $('#password'),
password_confirm = $('#password-confirm'),
register = $('#register'),
emailEl = $('#email'),
username_notify = $('#username-notify'),
email_notify = $('#email-notify'),
password_notify = $('#password-notify'),
password_confirm_notify = $('#password-confirm-notify'),
agreeTerms = $('#agree-terms'),
validationError = false,
successIcon = '<i class="fa fa-check"></i>';
/* globals define, app, utils, socket, config */
$('#referrer').val(app.previousUrl);
function showError(element, msg) {
element.html(msg);
element.parent()
.removeClass('alert-success')
.addClass('alert-danger');
element.show();
define(function() {
var Register = {},
validationError = false,
successIcon = '<i class="fa fa-check"></i>';
function showError(element, msg) {
element.html(msg);
element.parent()
.removeClass('alert-success')
.addClass('alert-danger');
element.show();
validationError = true;
}
function showSuccess(element, msg) {
element.html(msg);
element.parent()
.removeClass('alert-danger')
.addClass('alert-success');
element.show();
}
function validateEmail(email) {
var email_notify = $('#email-notify');
if (!email) {
validationError = true;
return;
}
function showSuccess(element, msg) {
element.html(msg);
element.parent()
.removeClass('alert-danger')
.addClass('alert-success');
element.show();
if (!utils.isEmailValid(email)) {
showError(email_notify, 'Invalid email address.');
return;
}
function validateEmail() {
if (!emailEl.val()) {
validationError = true;
return;
socket.emit('user.emailExists', {
email: email
}, function(err, exists) {
if(err) {
return app.alertError(err.message);
}
if (!utils.isEmailValid(emailEl.val())) {
showError(email_notify, 'Invalid email address.');
if (exists) {
showError(email_notify, 'Email address already taken!');
} else {
socket.emit('user.emailExists', {
email: emailEl.val()
}, function(err, exists) {
if(err) {
return app.alertError(err.message);
}
if (exists) {
showError(email_notify, 'Email address already taken!');
} else {
showSuccess(email_notify, successIcon);
}
});
showSuccess(email_notify, successIcon);
}
}
emailEl.on('blur', function() {
validateEmail();
});
}
function validateUsername() {
if (!username.val()) {
validationError = true;
return;
}
function validateUsername(username) {
var username_notify = $('#username-notify');
if (username.val().length < config.minimumUsernameLength) {
showError(username_notify, 'Username too short!');
} else if (username.val().length > config.maximumUsernameLength) {
showError(username_notify, 'Username too long!');
} else if (!utils.isUserNameValid(username.val()) || !utils.slugify(username.val())) {
showError(username_notify, 'Invalid username!');
} else {
socket.emit('user.exists', {
username: username.val()
}, function(err, exists) {
if(err) {
return app.alertError(err.message);
}
if (exists) {
showError(username_notify, 'Username already taken!');
} else {
showSuccess(username_notify, successIcon);
}
});
}
if (!username) {
validationError = true;
return;
}
username.on('keyup', function() {
$('#yourUsername').html(this.value.length > 0 ? this.value : 'username');
});
if (username.length < config.minimumUsernameLength) {
showError(username_notify, 'Username too short!');
} else if (username.length > config.maximumUsernameLength) {
showError(username_notify, 'Username too long!');
} else if (!utils.isUserNameValid(username) || !utils.slugify(username)) {
showError(username_notify, 'Invalid username!');
} else {
socket.emit('user.exists', {
username: username
}, function(err, exists) {
if(err) {
return app.alertError(err.message);
}
username.on('blur', function() {
validateUsername();
});
if (exists) {
showError(username_notify, 'Username already taken!');
} else {
showSuccess(username_notify, successIcon);
}
});
}
}
function validatePassword() {
if (!password.val()) {
validationError = true;
return;
}
function validatePassword(password, password_confirm) {
if (!password) {
validationError = true;
return;
}
var password_notify = $('#password-notify'),
password_confirm_notify = $('#password-confirm-notify');
if (password.length < config.minimumPasswordLength) {
showError(password_notify, 'Password too short!');
} else if (!utils.isPasswordValid(password)) {
showError(password_notify, 'Invalid password!');
} else {
showSuccess(password_notify, successIcon);
}
if (password.val().length < config.minimumPasswordLength) {
showError(password_notify, 'Password too short!');
} else if (!utils.isPasswordValid(password.val())) {
showError(password_notify, 'Invalid password!');
} else {
showSuccess(password_notify, successIcon);
}
if (password !== password_confirm && password_confirm !== '') {
showError(password_confirm_notify, 'Passwords must match!');
}
}
if (password.val() !== password_confirm.val() && password_confirm.val() !== '') {
showError(password_confirm_notify, 'Passwords must match!');
}
function validatePasswordConfirm(password, password_confirm) {
var password_notify = $('#password-notify'),
password_confirm_notify = $('#password-confirm-notify');
if (!password || password_notify.hasClass('alert-error')) {
return;
}
$(password).on('blur', function() {
validatePassword();
if (password !== password_confirm) {
showError(password_confirm_notify, 'Passwords must match!');
} else {
showSuccess(password_confirm_notify, successIcon);
}
}
Register.init = function() {
var email = $('#email'),
username = $('#username'),
password = $('#password'),
password_confirm = $('#password-confirm'),
register = $('#register'),
agreeTerms = $('#agree-terms');
$('#referrer').val(app.previousUrl);
email.on('blur', function() {
validateEmail(email.val());
});
function validatePasswordConfirm() {
if (!password.val() || password_notify.hasClass('alert-error')) {
return;
}
username.on('keyup', function() {
$('#yourUsername').html(this.value.length > 0 ? this.value : 'username');
});
if (password.val() !== password_confirm.val()) {
showError(password_confirm_notify, 'Passwords must match!');
} else {
showSuccess(password_confirm_notify, successIcon);
}
}
username.on('blur', function() {
validateUsername(username.val());
});
password.on('blur', function() {
validatePassword(password.val(), password_confirm.val());
});
$(password_confirm).on('blur', function() {
validatePasswordConfirm();
password_confirm.on('blur', function() {
validatePasswordConfirm(password.val(), password_confirm.val());
});
function validateForm() {
validationError = false;
validateEmail();
validateUsername();
validatePassword();
validatePasswordConfirm();
validateEmail(email.val());
validateUsername(username.val());
validatePassword(password.val(), password_confirm.val());
validatePasswordConfirm(password.val(), password_confirm.val());
return validationError;
}

@ -110,7 +110,6 @@ define(['taskbar'], function(taskbar) {
}
function removeDraft(save_id) {
console.log('removing draft');
return localStorage.removeItem(save_id);
}
@ -273,6 +272,10 @@ define(['taskbar'], function(taskbar) {
});
}
function escapeRegExp(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};
function uploadContentFiles(params) {
var files = params.files,
post_uuid = params.post_uuid,
@ -299,10 +302,15 @@ define(['taskbar'], function(taskbar) {
textarea.val(text);
uploadForm.off('submit').submit(function() {
function updateTextArea(filename, text) {
var current = textarea.val();
var re = new RegExp(escapeRegExp(filename) + "]\\([^)]+\\)", 'g');
textarea.val(current.replace(re, filename + '](' + text + ')'));
}
$(this).find('#postUploadCsrf').val($('#csrf_token').val());
if(formData) {
if (formData) {
formData.append('_csrf', $('#csrf_token').val());
}
@ -317,15 +325,14 @@ define(['taskbar'], function(taskbar) {
xhr = maybeParse(xhr);
app.alertError('Error uploading file!\nStatus : ' + xhr.status + '\nMessage : ' + xhr.responseText);
if (typeof callback == 'function')
if (typeof callback === 'function') {
callback(xhr);
}
},
uploadProgress: function(event, position, total, percent) {
var current = textarea.val();
for(var i=0; i < files.length; ++i) {
var re = new RegExp(files[i].name + "]\\([^)]+\\)", 'g');
textarea.val(current.replace(re, files[i].name+'](uploading ' + percent + '%)'));
updateTextArea(files[i].name, 'uploading' + percent + '%');
}
},
@ -334,15 +341,14 @@ define(['taskbar'], function(taskbar) {
if(uploads && uploads.length) {
for(var i=0; i<uploads.length; ++i) {
var current = textarea.val();
var re = new RegExp(uploads[i].name + "]\\([^)]+\\)", 'g');
textarea.val(current.replace(re, uploads[i].name + '](' + uploads[i].url + ')'));
updateTextArea(uploads[i].name, uploads[i].url);
}
}
textarea.focus();
if (typeof callback == 'function')
if (typeof callback === 'function') {
callback(null, uploads);
}
},
complete: function() {

@ -17,6 +17,9 @@ var db = require('./database'),
(function(Categories) {
require('./categories/activeusers')(Categories);
require('./categories/recentreplies')(Categories);
Categories.create = function(data, callback) {
db.incrObjectField('global', 'nextCid', function(err, cid) {
if (err) {
@ -56,33 +59,38 @@ var db = require('./database'),
};
Categories.getCategoryById = function(cid, start, end, uid, callback) {
if(parseInt(uid, 10)) {
Categories.markAsRead(cid, uid);
}
async.parallel({
category: function(next) {
Categories.getCategoryData(cid, next);
},
topics: function(next) {
Categories.getCategoryTopics(cid, start, end, uid, next);
},
pageCount: function(next) {
Categories.getPageCount(cid, uid, next);
CategoryTools.exists(cid, function(err, exists) {
if(err || !exists) {
return callback(err || new Error('category-not-found [' + cid + ']'));
}
}, function(err, results) {
if(err) {
return callback(err);
if(parseInt(uid, 10)) {
Categories.markAsRead(cid, uid);
}
var category = results.category;
category.topics = results.topics.topics;
category.nextStart = results.topics.nextStart;
category.pageCount = results.pageCount;
category.topic_row_size = 'col-md-9';
async.parallel({
category: function(next) {
Categories.getCategoryData(cid, next);
},
topics: function(next) {
Categories.getCategoryTopics(cid, start, end, uid, next);
},
pageCount: function(next) {
Categories.getPageCount(cid, uid, next);
}
}, function(err, results) {
if(err) {
return callback(err);
}
var category = results.category;
category.topics = results.topics.topics;
category.nextStart = results.topics.nextStart;
category.pageCount = results.pageCount;
category.topic_row_size = 'col-md-9';
callback(null, category);
callback(null, category);
});
});
};
@ -220,56 +228,6 @@ var db = require('./database'),
db.isSetMember('cid:' + cid + ':read_by_uid', uid, callback);
};
Categories.getRecentReplies = function(cid, uid, count, callback) {
if(count === 0 || !count) {
return callback(null, []);
}
CategoryTools.privileges(cid, uid, function(err, privileges) {
if(err) {
return callback(err);
}
if (!privileges.read) {
return callback(null, []);
}
db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, count - 1, function(err, pids) {
if (err) {
return callback(err, []);
}
if (!pids || !pids.length) {
return callback(null, []);
}
posts.getPostSummaryByPids(pids, true, callback);
});
});
};
Categories.moveRecentReplies = function(tid, oldCid, cid, callback) {
function movePost(pid, callback) {
posts.getPostField(pid, 'timestamp', function(err, timestamp) {
if(err) {
return callback(err);
}
db.sortedSetRemove('categories:recent_posts:cid:' + oldCid, pid);
db.sortedSetAdd('categories:recent_posts:cid:' + cid, timestamp, pid);
callback();
});
}
topics.getPids(tid, function(err, pids) {
if(err) {
return callback(err);
}
async.each(pids, movePost, callback);
});
};
Categories.getCategoryData = function(cid, callback) {
Categories.getCategoriesData([cid], function(err, categories) {
callback(err, categories ? categories[0] : null);
@ -345,79 +303,6 @@ var db = require('./database'),
});
};
Categories.isUserActiveIn = function(cid, uid, callback) {
db.getSortedSetRange('uid:' + uid + ':posts', 0, -1, function(err, pids) {
if (err) {
return callback(err);
}
var index = 0,
active = false;
async.whilst(
function() {
return active === false && index < pids.length;
},
function(callback) {
posts.getCidByPid(pids[index], function(err, postCid) {
if (err) {
return callback(err);
}
if (postCid === cid) {
active = true;
}
++index;
callback();
});
},
function(err) {
callback(err, active);
}
);
});
};
Categories.addActiveUser = function(cid, uid, timestamp) {
if(parseInt(uid, 10)) {
db.sortedSetAdd('cid:' + cid + ':active_users', timestamp, uid);
}
};
Categories.removeActiveUser = function(cid, uid) {
db.sortedSetRemove('cid:' + cid + ':active_users', uid);
};
Categories.getActiveUsers = function(cid, callback) {
db.getSortedSetRevRange('cid:' + cid + ':active_users', 0, 23, callback);
};
Categories.moveActiveUsers = function(tid, oldCid, cid, callback) {
function updateUser(uid, timestamp) {
Categories.addActiveUser(cid, uid, timestamp);
Categories.isUserActiveIn(oldCid, uid, function(err, active) {
if (!err && !active) {
Categories.removeActiveUser(oldCid, uid);
}
});
}
topics.getTopicField(tid, 'timestamp', function(err, timestamp) {
if(!err) {
topics.getUids(tid, function(err, uids) {
if (!err && uids) {
for (var i = 0; i < uids.length; ++i) {
updateUser(uids[i], timestamp);
}
}
});
}
});
};
Categories.onNewPostMade = function(uid, tid, pid, timestamp) {
topics.getTopicFields(tid, ['cid', 'pinned'], function(err, topicData) {

@ -0,0 +1,83 @@
'use strict';
var async = require('async'),
db = require('./../database'),
posts = require('./../posts'),
topics = require('./../topics');
module.exports = function(Categories) {
Categories.isUserActiveIn = function(cid, uid, callback) {
db.getSortedSetRange('uid:' + uid + ':posts', 0, -1, function(err, pids) {
if (err) {
return callback(err);
}
var index = 0,
active = false;
async.whilst(
function() {
return active === false && index < pids.length;
},
function(callback) {
posts.getCidByPid(pids[index], function(err, postCid) {
if (err) {
return callback(err);
}
if (postCid === cid) {
active = true;
}
++index;
callback();
});
},
function(err) {
callback(err, active);
}
);
});
};
Categories.addActiveUser = function(cid, uid, timestamp) {
if(parseInt(uid, 10)) {
db.sortedSetAdd('cid:' + cid + ':active_users', timestamp, uid);
}
};
Categories.removeActiveUser = function(cid, uid) {
db.sortedSetRemove('cid:' + cid + ':active_users', uid);
};
Categories.getActiveUsers = function(cid, callback) {
db.getSortedSetRevRange('cid:' + cid + ':active_users', 0, 23, callback);
};
Categories.moveActiveUsers = function(tid, oldCid, cid, callback) {
function updateUser(uid, timestamp) {
Categories.addActiveUser(cid, uid, timestamp);
Categories.isUserActiveIn(oldCid, uid, function(err, active) {
if (!err && !active) {
Categories.removeActiveUser(oldCid, uid);
}
});
}
topics.getTopicField(tid, 'timestamp', function(err, timestamp) {
if(!err) {
topics.getUids(tid, function(err, uids) {
if (!err && uids) {
for (var i = 0; i < uids.length; ++i) {
updateUser(uids[i], timestamp);
}
}
});
}
});
};
};

@ -0,0 +1,62 @@
'use strict';
var async = require('async'),
db = require('./../database'),
posts = require('./../posts'),
topics = require('./../topics'),
CategoryTools = require('./../categoryTools');
module.exports = function(Categories) {
Categories.getRecentReplies = function(cid, uid, count, callback) {
if(count === 0 || !count) {
return callback(null, []);
}
CategoryTools.privileges(cid, uid, function(err, privileges) {
if(err) {
return callback(err);
}
if (!privileges.read) {
return callback(null, []);
}
db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, count - 1, function(err, pids) {
if (err) {
return callback(err, []);
}
if (!pids || !pids.length) {
return callback(null, []);
}
posts.getPostSummaryByPids(pids, true, callback);
});
});
};
Categories.moveRecentReplies = function(tid, oldCid, cid, callback) {
function movePost(pid, callback) {
posts.getPostField(pid, 'timestamp', function(err, timestamp) {
if(err) {
return callback(err);
}
db.sortedSetRemove('categories:recent_posts:cid:' + oldCid, pid);
db.sortedSetAdd('categories:recent_posts:cid:' + cid, timestamp, pid);
callback();
});
}
topics.getPids(tid, function(err, pids) {
if(err) {
return callback(err);
}
async.each(pids, movePost, callback);
});
};
};

@ -89,6 +89,10 @@ categoriesController.get = function(req, res, next) {
end = start + settings.topicsPerPage - 1;
categories.getCategoryById(cid, start, end, uid, function (err, categoryData) {
if (err) {
return next(err);
}
if (categoryData) {
if (parseInt(categoryData.disabled, 10) === 1) {
return next(new Error('Category disabled'), null);

@ -83,7 +83,7 @@ function uploadImage(image, callback) {
} else {
if (meta.config.allowFileUploads) {
Posts.uploadPostFile(image, callback);
uploadFile(image, callback);
} else {
callback(new Error('Uploads are disabled!'));
}
@ -109,7 +109,7 @@ function uploadFile(file, callback) {
}
var filename = 'upload-' + utils.generateUUID() + path.extname(file.name);
require('./file').saveFileToLocal(filename, file.path, function(err, upload) {
require('../file').saveFileToLocal(filename, file.path, function(err, upload) {
if(err) {
return callback(err);
}

@ -186,10 +186,8 @@ Sockets.logoutUser = function(uid) {
};
Sockets.emitUserCount = function() {
db.getObjectField('global', 'userCount', function(err, count) {
io.sockets.emit('user.count', err?{message:err.message}:null, {
count: count
});
user.count(function(err, count) {
io.sockets.emit('user.count', err ? {message:err.message} : null, count);
});
};

@ -1,3 +1,5 @@
'use strict';
var async = require('async'),
user = require('../user'),
topics = require('../topics'),
@ -93,8 +95,9 @@ SocketUser.updateProfile = function(socket, data, callback) {
if(err) {
return callback(err);
}
if(!isAdmin) {
return callback(new Error('not allowed!'))
return callback(new Error('not allowed!'));
}
user.updateProfile(data.uid, data, callback);

@ -19,9 +19,15 @@ var bcrypt = require('bcryptjs'),
(function(User) {
User.email = require('./useremail');
User.notifications = require('./usernotifications');
User.reset = require('./userreset');
User.email = require('./user/email');
User.notifications = require('./user/notifications');
User.reset = require('./user/reset');
require('./user/follow')(User);
require('./user/profile')(User);
require('./user/admin')(User);
require('./user/settings')(User);
require('./user/search')(User);
User.create = function(userData, callback) {
userData = userData || {};
@ -154,14 +160,6 @@ var bcrypt = require('bcryptjs'),
});
};
User.ban = function(uid, callback) {
User.setUserField(uid, 'banned', 1, callback);
};
User.unban = function(uid, callback) {
User.setUserField(uid, 'banned', 0, callback);
};
User.getUserField = function(uid, field, callback) {
db.getObjectField('user:' + uid, field, callback);
};
@ -224,52 +222,6 @@ var bcrypt = require('bcryptjs'),
});
};
User.getSettings = function(uid, callback) {
function sendDefaultSettings() {
callback(null, {
showemail: false,
usePagination: parseInt(meta.config.usePagination, 10) === 1,
topicsPerPage: parseInt(meta.config.topicsPerPage, 10) || 20,
postsPerPage: parseInt(meta.config.postsPerPage, 10) || 10
});
}
if(!parseInt(uid, 10)) {
return sendDefaultSettings();
}
db.getObject('user:' + uid + ':settings', function(err, settings) {
if(err) {
return callback(err);
}
if(!settings) {
settings = {};
}
settings.showemail = settings.showemail ? parseInt(settings.showemail, 10) !== 0 : false;
settings.usePagination = settings.usePagination ? parseInt(settings.usePagination, 10) === 1 : parseInt(meta.config.usePagination, 10) === 1;
settings.topicsPerPage = settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : parseInt(meta.config.topicsPerPage, 10) || 20;
settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10;
callback(null, settings);
});
};
User.saveSettings = function(uid, data, callback) {
if(!data.topicsPerPage || !data.postsPerPage || parseInt(data.topicsPerPage, 10) <= 0 || parseInt(data.postsPerPage, 10) <= 0) {
return callback(new Error('Invalid pagination value!'));
}
db.setObject('user:' + uid + ':settings', {
showemail: data.showemail,
usePagination: data.usePagination,
topicsPerPage: data.topicsPerPage,
postsPerPage: data.postsPerPage
}, callback);
};
User.updateLastOnlineTime = function(uid, callback) {
User.getUserField(uid, 'status', function(err, status) {
function cb(err) {
@ -286,157 +238,6 @@ var bcrypt = require('bcryptjs'),
});
};
User.updateProfile = function(uid, data, callback) {
var fields = ['username', 'email', 'fullname', 'website', 'location', 'birthday', 'signature'];
var returnData = {
success: false
};
function isSignatureValid(next) {
if (data.signature !== undefined && data.signature.length > meta.config.maximumSignatureLength) {
next(new Error('Signature can\'t be longer than ' + meta.config.maximumSignatureLength + ' characters!'), false);
} else {
next(null, true);
}
}
function isEmailAvailable(next) {
if (!data.email) {
return next(null, true);
}
User.getUserField(uid, 'email', function(err, email) {
if(email === data.email) {
return next(null, true);
}
User.email.available(data.email, function(err, available) {
if (err) {
return next(err, null);
}
if (!available) {
next(new Error('Email not available!'), false);
} else {
next(null, true);
}
});
});
}
function isUsernameAvailable(next) {
User.getUserFields(uid, ['username', 'userslug'], function(err, userData) {
var userslug = utils.slugify(data.username);
if(userslug === userData.userslug) {
return next(null, true);
}
if(!utils.isUserNameValid(data.username) || !userslug) {
return next(new Error('Invalid Username!'), false);
}
User.exists(userslug, function(err, exists) {
if(err) {
return next(err);
}
if(exists) {
next(new Error('Username not available!'), false);
} else {
next(null, true);
}
});
});
}
async.series([isSignatureValid, isEmailAvailable, isUsernameAvailable], function(err, results) {
if (err) {
return callback(err, returnData);
}
async.each(fields, updateField, function(err) {
if (err) {
return callback(err, returnData);
}
returnData.success = true;
callback(null, returnData);
});
});
function updateField(field, next) {
if (!(data[field] !== undefined && typeof data[field] === 'string')) {
return next();
}
data[field] = data[field].trim();
data[field] = validator.escape(data[field]);
if (field === 'email') {
User.getUserFields(uid, ['email', 'picture', 'uploadedpicture'], function(err, userData) {
if (err) {
return next(err);
}
if(userData.email === data.email) {
return next();
}
var gravatarpicture = User.createGravatarURLFromEmail(data.email);
User.setUserField(uid, 'gravatarpicture', gravatarpicture);
db.deleteObjectField('email:uid', userData.email);
db.setObjectField('email:uid', data.email, uid);
User.setUserField(uid, 'email', data.email);
if (userData.picture !== userData.uploadedpicture) {
returnData.picture = gravatarpicture;
User.setUserField(uid, 'picture', gravatarpicture);
}
returnData.gravatarpicture = gravatarpicture;
events.logEmailChange(uid, userData.email, data.email);
next();
});
return;
} else if (field === 'username') {
User.getUserFields(uid, ['username', 'userslug'], function(err, userData) {
var userslug = utils.slugify(data.username);
if(data.username !== userData.username) {
User.setUserField(uid, 'username', data.username);
db.deleteObjectField('username:uid', userData.username);
db.setObjectField('username:uid', data.username, uid);
events.logUsernameChange(uid, userData.username, data.username);
}
if(userslug !== userData.userslug) {
User.setUserField(uid, 'userslug', userslug);
db.deleteObjectField('userslug:uid', userData.userslug);
db.setObjectField('userslug:uid', userslug, uid);
returnData.userslug = userslug;
}
next();
});
return;
} else if (field === 'signature') {
data[field] = S(data[field]).stripTags().s;
} else if (field === 'website') {
if(data[field].substr(0, 7) !== 'http://' && data[field].substr(0, 8) !== 'https://') {
data[field] = 'http://' + data[field];
}
}
User.setUserField(uid, field, data[field]);
next();
}
};
User.isReadyToPost = function(uid, callback) {
User.getUserField(uid, 'lastposttime', function(err, lastposttime) {
if(err) {
@ -454,67 +255,6 @@ var bcrypt = require('bcryptjs'),
});
};
User.changePassword = function(uid, data, callback) {
if(!data || !data.uid) {
return callback(new Error('invalid-uid'));
}
function hashAndSetPassword(callback) {
User.hashPassword(data.newPassword, function(err, hash) {
if(err) {
return callback(err);
}
User.setUserField(data.uid, 'password', hash, function(err) {
if(err) {
return callback(err);
}
if(parseInt(uid, 10) === parseInt(data.uid, 10)) {
events.logPasswordChange(data.uid);
} else {
events.logAdminChangeUserPassword(uid, data.uid);
}
callback();
});
});
}
if (!utils.isPasswordValid(data.newPassword)) {
return callback(new Error('Invalid password!'));
}
if(parseInt(uid, 10) !== parseInt(data.uid, 10)) {
User.isAdministrator(uid, function(err, isAdmin) {
if(err || !isAdmin) {
return callback(err || new Error('not-allowed'));
}
hashAndSetPassword(callback);
});
} else {
User.getUserField(uid, 'password', function(err, currentPassword) {
if(err) {
return callback(err);
}
if (currentPassword !== null) {
bcrypt.compare(data.currentPassword, currentPassword, function(err, res) {
if (err || !res) {
return callback(err || new Error('Your current password is not correct!'));
}
hashAndSetPassword(callback);
});
} else {
// No password in account (probably SSO login)
hashAndSetPassword(callback);
}
});
}
};
User.setUserField = function(uid, field, value, callback) {
db.setObjectField('user:' + uid, field, value, callback);
};
@ -532,52 +272,43 @@ var bcrypt = require('bcryptjs'),
};
User.getUsers = function(set, start, stop, callback) {
db.getSortedSetRevRange(set, start, stop, function(err, uids) {
if (err) {
return callback(err);
function loadUserInfo(user, callback) {
if (!user) {
return callback(null, user);
}
User.getUsersData(uids, function(err, users) {
if (err) {
return callback(err);
}
async.map(users, function(user, next) {
if (!user) {
return next(null, user);
async.waterfall([
function(next) {
User.isAdministrator(user.uid, next);
},
function(isAdmin, next) {
user.status = !user.status ? 'online' : '';
user.administrator = isAdmin ? '1':'0';
if (set === 'users:online') {
return callback(null, user);
}
if (!user.status) {
user.status = 'online';
db.sortedSetScore('users:online', user.uid, next);
},
function(score, next) {
if (!score) {
user.status = 'offline';
}
next(null, user);
}
], callback);
}
User.isAdministrator(user.uid, function(err, isAdmin) {
if (err) {
return next(err);
}
user.administrator = isAdmin ? '1':'0';
if(set === 'users:online') {
return next(null, user);
}
db.sortedSetScore('users:online', user.uid, function(err, score) {
if (err) {
return next(err);
}
if(!score) {
user.status = 'offline';
}
next(null, user);
});
});
}, callback);
});
});
async.waterfall([
function(next) {
db.getSortedSetRevRange(set, start, stop, next);
},
function(uids, next) {
User.getUsersData(uids, next);
},
function(users, next) {
async.map(users, loadUserInfo, next);
}
], callback);
};
User.createGravatarURLFromEmail = function(email) {
@ -597,74 +328,14 @@ var bcrypt = require('bcryptjs'),
User.hashPassword = function(password, callback) {
if (!password) {
callback(password);
return;
return callback(password);
}
bcrypt.genSalt(nconf.get('bcrypt_rounds'), function(err, salt) {
bcrypt.hash(password, salt, callback);
});
};
User.getUsersCSV = function(callback) {
var csvContent = '';
db.getObjectValues('username:uid', function(err, uids) {
if (err) {
return callback(err);
}
User.getMultipleUserFields(uids, ['email', 'username'], function(err, usersData) {
if (err) {
return callback(err);
}
usersData.forEach(function(user, index) {
if (user) {
csvContent += user.email + ',' + user.username + ',' + uids[index] + '\n';
}
});
callback(null, csvContent);
});
});
};
User.search = function(query, callback) {
if (!query || query.length === 0) {
return callback(null, {timing:0, users:[]});
}
var start = process.hrtime();
db.getObject('username:uid', function(err, usernamesHash) {
if (err) {
return callback(null, {timing: 0, users:[]});
}
query = query.toLowerCase();
var usernames = Object.keys(usernamesHash),
uids = [];
uids = usernames.filter(function(username) {
return username.toLowerCase().indexOf(query) === 0;
})
.slice(0, 10)
.sort(function(a, b) {
return a > b;
})
.map(function(username) {
return usernamesHash[username];
});
User.getUsersData(uids, function(err, userdata) {
if (err) {
return callback(err);
}
var diff = process.hrtime(start);
var timing = (diff[0] * 1e3 + diff[1] / 1e6).toFixed(1);
callback(null, {timing: timing, users: userdata});
});
bcrypt.hash(password, salt, callback);
});
};
@ -688,78 +359,8 @@ var bcrypt = require('bcryptjs'),
User.getPostIds = function(uid, start, stop, callback) {
db.getSortedSetRevRange('uid:' + uid + ':posts', start, stop, function(err, pids) {
if(err) {
return callback(err);
}
if (pids && pids.length) {
callback(null, pids);
} else {
callback(null, []);
}
});
};
User.follow = function(uid, followuid, callback) {
toggleFollow('follow', uid, followuid, callback);
};
User.unfollow = function(uid, unfollowuid, callback) {
toggleFollow('unfollow', uid, unfollowuid, callback);
};
function toggleFollow(type, uid, theiruid, callback) {
var command = type === 'follow' ? 'setAdd' : 'setRemove';
db[command]('following:' + uid, theiruid, function(err) {
if(err) {
return callback(err);
}
db[command]('followers:' + theiruid, uid, callback);
});
}
User.getFollowing = function(uid, callback) {
getFollow('following:' + uid, callback);
};
User.getFollowers = function(uid, callback) {
getFollow('followers:' + uid, callback);
};
function getFollow(set, callback) {
db.getSetMembers(set, function(err, uids) {
if(err) {
return callback(err);
}
User.getUsersData(uids, callback);
callback(err, Array.isArray(pids) ? pids : []);
});
}
User.getFollowingCount = function(uid, callback) {
db.setCount('following:' + uid, callback);
};
User.getFollowerCount = function(uid, callback) {
db.setCount('followers:' + uid, callback);
};
User.getFollowStats = function (uid, callback) {
async.parallel({
followingCount: function(next) {
User.getFollowingCount(uid, next);
},
followerCount : function(next) {
User.getFollowerCount(uid, next);
}
}, callback);
};
User.isFollowing = function(uid, theirid, callback) {
db.isSetMember('following:' + uid, theirid, callback);
};
User.exists = function(userslug, callback) {
@ -770,13 +371,7 @@ var bcrypt = require('bcryptjs'),
User.count = function(callback) {
db.getObjectField('global', 'userCount', function(err, count) {
if(err) {
return callback(err);
}
callback(null, {
count: count ? count : 0
});
callback(err, count ? count : 0);
});
};
@ -825,21 +420,5 @@ var bcrypt = require('bcryptjs'),
groups.isMemberByGroupName(uid, 'administrators', callback);
};
User.logIP = function(uid, ip) {
db.sortedSetAdd('uid:' + uid + ':ip', +new Date(), ip || 'Unknown');
};
User.getIPs = function(uid, end, callback) {
db.getSortedSetRevRange('uid:' + uid + ':ip', 0, end, function(err, ips) {
if(err) {
return callback(err);
}
callback(null, ips.map(function(ip) {
return {ip:ip};
}));
});
};
}(exports));

@ -0,0 +1,54 @@
'use strict';
var async = require('async'),
db = require('./../database');
module.exports = function(User) {
User.logIP = function(uid, ip) {
db.sortedSetAdd('uid:' + uid + ':ip', Date.now(), ip || 'Unknown');
};
User.getIPs = function(uid, end, callback) {
db.getSortedSetRevRange('uid:' + uid + ':ip', 0, end, function(err, ips) {
if(err) {
return callback(err);
}
callback(null, ips.map(function(ip) {
return {ip:ip};
}));
});
};
User.getUsersCSV = function(callback) {
var csvContent = '';
async.waterfall([
function(next) {
db.getObjectValues('username:uid', next);
},
function(uids, next) {
User.getMultipleUserFields(uids, ['uid', 'email', 'username'], next);
},
function(usersData, next) {
usersData.forEach(function(user, index) {
if (user) {
csvContent += user.email + ',' + user.username + ',' + user.uid + '\n';
}
});
next(null, csvContent);
}
], callback);
};
User.ban = function(uid, callback) {
User.setUserField(uid, 'banned', 1, callback);
};
User.unban = function(uid, callback) {
User.setUserField(uid, 'banned', 0, callback);
};
};

@ -5,12 +5,12 @@ var async = require('async'),
nconf = require('nconf'),
winston = require('winston'),
user = require('./user'),
utils = require('./../public/src/utils'),
plugins = require('./plugins'),
db = require('./database'),
meta = require('./meta'),
emailer = require('./emailer');
user = require('./../user'),
utils = require('./../../public/src/utils'),
plugins = require('./../plugins'),
db = require('./../database'),
meta = require('./../meta'),
emailer = require('./../emailer');
(function(UserEmail) {

@ -0,0 +1,68 @@
'use strict';
var async = require('async'),
db = require('./../database');
module.exports = function(User) {
User.follow = function(uid, followuid, callback) {
toggleFollow('follow', uid, followuid, callback);
};
User.unfollow = function(uid, unfollowuid, callback) {
toggleFollow('unfollow', uid, unfollowuid, callback);
};
function toggleFollow(type, uid, theiruid, callback) {
var command = type === 'follow' ? 'setAdd' : 'setRemove';
db[command]('following:' + uid, theiruid, function(err) {
if(err) {
return callback(err);
}
db[command]('followers:' + theiruid, uid, callback);
});
}
User.getFollowing = function(uid, callback) {
getFollow('following:' + uid, callback);
};
User.getFollowers = function(uid, callback) {
getFollow('followers:' + uid, callback);
};
function getFollow(set, callback) {
db.getSetMembers(set, function(err, uids) {
if(err) {
return callback(err);
}
User.getUsersData(uids, callback);
});
}
User.getFollowingCount = function(uid, callback) {
db.setCount('following:' + uid, callback);
};
User.getFollowerCount = function(uid, callback) {
db.setCount('followers:' + uid, callback);
};
User.getFollowStats = function (uid, callback) {
async.parallel({
followingCount: function(next) {
User.getFollowingCount(uid, next);
},
followerCount : function(next) {
User.getFollowerCount(uid, next);
}
}, callback);
};
User.isFollowing = function(uid, theirid, callback) {
db.isSetMember('following:' + uid, theirid, callback);
};
};

@ -5,12 +5,11 @@ var async = require('async'),
nconf = require('nconf'),
winston = require('winston'),
user = require('./user'),
utils = require('./../public/src/utils'),
db = require('./database'),
notifications = require('./notifications'),
topics = require('./topics'),
websockets = require('./socket.io');
user = require('./../user'),
utils = require('./../../public/src/utils'),
db = require('./../database'),
notifications = require('./../notifications'),
topics = require('./../topics');
(function(UserNotifications) {
@ -161,7 +160,7 @@ var async = require('async'),
};
UserNotifications.pushCount = function(uid) {
var websockets = require('./../socket.io');
UserNotifications.getUnreadCount(uid, function(err, count) {
if (err) {
return winston.warn('[User.pushNotifCount] Count not retrieve unread notifications count to push to uid ' + uid + '\'s client(s)');

@ -0,0 +1,256 @@
'use strict';
var bcrypt = require('bcryptjs'),
async = require('async'),
validator = require('validator'),
S = require('string'),
utils = require('./../../public/src/utils'),
meta = require('./../meta'),
events = require('./../events'),
db = require('./../database');
module.exports = function(User) {
User.updateProfile = function(uid, data, callback) {
var fields = ['username', 'email', 'fullname', 'website', 'location', 'birthday', 'signature'];
function isSignatureValid(next) {
if (data.signature !== undefined && data.signature.length > meta.config.maximumSignatureLength) {
next(new Error('Signature can\'t be longer than ' + meta.config.maximumSignatureLength + ' characters!'));
} else {
next();
}
}
function isEmailAvailable(next) {
if (!data.email) {
return next();
}
User.getUserField(uid, 'email', function(err, email) {
if(email === data.email) {
return next();
}
User.email.available(data.email, function(err, available) {
if (err) {
return next(err);
}
next(!available ? new Error('Email not available!') : null);
});
});
}
function isUsernameAvailable(next) {
User.getUserFields(uid, ['username', 'userslug'], function(err, userData) {
var userslug = utils.slugify(data.username);
if(userslug === userData.userslug) {
return next();
}
if(!utils.isUserNameValid(data.username) || !userslug) {
return next(new Error('Invalid Username!'));
}
User.exists(userslug, function(err, exists) {
if(err) {
return next(err);
}
next(exists ? new Error('Username not available!') : null);
});
});
}
async.series([isSignatureValid, isEmailAvailable, isUsernameAvailable], function(err, results) {
if (err) {
return callback(err);
}
async.each(fields, updateField, function(err) {
if (err) {
return callback(err);
}
User.getUserFields(uid, ['userslug', 'picture', 'gravatarpicture'], callback);
});
});
function updateField(field, next) {
if (!(data[field] !== undefined && typeof data[field] === 'string')) {
return next();
}
data[field] = data[field].trim();
data[field] = validator.escape(data[field]);
if (field === 'email') {
return updateEmail(uid, data.email, next);
} else if (field === 'username') {
return updateUsername(uid, data.username, next);
} else if (field === 'signature') {
data[field] = S(data[field]).stripTags().s;
} else if (field === 'website') {
if(data[field].substr(0, 7) !== 'http://' && data[field].substr(0, 8) !== 'https://') {
data[field] = 'http://' + data[field];
}
}
User.setUserField(uid, field, data[field]);
next();
}
};
function updateEmail(uid, newEmail, callback) {
User.getUserFields(uid, ['email', 'picture', 'uploadedpicture'], function(err, userData) {
if (err) {
return callback(err);
}
if(userData.email === newEmail) {
return callback();
}
db.deleteObjectField('email:uid', userData.email, function(err) {
if (err) {
return callback(err);
}
events.logEmailChange(uid, userData.email, newEmail);
var gravatarpicture = User.createGravatarURLFromEmail(newEmail);
async.parallel([
function(next) {
User.setUserField(uid, 'gravatarpicture', gravatarpicture, next);
},
function(next) {
db.setObjectField('email:uid', newEmail, uid, next);
},
function(next) {
User.setUserField(uid, 'email', newEmail, next);
},
function(next) {
if (userData.picture !== userData.uploadedpicture) {
User.setUserField(uid, 'picture', gravatarpicture, next);
}
},
], callback);
});
});
}
function updateUsername(uid, newUsername, callback) {
User.getUserFields(uid, ['username', 'userslug'], function(err, userData) {
function update(field, object, value, callback) {
async.parallel([
function(next) {
User.setUserField(uid, field, value, next);
},
function(next) {
db.setObjectField(object, value, uid, next);
}
], callback);
}
if (err) {
return callback(err);
}
var userslug = utils.slugify(newUsername);
async.parallel([
function(next) {
if (newUsername === userData.username) {
return next();
}
db.deleteObjectField('username:uid', userData.username, function(err) {
if (err) {
return next(err);
}
events.logUsernameChange(uid, userData.username, newUsername);
update('username', 'username:uid', newUsername, next);
});
},
function(next) {
if (userslug === userData.userslug) {
return next();
}
db.deleteObjectField('userslug:uid', userData.userslug, function(err) {
if (err) {
return next(err);
}
update('userslug', 'userslug:uid', userslug, next);
});
}
], callback);
});
}
User.changePassword = function(uid, data, callback) {
if(!data || !data.uid) {
return callback(new Error('invalid-uid'));
}
function hashAndSetPassword(callback) {
User.hashPassword(data.newPassword, function(err, hash) {
if(err) {
return callback(err);
}
User.setUserField(data.uid, 'password', hash, function(err) {
if(err) {
return callback(err);
}
if(parseInt(uid, 10) === parseInt(data.uid, 10)) {
events.logPasswordChange(data.uid);
} else {
events.logAdminChangeUserPassword(uid, data.uid);
}
callback();
});
});
}
if (!utils.isPasswordValid(data.newPassword)) {
return callback(new Error('Invalid password!'));
}
if(parseInt(uid, 10) !== parseInt(data.uid, 10)) {
User.isAdministrator(uid, function(err, isAdmin) {
if(err || !isAdmin) {
return callback(err || new Error('not-allowed'));
}
hashAndSetPassword(callback);
});
} else {
User.getUserField(uid, 'password', function(err, currentPassword) {
if(err) {
return callback(err);
}
if (!currentPassword) {
return hashAndSetPassword(callback);
}
bcrypt.compare(data.currentPassword, currentPassword, function(err, res) {
if (err || !res) {
return callback(err || new Error('Your current password is not correct!'));
}
hashAndSetPassword(callback);
});
});
}
};
};

@ -4,13 +4,13 @@
var async = require('async'),
nconf = require('nconf'),
user = require('./user'),
utils = require('./../public/src/utils'),
user = require('./../user'),
utils = require('./../../public/src/utils'),
db = require('./database'),
meta = require('./meta'),
events = require('./events'),
emailer = require('./emailer');
db = require('./../database'),
meta = require('./../meta'),
events = require('./../events'),
emailer = require('./../emailer');
(function(UserReset) {

@ -0,0 +1,45 @@
'use strict';
var db = require('./../database');
module.exports = function(User) {
User.search = function(query, callback) {
if (!query || query.length === 0) {
return callback(null, {timing:0, users:[]});
}
var start = process.hrtime();
db.getObject('username:uid', function(err, usernamesHash) {
if (err) {
return callback(null, {timing: 0, users:[]});
}
query = query.toLowerCase();
var usernames = Object.keys(usernamesHash),
uids = [];
uids = usernames.filter(function(username) {
return username.toLowerCase().indexOf(query) === 0;
})
.slice(0, 10)
.sort(function(a, b) {
return a > b;
})
.map(function(username) {
return usernamesHash[username];
});
User.getUsersData(uids, function(err, userdata) {
if (err) {
return callback(err);
}
var diff = process.hrtime(start);
var timing = (diff[0] * 1e3 + diff[1] / 1e6).toFixed(1);
callback(null, {timing: timing, users: userdata});
});
});
};
};

@ -0,0 +1,54 @@
'use strict';
var meta = require('./../meta'),
db = require('./../database');
module.exports = function(User) {
User.getSettings = function(uid, callback) {
function sendDefaultSettings() {
callback(null, {
showemail: false,
usePagination: parseInt(meta.config.usePagination, 10) === 1,
topicsPerPage: parseInt(meta.config.topicsPerPage, 10) || 20,
postsPerPage: parseInt(meta.config.postsPerPage, 10) || 10
});
}
if(!parseInt(uid, 10)) {
return sendDefaultSettings();
}
db.getObject('user:' + uid + ':settings', function(err, settings) {
if(err) {
return callback(err);
}
if(!settings) {
settings = {};
}
settings.showemail = settings.showemail ? parseInt(settings.showemail, 10) !== 0 : false;
settings.usePagination = settings.usePagination ? parseInt(settings.usePagination, 10) === 1 : parseInt(meta.config.usePagination, 10) === 1;
settings.topicsPerPage = settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : parseInt(meta.config.topicsPerPage, 10) || 20;
settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10;
callback(null, settings);
});
};
User.saveSettings = function(uid, data, callback) {
if(!data.topicsPerPage || !data.postsPerPage || parseInt(data.topicsPerPage, 10) <= 0 || parseInt(data.postsPerPage, 10) <= 0) {
return callback(new Error('Invalid pagination value!'));
}
db.setObject('user:' + uid + ':settings', {
showemail: data.showemail,
usePagination: data.usePagination,
topicsPerPage: data.topicsPerPage,
postsPerPage: data.postsPerPage
}, callback);
};
};
Loading…
Cancel
Save