diff --git a/.gitignore b/.gitignore index 283097a56e..c6ab6e2a8d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ Vagrantfile .vagrant provision.sh *.komodoproject + +feeds/recent.rss diff --git a/src/feed.js b/src/feed.js index 3088c5550d..ac35644fc7 100644 --- a/src/feed.js +++ b/src/feed.js @@ -2,12 +2,14 @@ var RDB = require('./redis.js'), posts = require('./posts.js'), topics = require('./topics.js'), + categories = require('./categories'), + fs = require('fs'), rss = require('rss'), winston = require('winston'), path = require('path'), nconf = require('nconf'), - categories = require('./categories'); + async = require('async'); Feed.defaults = { ttl: 60, @@ -26,43 +28,43 @@ } Feed.updateTopic = function (tid, callback) { - if (process.env.NODE_ENV === 'development') winston.info('[rss] Updating RSS feeds for topic ' + tid); - topics.getTopicWithPosts(tid, 0, 0, -1, function (err, topicData) { if (err) return callback(new Error('topic-invalid')); var feed = new rss({ - title: topicData.topic_name, - description: topicData.main_posts[0].content, - feed_url: Feed.defaults.baseUrl + '/topics/' + tid + '.rss', - site_url: nconf.get('url') + 'topic/' + topicData.slug, - image_url: topicData.main_posts[0].picture, - author: topicData.main_posts[0].username, - ttl: Feed.defaults.ttl - }), + title: topicData.topic_name, + description: topicData.main_posts[0].content, + feed_url: Feed.defaults.baseUrl + '/topics/' + tid + '.rss', + site_url: nconf.get('url') + 'topic/' + topicData.slug, + image_url: topicData.main_posts[0].picture, + author: topicData.main_posts[0].username, + ttl: Feed.defaults.ttl + }), topic_posts = topicData.main_posts.concat(topicData.posts), - title, postData, dateStamp; + dateStamp; // Add pubDate if topic contains posts if (topicData.main_posts.length > 0) feed.pubDate = new Date(parseInt(topicData.main_posts[0].timestamp, 10)).toUTCString(); - for (var i = 0, ii = topic_posts.length; i < ii; i++) { - if (topic_posts[i].deleted === '0') { - postData = topic_posts[i]; + async.each(topic_posts, function(postData, next) { + if (postData.deleted === '0') { dateStamp = new Date(parseInt(postData.edited === '0' ? postData.timestamp : postData.edited, 10)).toUTCString(); - title = 'Reply to ' + topicData.topic_name + ' on ' + dateStamp; feed.item({ - title: title, + title: 'Reply to ' + topicData.topic_name + ' on ' + dateStamp, description: postData.content, url: nconf.get('url') + 'topic/' + topicData.slug + '#' + postData.pid, author: postData.username, date: dateStamp }); } - } - Feed.saveFeed('feeds/topics/' + tid + '.rss', feed, function (err) { + next(); + }, function() { + if (process.env.NODE_ENV === 'development') { + winston.info('[rss] Re-generated RSS Feed for tid ' + tid + '.'); + } + if (callback) callback(); }); }); @@ -70,40 +72,75 @@ }; Feed.updateCategory = function (cid, callback) { - if (process.env.NODE_ENV === 'development') winston.info('[rss] Updating RSS feeds for category ' + cid); categories.getCategoryById(cid, 0, function (err, categoryData) { if (err) return callback(new Error('category-invalid')); var feed = new rss({ - title: categoryData.category_name, - description: categoryData.category_description, - feed_url: Feed.defaults.baseUrl + '/categories/' + cid + '.rss', - site_url: nconf.get('url') + 'category/' + categoryData.category_id, - ttl: Feed.defaults.ttl - }), - topics = categoryData.topics, - title, topicData, dateStamp; + title: categoryData.category_name, + description: categoryData.category_description, + feed_url: Feed.defaults.baseUrl + '/categories/' + cid + '.rss', + site_url: nconf.get('url') + 'category/' + categoryData.category_id, + ttl: Feed.defaults.ttl + }); // Add pubDate if category has topics if (categoryData.topics.length > 0) feed.pubDate = new Date(parseInt(categoryData.topics[0].lastposttime, 10)).toUTCString(); - for (var i = 0, ii = topics.length; i < ii; i++) { - topicData = topics[i]; - dateStamp = new Date(parseInt(topicData.lastposttime, 10)).toUTCString(); - title = topics[i].title; - + async.eachSeries(categoryData.topics, function(topicData, next) { feed.item({ - title: title, + title: topicData.title, url: nconf.get('url') + 'topic/' + topicData.slug, author: topicData.username, - date: dateStamp + date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() }); - } - Feed.saveFeed('feeds/categories/' + cid + '.rss', feed, function (err) { - if (callback) callback(); + next(); + }, function() { + Feed.saveFeed('feeds/categories/' + cid + '.rss', feed, function (err) { + if (process.env.NODE_ENV === 'development') { + winston.info('[rss] Re-generated RSS Feed for cid ' + cid + '.'); + } + + if (callback) callback(); + }); }); }); + }; + Feed.updateRecent = function(callback) { + console.log('entered'); + if (process.env.NODE_ENV === 'development') winston.info('[rss] Updating Recent Posts RSS feed'); + topics.getLatestTopics(0, 0, 19, undefined, function (err, recentData) { + var feed = new rss({ + title: 'Recently Active Topics', + description: 'A list of topics that have been active within the past 24 hours', + feed_url: Feed.defaults.baseUrl + '/recent.rss', + site_url: nconf.get('url') + 'recent', + ttl: Feed.defaults.ttl + }); + + // Add pubDate if recent topics list contains topics + if (recentData.topics.length > 0) { + feed.pubDate = new Date(parseInt(recentData.topics[0].lastposttime, 10)).toUTCString(); + } + + async.eachSeries(recentData.topics, function(topicData, next) { + feed.item({ + title: topicData.title, + url: nconf.get('url') + 'topic/' + topicData.slug, + author: topicData.username, + date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() + }); + next(); + }, function() { + Feed.saveFeed('feeds/recent.rss', feed, function (err) { + if (process.env.NODE_ENV === 'development') { + winston.info('[rss] Re-generated "recent posts" RSS Feed.'); + } + + if (callback) callback(); + }); + }); + }); }; }(exports)); \ No newline at end of file diff --git a/src/postTools.js b/src/postTools.js index 899ce9fb9a..90f9fd25bf 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -157,6 +157,7 @@ var RDB = require('./redis.js'), }); Feed.updateTopic(postData.tid); + Feed.updateRecent(); callback(); }); @@ -197,6 +198,7 @@ var RDB = require('./redis.js'), }); Feed.updateTopic(postData.tid); + Feed.updateRecent(); postSearch.index(postData.content, pid); diff --git a/src/posts.js b/src/posts.js index b47a9ed34c..ad56998585 100644 --- a/src/posts.js +++ b/src/posts.js @@ -78,6 +78,7 @@ var RDB = require('./redis.js'), var cid = topicData.cid; feed.updateTopic(tid); + feed.updateRecent(); RDB.zadd('categories:recent_posts:cid:' + cid, timestamp, pid); diff --git a/src/routes/api.js b/src/routes/api.js index 3d382ee490..d18707517a 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -138,8 +138,12 @@ var user = require('./../user.js'), app.get('/recent/:term?', function (req, res) { var uid = (req.user) ? req.user.uid : 0; - topics.getLatestTopics(uid, 0, 19, req.params.term, function (data) { - res.json(data); + topics.getLatestTopics(uid, 0, 19, req.params.term, function (err, data) { + if (!err) { + res.json(data); + } else { + res.send(500); + } }); }); diff --git a/src/routes/debug.js b/src/routes/debug.js index 6ee816e702..d2f216f729 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -4,7 +4,6 @@ var user = require('./../user'), topics = require('./../topics'), posts = require('./../posts'); - var DebugRoute = function(app) { app.namespace('/debug', function() { diff --git a/src/topics.js b/src/topics.js index e086903b99..171d204cc1 100644 --- a/src/topics.js +++ b/src/topics.js @@ -221,6 +221,9 @@ var RDB = require('./redis.js'), var args = ['topics:recent', '+inf', timestamp - since, 'LIMIT', start, end - start + 1]; RDB.zrevrangebyscore(args, function(err, tids) { + if (err) { + return callback(err); + } var latestTopics = { 'category_name': 'Recent', @@ -234,13 +237,13 @@ var RDB = require('./redis.js'), if (!tids || !tids.length) { latestTopics.no_topics_message = 'show'; - callback(latestTopics); + callback(err, latestTopics); return; } Topics.getTopicsByTids(tids, current_user, function(topicData) { latestTopics.topics = topicData; - callback(latestTopics); + callback(err, latestTopics); }); }); } diff --git a/src/webserver.js b/src/webserver.js index b520404ae8..a7c0acef55 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -318,7 +318,7 @@ var path = require('path'), }); }); - + translator.translate(templates.logout.toString(), function(parsedTemplate) { templates.logout = parsedTemplate; }); @@ -649,6 +649,32 @@ var path = require('path'), "Sitemap: " + nconf.get('url') + "sitemap.xml"); }); + app.get('/recent.rss', function(req, res) { + var rssPath = path.join(__dirname, '../', 'feeds/recent.rss'), + loadFeed = function () { + fs.readFile(rssPath, function (err, data) { + if (err) { + res.type('text').send(404, "Unable to locate an rss feed at this location."); + } else { + res.type('xml').set('Content-Length', data.length).send(data); + } + }); + + }; + + if (!fs.existsSync(rssPath)) { + feed.updaterecent(function (err) { + if (err) { + res.redirect('/404'); + } else { + loadFeed(); + } + }); + } else { + loadFeed(); + } + }); + app.get('/recent/:term?', function (req, res) { // TODO consolidate with /recent route as well -> that can be combined into this area. See "Basic Routes" near top. app.build_header({ diff --git a/src/websockets.js b/src/websockets.js index 211129cec5..e51dc8362c 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -807,8 +807,12 @@ module.exports.init = function(io) { var start = data.after, end = start + 9; - topics.getLatestTopics(uid, start, end, data.term, function(latestTopics) { - callback(latestTopics); + topics.getLatestTopics(uid, start, end, data.term, function(err, latestTopics) { + if (!err) { + callback(latestTopics); + } else { + winston.error('[socket api:topics.loadMoreRecentTopics] ' + err.message); + } }); });