From 8a4a0154f60800bb889d7d95d4b86eb4d58954a2 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 27 Aug 2013 12:10:23 -0400 Subject: [PATCH 01/19] closes #211, closes #213 --- public/src/forum/footer.js | 11 +++++++--- public/src/modules/chat.js | 28 +++++++++++++++++-------- src/websockets.js | 42 +++++++++++++++++++++++--------------- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/public/src/forum/footer.js b/public/src/forum/footer.js index 6eca0edbdf..3030bc53d4 100644 --- a/public/src/forum/footer.js +++ b/public/src/forum/footer.js @@ -132,6 +132,7 @@ }); } }); + notifList.addEventListener('click', function(e) { var target; switch(e.target.nodeName) { @@ -144,6 +145,7 @@ if (nid > 0) socket.emit('api:notifications.mark_read', nid); } }); + socket.on('event:new_notification', function() { document.querySelector('.notifications a i').className = 'icon-circle active'; app.alert({ @@ -161,13 +163,16 @@ var username = data.username; var fromuid = data.fromuid; var message = data.message; + var timestamp = data.timestamp; require(['chat'], function(chat) { - var chatModal = chat.createModalIfDoesntExist(username, fromuid); + var chatModal = chat.createModalIfDoesntExist(username, fromuid, function(created, modal) { + if(!created) + chat.appendChatMessage(modal, message, timestamp); + }); + chatModal.show(); chat.bringModalToTop(chatModal); - - chat.appendChatMessage(chatModal, message); }); }); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 0b850b5889..f5f9702be3 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -13,7 +13,7 @@ define(['taskbar'], function(taskbar) { chatModal.css('zIndex', topZ + 1); } - module.createModalIfDoesntExist = function(username, touid) { + module.createModalIfDoesntExist = function(username, touid, callback) { var chatModal = $('#chat-modal-'+touid); if(!chatModal.length) { @@ -29,7 +29,7 @@ define(['taskbar'], function(taskbar) { }); chatModal.find('#chat-with-name').html(username); - chatModal.find('.close').on('click',function(e){ + chatModal.find('.close').on('click', function(e) { chatModal.hide(); taskbar.discard('chat', uuid); }); @@ -40,9 +40,15 @@ define(['taskbar'], function(taskbar) { 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}); return chatModal; } @@ -59,11 +65,14 @@ define(['taskbar'], function(taskbar) { taskbar.minimize('chat', uuid); } - function getChatMessages(chatModal, touid) { + function getChatMessages(chatModal, touid, callback) { socket.emit('getChatMessages', {touid:touid}, function(messages) { for(var i = 0; i Date: Tue, 27 Aug 2013 12:14:27 -0400 Subject: [PATCH 02/19] issue #214, preparing for addition of post.parse hook by renaming markdownToHTML to just "toHTML", and making it asynchronous. --- src/postTools.js | 45 +++++++++-------- src/posts.js | 117 +++++++++++++++++++++++++-------------------- src/routes/api.js | 2 +- src/routes/user.js | 8 ++-- src/topics.js | 22 ++++----- src/user.js | 1 - src/webserver.js | 1 - 7 files changed, 107 insertions(+), 89 deletions(-) diff --git a/src/postTools.js b/src/postTools.js index b722095e05..1ef7d9da78 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -66,20 +66,28 @@ var RDB = require('./redis.js'), postSearch.index(content, pid); }); - posts.getPostField(pid, 'tid', function(tid) { - PostTools.isMain(pid, tid, function(isMainPost) { - if (isMainPost) { - topics.setTopicField(tid, 'title', title); - topicSearch.remove(tid, function() { - topicSearch.index(title, tid); + async.parallel([ + function(next) { + posts.getPostField(pid, 'tid', function(tid) { + PostTools.isMain(pid, tid, function(isMainPost) { + if (isMainPost) { + 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] }); }); }; @@ -161,7 +169,7 @@ var RDB = require('./redis.js'), }); } - PostTools.markdownToHTML = function(md, isSignature) { + PostTools.toHTML = function(raw, callback) { var marked = require('marked'), cheerio = require('cheerio'); @@ -169,8 +177,8 @@ var RDB = require('./redis.js'), breaks: true }); - if (md && md.length > 0) { - var parsedContentDOM = cheerio.load(marked(md)); + if (raw && raw.length > 0) { + var parsedContentDOM = cheerio.load(marked(raw)); var domain = nconf.get('url'); parsedContentDOM('a').each(function() { @@ -179,17 +187,14 @@ var RDB = require('./redis.js'), if (href && !href.match(domain) && !utils.isRelativeUrl(href)) { this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href)); - if (!isSignature) this.append(' '); } }); - html = parsedContentDOM.html(); + callback(null, parsedContentDOM.html()); } else { - html = '

'; + callback(null, '

'); } - - return html; } diff --git a/src/posts.js b/src/posts.js index 5ada90d6e5..43bead0069 100644 --- a/src/posts.js +++ b/src/posts.js @@ -34,28 +34,29 @@ var RDB = require('./redis.js'), Posts.addUserInfoToPost = function(post, callback) { user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) { - if(err) - return callback(); + if(err) return callback(); - post.username = userData.username || 'anonymous'; - post.userslug = userData.userslug || ''; - post.user_rep = userData.reputation || 0; - post.user_postcount = userData.postcount || 0; - post.user_banned = userData.banned || '0'; - post.picture = userData.picture || require('gravatar').url('', {}, https=nconf.get('https')); - post.signature = postTools.markdownToHTML(userData.signature, true); + postTools.toHTML(userData.signature, function(err, signature) { + post.username = userData.username || 'anonymous'; + post.userslug = userData.userslug || ''; + post.user_rep = userData.reputation || 0; + post.user_postcount = userData.postcount || 0; + post.user_banned = userData.banned || '0'; + post.picture = userData.picture || require('gravatar').url('', {}, https=nconf.get('https')); + post.signature = signature; - if(post.editor !== '') { - user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) { - if(err) - return callback(); - post.editorname = editorData.username; - post.editorslug = editorData.userslug; + if(post.editor !== '') { + user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) { + if(err) return callback(); + + post.editorname = editorData.username; + post.editorslug = editorData.userslug; + callback(); + }); + } else { callback(); - }); - } else { - callback(); - } + } + }); }); } @@ -64,28 +65,41 @@ var RDB = require('./redis.js'), var posts = []; function getPostSummary(pid, callback) { - Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) { - if(postData.deleted === '1') { - return callback(null); - } - - Posts.addUserInfoToPost(postData, function() { - topics.getTopicFields(postData.tid, ['slug', 'deleted'], function(err, topicData) { - if(err) - return callback(err); - - 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; - posts.push(postData); - callback(null); + async.waterfall([ + function(next) { + Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) { + if (postData.deleted === '1') return callback(null); + else { + 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) { + if (err) return callback(err); + else if (topicData.deleted === '1') return callback(null); + + postData.topicSlug = topicData.slug; + next(null, postData); + }); + }, + 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) { var posts = []; - function iterator(pid, callback) { + async.eachSeries(pids, function (pid, callback) { Posts.getPostData(pid, function(postData) { if(postData) { postData.relativeTime = utils.relativeTime(postData.timestamp); @@ -152,8 +166,6 @@ var RDB = require('./redis.js'), postData['edited-class'] = postData.editor !== '' ? '' : 'none'; postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : ''; - postData.content = postTools.markdownToHTML(postData.content); - if(postData.uploadedImages) { try { postData.uploadedImages = JSON.parse(postData.uploadedImages); @@ -164,13 +176,15 @@ var RDB = require('./redis.js'), } else { postData.uploadedImages = []; } - posts.push(postData); - } - callback(null); - }); - } - async.eachSeries(pids, iterator, function(err) { + postTools.toHTML(postData.content, function(err, content) { + postData.content = content; + posts.push(postData); + callback(null); + }); + } + }); + }, function(err) { if(!err) { callback(null, posts); } else { @@ -329,8 +343,9 @@ var RDB = require('./redis.js'), }, content: function(next) { plugins.fireHook('filter:post.get', postData, function(postData) { - postData.content = postTools.markdownToHTML(postData.content, false); - next(null, postData.content); + postTools.toHTML(postData.content, function(err, content) { + next(null, content); + }); }); } }, function(err, results) { diff --git a/src/routes/api.js b/src/routes/api.js index f5f19a8075..cca3522fa3 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -44,7 +44,7 @@ var user = require('./../user.js'), require('async').each(data.categories, iterator, function(err) { data.motd_class = (meta.config.show_motd === '1' || meta.config.show_motd === undefined) ? '' : 'none'; - data.motd = marked(meta.config.motd || "# NodeBB v " + pkg.version + "\nWelcome to NodeBB, the discussion platform of the future.\n\n Get NodeBB  Fork us on Github  @dcplabs"); + data.motd = require('marked')(meta.config.motd || "# NodeBB v " + pkg.version + "\nWelcome to NodeBB, the discussion platform of the future.\n\n Get NodeBB  Fork us on Github  @dcplabs"); res.json(data); }); diff --git a/src/routes/user.js b/src/routes/user.js index cd17791c31..f05aed6207 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -4,7 +4,6 @@ var user = require('./../user.js'), fs = require('fs'), utils = require('./../../public/src/utils.js'), path = require('path'), - marked = require('marked'), winston = require('winston'); (function(User) { @@ -353,12 +352,15 @@ var user = require('./../user.js'), userData.posts = posts.filter(function(p) {return p.deleted !== "1";}); userData.isFollowing = isFollowing; - userData.signature = postTools.markdownToHTML(userData.signature, true); if(!userData.profileviews) userData.profileviews = 1; if(callerUID !== userData.uid) user.incrementUserFieldBy(userData.uid, 'profileviews', 1); - res.json(userData); + + postTools.toHTML(userData.signature, function(err, signature) { + userData.signature = signature; + res.json(userData); + }); }); }); } else { diff --git a/src/topics.js b/src/topics.js index 10cf449541..149a9e2d18 100644 --- a/src/topics.js +++ b/src/topics.js @@ -5,7 +5,6 @@ var RDB = require('./redis.js') user = require('./user.js'), categories = require('./categories.js'), posts = require('./posts.js'), - marked = require('marked'), threadTools = require('./threadTools.js'), postTools = require('./postTools'), async = require('async'), @@ -14,9 +13,6 @@ var RDB = require('./redis.js') reds = require('reds'), topicSearch = reds.createSearch('nodebbtopicsearch'); -marked.setOptions({ - breaks: true -}); (function(Topics) { @@ -569,15 +565,17 @@ marked.setOptions({ if(postData.content) { stripped = postData.content.replace(/>.+\n\n/, ''); - stripped = utils.strip_tags(postTools.markdownToHTML(stripped)); - } + postTools.toHTML(stripped, function(err, stripped) { + stripped = utils.strip_tags(stripped); - callback(null, { - "text": stripped, - "username": userData.username, - "picture": userData.picture, - "timestamp" : timestamp - }); + callback(null, { + "text": stripped, + "username": userData.username, + "picture": userData.picture, + "timestamp" : timestamp + }); + }); + } }); }); } else callback(new Error('no-teaser-found')); diff --git a/src/user.js b/src/user.js index 8a5f37f0f3..98c50eaf14 100644 --- a/src/user.js +++ b/src/user.js @@ -5,7 +5,6 @@ var utils = require('./../public/src/utils.js'), meta = require('./meta.js'), emailjsServer = emailjs.server.connect(meta.config.mailer), bcrypt = require('bcrypt'), - marked = require('marked'), notifications = require('./notifications.js'), topics = require('./topics.js'), async = require('async'); diff --git a/src/webserver.js b/src/webserver.js index 8eb83f76aa..9999676857 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -6,7 +6,6 @@ var express = require('express'), path = require('path'), redis = require('redis'), redisServer = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host')), - marked = require('marked'), utils = require('../public/src/utils.js'), pkg = require('../package.json'), fs = require('fs'), From abce5fd120c2bc54b044345ed5a521361e285440 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 12:50:15 -0400 Subject: [PATCH 03/19] refactored postTools.toHTML to fire post.parse hook, and removed auto-markdowning closed #214 --- package.json | 3 ++- src/postTools.js | 44 ++++++++++++++++++++------------------------ 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 6a039fd17c..41d1b7a637 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "request": "~2.25.0", "reds": "~0.2.4", "winston": "~0.7.2", - "nodebb-plugin-mentions": "~0.1.0" + "nodebb-plugin-mentions": "~0.1.0", + "nodebb-plugin-markdown": "~0.1.0" }, "bugs": { "url": "https://github.com/designcreateplay/NodeBB/issues" diff --git a/src/postTools.js b/src/postTools.js index 1ef7d9da78..d853dc5583 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -94,7 +94,7 @@ var RDB = require('./redis.js'), PostTools.privileges(pid, uid, function(privileges) { if (privileges.editable) { - plugins.fireHook('filter:save_post_content', content, function(parsedContent) { + plugins.fireHook('filter:post.save', content, function(parsedContent) { content = parsedContent; success(); }); @@ -170,31 +170,27 @@ var RDB = require('./redis.js'), } PostTools.toHTML = function(raw, callback) { - var marked = require('marked'), - cheerio = require('cheerio'); + plugins.fireHook('filter:post.parse', raw, function(parsed) { + var cheerio = require('cheerio'); - marked.setOptions({ - breaks: true + if (parsed && parsed.length > 0) { + var parsedContentDOM = cheerio.load(parsed); + 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)) { + this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href)); + } + }); + + callback(null, parsedContentDOM.html()); + } else { + callback(null, '

'); + } }); - - if (raw && raw.length > 0) { - var parsedContentDOM = cheerio.load(marked(raw)); - 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)) { - this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href)); - } - }); - - - callback(null, parsedContentDOM.html()); - } else { - callback(null, '

'); - } } From 860a83ba906b9232eb39a6131f9c8583560d0195 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 13:04:18 -0400 Subject: [PATCH 04/19] closed #212 --- src/threadTools.js | 2 +- src/user.js | 2 +- src/websockets.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/threadTools.js b/src/threadTools.js index a20323eb1f..620eb7d089 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -264,7 +264,7 @@ var RDB = require('./redis.js'), topics.getTopicField(tid, 'title', function(err, title) { topics.getTeaser(tid, function(err, teaser) { if (!err) { - notifications.create(teaser.username + ' has posted a reply to: "' + title + '"', null, '/topic/' + tid, 'topic:' + tid, function(nid) { + notifications.create('' + teaser.username + ' has posted a reply to: "' + title + '"', null, '/topic/' + tid, 'topic:' + tid, function(nid) { next(null, nid); }); } else next(err); diff --git a/src/user.js b/src/user.js index 98c50eaf14..3ac1b7830d 100644 --- a/src/user.js +++ b/src/user.js @@ -580,7 +580,7 @@ var utils = require('./../public/src/utils.js'), User.getUserField(uid, 'username', function(err, username) { RDB.smembers('followers:' + uid, function(err, followers) { topics.getTopicField(tid, 'slug', function(err, slug) { - var message = username + ' made a new post'; + var message = '' + username + ' made a new post'; notifications.create(message, 5, nconf.get('url') + 'topic/' + slug + '#' + pid, 'notification_'+ Date.now(), function(nid) { notifications.push(nid, followers); diff --git a/src/websockets.js b/src/websockets.js index d5bee80316..a3edea4f19 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -527,7 +527,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), user.getUserField(uid, 'username', function(err, username) { - var finalMessage = username + ' : ' + msg; + var finalMessage = 'New message from ' + username + ''; notifications.create(finalMessage, 5, '#', 'notification_' + uid + '_' + touid, function(nid) { notifications.push(nid, [touid], function(success) { From a317a4d6895f645d13aeadc1e55623d8bcd682bc Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 27 Aug 2013 13:32:43 -0400 Subject: [PATCH 05/19] closes #206 --- src/categories.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++ src/plugins.js | 2 +- src/posts.js | 2 +- src/threadTools.js | 7 +++++ src/topics.js | 22 ++++++++++++++ 5 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/categories.js b/src/categories.js index 01c831c5af..479bd29d41 100644 --- a/src/categories.js +++ b/src/categories.js @@ -74,6 +74,7 @@ var RDB = require('./redis.js'), categoryData.moderator_block_class = results[1].length > 0 ? '' : 'none'; categoryData.moderators = results[1]; categoryData.active_users = results[2]; + categoryData.show_sidebar = categoryData.topics.length > 0 ? 'show':'hidden'; 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 Date: Tue, 27 Aug 2013 13:38:09 -0400 Subject: [PATCH 06/19] closes #216 --- src/websockets.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/websockets.js b/src/websockets.js index a3edea4f19..92546790bb 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -529,11 +529,13 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), user.getUserField(uid, 'username', function(err, username) { var finalMessage = 'New message from ' + username + ''; - notifications.create(finalMessage, 5, '#', 'notification_' + uid + '_' + touid, function(nid) { - notifications.push(nid, [touid], function(success) { + if(!isUserOnline(touid)) { + notifications.create(finalMessage, 5, '#', 'notification_' + uid + '_' + touid, function(nid) { + notifications.push(nid, [touid], function(success) { + }); }); - }); + } require('./messaging').addMessage(uid, touid, msg, function(err, message) { var numSockets = 0; From aeb831eeff96b8e3243ad1fb038b68c11610a3ad Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 27 Aug 2013 13:47:19 -0400 Subject: [PATCH 07/19] closes #217 --- public/src/forum/admin/users.js | 57 +++++++++++++++++---------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/public/src/forum/admin/users.js b/public/src/forum/admin/users.js index 46a2f68b5f..3cc4f1fb12 100644 --- a/public/src/forum/admin/users.js +++ b/public/src/forum/admin/users.js @@ -1,6 +1,8 @@ (function() { + var yourid = templates.get('yourid'); + function initUsers() { function isUserAdmin(element) { @@ -10,29 +12,32 @@ function isUserBanned(element) { 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) { var parent = $(element).parents('.users-box'); - return parent.attr('data-uid'); + return parent.attr('data-uid'); } jQuery('.admin-btn').each(function(index, element) { var adminBtn = $(element); var isAdmin = isUserAdmin(adminBtn); - + var uid = getUID(adminBtn); + if(isAdmin) adminBtn.addClass('btn-success'); else adminBtn.removeClass('btn-success'); + if(uid === yourid) + adminBtn.addClass('disabled'); }); jQuery('.delete-btn').each(function(index, element) { var deleteBtn = $(element); var isAdmin = isUserAdmin(deleteBtn); - + if(isAdmin) deleteBtn.addClass('disabled'); else @@ -43,12 +48,12 @@ var banBtn = $(element); var isAdmin = isUserAdmin(banBtn); var isBanned = isUserBanned(banBtn); - + if(isAdmin) banBtn.addClass('disabled'); else if(isBanned) banBtn.addClass('btn-warning'); - else + else banBtn.removeClass('btn-warning'); }); @@ -59,13 +64,12 @@ var parent = adminBtn.parents('.users-box'); var uid = getUID(adminBtn); - if(isAdmin) { - socket.emit('api:admin.user.removeAdmin', uid); + if(isAdmin && uid != yourid) { + socket.emit('api:admin.user.removeAdmin', uid); adminBtn.removeClass('btn-success'); parent.find('.delete-btn').removeClass('disabled'); parent.attr('data-admin', 0); - } - else { + } else if(uid != yourid) { bootbox.confirm('Do you really want to make "' + parent.attr('data-username') +'" an admin?', function(confirm) { if(confirm) { socket.emit('api:admin.user.makeAdmin', uid); @@ -75,7 +79,7 @@ } }); } - + return false; }); @@ -87,10 +91,10 @@ if(!isAdmin) { 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; }); @@ -108,13 +112,13 @@ parent.attr('data-banned', 0); } else { 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'); parent.attr('data-banned', 1); }); } } - + return false; }); } @@ -122,8 +126,7 @@ jQuery('document').ready(function() { - var yourid = templates.get('yourid'), - timeoutId = 0, + var timeoutId = 0, loadingMoreUsers = false; var url = window.location.href, @@ -146,17 +149,17 @@ timeoutId = setTimeout(function() { var username = $('#search-user').val(); - + jQuery('.icon-spinner').removeClass('none'); socket.emit('api:admin.user.search', username); - + }, 250); }); - + initUsers(); - + socket.removeAllListeners('api:admin.user.search'); - + socket.on('api:admin.user.search', function(data) { var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: data @@ -164,7 +167,7 @@ userListEl = document.querySelector('.users'); userListEl.innerHTML = html; - jQuery('.icon-spinner').addClass('none'); + jQuery('.icon-spinner').addClass('none'); if(data && data.length === 0) { $('#user-notfound-notify').html('User not found!') @@ -178,10 +181,10 @@ .addClass('label-success') .removeClass('label-important'); } - + initUsers(); }); - + function onUsersLoaded(users) { var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: users }); $('#users-container').append(html); @@ -200,8 +203,8 @@ if(set) { loadingMoreUsers = true; socket.emit('api:users.loadMore', { - set: set, - after: $('#users-container').children().length + set: set, + after: $('#users-container').children().length }, function(data) { if(data.users.length) { onUsersLoaded(data.users); From 8d044544575da407dd9e5dadd7afd4767b44c9ee Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 13:52:30 -0400 Subject: [PATCH 08/19] closed #218 --- src/sitemap.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sitemap.js b/src/sitemap.js index 620e205e88..15f9cb69f6 100644 --- a/src/sitemap.js +++ b/src/sitemap.js @@ -20,11 +20,13 @@ var path = require('path'), var categoryUrls = []; categories.getAllCategories(function(data) { data.categories.forEach(function(category) { - categoryUrls.push({ - url: path.join('category', category.slug), - changefreq: 'weekly', - priority: '0.4' - }); + if (!category.disabled) { + categoryUrls.push({ + url: path.join('category', category.slug), + changefreq: 'weekly', + priority: '0.4' + }); + } }); next(null, categoryUrls); @@ -34,11 +36,13 @@ var path = require('path'), var topicUrls = []; topics.getAllTopics(null, null, function(topics) { topics.forEach(function(topic) { - topicUrls.push({ - url: path.join('topic', topic.slug), - changefreq: 'daily', - priority: '0.6' - }); + if (topic.deleted !== '1') { + topicUrls.push({ + url: path.join('topic', topic.slug), + changefreq: 'daily', + priority: '0.6' + }); + } }); next(null, topicUrls); From 1a6ba8c230f8c86eed414e416fef5d93617dbb13 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 14:04:09 -0400 Subject: [PATCH 09/19] fixed derpiness I introduced last commit --- src/websockets.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/websockets.js b/src/websockets.js index 92546790bb..3a24ea4ff5 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -527,10 +527,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), user.getUserField(uid, 'username', function(err, username) { - var finalMessage = 'New message from ' + username + ''; + var finalMessage = username + ': ' + msg, + notifText = 'New message from ' + username + ''; if(!isUserOnline(touid)) { - notifications.create(finalMessage, 5, '#', 'notification_' + uid + '_' + touid, function(nid) { + notifications.create(notifText, 5, '#', 'notification_' + uid + '_' + touid, function(nid) { notifications.push(nid, [touid], function(success) { }); From 4b4b26651a5dfef7cd0ea8956af40b4024825a39 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 27 Aug 2013 14:04:22 -0400 Subject: [PATCH 10/19] derp --- src/websockets.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/websockets.js b/src/websockets.js index 92546790bb..b8366021d0 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -72,8 +72,9 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), if(userSockets[uid].length === 0) { delete users[sessionID]; - if(uid) + if(uid) { io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid)); + } } for(var roomName in rooms) { @@ -525,6 +526,10 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), var msg = utils.strip_tags(data.message); + var uids = [touid,uid].sort(); + var chatroom = 'chat_' + uids[0] + '_' + uids[1]; + console.log('entering chat room ', chatroom); + socket.join('chat_' + uids[0] + '_' + uids[1]); user.getUserField(uid, 'username', function(err, username) { var finalMessage = 'New message from ' + username + ''; From 5f0e0c993ec19825c65e727028fe402bc58443ef Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 14:16:56 -0400 Subject: [PATCH 11/19] adding localhost as default for email server --- src/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user.js b/src/user.js index 3ac1b7830d..5f84b492fb 100644 --- a/src/user.js +++ b/src/user.js @@ -3,7 +3,7 @@ var utils = require('./../public/src/utils.js'), crypto = require('crypto'), emailjs = require('emailjs'), 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'), notifications = require('./notifications.js'), topics = require('./topics.js'), From 54fdbcd947a62e163e804b287c8be0eec3d508da Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 14:57:21 -0400 Subject: [PATCH 12/19] fixing broken category --- src/topics.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/topics.js b/src/topics.js index a52e32c81a..9f26064016 100644 --- a/src/topics.js +++ b/src/topics.js @@ -561,20 +561,22 @@ var RDB = require('./redis.js') return callback(err, null); var stripped = postData.content, - timestamp = postData.timestamp; + timestamp = postData.timestamp, + returnObj = { + "username": userData.username, + "picture": userData.picture, + "timestamp" : timestamp + }; if(postData.content) { stripped = postData.content.replace(/>.+\n\n/, ''); postTools.toHTML(stripped, function(err, stripped) { - stripped = utils.strip_tags(stripped); - - callback(null, { - "text": stripped, - "username": userData.username, - "picture": userData.picture, - "timestamp" : timestamp - }); + returnObj.stripped = utils.strip_tags(stripped); + callback(null, returnObj); }); + } else { + returnObj.stripped = ''; + callback(null, returnObj); } }); }); From 97641dbcda560e38d5e06f0a63f67f818c400cb1 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 15:00:35 -0400 Subject: [PATCH 13/19] fixing teasers, that I broke in the last commit --- src/topics.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/topics.js b/src/topics.js index 9f26064016..21a6861b54 100644 --- a/src/topics.js +++ b/src/topics.js @@ -568,14 +568,14 @@ var RDB = require('./redis.js') "timestamp" : timestamp }; - if(postData.content) { + if (postData.content) { stripped = postData.content.replace(/>.+\n\n/, ''); postTools.toHTML(stripped, function(err, stripped) { - returnObj.stripped = utils.strip_tags(stripped); + returnObj.text = utils.strip_tags(stripped); callback(null, returnObj); }); } else { - returnObj.stripped = ''; + returnObj.text = ''; callback(null, returnObj); } }); From 6a08fedf1874125167f8c6d6dd1d493856c9f44c Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 27 Aug 2013 15:55:44 -0400 Subject: [PATCH 14/19] closes #210 --- public/src/forum/footer.js | 16 +++++++++------ public/src/modules/chat.js | 11 ++++++++-- src/websockets.js | 41 ++++++++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/public/src/forum/footer.js b/public/src/forum/footer.js index 3030bc53d4..eba06ee4cf 100644 --- a/public/src/forum/footer.js +++ b/public/src/forum/footer.js @@ -160,15 +160,11 @@ socket.on('chatMessage', function(data) { - var username = data.username; - var fromuid = data.fromuid; - var message = data.message; - var timestamp = data.timestamp; require(['chat'], function(chat) { - var chatModal = chat.createModalIfDoesntExist(username, fromuid, function(created, modal) { + var chatModal = chat.createModalIfDoesntExist(data.username, data.fromuid, function(created, modal) { if(!created) - chat.appendChatMessage(modal, message, timestamp); + chat.appendChatMessage(modal, data.message, data.timestamp); }); chatModal.show(); @@ -176,6 +172,14 @@ }); }); + 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) { mobileMenu.init(); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index f5f9702be3..704bf16b5a 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -13,12 +13,19 @@ define(['taskbar'], function(taskbar) { chatModal.css('zIndex', topZ + 1); } + module.getModal = function(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); + var chatModal = $('#chat-modal-' + touid); if(!chatModal.length) { var chatModal = $('#chat-modal').clone(); - chatModal.attr('id','chat-modal-'+touid); + chatModal.attr('id','chat-modal-' + touid); var uuid = utils.generateUUID(); chatModal.attr('UUID', uuid); chatModal.appendTo($('body')); diff --git a/src/websockets.js b/src/websockets.js index 0440d9643b..c98ec013f5 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -32,7 +32,8 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), (function(io) { var users = {}, userSockets = {}, - rooms = {} + rooms = {}, + chats = {}; 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)); 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 Date: Tue, 27 Aug 2013 23:40:38 -0400 Subject: [PATCH 15/19] changed max age to milliseconds --- src/webserver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver.js b/src/webserver.js index 9999676857..278d3b9f64 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -71,7 +71,7 @@ var express = require('express'), secret: nconf.get('secret'), key: 'express.sid', cookie: { - maxAge: 60*60*24*30 // 30 days + maxAge: 60*60*24*30*1000 // 30 days } })); app.use(express.csrf()); From 4416f8530dd55699d04dd08d48f39ac7e2b78b1c Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 28 Aug 2013 10:18:17 -0400 Subject: [PATCH 16/19] matching connect-redis session with cookie ttl --- src/webserver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver.js b/src/webserver.js index 278d3b9f64..79f9ca741c 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -66,7 +66,7 @@ var express = require('express'), app.use(express.session({ store: new RedisStore({ client: redisServer, - ttl: 60*60*24*14 + ttl: 60*60*24*30 }), secret: nconf.get('secret'), key: 'express.sid', From f1b4367168d11e37adff0ed3682f3945151f94d1 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 28 Aug 2013 11:00:34 -0400 Subject: [PATCH 17/19] closed #180, closed #223 --- src/postTools.js | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/postTools.js b/src/postTools.js index d853dc5583..29287610a7 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -109,6 +109,7 @@ var RDB = require('./redis.js'), postSearch.remove(pid); posts.getPostFields(pid, ['tid', 'uid'], function(postData) { + RDB.hincrby('topic:'+postData.tid, 'postcount', -1); user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) { RDB.zadd('users:postcount', postcount, postData.uid); @@ -142,25 +143,33 @@ var RDB = require('./redis.js'), PostTools.restore = function(uid, pid) { 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', { - pid: pid - }); - - threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) { - posts.getPostField(pid, 'timestamp', function(timestamp) { - topics.updateTimestamp(postData.tid, timestamp); + io.sockets.in('topic_' + postData.tid).emit('event:post_restored', { + pid: pid }); - }); - postSearch.index(postData.content, pid); - }); - }; + threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) { + posts.getPostField(pid, 'timestamp', function(timestamp) { + topics.updateTimestamp(postData.tid, timestamp); + }); + }); + + // 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) { if (privileges.editable) { From 96c43b4607542aa32d55a4b5a828496798492e93 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 28 Aug 2013 12:29:15 -0400 Subject: [PATCH 18/19] fixed #221 - issue where replies would not automatically refresh a post after editing --- src/postTools.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/postTools.js b/src/postTools.js index 29287610a7..edef132e4c 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -56,7 +56,6 @@ var RDB = require('./redis.js'), } PostTools.edit = function(uid, pid, title, content) { - var success = function() { posts.setPostField(pid, 'content', content); posts.setPostField(pid, 'edited', Date.now()); @@ -74,9 +73,10 @@ var RDB = require('./redis.js'), topics.setTopicField(tid, 'title', title); topicSearch.remove(tid, function() { topicSearch.index(title, tid); - next(null, tid); }); } + + next(null, tid); }); }); }, From cc55073107348a6795af49850da571dddb0feffd Mon Sep 17 00:00:00 2001 From: Baris Soner Usakli Date: Wed, 28 Aug 2013 13:47:52 -0400 Subject: [PATCH 19/19] issue #224 --- public/src/forum/register.js | 222 +++++++++++++--------------- public/src/utils.js | 4 +- public/templates/admin/settings.tpl | 8 + public/templates/register.tpl | 32 +++- src/install.js | 4 + src/routes/api.js | 9 +- src/websockets.js | 8 +- 7 files changed, 158 insertions(+), 129 deletions(-) diff --git a/public/src/forum/register.js b/public/src/forum/register.js index 7818025be0..62d4b32fef 100644 --- a/public/src/forum/register.js +++ b/public/src/forum/register.js @@ -1,157 +1,147 @@ (function() { - var username = document.getElementById('username'), - password = document.getElementById('password'), - password_confirm = document.getElementById('password-confirm'), - register = document.getElementById('register'), - emailEl = document.getElementById('email'), - username_notify = document.getElementById('username-notify'), - email_notify = document.getElementById('email-notify'), - password_notify = document.getElementById('password-notify'), - password_confirm_notify = document.getElementById('password-confirm-notify'), - usernamevalid = false; - emailexists = false, - emailvalid = false, - userexists = false, - passwordsmatch = false, - passwordvalid = false; + 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'), + validationError = false; - $(username).on('keyup change', function() { - usernamevalid = utils.isUserNameValid(username.value); + function showError(element, msg) { + element.html(msg); + element.attr('class', 'alert alert-error'); + element.show(); + validationError = true; + } + + function showSuccess(element, msg) { + element.html(msg); + element.attr('class', 'alert alert-success'); + element.show(); + } - - if(username.value.length < 3) { - username_notify.innerHTML = 'Username too short'; - username_notify.className = 'label label-important'; - } else if(username.value.length > 13) { - username_notify.innerHTML = 'Username too long'; - username_notify.className = 'label label-important'; - } else if(!usernamevalid) { - username_notify.innerHTML = 'Invalid username'; - username_notify.className = 'label label-important'; - } else { - socket.emit('user.exists', {username: username.value}); + function validateEmail() { + if(!emailEl.val()) { + validationError = true; + email_notify.hide(); + return; } - }); - $(emailEl).on('keyup change', function() { - emailvalid = utils.isEmailValid(email.value); - - if(!emailvalid) { - email_notify.innerHTML = 'Invalid email address'; - email_notify.className = 'label label-important'; + if(!utils.isEmailValid(emailEl.val())) { + showError(email_notify, 'Invalid email address.'); } else - socket.emit('user.email.exists', { email: emailEl.value }); + socket.emit('user.email.exists', { email: emailEl.val() }); + } + + emailEl.on('blur', function() { + validateEmail(); + }); + + function validateUsername() { + if(!username.val()) { + validationError = true; + username_notify.hide(); + return; + } + + 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())) { + showError(username_notify, 'Invalid username!'); + } else { + socket.emit('user.exists', {username: username.val()}); + } + } + + username.on('blur', function() { + validateUsername(); }); - $(password).on('keyup', function() { - passwordvalid = utils.isPasswordValid(password.value); - if (password.value.length < 6) { - password_notify.innerHTML = 'Password too short'; - password_notify.className = 'label label-important'; - } else if(!passwordvalid) { - password_notify.innerHTML = 'Invalid password'; - password_notify.className = 'label label-important'; - } else { - password_notify.innerHTML = 'OK!'; - password_notify.className = 'label label-success'; + function validatePassword() { + if(!password.val()){ + validationError = true; + password_notify.hide(); + return; } - if(password.value !== password_confirm.value) { - password_confirm_notify.innerHTML = 'Passwords must match!'; - password_confirm_notify.className = 'label label-important'; - passwordsmatch = false; + if (password.val().length < config.minimumPasswordLength) { + showError(password_notify, 'Password too short!'); + } else if(password.val().length > config.maximumPasswordLength) { + showError(password_notify, 'Password too long!'); + } else if(!utils.isPasswordValid(password.val())) { + showError(password_notify, 'Invalid password!'); + } else { + showSuccess(password_notify, 'OK!'); } + + 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() { - if(password.value !== password_confirm.value) { - password_confirm_notify.innerHTML = 'Passwords must match!'; - password_confirm_notify.className = 'label label-important'; - passwordsmatch = false; + function validatePasswordConfirm() { + if(!password.val() || password_notify.hasClass('alert-error')) { + password_confirm_notify.hide(); + return; } - else { - password_confirm_notify.innerHTML = 'OK!'; - password_confirm_notify.className = 'label label-success'; - passwordsmatch = true; + + if(password.val() !== password_confirm.val()) { + showError(password_confirm_notify, 'Passwords must match!'); + } else { + showSuccess(password_confirm_notify, 'OK!'); } + } + + $(password_confirm).on('blur', function() { + validatePasswordConfirm(); }); ajaxify.register_events(['user.exists', 'user.email.exists']); socket.on('user.exists', function(data) { - userexists = data.exists; if (data.exists === true) { - username_notify.innerHTML = 'Username exists'; - username_notify.className = 'label label-important'; + showError(username_notify, 'Username already taken!'); } else { - username_notify.innerHTML = 'OK!'; - username_notify.className = 'label label-success'; + showSuccess(username_notify, 'OK!'); } }); socket.on('user.email.exists', function(data) { - emailexists = data.exists; - if (data.exists === true) { - email_notify.innerHTML = 'Email Address exists'; - email_notify.className = 'label label-important'; - } - else { - email_notify.innerHTML = 'OK!'; - email_notify.className = 'label label-success'; + showError(email_notify, 'Email address already taken!'); + } else { + showSuccess(email_notify, 'OK!'); } }); // Alternate Logins - var altLoginEl = document.querySelector('.alt-logins'); - altLoginEl.addEventListener('click', function(e) { - 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'); - } + $('.alt-logins li').on('click', function(e) { + document.location.href = $(this).attr('data-url'); }); function validateForm() { - var validated = true; + validationError = false; - if (username.value.length < 2 || !usernamevalid) { - username_notify.innerHTML = 'Invalid username'; - username_notify.className = 'label label-important'; - validated = false; - } + validateEmail(); + validateUsername(); + validatePassword(); + validatePasswordConfirm(); - if (password.value.length < 5) { - password_notify.innerHTML = 'Password too short'; - validated = false; - } - - if(password.value !== password_confirm.value) { - password_confirm_notify.innerHTML = 'Passwords must match!'; - } - - if (!emailvalid) { - email_notify.innerHTML = 'Invalid email address'; - validated = false; - } - - if(emailexists) { - email_notify.innerHTML = 'Email Address exists'; - validated = false; - } - - if(userexists || !passwordsmatch || !passwordvalid) - validated = false; - - return validated; + return validationError; } - register.addEventListener('click', function(e) { - if (!validateForm()) e.preventDefault(); - }, false); + register.on('click', function(e) { + if (validateForm()) e.preventDefault(); + }); }()); diff --git a/public/src/utils.js b/public/src/utils.js index b3d3f756f4..790fc9754c 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -91,11 +91,11 @@ }, 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) { - return password && password.indexOf(' ') === -1 && password.length > 5; + return password && password.indexOf(' ') === -1; }, // Blatently stolen from: http://phpjs.org/functions/strip_tags/ diff --git a/public/templates/admin/settings.tpl b/public/templates/admin/settings.tpl index ca92b0faf3..1d3bc5311a 100644 --- a/public/templates/admin/settings.tpl +++ b/public/templates/admin/settings.tpl @@ -50,6 +50,14 @@ +
+

User Settings

+
+ Minimum Username Length

+ Maximum Username Length

+
+
+

Post Settings

diff --git a/public/templates/register.tpl b/public/templates/register.tpl index 0656336f43..29eb260ddd 100644 --- a/public/templates/register.tpl +++ b/public/templates/register.tpl @@ -1,13 +1,31 @@

Register

- -
-
-
-
- - + +
+ + + + Your email won't be shown to the public unless you want. + + + + + A unique username. {minimumUsernameLength}-{maximumUsernameLength} characters. Others can mention you with @username. + + + + + {minimumPasswordLength}-{maximumPasswordLength} characters. + + + + + + +
+ +
diff --git a/src/install.js b/src/install.js index 1afd20ad69..6431b0a689 100644 --- a/src/install.js +++ b/src/install.js @@ -88,6 +88,10 @@ var async = require('async'), meta.configs.set('postDelay', 10000); meta.configs.set('minimumPostLength', 8); 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', ''); install.save(server_conf, client_conf, callback); diff --git a/src/routes/api.js b/src/routes/api.js index cca3522fa3..88cc74495b 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -22,6 +22,10 @@ var user = require('./../user.js'), config['minimumTitleLength'] = meta.config['minimumTitleLength']; config['minimumPostLength'] = meta.config['minimumPostLength']; 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); }); @@ -97,7 +101,10 @@ var user = require('./../user.js'), } 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); }); diff --git a/src/websockets.js b/src/websockets.js index c98ec013f5..c62f51e7e1 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -217,9 +217,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), }); socket.on('user.exists', function(data) { - user.exists(utils.slugify(data.username), function(exists){ - socket.emit('user.exists', {exists: exists}); - }); + if(data.username) { + user.exists(utils.slugify(data.username), function(exists){ + socket.emit('user.exists', {exists: exists}); + }); + } }); socket.on('user.count', function(data) {