From 20aa5d439eb38493ea6c3d68f70a38bb73a76659 Mon Sep 17 00:00:00 2001 From: Baris Soner Usakli Date: Tue, 30 Apr 2013 12:40:16 -0400 Subject: [PATCH 01/21] log server errors in browser added uid to posts --- .project | 12 ++++++++++++ app.js | 8 +++++++- public/src/app.js | 4 ++++ src/posts.js | 10 ++++++---- src/topics.js | 2 +- 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 .project diff --git a/.project b/.project new file mode 100644 index 0000000000..d382cb0b53 --- /dev/null +++ b/.project @@ -0,0 +1,12 @@ + + + node-forum + + + + + + + com.aptana.projects.webnature + + diff --git a/app.js b/app.js index 8732c4aee4..b9759de5bc 100644 --- a/app.js +++ b/app.js @@ -17,6 +17,12 @@ global.modules = modules; // global.uid = 1; +process.on('uncaughtException', function(err) { + // handle the error safely + console.log("error message "+err); + global.socket.emit('event:consolelog',{type:'uncaughtException',stack:err.stack,error:err.toString()}); +}); + (function(config) { config['ROOT_DIRECTORY'] = __dirname; @@ -25,6 +31,6 @@ global.modules = modules; // modules.webserver.init(); modules.websockets.init(); - + }(global.configuration)); \ No newline at end of file diff --git a/public/src/app.js b/public/src/app.js index 0fdd83a550..8b50d34af6 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -18,6 +18,10 @@ var socket, socket.on('event:alert', function(data) { app.alert(data); }); + + socket.on('event:consolelog', function(data) { + console.log(data); + }); }, async: false diff --git a/src/posts.js b/src/posts.js index 78e55d4562..c34d088232 100644 --- a/src/posts.js +++ b/src/posts.js @@ -62,13 +62,15 @@ var RDB = require('./redis.js'); }; - Posts.create = function(content, callback) { - if (global.uid === null) return; - + Posts.create = function(uid, content, callback) { + console.log("global uid "+uid); + + if (uid === null) return; + RDB.incr('global:next_post_id', function(pid) { // Posts Info RDB.set('pid:' + pid + ':content', content); - RDB.set('pid:' + pid + ':uid', global.uid); + RDB.set('pid:' + pid + ':uid', uid); RDB.set('pid:' + pid + ':timestamp', new Date().getTime()); // User Details - move this out later diff --git a/src/topics.js b/src/topics.js index cd06162091..fdc76cd8c7 100644 --- a/src/topics.js +++ b/src/topics.js @@ -137,7 +137,7 @@ var RDB = require('./redis.js'), RDB.set('topic:slug:' + slug + ':tid', tid); // Posts - posts.create(content, function(pid) { + posts.create(uid, content, function(pid) { RDB.lpush('tid:' + tid + ':posts', pid); }); From 93d7f8d52c2cbbef6f9e02144da2e6bf6be3efeb Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 1 May 2013 15:41:01 +0000 Subject: [PATCH 02/21] hide latest user block if doesn't exist --- public/templates/footer.tpl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/templates/footer.tpl b/public/templates/footer.tpl index 0d5ee09518..b89ed859dd 100644 --- a/public/templates/footer.tpl +++ b/public/templates/footer.tpl @@ -24,7 +24,11 @@ }); socket.emit('user.latest', {}); socket.on('user.latest', function(data) { - latest_user.innerHTML = "The most recent user to register is " + data.username + "."; + if (data.username == '') { + latest_user.innerHTML = ''; + } else { + latest_user.innerHTML = "The most recent user to register is " + data.username + "."; + } }); socket.emit('api:user.active.get'); socket.on('api:user.active.get', function(data) { From bb8d5098e4e1ac26a59557f4139bf84b0a62c516 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 1 May 2013 15:44:54 +0000 Subject: [PATCH 03/21] fixed bottom border on last topicrow --- public/templates/header.tpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/templates/header.tpl b/public/templates/header.tpl index 6bb2801fab..d18ac06159 100644 --- a/public/templates/header.tpl +++ b/public/templates/header.tpl @@ -100,7 +100,9 @@ cursor: pointer; border-bottom: 1px solid #eee; padding: 10px; - + } + .topic-container li:last-child { + border-bottom: 0; } .topic-container li.topic-row:hover { background-color: #eee; From a655ebb29083ac4e4f6273e05d8d1d46d2c8272d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 1 May 2013 16:14:09 +0000 Subject: [PATCH 04/21] most users ever online block --- public/templates/footer.tpl | 14 +++++++--- src/user.js | 52 ++++++++++++++++++++++++------------- src/websockets.js | 4 +++ 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/public/templates/footer.tpl b/public/templates/footer.tpl index b89ed859dd..1036460e01 100644 --- a/public/templates/footer.tpl +++ b/public/templates/footer.tpl @@ -4,7 +4,7 @@ diff --git a/public/templates/topic.tpl b/public/templates/topic.tpl index b5e32b08c4..fa901d285c 100644 --- a/public/templates/topic.tpl +++ b/public/templates/topic.tpl @@ -13,4 +13,4 @@ var post_reply = document.getElementById('post_reply'); post_reply.onclick = function() { app.open_post_window('reply', {TOPIC_ID}); } - + diff --git a/src/posts.js b/src/posts.js index 4c51b92ea5..b3117b3286 100644 --- a/src/posts.js +++ b/src/posts.js @@ -48,7 +48,7 @@ var RDB = require('./redis.js'), }); } - callback({'posts': posts, 'TOPIC_ID': tid}); + callback({'TOPIC_ID': tid, 'posts': posts}); }); } else { callback({}); @@ -60,8 +60,17 @@ var RDB = require('./redis.js'), } - Posts.reply = function() { + Posts.reply = function(tid, uid, content) { + Posts.create(uid, content, function(pid) { + RDB.rpush('tid:' + tid + ':posts', pid); + global.socket.emit('event:alert', { + title: 'Reply Successful', + message: 'You have successfully replied. Click here to view your reply.', + type: 'notify', + timeout: 2000 + }); + }); }; Posts.create = function(uid, content, callback) { diff --git a/src/redis.js b/src/redis.js index 0a6e633272..a71cc1e3d5 100644 --- a/src/redis.js +++ b/src/redis.js @@ -76,6 +76,10 @@ db.lpush(key, item); } + RedisDB.rpush = function(key, item) { + db.rpush(key, item); + } + RedisDB.lrange = function(key, start, end, callback, error_handler) { db.lrange(key, start, end, function(error, data) { return_handler(error, data, callback, error_handler); diff --git a/src/templates.js b/src/templates.js index c74aba7934..8fb384a2e6 100644 --- a/src/templates.js +++ b/src/templates.js @@ -93,7 +93,7 @@ var fs = require('fs'); block = parse(data[d], namespace, block); template = setBlock(regex, block, template); - } else { + } else { template = replace(namespace + d, data[d], template); } } diff --git a/src/websockets.js b/src/websockets.js index ba6786fc80..aa8fb58ac1 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -93,6 +93,10 @@ var SocketIO = require('socket.io').listen(global.server), modules.topics.post(uid, data.title, data.content); }); + socket.on('api:posts.reply', function(data) { + modules.posts.reply(data.topic_id, uid, data.content); + }); + socket.on('api:user.active.get', function() { modules.user.active.get(); }); From b2bc967e9b63508590ab490717469841481e6d5a Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 1 May 2013 21:26:47 +0000 Subject: [PATCH 14/21] got ajaxify working with threads, some cleanup, fixed anon posting, got rid of a few more global.sockets calls --- public/src/ajaxify.js | 4 ++-- public/src/app.js | 6 +++++- public/src/templates.js | 9 +++++---- public/templates/home.tpl | 2 +- src/posts.js | 4 +--- src/topics.js | 4 ++-- src/webserver.js | 26 +++++++++++++++----------- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index ac3d7d4db0..9646720521 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -22,8 +22,8 @@ var ajaxify = {}; ajaxify.go = function(url, callback) { var url = url.replace(/\/$/, ""); - var tpl_url = (url === '') ? 'home' : url; - + var tpl_url = (url === '') ? 'home' : url.split('/')[0]; + if (templates[tpl_url]) { window.history.pushState({}, url, "/" + url); diff --git a/public/src/app.js b/public/src/app.js index 20732a2b5a..1061b2d935 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -1,6 +1,8 @@ var socket, config, - app = {}; + app = {}, + + API_URL = null; // todo: cleanup,etc (function() { @@ -8,6 +10,8 @@ var socket, $.ajax({ url: '/config.json?v=' + new Date().getTime(), success: function(data) { + API_URL = data.api_url; + config = data; socket = io.connect('http://' + config.socket.address + config.socket.port? ':' + config.socket.port : ''); diff --git a/public/src/templates.js b/public/src/templates.js index fe7036a778..7605f9191a 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -26,7 +26,7 @@ var templates = {}; function init() { loadTemplates([ - 'header', 'footer', 'register', 'home', + 'header', 'footer', 'register', 'home', 'topic', 'login', 'reset', 'reset_code', 'account_settings', 'emails/reset', 'emails/reset_plaintext' ]); @@ -116,10 +116,11 @@ function load_template(callback) { rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''); var url = location.href.replace(rootUrl +'/', ''); - if (url == '') url = 'home'; - jQuery.get('api/' + url, function(data) { + url = (url === '') ? 'home' : url; + + jQuery.get(API_URL + url, function(data) { - document.getElementById('content').innerHTML = templates[url].parse(JSON.parse(data)); + document.getElementById('content').innerHTML = templates[url.split('/')[0]].parse(JSON.parse(data)); if (callback) callback(); }); } \ No newline at end of file diff --git a/public/templates/home.tpl b/public/templates/home.tpl index e65f469776..b49f4c2e85 100644 --- a/public/templates/home.tpl +++ b/public/templates/home.tpl @@ -1,7 +1,7 @@
    -
  • +
  • {topics.title}

    Posted {topics.relativeTime} by user {topics.uid}. {topics.post_count} posts.

  • diff --git a/src/posts.js b/src/posts.js index b3117b3286..07e8fc239a 100644 --- a/src/posts.js +++ b/src/posts.js @@ -64,7 +64,7 @@ var RDB = require('./redis.js'), Posts.create(uid, content, function(pid) { RDB.rpush('tid:' + tid + ':posts', pid); - global.socket.emit('event:alert', { + socket.emit('event:alert', { title: 'Reply Successful', message: 'You have successfully replied. Click here to view your reply.', type: 'notify', @@ -74,8 +74,6 @@ var RDB = require('./redis.js'), }; Posts.create = function(uid, content, callback) { - console.log("global uid "+uid); - if (uid === null) return; RDB.incr('global:next_post_id', function(pid) { diff --git a/src/topics.js b/src/topics.js index aa41f8684e..15cadbb806 100644 --- a/src/topics.js +++ b/src/topics.js @@ -96,7 +96,7 @@ var RDB = require('./redis.js'), Topics.post = function(uid, title, content, category) { if (uid === 0) { - global.socket.emit('event:alert', { + socket.emit('event:alert', { title: 'Thank you for posting', message: 'Since you are unregistered, your post is awaiting approval. Click here to register now.', type: 'warning', @@ -145,7 +145,7 @@ var RDB = require('./redis.js'), RDB.lpush('uid:' + uid + ':topics', tid); - global.socket.emit('event:alert', { + socket.emit('event:alert', { title: 'Thank you for posting', message: 'You have successfully posted. Click here to view your post.', type: 'notify', diff --git a/src/webserver.js b/src/webserver.js index e895b72200..740d0aefdf 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -69,32 +69,36 @@ var express = require('express'), }); - // need a proper way to combine these two routes together - app.get('/topics/:topic_id', function(req, res) { + function generate_topic_body(req, res) { global.modules.topics.generate_topic_body(function(topic_body) { res.send(templates['header'] + topic_body + templates['footer']); - }, req.params.topic_id) - }); - app.get('/topics/:topic_id/:slug', function(req, res) { - global.modules.topics.generate_topic_body(function(topic_body) { - res.send(templates['header'] + topic_body + templates['footer']); - }, req.params.topic_id) - }); + }, req.params.topic_id); + } + app.get('/topic/:topic_id', generate_topic_body); + app.get('/topic/:topic_id*', generate_topic_body); - app.get('/api/:method', function(req, res) { + function api_method(req, res) { switch(req.params.method) { case 'home' : global.modules.topics.get(function(data) { res.send(JSON.stringify(data)); }); break; + case 'topic' : + global.modules.posts.get(function(data) { + res.send(JSON.stringify(data)); + }, req.params.id); + break; default : res.send('{}'); break; } - }); + } + app.get('/api/:method', api_method); + app.get('/api/:method/:id', api_method); + app.get('/api/:method/:id*', api_method); app.get('/login', function(req, res) { res.send(templates['header'] + templates['login'] + templates['footer']); From 1bec9fc5aa86af17cea52edbe6c0ca14eb61f810 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 1 May 2013 21:52:40 +0000 Subject: [PATCH 15/21] breadcrumbs, and changed home in nav to 'forum' --- public/src/app.js | 11 ++++-- public/src/templates.js | 1 - public/templates/header.tpl | 9 ++++- public/templates/topic.tpl | 9 ++++- src/posts.js | 78 ++++++++++++++++++------------------- 5 files changed, 63 insertions(+), 45 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index 1061b2d935..a45effa90d 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -85,12 +85,14 @@ var socket, var post_window = null, submit_post_btn = null, post_title = null, + reply_title = null, post_content = null; - app.open_post_window = function(post_mode, id) { + app.open_post_window = function(post_mode, id, title) { submit_post_btn = submit_post_btn || document.getElementById('submit_post_btn'); post_title = post_title || document.getElementById('post_title'); + reply_title = reply_title || document.getElementById('reply_title'); post_content = post_content || document.getElementById('post_content'); @@ -98,13 +100,16 @@ var socket, jQuery(post_window).slideToggle(250); if (post_mode == null || post_mode == 'topic') { - post_title.style.display = 'block'; + post_title.style.display = "block"; + reply_title.style.display = "none"; post_title.focus(); submit_post_btn.onclick = function() { app.post_topic(); } } else { - post_title.style.display = 'none'; + post_title.style.display = "none"; + reply_title.style.display = "block"; + reply_title.innerHTML = 'You are replying to "' + title + '"'; post_content.focus(); submit_post_btn.onclick = function() { app.post_reply(id) diff --git a/public/src/templates.js b/public/src/templates.js index 7605f9191a..e7ead3b743 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -119,7 +119,6 @@ function load_template(callback) { url = (url === '') ? 'home' : url; jQuery.get(API_URL + url, function(data) { - document.getElementById('content').innerHTML = templates[url.split('/')[0]].parse(JSON.parse(data)); if (callback) callback(); }); diff --git a/public/templates/header.tpl b/public/templates/header.tpl index 3f0ac6af5a..45604a7adf 100644 --- a/public/templates/header.tpl +++ b/public/templates/header.tpl @@ -117,6 +117,11 @@ font-size: 12px; font-weight: bold; } + #reply_title { + font-size: 17px; + padding-top: 14px; + font-weight: 600; + } @@ -132,7 +137,7 @@
    +
    \ No newline at end of file diff --git a/public/templates/topic.tpl b/public/templates/topic.tpl index fa901d285c..6abc380cf8 100644 --- a/public/templates/topic.tpl +++ b/public/templates/topic.tpl @@ -1,3 +1,10 @@ +
    + +
    +
    • @@ -11,6 +18,6 @@ diff --git a/src/posts.js b/src/posts.js index 07e8fc239a..9e46407864 100644 --- a/src/posts.js +++ b/src/posts.js @@ -16,47 +16,47 @@ var RDB = require('./redis.js'), if (start == null) start = 0; if (end == null) end = start + 10; - RDB.lrange('tid:' + tid + ':posts', start, end, function(pids) { - - var content = [], - uid = [], - timestamp = []; - - for (var i=0, ii=pids.length; i 0) { - RDB.multi() - .mget(content) - .mget(uid) - .mget(timestamp) - .exec(function(err, replies) { - content = replies[0]; - uid = replies[1]; - timestamp = replies[2]; - - var posts = []; - for (var i=0, ii=content.length; i 0) { + RDB.multi() + .mget(content) + .mget(uid) + .mget(timestamp) + .exec(function(err, replies) { + content = replies[0]; + uid = replies[1]; + timestamp = replies[2]; + + var posts = []; + for (var i=0, ii=content.length; i Date: Wed, 1 May 2013 22:19:54 +0000 Subject: [PATCH 16/21] small refactor of routing, cleanup, templates are now parsed entirely on client side for /, /register, /login for now --- public/src/ajaxify.js | 2 +- public/src/templates.js | 16 +++++++++++++++- public/templates/header.tpl | 29 +++++++++++++++++++++++++++++ public/templates/topic.tpl | 4 ++-- src/webserver.js | 26 +++++++++++++------------- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 9646720521..ac96a7d6be 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -22,7 +22,7 @@ var ajaxify = {}; ajaxify.go = function(url, callback) { var url = url.replace(/\/$/, ""); - var tpl_url = (url === '') ? 'home' : url.split('/')[0]; + var tpl_url = (url === '' || url === '/') ? 'home' : url.split('/')[0]; if (templates[tpl_url]) { window.history.pushState({}, url, "/" + url); diff --git a/public/src/templates.js b/public/src/templates.js index e7ead3b743..f18b1e50b6 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -1,9 +1,17 @@ var templates = {}; (function() { + var ready_callback; + + templates.ready = function(callback) { + //quick implementation because introducing a lib to handle several async callbacks + if (callback == null) ready_callback(); + else ready_callback = callback; + } function loadTemplates(templatesToLoad) { var timestamp = new Date().getTime(); + var loaded = templatesToLoad.length; for (var t in templatesToLoad) { (function(file) { @@ -18,6 +26,12 @@ var templates = {}; template.prototype.html = String(html); templates[file] = new template; + + loaded--; + if (loaded == 0) templates.ready(); + }).fail(function() { + loaded--; + if (loaded == 0) templates.ready(); }); }(templatesToLoad[t])); } @@ -116,7 +130,7 @@ function load_template(callback) { rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''); var url = location.href.replace(rootUrl +'/', ''); - url = (url === '') ? 'home' : url; + url = (url === '' || url === '/') ? 'home' : url; jQuery.get(API_URL + url, function(data) { document.getElementById('content').innerHTML = templates[url.split('/')[0]].parse(JSON.parse(data)); diff --git a/public/templates/header.tpl b/public/templates/header.tpl index 45604a7adf..a22c9e7e0a 100644 --- a/public/templates/header.tpl +++ b/public/templates/header.tpl @@ -108,6 +108,35 @@ background-color: #eee; } + + + .post-container { + list-style-type: none; + padding: 0; + margin: 0; + border: 1px solid #eee; + + } + .post-container li.post-row:nth-child(odd) { + background-color:#fdfdfd; + } + .post-container li.post-row:nth-child(even) { + background-color:#fff; + } + .post-container li.post-row { + cursor: pointer; + border-bottom: 1px solid #eee; + padding: 10px; + } + .post-container li:last-child { + border-bottom: 0; + } + .post-container li.post-row:hover { + background-color: #eee; + } + + + #user_label img { border: 1px solid #999; margin-right: 8px; diff --git a/public/templates/topic.tpl b/public/templates/topic.tpl index 6abc380cf8..4c8ebfa9cb 100644 --- a/public/templates/topic.tpl +++ b/public/templates/topic.tpl @@ -5,9 +5,9 @@
    -
      +
        -
      • +
      • {posts.content}

        Posted {posts.relativeTime} by user {posts.uid}.

      • diff --git a/src/webserver.js b/src/webserver.js index 740d0aefdf..8a7a229c50 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -62,12 +62,20 @@ var express = require('express'), // Useful if you want to use app.put and app.delete (instead of app.post all the time) // app.use(express.methodOverride()); - app.get('/', function(req, res) { - global.modules.topics.generate_forum_body(function(forum_body) { - res.send(templates['header'] + forum_body + templates['footer']); - }); - }); + // Basic Routes (entirely client-side parsed, goal is to move the rest of the crap in this file into this one section) + (function() { + var routes = ['', 'login', 'register']; + + for (var i=0, ii=routes.length; itemplates.ready(function(){ajaxify.go("' + route + '");});' + templates['footer']); + }); + }(routes[i])); + } + }()); + function generate_topic_body(req, res) { global.modules.topics.generate_topic_body(function(topic_body) { @@ -100,10 +108,6 @@ var express = require('express'), app.get('/api/:method/:id', api_method); app.get('/api/:method/:id*', api_method); - app.get('/login', function(req, res) { - res.send(templates['header'] + templates['login'] + templates['footer']); - }); - app.get('/logout', function(req, res) { console.log('info: [Auth] Session ' + res.sessionID + ' logout (uid: ' + global.uid + ')'); global.modules.user.logout(req.sessionID, function(logout) { @@ -124,10 +128,6 @@ var express = require('express'), res.send(templates['header'] + templates['reset'] + templates['footer']); }); - app.get('/register', function(req, res) { - res.send(templates['header'] + templates['register'] + templates['footer']); - }); - app.get('/403', function(req, res) { res.send(templates['header'] + templates['403'] + templates['footer']); }); From d712f571411def4236f5e32642cde0af93923c79 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 May 2013 21:03:37 -0400 Subject: [PATCH 17/21] refactored user authentication (passport-local, instead of my own half-baked implementation) --- package.json | 4 ++- public/templates/login.tpl | 35 ++++--------------- src/user.js | 53 +++++++++++++++++++++++++++++ src/webserver.js | 70 ++++++++++++++++++++++++++------------ src/websockets.js | 5 +-- 5 files changed, 114 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index a496ed42f6..645c519fe6 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,9 @@ "cookie": "0.0.6", "connect-redis": "1.4.5", "path": "0.4.9", - "crypto": "0.0.3" + "crypto": "0.0.3", + "passport": "0.1.16", + "passport-local": "0.1.6" }, "devDependencies": {}, "optionalDependencies": {}, diff --git a/public/templates/login.tpl b/public/templates/login.tpl index e9a96e7862..c430b90f17 100644 --- a/public/templates/login.tpl +++ b/public/templates/login.tpl @@ -4,33 +4,10 @@ Failed Login Attempt

        -
        -
        -   +
        +
        +
        +   +
        Forgot Password? - - \ No newline at end of file + \ No newline at end of file diff --git a/src/user.js b/src/user.js index a743a39abe..6be93a4e99 100644 --- a/src/user.js +++ b/src/user.js @@ -76,6 +76,51 @@ var config = require('../config.js'), }); }; + User.loginViaLocal = function(username, password, next) { + if (!username || !password) { + return next({ + status: 'error', + message: 'invalid-user' + }); + } else { + RDB.get('username:' + username + ':uid', function(uid) { + if (uid == null) { + return next({ + status: 'error', + message: 'invalid-user' + }); + } + + RDB.get('uid:' + uid + ':password', function(user_password) { + if (password == user_password) { + // Start, replace, or extend a session + // RDB.get('sess:' + user.sessionID, function(session) { + // if (session !== user.sessionID) { + // RDB.set('sess:' + user.sessionID + ':uid', uid, 60*60*24*14); // Login valid for two weeks + // RDB.set('uid:' + uid + ':session', user.sessionID, 60*60*24*14); + // } else { + // RDB.expire('sess:' + user.sessionID + ':uid', 60*60*24*14); // Defer expiration to two weeks from now + // RDB.expire('uid:' + uid + ':session', 60*60*24*14); + // } + // }); + + next({ + status: "ok", + user: { + uid: uid + } + }); + } else { + next({ + status: 'error', + message: 'invalid-password' + }); + } + }); + }); + } + } + User.logout = function(sessionID, callback) { User.get_uid_by_session(sessionID, function(uid) { if (uid) { @@ -157,6 +202,14 @@ var config = require('../config.js'), RDB.get('sess:' + session + ':uid', callback); }; + User.session_ping = function(sessionID, uid) { + // Start, replace, or extend a session + RDB.get('sess:' + sessionID, function(session) { + RDB.set('sess:' + sessionID + ':uid', uid, 60*60*24*14); // Login valid for two weeks + RDB.set('uid:' + uid + ':session', sessionID, 60*60*24*14); + }); + } + User.reset = { validate: function(code, callback) { if (typeof callback !== 'function') callback = undefined; diff --git a/src/webserver.js b/src/webserver.js index e895b72200..13f626c67e 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -5,7 +5,26 @@ var express = require('express'), path = require('path'), config = require('../config.js'), redis = require('redis'), - redisServer = redis.createClient(config.redis.port, config.redis.host, config.redis.options); + redisServer = redis.createClient(config.redis.port, config.redis.host, config.redis.options), + passport = require('passport'), + passportLocal = require('passport-local').Strategy; + +passport.use(new passportLocal(function(user, password, next) { + global.modules.user.loginViaLocal(user, password, function(login) { + if (login.status === 'ok') next(null, login.user); + else next(null, false, login); + }); +})); + +passport.serializeUser(function(user, done) { + done(null, user.uid); +}); + +passport.deserializeUser(function(uid, done) { + done(null, { + uid: uid + }); +}); (function(app) { var templates = global.templates; @@ -32,26 +51,34 @@ var express = require('express'), secret: config.secret, key: 'express.sid' })); + app.use(passport.initialize()); + app.use(passport.session()); app.use(function(req, res, next) { // Don't bother with session handling for API requests if (/^\/api\//.test(req.url)) return next(); - if (req.session.uid === undefined) { - console.log('info: [Auth] First load, retrieving uid...'); - global.modules.user.get_uid_by_session(req.sessionID, function(uid) { - if (uid !== null) { - req.session.uid = uid; - console.log('info: [Auth] uid ' + req.session.uid + ' found. Welcome back.'); - } else { - req.session.uid = 0; - console.log('info: [Auth] No login session found.'); - } - }); - } else { - // console.log('SESSION: ' + req.sessionID); - // console.log('info: [Auth] Ping from uid ' + req.session.uid); + if (req.user && req.user.uid) { + console.log('** YOU ARE LOGGED IN AS UID: ' + req.user.uid + ' ***'); + global.modules.user.session_ping(req.sessionID, req.user.uid); } + // if (req.session.uid === undefined) { + // console.log('info: [Auth] First load, retrieving uid...'); + + // global.modules.user.get_uid_by_session(req.sessionID, function(uid) { + // if (uid !== null) { + // req.session.uid = uid; + // console.log('info: [Auth] uid ' + req.session.uid + ' found. Welcome back.'); + // } else { + // req.session.uid = 0; + // console.log('info: [Auth] No login session found.'); + // } + // }); + // } else { + // // console.log('SESSION: ' + req.sessionID); + // // console.log('info: [Auth] Ping from uid ' + req.session.uid); + // } + // (Re-)register the session as active global.modules.user.active.register(req.sessionID); @@ -100,16 +127,17 @@ var express = require('express'), res.send(templates['header'] + templates['login'] + templates['footer']); }); + app.post('/login', passport.authenticate('local', { + successRedirect: '/', + failureRedirect: '/login' + })); + app.get('/logout', function(req, res) { console.log('info: [Auth] Session ' + res.sessionID + ' logout (uid: ' + global.uid + ')'); global.modules.user.logout(req.sessionID, function(logout) { - if (logout === true) { - delete(req.session.uid); - req.session.destroy(); - } + req.logout(); + res.send(templates['header'] + templates['logout'] + templates['footer']); }); - - res.send(templates['header'] + templates['logout'] + templates['footer']); }); app.get('/reset/:code', function(req, res) { diff --git a/src/websockets.js b/src/websockets.js index ba6786fc80..a83fea5785 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -1,6 +1,7 @@ var SocketIO = require('socket.io').listen(global.server), cookie = require('cookie'), - connect = require('connect'); + connect = require('connect'), + config = require('../config.js'); (function(io) { var modules = null, @@ -16,7 +17,7 @@ var SocketIO = require('socket.io').listen(global.server), io.set('authorization', function(handshakeData, accept) { if (handshakeData.headers.cookie) { handshakeData.cookie = cookie.parse(handshakeData.headers.cookie); - handshakeData.sessionID = connect.utils.parseSignedCookie(handshakeData.cookie['express.sid'], 'nodebb'); + handshakeData.sessionID = connect.utils.parseSignedCookie(handshakeData.cookie['express.sid'], config.secret); if (handshakeData.cookie['express.sid'] == handshakeData.sessionID) { return accept('Cookie is invalid.', false); From 829dae05c55b370281200dd3aff504676b5351f3 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 May 2013 22:00:49 -0400 Subject: [PATCH 18/21] updating header to show user label when logged in, and register/login when not --- public/templates/footer.tpl | 31 ++++++++++++++++++++++++------- public/templates/header.tpl | 8 ++++---- src/user.js | 4 +++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/public/templates/footer.tpl b/public/templates/footer.tpl index 6d09ca3b16..dd3de05b00 100644 --- a/public/templates/footer.tpl +++ b/public/templates/footer.tpl @@ -17,7 +17,8 @@ latest_user = document.getElementById('latest_user'), active_users = document.getElementById('active_users'), user_label = document.getElementById('user_label'), - active_record = document.getElementById('active_record'); + active_record = document.getElementById('active_record'), + right_menu = document.getElementById('right-menu'); socket.emit('user.count', {}); socket.on('user.count', function(data) { @@ -44,14 +45,30 @@ }); socket.emit('api:user.get', { fields: ['username', 'picture'] }); socket.on('api:user.get', function(data) { - var gravatar = document.createElement('img'), - name = document.createElement('span'); + if (data.uid > 0) { + var gravatar = document.createElement('img'), + name = document.createElement('span') + logoutEl = document.createElement('li'); - name.innerHTML = data['username']; - gravatar.src = data['picture']; + logoutEl.innerHTML = 'Log out'; - user_label.appendChild(gravatar); - user_label.appendChild(name); + name.innerHTML = data['username']; + gravatar.src = data['picture']; + + user_label.innerHTML = ''; + user_label.appendChild(gravatar); + user_label.appendChild(name); + right_menu.appendChild(logoutEl); + } else { + var registerEl = document.createElement('li'), + loginEl = document.createElement('li'); + + registerEl.innerHTML = 'Register'; + loginEl.innerHTML = 'Login'; + + right_menu.appendChild(registerEl); + right_menu.appendChild(loginEl); + } }); }()); diff --git a/public/templates/header.tpl b/public/templates/header.tpl index a22c9e7e0a..1f517a7b4f 100644 --- a/public/templates/header.tpl +++ b/public/templates/header.tpl @@ -167,12 +167,12 @@ diff --git a/src/user.js b/src/user.js index 6be93a4e99..1610352477 100644 --- a/src/user.js +++ b/src/user.js @@ -10,7 +10,9 @@ var config = require('../config.js'), User.get = function(uid, fields) { if (uid > 0) { var keys = [], - returnData = {}, + returnData = { + uid: uid + }, removeEmail = false; if (!(fields instanceof Array)) fields = ['username', 'email']; From f68d9c6635495e1a9974c5a9c269220fdbc6df4e Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 2 May 2013 02:04:28 +0000 Subject: [PATCH 19/21] forgot to update config, derp --- public/config.default.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/config.default.json b/public/config.default.json index 67acc5b7d3..2d9225ec9e 100644 --- a/public/config.default.json +++ b/public/config.default.json @@ -2,5 +2,6 @@ "socket" : { "address" : "localhost", "port" : "4567" - } + }, + "api_url" : "localhost" } \ No newline at end of file From 3ef6cf6cb23f2220da5957d182090d23bb7cc828 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 May 2013 22:15:07 -0400 Subject: [PATCH 20/21] updaring config template --- public/config.default.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/config.default.json b/public/config.default.json index 2d9225ec9e..b3794291ce 100644 --- a/public/config.default.json +++ b/public/config.default.json @@ -3,5 +3,5 @@ "address" : "localhost", "port" : "4567" }, - "api_url" : "localhost" + "api_url" : "http://localhost:4567/api/" } \ No newline at end of file From de26a303d40980b9084c2f3b00679b8156ac060a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 May 2013 22:20:30 -0400 Subject: [PATCH 21/21] housekeeping --- src/templates.js | 4 ++-- src/webserver.js | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/templates.js b/src/templates.js index 8fb384a2e6..98e0ed6f99 100644 --- a/src/templates.js +++ b/src/templates.js @@ -26,8 +26,8 @@ var fs = require('fs'); Templates.init = function() { loadTemplates([ 'header', 'footer', 'register', 'home', 'topic', - 'login', 'reset', 'reset_code', 'account_settings', - 'logout', '403', + 'login', 'reset', 'reset_code', 'logout', + '403', 'emails/reset', 'emails/reset_plaintext' ]); } diff --git a/src/webserver.js b/src/webserver.js index c0b048a7ff..05268c36ec 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -58,7 +58,6 @@ passport.deserializeUser(function(uid, done) { if (/^\/api\//.test(req.url)) return next(); if (req.user && req.user.uid) { - console.log('** YOU ARE LOGGED IN AS UID: ' + req.user.uid + ' ***'); global.modules.user.session_ping(req.sessionID, req.user.uid); }