merged.. conflicted up the ass. registration looks gud again

v1.18.x
psychobunny 12 years ago
commit bb8f75b4be

@ -35,7 +35,8 @@
"request": "~2.25.0", "request": "~2.25.0",
"reds": "~0.2.4", "reds": "~0.2.4",
"winston": "~0.7.2", "winston": "~0.7.2",
"nodebb-plugin-mentions": "~0.1.0" "nodebb-plugin-mentions": "~0.1.0",
"nodebb-plugin-markdown": "~0.1.0"
}, },
"bugs": { "bugs": {
"url": "https://github.com/designcreateplay/NodeBB/issues" "url": "https://github.com/designcreateplay/NodeBB/issues"

@ -1,6 +1,8 @@
(function() { (function() {
var yourid = templates.get('yourid');
function initUsers() { function initUsers() {
function isUserAdmin(element) { function isUserAdmin(element) {
@ -10,29 +12,32 @@
function isUserBanned(element) { function isUserBanned(element) {
var parent = $(element).parents('.users-box'); var parent = $(element).parents('.users-box');
return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0"); return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0");
} }
function getUID(element) { function getUID(element) {
var parent = $(element).parents('.users-box'); var parent = $(element).parents('.users-box');
return parent.attr('data-uid'); return parent.attr('data-uid');
} }
jQuery('.admin-btn').each(function(index, element) { jQuery('.admin-btn').each(function(index, element) {
var adminBtn = $(element); var adminBtn = $(element);
var isAdmin = isUserAdmin(adminBtn); var isAdmin = isUserAdmin(adminBtn);
var uid = getUID(adminBtn);
if(isAdmin) if(isAdmin)
adminBtn.addClass('btn-success'); adminBtn.addClass('btn-success');
else else
adminBtn.removeClass('btn-success'); adminBtn.removeClass('btn-success');
if(uid === yourid)
adminBtn.addClass('disabled');
}); });
jQuery('.delete-btn').each(function(index, element) { jQuery('.delete-btn').each(function(index, element) {
var deleteBtn = $(element); var deleteBtn = $(element);
var isAdmin = isUserAdmin(deleteBtn); var isAdmin = isUserAdmin(deleteBtn);
if(isAdmin) if(isAdmin)
deleteBtn.addClass('disabled'); deleteBtn.addClass('disabled');
else else
@ -43,12 +48,12 @@
var banBtn = $(element); var banBtn = $(element);
var isAdmin = isUserAdmin(banBtn); var isAdmin = isUserAdmin(banBtn);
var isBanned = isUserBanned(banBtn); var isBanned = isUserBanned(banBtn);
if(isAdmin) if(isAdmin)
banBtn.addClass('disabled'); banBtn.addClass('disabled');
else if(isBanned) else if(isBanned)
banBtn.addClass('btn-warning'); banBtn.addClass('btn-warning');
else else
banBtn.removeClass('btn-warning'); banBtn.removeClass('btn-warning');
}); });
@ -59,13 +64,12 @@
var parent = adminBtn.parents('.users-box'); var parent = adminBtn.parents('.users-box');
var uid = getUID(adminBtn); var uid = getUID(adminBtn);
if(isAdmin) { if(isAdmin && uid != yourid) {
socket.emit('api:admin.user.removeAdmin', uid); socket.emit('api:admin.user.removeAdmin', uid);
adminBtn.removeClass('btn-success'); adminBtn.removeClass('btn-success');
parent.find('.delete-btn').removeClass('disabled'); parent.find('.delete-btn').removeClass('disabled');
parent.attr('data-admin', 0); parent.attr('data-admin', 0);
} } else if(uid != yourid) {
else {
bootbox.confirm('Do you really want to make "' + parent.attr('data-username') +'" an admin?', function(confirm) { bootbox.confirm('Do you really want to make "' + parent.attr('data-username') +'" an admin?', function(confirm) {
if(confirm) { if(confirm) {
socket.emit('api:admin.user.makeAdmin', uid); socket.emit('api:admin.user.makeAdmin', uid);
@ -75,7 +79,7 @@
} }
}); });
} }
return false; return false;
}); });
@ -87,10 +91,10 @@
if(!isAdmin) { if(!isAdmin) {
bootbox.confirm('Do you really want to delete "' + parent.attr('data-username') +'"?', function(confirm) { bootbox.confirm('Do you really want to delete "' + parent.attr('data-username') +'"?', function(confirm) {
socket.emit('api:admin.user.deleteUser', uid); socket.emit('api:admin.user.deleteUser', uid);
}); });
} }
return false; return false;
}); });
@ -108,13 +112,13 @@
parent.attr('data-banned', 0); parent.attr('data-banned', 0);
} else { } else {
bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') +'"?', function(confirm) { bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') +'"?', function(confirm) {
socket.emit('api:admin.user.banUser', uid); socket.emit('api:admin.user.banUser', uid);
banBtn.addClass('btn-warning'); banBtn.addClass('btn-warning');
parent.attr('data-banned', 1); parent.attr('data-banned', 1);
}); });
} }
} }
return false; return false;
}); });
} }
@ -122,8 +126,7 @@
jQuery('document').ready(function() { jQuery('document').ready(function() {
var yourid = templates.get('yourid'), var timeoutId = 0,
timeoutId = 0,
loadingMoreUsers = false; loadingMoreUsers = false;
var url = window.location.href, var url = window.location.href,
@ -146,17 +149,17 @@
timeoutId = setTimeout(function() { timeoutId = setTimeout(function() {
var username = $('#search-user').val(); var username = $('#search-user').val();
jQuery('.icon-spinner').removeClass('none'); jQuery('.icon-spinner').removeClass('none');
socket.emit('api:admin.user.search', username); socket.emit('api:admin.user.search', username);
}, 250); }, 250);
}); });
initUsers(); initUsers();
socket.removeAllListeners('api:admin.user.search'); socket.removeAllListeners('api:admin.user.search');
socket.on('api:admin.user.search', function(data) { socket.on('api:admin.user.search', function(data) {
var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ var html = templates.prepare(templates['admin/users'].blocks['users']).parse({
users: data users: data
@ -164,7 +167,7 @@
userListEl = document.querySelector('.users'); userListEl = document.querySelector('.users');
userListEl.innerHTML = html; userListEl.innerHTML = html;
jQuery('.icon-spinner').addClass('none'); jQuery('.icon-spinner').addClass('none');
if(data && data.length === 0) { if(data && data.length === 0) {
$('#user-notfound-notify').html('User not found!') $('#user-notfound-notify').html('User not found!')
@ -178,10 +181,10 @@
.addClass('label-success') .addClass('label-success')
.removeClass('label-danger'); .removeClass('label-danger');
} }
initUsers(); initUsers();
}); });
function onUsersLoaded(users) { function onUsersLoaded(users) {
var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: users }); var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: users });
$('#users-container').append(html); $('#users-container').append(html);
@ -200,8 +203,8 @@
if(set) { if(set) {
loadingMoreUsers = true; loadingMoreUsers = true;
socket.emit('api:users.loadMore', { socket.emit('api:users.loadMore', {
set: set, set: set,
after: $('#users-container').children().length after: $('#users-container').children().length
}, function(data) { }, function(data) {
if(data.users.length) { if(data.users.length) {
onUsersLoaded(data.users); onUsersLoaded(data.users);

@ -132,6 +132,7 @@
}); });
} }
}); });
notifList.addEventListener('click', function(e) { notifList.addEventListener('click', function(e) {
var target; var target;
switch(e.target.nodeName) { switch(e.target.nodeName) {
@ -144,6 +145,7 @@
if (nid > 0) socket.emit('api:notifications.mark_read', nid); if (nid > 0) socket.emit('api:notifications.mark_read', nid);
} }
}); });
socket.on('event:new_notification', function() { socket.on('event:new_notification', function() {
document.querySelector('.notifications a i').className = 'icon-circle active'; document.querySelector('.notifications a i').className = 'icon-circle active';
app.alert({ app.alert({
@ -158,19 +160,26 @@
socket.on('chatMessage', function(data) { socket.on('chatMessage', function(data) {
var username = data.username;
var fromuid = data.fromuid;
var message = data.message;
require(['chat'], function(chat) { require(['chat'], function(chat) {
var chatModal = chat.createModalIfDoesntExist(username, fromuid); var chatModal = chat.createModalIfDoesntExist(data.username, data.fromuid, function(created, modal) {
if(!created)
chat.appendChatMessage(modal, data.message, data.timestamp);
});
chatModal.show(); chatModal.show();
chat.bringModalToTop(chatModal); chat.bringModalToTop(chatModal);
chat.appendChatMessage(chatModal, message);
}); });
}); });
socket.on('chatGoOffline', function(data) {
require(['chat'], function(chat) {
if(chat.modalOpen(data.uid)) {
var modal = chat.getModal(data.uid);
chat.appendChatMessage(modal, data.username + ' went offline\n', data.timestamp);
}
});
})
require(['mobileMenu'], function(mobileMenu) { require(['mobileMenu'], function(mobileMenu) {
mobileMenu.init(); mobileMenu.init();

@ -1,161 +1,151 @@
(function() { (function() {
var username = document.getElementById('username'), var username = $('#username'),
password = document.getElementById('password'), password = $('#password'),
password_confirm = document.getElementById('password-confirm'), password_confirm = $('#password-confirm'),
register = document.getElementById('register'), register = $('#register'),
emailEl = document.getElementById('email'), emailEl = $('#email'),
username_notify = document.getElementById('username-notify'), username_notify = $('#username-notify'),
email_notify = document.getElementById('email-notify'), email_notify = $('#email-notify'),
password_notify = document.getElementById('password-notify'), password_notify = $('#password-notify'),
password_confirm_notify = document.getElementById('password-confirm-notify'), password_confirm_notify = $('#password-confirm-notify'),
usernamevalid = false; validationError = false,
emailexists = false, successIcon = '<i class="icon icon-ok"></i>';
emailvalid = false,
userexists = false, function showError(element, msg) {
passwordsmatch = false, element.html(msg);
passwordvalid = false; element.parent().removeClass('alert-success').addClass('alert-danger');
element.show();
$(username).on('keyup change', function() { validationError = true;
usernamevalid = utils.isUserNameValid(username.value); }
function showSuccess(element, msg) {
if(username.value.length < 3) { element.html(msg);
username_notify.innerHTML = 'Username too short'; element.parent().removeClass('alert-danger').addClass('alert-success');
username_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; element.show();
} else if(username.value.length > 13) { }
username_notify.innerHTML = 'Username too long';
username_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; function validateEmail() {
} else if(!usernamevalid) { if(!emailEl.val()) {
username_notify.innerHTML = 'Invalid username'; validationError = true;
username_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; //email_notify.hide();
} else { return;
socket.emit('user.exists', {username: username.value});
} }
if(!utils.isEmailValid(emailEl.val())) {
showError(email_notify, 'Invalid email address.');
}
else
socket.emit('user.email.exists', { email: emailEl.val() });
}
emailEl.on('blur', function() {
validateEmail();
}); });
$(emailEl).on('keyup change', function() { function validateUsername() {
emailvalid = utils.isEmailValid(email.value); if(!username.val()) {
validationError = true;
//username_notify.hide();
return;
}
if(!emailvalid) { if(username.val().length < config.minimumUsernameLength) {
email_notify.innerHTML = 'Invalid email address'; showError(username_notify, 'Username too short!');
email_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; } else if(username.val().length > config.maximumUsernameLength) {
showError(username_notify, 'Username too long!');
} else if(!utils.isUserNameValid(username.val())) {
showError(username_notify, 'Invalid username!');
} else {
socket.emit('user.exists', {username: username.val()});
} }
else }
socket.emit('user.email.exists', { email: emailEl.value });
username.on('keyup', function() {
jQuery('#yourUsername').html(this.value.length > 0 ? this.value : 'username');
}); });
username.on('blur', function() {
$(password).on('keyup', function() { validateUsername();
passwordvalid = utils.isPasswordValid(password.value); });
if (password.value.length < 6) {
password_notify.innerHTML = 'Password too short'; function validatePassword() {
password_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; if(!password.val()){
} else if(!passwordvalid) { validationError = true;
password_notify.innerHTML = 'Invalid password'; //password_notify.hide();
password_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; return;
} else {
password_notify.innerHTML = '<i class="icon icon-ok"></i>';
password_notify.parentNode.className = 'input-group-addon btn-success label-success';
} }
if(password.value !== password_confirm.value && password_confirm.value.length > 0) { if (password.val().length < config.minimumPasswordLength) {
password_confirm_notify.innerHTML = 'Passwords must match!'; showError(password_notify, 'Password too short!');
password_confirm_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; } else if(password.val().length > config.maximumPasswordLength) {
passwordsmatch = false; showError(password_notify, 'Password too long!');
} else if (password.value === password_confirm.value && password_confirm.value.length > 0) { } else if(!utils.isPasswordValid(password.val())) {
password_confirm_notify.innerHTML = '<i class="icon icon-ok"></i>'; showError(password_notify, 'Invalid password!');
password_confirm_notify.parentNode.className = 'input-group-addon btn-success label-success'; } else {
passwordsmatch = true; showSuccess(password_notify, successIcon);
} }
if(password.val() !== password_confirm.val() && password_confirm.val() !== '') {
showError(password_confirm_notify, 'Passwords must match!');
}
}
$(password).on('blur', function() {
validatePassword();
}); });
$(password_confirm).on('keyup', function() { function validatePasswordConfirm() {
if(password.value !== password_confirm.value) { if(!password.val() || password_notify.hasClass('alert-error')) {
password_confirm_notify.innerHTML = 'Passwords must match!'; //password_confirm_notify.hide();
password_confirm_notify.parentNode.className = 'input-group-addon btn-warning label-warning'; return;
passwordsmatch = false;
} }
else {
password_confirm_notify.innerHTML = '<i class="icon icon-ok"></i>'; if(password.val() !== password_confirm.val()) {
password_confirm_notify.parentNode.className = 'input-group-addon btn-success label-success'; showError(password_confirm_notify, 'Passwords must match!');
passwordsmatch = true; } else {
showSuccess(password_confirm_notify, successIcon);
} }
}
$(password_confirm).on('blur', function() {
validatePasswordConfirm();
}); });
ajaxify.register_events(['user.exists', 'user.email.exists']); ajaxify.register_events(['user.exists', 'user.email.exists']);
socket.on('user.exists', function(data) { socket.on('user.exists', function(data) {
userexists = data.exists;
if (data.exists === true) { if (data.exists === true) {
username_notify.innerHTML = 'Username exists'; showError(username_notify, 'Username already taken!');
username_notify.parentNode.className = 'input-group-addon btn-warning label-warning';
} else { } else {
username_notify.innerHTML = '<i class="icon icon-ok"></i>'; showSuccess(username_notify, successIcon);
username_notify.parentNode.className = 'input-group-addon btn-success label-success';
} }
}); });
socket.on('user.email.exists', function(data) {
emailexists = data.exists;
socket.on('user.email.exists', function(data) {
if (data.exists === true) { if (data.exists === true) {
email_notify.innerHTML = 'Email Address exists'; showError(email_notify, 'Email address already taken!');
email_notify.className = 'label label-warning'; } else {
} showSuccess(email_notify, successIcon);
else {
email_notify.innerHTML = '<i class="icon icon-ok"></i>';
email_notify.parentNode.className = 'input-group-addon btn-success label-success';
} }
}); });
// Alternate Logins // Alternate Logins
var altLoginEl = document.querySelector('.alt-logins'); $('.alt-logins li').on('click', function(e) {
altLoginEl.addEventListener('click', function(e) { document.location.href = $(this).attr('data-url');
var target;
switch(e.target.nodeName) {
case 'LI': target = e.target; break;
case 'I': target = e.target.parentNode; break;
}
if (target) {
document.location.href = target.getAttribute('data-url');
}
}); });
function validateForm() { function validateForm() {
var validated = true; validationError = false;
if (username.value.length < 2 || !usernamevalid) {
username_notify.innerHTML = 'Invalid username';
username_notify.className = 'label label-warning';
validated = false;
}
if (password.value.length < 5) { validateEmail();
password_notify.innerHTML = 'Password too short'; validateUsername();
validated = false; validatePassword();
} validatePasswordConfirm();
if(password.value !== password_confirm.value) {
password_confirm_notify.innerHTML = 'Passwords must match!';
}
if (!emailvalid) { return validationError;
email_notify.innerHTML = 'Invalid email address'; }
validated = false;
}
if(emailexists) {
email_notify.innerHTML = 'Email Address exists';
validated = false;
}
if(userexists || !passwordsmatch || !passwordvalid) register.on('click', function(e) {
validated = false; if (validateForm()) e.preventDefault();
});
return validated; }());
}
register.addEventListener('click', function(e) {
if (!validateForm()) e.preventDefault();
}, false);
}());

@ -13,12 +13,19 @@ define(['taskbar'], function(taskbar) {
chatModal.css('zIndex', topZ + 1); chatModal.css('zIndex', topZ + 1);
} }
module.createModalIfDoesntExist = function(username, touid) { module.getModal = function(touid) {
var chatModal = $('#chat-modal-'+touid); return $('#chat-modal-' + touid);
}
module.modalOpen = function(touid) {
return $('#chat-modal-' + touid).length !== 0;
}
module.createModalIfDoesntExist = function(username, touid, callback) {
var chatModal = $('#chat-modal-' + touid);
if(!chatModal.length) { if(!chatModal.length) {
var chatModal = $('#chat-modal').clone(); var chatModal = $('#chat-modal').clone();
chatModal.attr('id','chat-modal-'+touid); chatModal.attr('id','chat-modal-' + touid);
var uuid = utils.generateUUID(); var uuid = utils.generateUUID();
chatModal.attr('UUID', uuid); chatModal.attr('UUID', uuid);
chatModal.appendTo($('body')); chatModal.appendTo($('body'));
@ -29,7 +36,7 @@ define(['taskbar'], function(taskbar) {
}); });
chatModal.find('#chat-with-name').html(username); chatModal.find('#chat-with-name').html(username);
chatModal.find('.close').on('click',function(e){ chatModal.find('.close').on('click', function(e) {
chatModal.hide(); chatModal.hide();
taskbar.discard('chat', uuid); taskbar.discard('chat', uuid);
}); });
@ -40,9 +47,15 @@ define(['taskbar'], function(taskbar) {
addSendHandler(chatModal, touid); addSendHandler(chatModal, touid);
getChatMessages(chatModal, touid); getChatMessages(chatModal, touid, callback);
taskbar.push('chat', chatModal.attr('UUID'), {title:'chat with '+username});
return chatModal;
} }
if(callback)
callback(false, chatModal);
taskbar.push('chat', chatModal.attr('UUID'), {title:'chat with '+username}); taskbar.push('chat', chatModal.attr('UUID'), {title:'chat with '+username});
return chatModal; return chatModal;
} }
@ -59,11 +72,14 @@ define(['taskbar'], function(taskbar) {
taskbar.minimize('chat', uuid); taskbar.minimize('chat', uuid);
} }
function getChatMessages(chatModal, touid) { function getChatMessages(chatModal, touid, callback) {
socket.emit('getChatMessages', {touid:touid}, function(messages) { socket.emit('getChatMessages', {touid:touid}, function(messages) {
for(var i = 0; i<messages.length; ++i) { for(var i = 0; i<messages.length; ++i) {
module.appendChatMessage(chatModal, messages[i].content); module.appendChatMessage(chatModal, messages[i].content, messages[i].timestamp);
} }
if(callback)
callback(true, chatModal);
}); });
} }
@ -88,14 +104,15 @@ define(['taskbar'], function(taskbar) {
msg = msg +'\n'; msg = msg +'\n';
socket.emit('sendChatMessage', { touid:touid, message:msg}); socket.emit('sendChatMessage', { touid:touid, message:msg});
chatModal.find('#chat-message-input').val(''); chatModal.find('#chat-message-input').val('');
module.appendChatMessage(chatModal, 'You : ' + msg);
} }
} }
module.appendChatMessage = function(chatModal, message, timestamp) {
module.appendChatMessage = function(chatModal, message){
var chatContent = chatModal.find('#chat-content'); var chatContent = chatModal.find('#chat-content');
chatContent.append(message);
var date = new Date(parseInt(timestamp, 10));
chatContent.append('[' + date.toLocaleTimeString() + '] ' + message);
chatContent.scrollTop( chatContent.scrollTop(
chatContent[0].scrollHeight - chatContent.height() chatContent[0].scrollHeight - chatContent.height()
); );

@ -91,11 +91,11 @@
}, },
isUserNameValid: function(name) { isUserNameValid: function(name) {
return (name && name !== "" && (/^[a-zA-Z0-9 _-]{3,14}$/.test(name))); return (name && name !== "" && (/^[a-zA-Z0-9 _-]+$/.test(name)));
}, },
isPasswordValid: function(password) { isPasswordValid: function(password) {
return password && password.indexOf(' ') === -1 && password.length > 5; return password && password.indexOf(' ') === -1;
}, },
// Blatently stolen from: http://phpjs.org/functions/strip_tags/ // Blatently stolen from: http://phpjs.org/functions/strip_tags/

@ -50,6 +50,14 @@
</div> </div>
</form> </form>
<form>
<h3>User Settings</h3>
<div class="alert alert-notify">
<strong>Minimum Username Length</strong><br /> <input type="text" class="" value="2" data-field="minimumUsernameLength"><br />
<strong>Maximum Username Length</strong><br /> <input type="text" class="" value="16" data-field="maximumUsernameLength"><br />
</div>
</form>
<form> <form>
<h3>Post Settings</h3> <h3>Post Settings</h3>
<div class="alert alert-warning"> <div class="alert alert-warning">

@ -15,11 +15,12 @@
<label for="email" class="col-lg-4 control-label">Email Address</label> <label for="email" class="col-lg-4 control-label">Email Address</label>
<div class="col-lg-8"> <div class="col-lg-8">
<div class="input-group"> <div class="input-group">
<input class="form-control" type="text" placeholder="Enter Email Address" name="email" id="email" /> <input class="form-control" type="text" placeholder="Enter Email Address" name="email" id="email" />
<span class="input-group-addon"> <span class="input-group-addon">
<span id="email-notify"><i class="icon icon-circle-blank"></i></span> <span id="email-notify"><i class="icon icon-circle-blank"></i></span>
</span> </span>
</div> </div>
<span class="help-block">By default, your email will be hidden from the public.</span>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -31,6 +32,7 @@
<span id="username-notify"><i class="icon icon-circle-blank"></i></span> <span id="username-notify"><i class="icon icon-circle-blank"></i></span>
</span> </span>
</div> </div>
<span class="help-block">A unique username. {minimumUsernameLength}-{maximumUsernameLength} characters. Others can mention you with @<span id="yourUsername">username</span>.</span>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -42,6 +44,7 @@
<span id="password-notify"><i class="icon icon-circle-blank"></i></span> <span id="password-notify"><i class="icon icon-circle-blank"></i></span>
</span> </span>
</div> </div>
<span class="help-block">Your password's length must be {minimumPasswordLength}-{maximumPasswordLength} characters.</span>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -57,7 +60,8 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-lg-offset-4 col-lg-8"> <div class="col-lg-offset-4 col-lg-8">
<button class="btn btn-primary" id="register" type="submit">Register Now</button> <hr />
<button class="btn btn-primary btn-lg btn-block" id="register" type="submit">Register Now</button>
</div> </div>
</div> </div>
<input type="hidden" name="_csrf" value="{token}" /> <input type="hidden" name="_csrf" value="{token}" />

@ -74,6 +74,7 @@ var RDB = require('./redis.js'),
categoryData.moderator_block_class = results[1].length > 0 ? '' : 'none'; categoryData.moderator_block_class = results[1].length > 0 ? '' : 'none';
categoryData.moderators = results[1]; categoryData.moderators = results[1];
categoryData.active_users = results[2]; categoryData.active_users = results[2];
categoryData.show_sidebar = categoryData.topics.length > 0 ? 'show':'hidden';
callback(null, categoryData); callback(null, categoryData);
}); });
} }
@ -234,6 +235,26 @@ var RDB = require('./redis.js'),
}); });
} }
Categories.moveActiveUsers = function(tid, oldCid, cid, callback) {
topics.getUids(tid, function(err, uids) {
if(!err && uids) {
function updateUser(uid) {
Categories.addActiveUser(cid, uid);
Categories.isUserActiveIn(oldCid, uid, function(err, active) {
if(!err && !active) {
Categories.removeActiveUser(oldCid, uid);
}
});
}
for(var i=0; i<uids.length; ++i) {
updateUser(uids[i]);
}
}
});
}
Categories.getCategoryData = function(cid, callback) { Categories.getCategoryData = function(cid, callback) {
RDB.exists('category:' + cid, function(err, exists) { RDB.exists('category:' + cid, function(err, exists) {
if (exists) RDB.hgetall('category:' + cid, callback); if (exists) RDB.hgetall('category:' + cid, callback);
@ -299,5 +320,58 @@ var RDB = require('./redis.js'),
}; };
Categories.isUserActiveIn = function(cid, uid, callback) {
RDB.lrange('uid:' + uid + ':posts', 0, -1, function(err, pids) {
if(err)
return callback(err, null);
function getPostCategory(pid, callback) {
posts.getPostField(pid, 'tid', function(tid) {
topics.getTopicField(tid, 'cid', function(err, postCid) {
if(err)
return callback(err, null);
return callback(null, postCid);
});
});
}
var index = 0,
active = false;
async.whilst(
function() {
return active === false && index < pids.length;
},
function(callback) {
getPostCategory(pids[index], function(err, postCid) {
if(err)
return callback(err);
if(postCid === cid)
active = true;
++index;
callback(null);
})
},
function(err) {
if(err)
return callback(err, null);
callback(null, active);
}
);
});
}
Categories.addActiveUser = function(cid, uid) {
RDB.sadd('cid:' + cid + ':active_users', uid);
}
Categories.removeActiveUser = function(cid, uid) {
RDB.srem('cid:' + cid + ':active_users', uid);
}
}(exports)); }(exports));

@ -88,6 +88,10 @@ var async = require('async'),
meta.configs.set('postDelay', 10000); meta.configs.set('postDelay', 10000);
meta.configs.set('minimumPostLength', 8); meta.configs.set('minimumPostLength', 8);
meta.configs.set('minimumTitleLength', 3); meta.configs.set('minimumTitleLength', 3);
meta.configs.set('minimumUsernameLength', 2);
meta.configs.set('maximumUsernameLength', 16);
meta.configs.set('minimumPasswordLength', 6);
meta.configs.set('maximumPasswordLength', 16);
meta.configs.set('imgurClientID', ''); meta.configs.set('imgurClientID', '');
install.save(server_conf, client_conf, callback); install.save(server_conf, client_conf, callback);

@ -80,7 +80,7 @@ var fs = require('fs'),
hookList = this.loadedHooks[hook]; hookList = this.loadedHooks[hook];
if (hookList && Array.isArray(hookList)) { if (hookList && Array.isArray(hookList)) {
if (global.env === 'development') winston.info('[plugins] Firing hook: \'' + hook + '\''); //if (global.env === 'development') winston.info('[plugins] Firing hook: \'' + hook + '\'');
var hookType = hook.split(':')[0]; var hookType = hook.split(':')[0];
switch(hookType) { switch(hookType) {
case 'filter': case 'filter':

@ -56,7 +56,6 @@ var RDB = require('./redis.js'),
} }
PostTools.edit = function(uid, pid, title, content) { PostTools.edit = function(uid, pid, title, content) {
var success = function() { var success = function() {
posts.setPostField(pid, 'content', content); posts.setPostField(pid, 'content', content);
posts.setPostField(pid, 'edited', Date.now()); posts.setPostField(pid, 'edited', Date.now());
@ -66,27 +65,36 @@ var RDB = require('./redis.js'),
postSearch.index(content, pid); postSearch.index(content, pid);
}); });
posts.getPostField(pid, 'tid', function(tid) { async.parallel([
PostTools.isMain(pid, tid, function(isMainPost) { function(next) {
if (isMainPost) { posts.getPostField(pid, 'tid', function(tid) {
topics.setTopicField(tid, 'title', title); PostTools.isMain(pid, tid, function(isMainPost) {
topicSearch.remove(tid, function() { if (isMainPost) {
topicSearch.index(title, tid); topics.setTopicField(tid, 'title', title);
topicSearch.remove(tid, function() {
topicSearch.index(title, tid);
});
}
next(null, tid);
}); });
}
io.sockets.in('topic_' + tid).emit('event:post_edited', {
pid: pid,
title: title,
content: PostTools.markdownToHTML(content)
}); });
},
function(next) {
PostTools.toHTML(content, next);
}
], function(err, results) {
io.sockets.in('topic_' + results[0]).emit('event:post_edited', {
pid: pid,
title: title,
content: results[1]
}); });
}); });
}; };
PostTools.privileges(pid, uid, function(privileges) { PostTools.privileges(pid, uid, function(privileges) {
if (privileges.editable) { if (privileges.editable) {
plugins.fireHook('filter:save_post_content', content, function(parsedContent) { plugins.fireHook('filter:post.save', content, function(parsedContent) {
content = parsedContent; content = parsedContent;
success(); success();
}); });
@ -101,6 +109,7 @@ var RDB = require('./redis.js'),
postSearch.remove(pid); postSearch.remove(pid);
posts.getPostFields(pid, ['tid', 'uid'], function(postData) { posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
RDB.hincrby('topic:'+postData.tid, 'postcount', -1);
user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) { user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) {
RDB.zadd('users:postcount', postcount, postData.uid); RDB.zadd('users:postcount', postcount, postData.uid);
@ -134,25 +143,33 @@ var RDB = require('./redis.js'),
PostTools.restore = function(uid, pid) { PostTools.restore = function(uid, pid) {
var success = function() { var success = function() {
posts.setPostField(pid, 'deleted', 0); posts.setPostField(pid, 'deleted', 0);
posts.getPostFields(pid, ['tid', 'uid', 'content'], function(postData) { posts.getPostFields(pid, ['tid', 'uid', 'content'], function(postData) {
RDB.hincrby('topic:'+postData.tid, 'postcount', 1);
user.incrementUserFieldBy(postData.uid, 'postcount', 1); user.incrementUserFieldBy(postData.uid, 'postcount', 1);
io.sockets.in('topic_' + postData.tid).emit('event:post_restored', { io.sockets.in('topic_' + postData.tid).emit('event:post_restored', {
pid: pid pid: pid
}); });
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) { threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
posts.getPostField(pid, 'timestamp', function(timestamp) { posts.getPostField(pid, 'timestamp', function(timestamp) {
topics.updateTimestamp(postData.tid, timestamp); topics.updateTimestamp(postData.tid, timestamp);
});
}); });
});
postSearch.index(postData.content, pid); // Restore topic if it is the only post
}); topics.getTopicField(postData.tid, 'postcount', function(err, count) {
}; if (count === '1') {
threadTools.restore(postData.tid, uid);
}
});
postSearch.index(postData.content, pid);
});
};
PostTools.privileges(pid, uid, function(privileges) { PostTools.privileges(pid, uid, function(privileges) {
if (privileges.editable) { if (privileges.editable) {
@ -161,35 +178,28 @@ var RDB = require('./redis.js'),
}); });
} }
PostTools.markdownToHTML = function(md, isSignature) { PostTools.toHTML = function(raw, callback) {
var marked = require('marked'), plugins.fireHook('filter:post.parse', raw, function(parsed) {
cheerio = require('cheerio'); var cheerio = require('cheerio');
marked.setOptions({
breaks: true
});
if (md && md.length > 0) {
var parsedContentDOM = cheerio.load(marked(md));
var domain = nconf.get('url');
parsedContentDOM('a').each(function() {
this.attr('rel', 'nofollow');
var href = this.attr('href');
if (href && !href.match(domain) && !utils.isRelativeUrl(href)) { if (parsed && parsed.length > 0) {
this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href)); var parsedContentDOM = cheerio.load(parsed);
if (!isSignature) this.append(' <i class="icon-external-link"></i>'); var domain = nconf.get('url');
}
});
parsedContentDOM('a').each(function() {
this.attr('rel', 'nofollow');
var href = this.attr('href');
html = parsedContentDOM.html(); if (href && !href.match(domain) && !utils.isRelativeUrl(href)) {
} else { this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href));
html = '<p></p>'; }
} });
return html; callback(null, parsedContentDOM.html());
} else {
callback(null, '<p></p>');
}
});
} }

@ -34,28 +34,29 @@ var RDB = require('./redis.js'),
Posts.addUserInfoToPost = function(post, callback) { Posts.addUserInfoToPost = function(post, callback) {
user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) { user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) {
if(err) if(err) return callback();
return callback();
postTools.toHTML(userData.signature, function(err, signature) {
post.username = userData.username || 'anonymous'; post.username = userData.username || 'anonymous';
post.userslug = userData.userslug || ''; post.userslug = userData.userslug || '';
post.user_rep = userData.reputation || 0; post.user_rep = userData.reputation || 0;
post.user_postcount = userData.postcount || 0; post.user_postcount = userData.postcount || 0;
post.user_banned = userData.banned || '0'; post.user_banned = userData.banned || '0';
post.picture = userData.picture || require('gravatar').url('', {}, https=nconf.get('https')); post.picture = userData.picture || require('gravatar').url('', {}, https=nconf.get('https'));
post.signature = postTools.markdownToHTML(userData.signature, true); post.signature = signature;
if(post.editor !== '') { if(post.editor !== '') {
user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) { user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) {
if(err) if(err) return callback();
return callback();
post.editorname = editorData.username; post.editorname = editorData.username;
post.editorslug = editorData.userslug; post.editorslug = editorData.userslug;
callback();
});
} else {
callback(); callback();
}); }
} else { });
callback();
}
}); });
} }
@ -64,28 +65,41 @@ var RDB = require('./redis.js'),
var posts = []; var posts = [];
function getPostSummary(pid, callback) { function getPostSummary(pid, callback) {
Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) { async.waterfall([
if(postData.deleted === '1') { function(next) {
return callback(null); Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) {
} if (postData.deleted === '1') return callback(null);
else {
Posts.addUserInfoToPost(postData, function() { postData.relativeTime = utils.relativeTime(postData.timestamp);
next(null, postData);
}
});
},
function(postData, next) {
Posts.addUserInfoToPost(postData, function() {
next(null, postData);
});
},
function(postData, next) {
topics.getTopicFields(postData.tid, ['slug', 'deleted'], function(err, topicData) { topics.getTopicFields(postData.tid, ['slug', 'deleted'], function(err, topicData) {
if(err) if (err) return callback(err);
return callback(err); else if (topicData.deleted === '1') return callback(null);
if(topicData.deleted === '1')
return callback(null);
if(postData.content)
postData.content = utils.strip_tags(postTools.markdownToHTML(postData.content));
postData.relativeTime = utils.relativeTime(postData.timestamp);
postData.topicSlug = topicData.slug; postData.topicSlug = topicData.slug;
posts.push(postData); next(null, postData);
callback(null);
}); });
}); },
function(postData, next) {
if (postData.content) {
postTools.toHTML(postData.content, function(err, content) {
if (!err) postData.content = utils.strip_tags(content);
next(err, postData);
});
} else next(null, postData);
}
], function(err, postData) {
if (!err) posts.push(postData);
callback(err);
}); });
} }
@ -144,7 +158,7 @@ var RDB = require('./redis.js'),
Posts.getPostsByPids = function(pids, callback) { Posts.getPostsByPids = function(pids, callback) {
var posts = []; var posts = [];
function iterator(pid, callback) { async.eachSeries(pids, function (pid, callback) {
Posts.getPostData(pid, function(postData) { Posts.getPostData(pid, function(postData) {
if(postData) { if(postData) {
postData.relativeTime = utils.relativeTime(postData.timestamp); postData.relativeTime = utils.relativeTime(postData.timestamp);
@ -152,8 +166,6 @@ var RDB = require('./redis.js'),
postData['edited-class'] = postData.editor !== '' ? '' : 'none'; postData['edited-class'] = postData.editor !== '' ? '' : 'none';
postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : ''; postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : '';
postData.content = postTools.markdownToHTML(postData.content);
if(postData.uploadedImages) { if(postData.uploadedImages) {
try { try {
postData.uploadedImages = JSON.parse(postData.uploadedImages); postData.uploadedImages = JSON.parse(postData.uploadedImages);
@ -164,13 +176,15 @@ var RDB = require('./redis.js'),
} else { } else {
postData.uploadedImages = []; postData.uploadedImages = [];
} }
posts.push(postData);
postTools.toHTML(postData.content, function(err, content) {
postData.content = content;
posts.push(postData);
callback(null);
});
} }
callback(null);
}); });
} }, function(err) {
async.eachSeries(pids, iterator, function(err) {
if(!err) { if(!err) {
callback(null, posts); callback(null, posts);
} else { } else {
@ -310,7 +324,7 @@ var RDB = require('./redis.js'),
RDB.spop('cid:' + cid + ':active_users'); RDB.spop('cid:' + cid + ':active_users');
} }
RDB.sadd('cid:' + cid + ':active_users', uid); categories.addActiveUser(cid, uid);
}); });
}); });
@ -329,8 +343,9 @@ var RDB = require('./redis.js'),
}, },
content: function(next) { content: function(next) {
plugins.fireHook('filter:post.get', postData, function(postData) { plugins.fireHook('filter:post.get', postData, function(postData) {
postData.content = postTools.markdownToHTML(postData.content, false); postTools.toHTML(postData.content, function(err, content) {
next(null, postData.content); next(null, content);
});
}); });
} }
}, function(err, results) { }, function(err, results) {

@ -22,6 +22,10 @@ var user = require('./../user.js'),
config['minimumTitleLength'] = meta.config['minimumTitleLength']; config['minimumTitleLength'] = meta.config['minimumTitleLength'];
config['minimumPostLength'] = meta.config['minimumPostLength']; config['minimumPostLength'] = meta.config['minimumPostLength'];
config['imgurClientIDSet'] = !!meta.config['imgurClientID']; config['imgurClientIDSet'] = !!meta.config['imgurClientID'];
config['minimumUsernameLength'] = meta.config['minimumUsernameLength'];
config['maximumUsernameLength'] = meta.config['maximumUsernameLength'];
config['minimumPasswordLength'] = meta.config['minimumPasswordLength'];
config['maximumPasswordLength'] = meta.config['maximumPasswordLength'];
res.json(200, config); res.json(200, config);
}); });
@ -44,8 +48,7 @@ var user = require('./../user.js'),
require('async').each(data.categories, iterator, function(err) { require('async').each(data.categories, iterator, function(err) {
data.motd_class = (meta.config.show_motd === '1' || meta.config.show_motd === undefined) ? '' : 'none'; data.motd_class = (meta.config.show_motd === '1' || meta.config.show_motd === undefined) ? '' : 'none';
data.motd = marked(meta.config.motd || "# NodeBB <span>v " + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.\n\n<div class='btn-group'><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"icon-comment\"></i><span class='hidden-mobile'>&nbsp;Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"icon-github-alt\"></i><span class='hidden-mobile'>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"icon-twitter\"></i><span class='hidden-mobile'>&nbsp;@dcplabs</span></a></div>"); data.motd = require('marked')(meta.config.motd || "# NodeBB <span>v " + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.\n\n<div class='btn-group'><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"icon-comment\"></i><span class='hidden-mobile'>&nbsp;Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"icon-github-alt\"></i><span class='hidden-mobile'>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"icon-twitter\"></i><span class='hidden-mobile'>&nbsp;@dcplabs</span></a></div>");
res.json(data); res.json(data);
}); });
@ -98,7 +101,10 @@ var user = require('./../user.js'),
} }
data.token = res.locals.csrf_token; data.token = res.locals.csrf_token;
data.minimumUsernameLength = meta.config['minimumUsernameLength'];
data.maximumUsernameLength = meta.config['maximumUsernameLength'];
data.minimumPasswordLength = meta.config['minimumPasswordLength'];
data.maximumPasswordLength = meta.config['maximumPasswordLength'];
res.json(data); res.json(data);
}); });

@ -4,7 +4,6 @@ var user = require('./../user.js'),
fs = require('fs'), fs = require('fs'),
utils = require('./../../public/src/utils.js'), utils = require('./../../public/src/utils.js'),
path = require('path'), path = require('path'),
marked = require('marked'),
winston = require('winston'); winston = require('winston');
(function(User) { (function(User) {
@ -353,12 +352,15 @@ var user = require('./../user.js'),
userData.posts = posts.filter(function(p) {return p.deleted !== "1";}); userData.posts = posts.filter(function(p) {return p.deleted !== "1";});
userData.isFollowing = isFollowing; userData.isFollowing = isFollowing;
userData.signature = postTools.markdownToHTML(userData.signature, true);
if(!userData.profileviews) if(!userData.profileviews)
userData.profileviews = 1; userData.profileviews = 1;
if(callerUID !== userData.uid) if(callerUID !== userData.uid)
user.incrementUserFieldBy(userData.uid, 'profileviews', 1); user.incrementUserFieldBy(userData.uid, 'profileviews', 1);
res.json(userData);
postTools.toHTML(userData.signature, function(err, signature) {
userData.signature = signature;
res.json(userData);
});
}); });
}); });
} else { } else {

@ -20,11 +20,13 @@ var path = require('path'),
var categoryUrls = []; var categoryUrls = [];
categories.getAllCategories(function(data) { categories.getAllCategories(function(data) {
data.categories.forEach(function(category) { data.categories.forEach(function(category) {
categoryUrls.push({ if (!category.disabled) {
url: path.join('category', category.slug), categoryUrls.push({
changefreq: 'weekly', url: path.join('category', category.slug),
priority: '0.4' changefreq: 'weekly',
}); priority: '0.4'
});
}
}); });
next(null, categoryUrls); next(null, categoryUrls);
@ -34,11 +36,13 @@ var path = require('path'),
var topicUrls = []; var topicUrls = [];
topics.getAllTopics(null, null, function(topics) { topics.getAllTopics(null, null, function(topics) {
topics.forEach(function(topic) { topics.forEach(function(topic) {
topicUrls.push({ if (topic.deleted !== '1') {
url: path.join('topic', topic.slug), topicUrls.push({
changefreq: 'daily', url: path.join('topic', topic.slug),
priority: '0.6' changefreq: 'daily',
}); priority: '0.6'
});
}
}); });
next(null, topicUrls); next(null, topicUrls);

@ -199,12 +199,19 @@ var RDB = require('./redis.js'),
} }
}); });
categories.moveActiveUsers(tid, oldCid, cid, function(err, data) {
if(err) {
winston.err(err);
}
});
categories.incrementCategoryFieldBy(oldCid, 'topic_count', -1); categories.incrementCategoryFieldBy(oldCid, 'topic_count', -1);
categories.incrementCategoryFieldBy(cid, 'topic_count', 1); categories.incrementCategoryFieldBy(cid, 'topic_count', 1);
socket.emit('api:topic.move', { socket.emit('api:topic.move', {
status: 'ok' status: 'ok'
}); });
io.sockets.in('topic_' + tid).emit('event:topic_moved', { io.sockets.in('topic_' + tid).emit('event:topic_moved', {
tid: tid tid: tid
}); });
@ -264,7 +271,7 @@ var RDB = require('./redis.js'),
topics.getTopicField(tid, 'title', function(err, title) { topics.getTopicField(tid, 'title', function(err, title) {
topics.getTeaser(tid, function(err, teaser) { topics.getTeaser(tid, function(err, teaser) {
if (!err) { if (!err) {
notifications.create(teaser.username + ' has posted a reply to: "' + title + '"', null, '/topic/' + tid, 'topic:' + tid, function(nid) { notifications.create('<strong>' + teaser.username + '</strong> has posted a reply to: "<strong>' + title + '</strong>"', null, '/topic/' + tid, 'topic:' + tid, function(nid) {
next(null, nid); next(null, nid);
}); });
} else next(err); } else next(err);

@ -5,7 +5,6 @@ var RDB = require('./redis.js')
user = require('./user.js'), user = require('./user.js'),
categories = require('./categories.js'), categories = require('./categories.js'),
posts = require('./posts.js'), posts = require('./posts.js'),
marked = require('marked'),
threadTools = require('./threadTools.js'), threadTools = require('./threadTools.js'),
postTools = require('./postTools'), postTools = require('./postTools'),
async = require('async'), async = require('async'),
@ -14,9 +13,6 @@ var RDB = require('./redis.js')
reds = require('reds'), reds = require('reds'),
topicSearch = reds.createSearch('nodebbtopicsearch'); topicSearch = reds.createSearch('nodebbtopicsearch');
marked.setOptions({
breaks: true
});
(function(Topics) { (function(Topics) {
@ -566,19 +562,23 @@ marked.setOptions({
return callback(err, null); return callback(err, null);
var stripped = postData.content, var stripped = postData.content,
timestamp = postData.timestamp; timestamp = postData.timestamp,
returnObj = {
if(postData.content) { "username": userData.username,
"picture": userData.picture,
"timestamp" : timestamp
};
if (postData.content) {
stripped = postData.content.replace(/>.+\n\n/, ''); stripped = postData.content.replace(/>.+\n\n/, '');
stripped = utils.strip_tags(postTools.markdownToHTML(stripped)); postTools.toHTML(stripped, function(err, stripped) {
returnObj.text = utils.strip_tags(stripped);
callback(null, returnObj);
});
} else {
returnObj.text = '';
callback(null, returnObj);
} }
callback(null, {
"text": stripped,
"username": userData.username,
"picture": userData.picture,
"timestamp" : timestamp
});
}); });
}); });
} else callback(new Error('no-teaser-found')); } else callback(new Error('no-teaser-found'));
@ -723,6 +723,28 @@ marked.setOptions({
RDB.lrange('tid:' + tid + ':posts', 0, -1, callback); RDB.lrange('tid:' + tid + ':posts', 0, -1, callback);
} }
Topics.getUids = function(tid, callback) {
var uids = {};
Topics.getPids(tid, function(err, pids) {
function getUid(pid, next) {
posts.getPostField(pid, 'uid', function(uid) {
if(err)
return next(err);
uids[uid] = 1;
next(null);
});
}
async.each(pids, getUid, function(err) {
if(err)
return callback(err, null);
callback(null, Object.keys(uids));
});
});
}
Topics.delete = function(tid) { Topics.delete = function(tid) {
Topics.setTopicField(tid, 'deleted', 1); Topics.setTopicField(tid, 'deleted', 1);
RDB.zrem('topics:recent', tid); RDB.zrem('topics:recent', tid);

@ -3,9 +3,8 @@ var utils = require('./../public/src/utils.js'),
crypto = require('crypto'), crypto = require('crypto'),
emailjs = require('emailjs'), emailjs = require('emailjs'),
meta = require('./meta.js'), meta = require('./meta.js'),
emailjsServer = emailjs.server.connect(meta.config.mailer), emailjsServer = emailjs.server.connect(meta.config.mailer || '127.0.0.1'),
bcrypt = require('bcrypt'), bcrypt = require('bcrypt'),
marked = require('marked'),
notifications = require('./notifications.js'), notifications = require('./notifications.js'),
topics = require('./topics.js'), topics = require('./topics.js'),
async = require('async'); async = require('async');
@ -581,7 +580,7 @@ var utils = require('./../public/src/utils.js'),
User.getUserField(uid, 'username', function(err, username) { User.getUserField(uid, 'username', function(err, username) {
RDB.smembers('followers:' + uid, function(err, followers) { RDB.smembers('followers:' + uid, function(err, followers) {
topics.getTopicField(tid, 'slug', function(err, slug) { topics.getTopicField(tid, 'slug', function(err, slug) {
var message = username + ' made a new post'; var message = '<strong>' + username + '</strong> made a new post';
notifications.create(message, 5, nconf.get('url') + 'topic/' + slug + '#' + pid, 'notification_'+ Date.now(), function(nid) { notifications.create(message, 5, nconf.get('url') + 'topic/' + slug + '#' + pid, 'notification_'+ Date.now(), function(nid) {
notifications.push(nid, followers); notifications.push(nid, followers);

@ -6,7 +6,6 @@ var express = require('express'),
path = require('path'), path = require('path'),
redis = require('redis'), redis = require('redis'),
redisServer = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host')), redisServer = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host')),
marked = require('marked'),
utils = require('../public/src/utils.js'), utils = require('../public/src/utils.js'),
pkg = require('../package.json'), pkg = require('../package.json'),
fs = require('fs'), fs = require('fs'),
@ -67,12 +66,12 @@ var express = require('express'),
app.use(express.session({ app.use(express.session({
store: new RedisStore({ store: new RedisStore({
client: redisServer, client: redisServer,
ttl: 60*60*24*14 ttl: 60*60*24*30
}), }),
secret: nconf.get('secret'), secret: nconf.get('secret'),
key: 'express.sid', key: 'express.sid',
cookie: { cookie: {
maxAge: 60*60*24*30 // 30 days maxAge: 60*60*24*30*1000 // 30 days
} }
})); }));
app.use(express.csrf()); app.use(express.csrf());

@ -32,7 +32,8 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
(function(io) { (function(io) {
var users = {}, var users = {},
userSockets = {}, userSockets = {},
rooms = {} rooms = {},
chats = {};
global.io = io; global.io = io;
@ -55,7 +56,14 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid)); io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid));
user.getUserField(uid, 'username', function(err, username) { user.getUserField(uid, 'username', function(err, username) {
socket.emit('event:connect', {status: 1, username:username}); socket.emit('event:connect', {status: 1, username:username, uid:uid});
if(chats[uid]) {
for(var i=0; i<chats[uid].length; ++i) {
io.sockets.in(chats[uid][i]).emit('chatMessage', {fromuid:uid, username:username, message: username+' came online\n', timestamp: Date.now()});
socket.join(chats[uid][i]);
}
}
}); });
} }
}); });
@ -72,8 +80,21 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
if(userSockets[uid].length === 0) { if(userSockets[uid].length === 0) {
delete users[sessionID]; delete users[sessionID];
if(uid) if(uid) {
io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid)); io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid));
user.getUserField(uid, 'username', function(err, username) {
if(chats[uid] && chats[uid].length) {
for(var i=0; i<chats[uid].length; ++i) {
io.sockets.in(chats[uid][i]).emit('chatGoOffline', {uid:uid, username:username, timestamp:Date.now()});
socket.leave(chats[uid][i]);
}
}
});
}
} }
for(var roomName in rooms) { for(var roomName in rooms) {
@ -196,9 +217,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
}); });
socket.on('user.exists', function(data) { socket.on('user.exists', function(data) {
user.exists(utils.slugify(data.username), function(exists){ if(data.username) {
socket.emit('user.exists', {exists: exists}); user.exists(utils.slugify(data.username), function(exists){
}); socket.emit('user.exists', {exists: exists});
});
}
}); });
socket.on('user.count', function(data) { socket.on('user.count', function(data) {
@ -523,28 +546,54 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
return; return;
} }
if(userSockets[touid]) { var msg = utils.strip_tags(data.message);
var msg = utils.strip_tags(data.message),
numSockets = userSockets[touid].length;
user.getUserField(uid, 'username', function(err, username) { var uids = [uid, touid].sort();
var finalMessage = username + ' says : ' + msg; var chatroom = 'chatroom_'+uids[0]+'_'+uids[1];
for(var x=0;x<numSockets;x++) { user.getUserField(uid, 'username', function(err, username) {
userSockets[touid][x].emit('chatMessage', {fromuid:uid, username:username, message:finalMessage}); var finalMessage = username + ': ' + msg,
} notifText = 'New message from <strong>' + username + '</strong>';
notifications.create(finalMessage, 5, '#', 'notification_' + uid + '_' + touid, function(nid) { if(!isUserOnline(touid)) {
notifications.create(notifText, 5, '#', 'notification_' + uid + '_' + touid, function(nid) {
notifications.push(nid, [touid], function(success) { notifications.push(nid, [touid], function(success) {
}); });
}); });
}
require('./messaging').addMessage(uid, touid, msg, function(err, message) { require('./messaging').addMessage(uid, touid, msg, function(err, message) {
var numSockets = 0;
}); if(userSockets[touid]) {
numSockets = userSockets[touid].length;
for(var x=0; x<numSockets; ++x) {
userSockets[touid][x].join(chatroom);
userSockets[touid][x].emit('chatMessage', {fromuid:uid, username:username, message: finalMessage, timestamp: Date.now()});
}
chats[touid] = chats[touid] || [];
if(chats[touid].indexOf(chatroom) === -1)
chats[touid].push(chatroom);
}
if(userSockets[uid]) {
numSockets = userSockets[uid].length;
for(var x=0; x<numSockets; ++x) {
userSockets[uid][x].join(chatroom);
userSockets[uid][x].emit('chatMessage', {fromuid:touid, username:username, message:'You : ' + msg, timestamp: Date.now()});
}
chats[uid] = chats[uid] || [];
if(chats[uid].indexOf(chatroom) === -1)
chats[uid].push(chatroom);
}
}); });
} });
}); });
socket.on('api:config.get', function(data) { socket.on('api:config.get', function(data) {

Loading…
Cancel
Save