From 0243e9c5be8bef9aeaf4aeee65da79c0327f5eb1 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Aug 2013 12:14:27 -0400 Subject: [PATCH 1/3] 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 | 113 +++++++++++++++++++++++++-------------------- 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, 105 insertions(+), 87 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(); - - 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); - - 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(err) return callback(); + + 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; + 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() { + 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); - - if(topicData.deleted === '1') - return callback(null); + if (err) return callback(err); + else 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); + 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); + + postTools.toHTML(postData.content, function(err, content) { + postData.content = content; + posts.push(postData); + callback(null); + }); } - callback(null); }); - } - - async.eachSeries(pids, iterator, function(err) { + }, 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 2/3] refactored postTools.toHTML to fire post.parse hook, and removed auto-markdowning closed #214 --- package.json | 3 ++- src/postTools.js | 40 ++++++++++++++++++---------------------- 2 files changed, 20 insertions(+), 23 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 (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 (parsed && parsed.length > 0) { + var parsedContentDOM = cheerio.load(parsed); + var domain = nconf.get('url'); - if (href && !href.match(domain) && !utils.isRelativeUrl(href)) { - this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href)); - } - }); + 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, '

'); - } + 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 3/3] 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) {