From a4ba88dc60a7b809b6c83644568779d6560e0f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 21 May 2017 19:45:25 -0400 Subject: [PATCH] more feed tests --- src/controllers/404.js | 24 ++-- src/routes/feeds.js | 262 +++++++++++++++++++---------------------- test/feeds.js | 119 +++++++++++++++++++ 3 files changed, 254 insertions(+), 151 deletions(-) create mode 100644 test/feeds.js diff --git a/src/controllers/404.js b/src/controllers/404.js index bc4e2e1d00..44dcf59174 100644 --- a/src/controllers/404.js +++ b/src/controllers/404.js @@ -30,18 +30,20 @@ exports.handle404 = function (req, res) { } meta.errors.log404(req.path.replace(/^\/api/, '') || ''); - res.status(404); - - var path = String(req.path || ''); - - if (res.locals.isAPI) { - return res.json({ path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]' }); - } - var middleware = require('../middleware'); - middleware.buildHeader(req, res, function () { - res.render('404', { path: validator.escape(path), title: '[[global:404.title]]' }); - }); + exports.send404(req, res); } else { res.status(404).type('txt').send('Not found'); } }; + +exports.send404 = function (req, res) { + res.status(404); + var path = String(req.path || ''); + if (res.locals.isAPI) { + return res.json({ path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]' }); + } + var middleware = require('../middleware'); + middleware.buildHeader(req, res, function () { + res.render('404', { path: validator.escape(path), title: '[[global:404.title]]' }); + }); +}; diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 5e3d75c34d..3171babbf6 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -12,6 +12,7 @@ var categories = require('../categories'); var meta = require('../meta'); var helpers = require('../controllers/helpers'); var privileges = require('../privileges'); +var controllers404 = require('../controllers/404.js'); module.exports = function (app, middleware) { app.get('/topic/:topic_id.rss', middleware.maintenanceMode, generateForTopic); @@ -25,10 +26,9 @@ module.exports = function (app, middleware) { app.get('/tags/:tag.rss', middleware.maintenanceMode, generateForTag); }; - function generateForTopic(req, res, callback) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return callback(); + return controllers404.send404(req, res); } var tid = req.params.topic_id; @@ -45,65 +45,59 @@ function generateForTopic(req, res, callback) { }, next); }, function (results, next) { - if (!results.topic) { - return callback(); + if (!results.topic || (parseInt(results.topic.deleted, 10) && !results.privileges.view_deleted)) { + return controllers404.send404(req, res); } - if (parseInt(results.topic.deleted, 10) && !results.privileges.view_deleted) { - return callback(); - } - if (!results.privileges.read || !results.privileges['topics:read']) { + if (!results.privileges['topics:read']) { return helpers.notAllowed(req, res); } userPrivileges = results.privileges; topics.getTopicWithPosts(results.topic, 'tid:' + tid + ':posts', req.uid, 0, 25, false, next); }, - ], function (err, topicData) { - if (err) { - return callback(err); - } - - topics.modifyPostsByPrivilege(topicData, userPrivileges); - - var description = topicData.posts.length ? topicData.posts[0].content : ''; - var image_url = topicData.posts.length ? topicData.posts[0].picture : ''; - var author = topicData.posts.length ? topicData.posts[0].username : ''; - - var feed = new rss({ - title: topicData.title, - description: description, - feed_url: nconf.get('url') + '/topic/' + tid + '.rss', - site_url: nconf.get('url') + '/topic/' + topicData.slug, - image_url: image_url, - author: author, - ttl: 60, - }); - var dateStamp; - - if (topicData.posts.length > 0) { - feed.pubDate = new Date(parseInt(topicData.posts[0].timestamp, 10)).toUTCString(); - } - - topicData.posts.forEach(function (postData) { - if (!postData.deleted) { - dateStamp = new Date(parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)).toUTCString(); - - feed.item({ - title: 'Reply to ' + topicData.title + ' on ' + dateStamp, - description: postData.content, - url: nconf.get('url') + '/post/' + postData.pid, - author: postData.user ? postData.user.username : '', - date: dateStamp, - }); + function (topicData) { + topics.modifyPostsByPrivilege(topicData, userPrivileges); + + var description = topicData.posts.length ? topicData.posts[0].content : ''; + var image_url = topicData.posts.length ? topicData.posts[0].picture : ''; + var author = topicData.posts.length ? topicData.posts[0].username : ''; + + var feed = new rss({ + title: topicData.title, + description: description, + feed_url: nconf.get('url') + '/topic/' + tid + '.rss', + site_url: nconf.get('url') + '/topic/' + topicData.slug, + image_url: image_url, + author: author, + ttl: 60, + }); + var dateStamp; + + if (topicData.posts.length > 0) { + feed.pubDate = new Date(parseInt(topicData.posts[0].timestamp, 10)).toUTCString(); } - }); - sendFeed(feed, res); - }); + topicData.posts.forEach(function (postData) { + if (!postData.deleted) { + dateStamp = new Date(parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)).toUTCString(); + + feed.item({ + title: 'Reply to ' + topicData.title + ' on ' + dateStamp, + description: postData.content, + url: nconf.get('url') + '/post/' + postData.pid, + author: postData.user ? postData.user.username : '', + date: dateStamp, + }); + } + }); + + sendFeed(feed, res); + }, + ], callback); } function generateForUserTopics(req, res, callback) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return callback(); + return controllers404.send404(req, res); } var userslug = req.params.userslug; @@ -118,24 +112,21 @@ function generateForUserTopics(req, res, callback) { } user.getUserFields(uid, ['uid', 'username'], next); }, - ], function (err, userData) { - if (err) { - return callback(err); - } - - generateForTopics({ - uid: req.uid, - title: 'Topics by ' + userData.username, - description: 'A list of topics that are posted by ' + userData.username, - feed_url: '/user/' + userslug + '/topics.rss', - site_url: '/user/' + userslug + '/topics', - }, 'uid:' + userData.uid + ':topics', req, res, callback); - }); + function (userData, next) { + generateForTopics({ + uid: req.uid, + title: 'Topics by ' + userData.username, + description: 'A list of topics that are posted by ' + userData.username, + feed_url: '/user/' + userslug + '/topics.rss', + site_url: '/user/' + userslug + '/topics', + }, 'uid:' + userData.uid + ':topics', req, res, next); + }, + ], callback); } function generateForCategory(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return next(); + return controllers404.send404(req, res); } var cid = req.params.category_id; @@ -169,17 +160,15 @@ function generateForCategory(req, res, next) { site_url: '/category/' + results.category.cid, }, results.category.topics, next); }, - ], function (err, feed) { - if (err) { - return next(err); - } - sendFeed(feed, res); - }); + function (feed) { + sendFeed(feed, res); + }, + ], next); } function generateForRecent(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return next(); + return controllers404.send404(req, res); } generateForTopics({ uid: req.uid, @@ -192,7 +181,7 @@ function generateForRecent(req, res, next) { function generateForPopular(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return next(); + return controllers404.send404(req, res); } var terms = { daily: 'day', @@ -215,12 +204,10 @@ function generateForPopular(req, res, next) { site_url: '/popular/' + (req.params.term || 'daily'), }, topics, next); }, - ], function (err, feed) { - if (err) { - return next(err); - } - sendFeed(feed, res); - }); + function (feed) { + sendFeed(feed, res); + }, + ], next); } function generateForTopics(options, set, req, res, next) { @@ -233,12 +220,10 @@ function generateForTopics(options, set, req, res, next) { function (data, next) { generateTopicsFeed(options, data.topics, next); }, - ], function (err, feed) { - if (err) { - return next(err); - } - sendFeed(feed, res); - }); + function (feed) { + sendFeed(feed, res); + }, + ], next); } function generateTopicsFeed(feedOptions, feedTopics, callback) { @@ -254,7 +239,7 @@ function generateTopicsFeed(feedOptions, feedTopics, callback) { feed.pubDate = new Date(parseInt(feedTopics[0].lastposttime, 10)).toUTCString(); } - async.map(feedTopics, function (topicData, next) { + async.each(feedTopics, function (topicData, next) { var feedItem = { title: topicData.title, url: nconf.get('url') + '/topic/' + topicData.slug, @@ -272,83 +257,80 @@ function generateTopicsFeed(feedOptions, feedTopics, callback) { return next(err); } if (!mainPost) { - return next(null, feedItem); + feed.item(feedItem); + return next(); } feedItem.description = mainPost.content; feedItem.author = mainPost.user.username; - next(null, feedItem); + feed.item(feedItem); + next(); }); - }, function (err, feedItems) { - if (err) { - return callback(err); - } - feedItems.forEach(function (feedItem) { - if (feedItem) { - feed.item(feedItem); - } - }); - callback(null, feed); + }, function (err) { + callback(err, feed); }); } function generateForRecentPosts(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return next(); + return controllers404.send404(req, res); } - posts.getRecentPosts(req.uid, 0, 19, 'month', function (err, posts) { - if (err) { - return next(err); - } - - var feed = generateForPostsFeed({ - title: 'Recent Posts', - description: 'A list of recent posts', - feed_url: '/recentposts.rss', - site_url: '/recentposts', - }, posts); - - sendFeed(feed, res); - }); + async.waterfall([ + function (next) { + posts.getRecentPosts(req.uid, 0, 19, 'month', next); + }, + function (posts) { + var feed = generateForPostsFeed({ + title: 'Recent Posts', + description: 'A list of recent posts', + feed_url: '/recentposts.rss', + site_url: '/recentposts', + }, posts); + + sendFeed(feed, res); + }, + ], next); } function generateForCategoryRecentPosts(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return next(); + return controllers404.send404(req, res); } var cid = req.params.category_id; - async.parallel({ - privileges: function (next) { - privileges.categories.get(cid, req.uid, next); - }, - category: function (next) { - categories.getCategoryData(cid, next); - }, - posts: function (next) { - categories.getRecentReplies(cid, req.uid, 20, next); + async.waterfall([ + function (next) { + async.parallel({ + privileges: function (next) { + privileges.categories.get(cid, req.uid, next); + }, + category: function (next) { + categories.getCategoryData(cid, next); + }, + posts: function (next) { + categories.getRecentReplies(cid, req.uid, 20, next); + }, + }, next); }, - }, function (err, results) { - if (err) { - return next(err); - } - if (!results.category) { - return next(); - } + function (results, next) { + if (!results.category) { + return next(); + } - if (!results.privileges.read) { - return helpers.notAllowed(req, res); - } + if (!results.privileges.read) { + return helpers.notAllowed(req, res); + } - var feed = generateForPostsFeed({ - title: results.category.name + ' Recent Posts', - description: 'A list of recent posts from ' + results.category.name, - feed_url: '/category/' + cid + '/recentposts.rss', - site_url: '/category/' + cid + '/recentposts', - }, results.posts); + var feed = generateForPostsFeed({ + title: results.category.name + ' Recent Posts', + description: 'A list of recent posts from ' + results.category.name, + feed_url: '/category/' + cid + '/recentposts.rss', + site_url: '/category/' + cid + '/recentposts', + }, results.posts); - sendFeed(feed, res); - }); + sendFeed(feed, res); + }, + ], next); } function generateForPostsFeed(feedOptions, posts) { @@ -377,7 +359,7 @@ function generateForPostsFeed(feedOptions, posts) { function generateForTag(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { - return next(); + return controllers404.send404(req, res); } var tag = validator.escape(String(req.params.tag)); var page = parseInt(req.query.page, 10) || 1; diff --git a/test/feeds.js b/test/feeds.js new file mode 100644 index 0000000000..6e6628c038 --- /dev/null +++ b/test/feeds.js @@ -0,0 +1,119 @@ +'use strict'; + +var assert = require('assert'); +var async = require('async'); +var request = require('request'); +var nconf = require('nconf'); + +var db = require('./mocks/databasemock'); +var topics = require('../src/topics'); +var categories = require('../src/categories'); +var groups = require('../src/groups'); +var user = require('../src/user'); +var meta = require('../src/meta'); +var privileges = require('../src/privileges'); + +describe('feeds', function () { + var tid; + var pid; + var fooUid; + var cid; + before(function (done) { + groups.resetCache(); + meta.config['feeds:disableRSS'] = 1; + async.series({ + category: function (next) { + categories.create({ + name: 'Test Category', + description: 'Test category created by testing script', + }, next); + }, + user: function (next) { + user.create({ username: 'foo', password: 'barbar', email: 'foo@test.com' }, next); + }, + }, function (err, results) { + if (err) { + return done(err); + } + cid = results.category.cid; + fooUid = results.user; + + topics.post({ uid: results.user, title: 'test topic title', content: 'test topic content', cid: results.category.cid }, function (err, result) { + tid = result.topicData.tid; + pid = result.postData.pid; + done(err); + }); + }); + }); + + + it('should 404', function (done) { + var feedUrls = [ + nconf.get('url') + '/topic/' + tid + '.rss', + nconf.get('url') + '/category/' + cid + '.rss', + nconf.get('url') + '/popular.rss', + nconf.get('url') + '/popular/day.rss', + nconf.get('url') + '/recentposts.rss', + nconf.get('url') + '/category/' + cid + '/recentposts.rss', + nconf.get('url') + '/user/foo/topics.rss', + nconf.get('url') + '/tags/nodebb.rss', + ]; + async.eachSeries(feedUrls, function (url, next) { + request(url, function (err, res) { + assert.ifError(err); + assert.equal(res.statusCode, 404); + next(); + }); + }, function (err) { + assert.ifError(err); + meta.config['feeds:disableRSS'] = 0; + done(); + }); + }); + + it('should 404 if topic does not exist', function (done) { + request(nconf.get('url') + '/topic/' + 1000 + '.rss', function (err, res) { + assert.ifError(err); + assert.equal(res.statusCode, 404); + done(); + }); + }); + + it('should redirect if we do not have read privilege', function (done) { + privileges.categories.rescind(['topics:read'], cid, 'guests', function (err) { + assert.ifError(err); + request(nconf.get('url') + '/topic/' + tid + '.rss', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + assert(body.indexOf('Login to your account') !== -1); + privileges.categories.give(['topics:read'], cid, 'guests', done); + }); + }); + }); + + it('should 404 if user is not found', function (done) { + request(nconf.get('url') + '/user/doesnotexist/topics.rss', function (err, res) { + assert.ifError(err); + assert.equal(res.statusCode, 404); + done(); + }); + }); + + it('should redirect if we do not have read privilege', function (done) { + privileges.categories.rescind(['read'], cid, 'guests', function (err) { + assert.ifError(err); + request(nconf.get('url') + '/category/' + cid + '.rss', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + assert(body.indexOf('Login to your account') !== -1); + privileges.categories.give(['read'], cid, 'guests', done); + }); + }); + }); + + after(function (done) { + db.emptydb(done); + }); +});