diff --git a/src/controllers/api.js b/src/controllers/api.js index 65140b70fe..b74a0d1b0f 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -158,7 +158,7 @@ apiController.getTopicData = function (tid, uid, callback) { return callback(err); } - if (!results.privileges.read || !results.privileges['topics:read'] || (parseInt(results.topic.deleted, 10) && !results.privileges.view_deleted)) { + if (!results.privileges.read || !results.privileges['topics:read'] || (results.topic.deleted && !results.privileges.view_deleted)) { return callback(); } callback(null, results.topic); diff --git a/src/controllers/topics.js b/src/controllers/topics.js index a5fc105131..31fe422509 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -54,7 +54,7 @@ topicsController.get = function (req, res, callback) { userPrivileges = results.privileges; rssToken = results.rssToken; - if (!userPrivileges['topics:read'] || (parseInt(results.topic.deleted, 10) && !userPrivileges.view_deleted)) { + if (!userPrivileges['topics:read'] || (results.topic.deleted && !userPrivileges.view_deleted)) { return helpers.notAllowed(req, res); } @@ -386,7 +386,7 @@ topicsController.pagination = function (req, res, callback) { return callback(err); } - if (!results.privileges.read || (parseInt(results.topic.deleted, 10) && !results.privileges.view_deleted)) { + if (!results.privileges.read || (results.topic.deleted && !results.privileges.view_deleted)) { return helpers.notAllowed(req, res); } diff --git a/src/posts.js b/src/posts.js index 8390653e69..5af246d36d 100644 --- a/src/posts.js +++ b/src/posts.js @@ -47,25 +47,14 @@ Posts.getPostsByPids = function (pids, uid, callback) { async.waterfall([ function (next) { - var keys = pids.map(function (pid) { - return 'post:' + pid; - }); - db.getObjects(keys, next); + Posts.getPostsData(pids, next); }, function (posts, next) { - async.map(posts, function (post, next) { - if (!post) { - return next(); - } - post.upvotes = parseInt(post.upvotes, 10) || 0; - post.downvotes = parseInt(post.downvotes, 10) || 0; - post.votes = post.upvotes - post.downvotes; - post.timestampISO = utils.toISOString(post.timestamp); - post.editedISO = parseInt(post.edited, 10) !== 0 ? utils.toISOString(post.edited) : ''; - Posts.parsePost(post, next); - }, next); + async.map(posts, Posts.parsePost, next); + }, + function (posts, next) { + user.blocks.filter(uid, posts, next); }, - async.apply(user.blocks.filter, uid), function (posts, next) { plugins.fireHook('filter:post.getPosts', { posts: posts, uid: uid }, next); }, diff --git a/src/posts/data.js b/src/posts/data.js index fc60fff021..45eaf8d845 100644 --- a/src/posts/data.js +++ b/src/posts/data.js @@ -4,8 +4,12 @@ var async = require('async'); var db = require('../database'); var plugins = require('../plugins'); +var utils = require('../utils'); -const intFields = ['uid', 'pid', 'tid', 'deleted', 'timestamp']; +const intFields = [ + 'uid', 'pid', 'tid', 'deleted', 'timestamp', + 'upvotes', 'downvotes', 'deleterUid', 'edited', +]; module.exports = function (Posts) { Posts.getPostsFields = function (pids, fields, callback) { @@ -13,10 +17,9 @@ module.exports = function (Posts) { return callback(null, []); } - var keys = pids.map(pid => 'post:' + pid); - async.waterfall([ function (next) { + const keys = pids.map(pid => 'post:' + pid); if (fields.length) { db.getObjectsFields(keys, fields, next); } else { @@ -76,5 +79,15 @@ module.exports = function (Posts) { function modifyPost(post) { if (post) { intFields.forEach(field => db.parseIntField(post, field)); + + if (post.hasOwnProperty('upvotes') && post.hasOwnProperty('downvotes')) { + post.votes = post.upvotes - post.downvotes; + } + if (post.hasOwnProperty('timestamp')) { + post.timestampISO = utils.toISOString(post.timestamp); + } + if (post.hasOwnProperty('edited')) { + post.editedISO = post.edited !== 0 ? utils.toISOString(post.edited) : ''; + } } } diff --git a/src/posts/parse.js b/src/posts/parse.js index 5fd2ca1818..f1f319ec24 100644 --- a/src/posts/parse.js +++ b/src/posts/parse.js @@ -22,6 +22,9 @@ module.exports = function (Posts) { }; Posts.parsePost = function (postData, callback) { + if (!postData) { + return setImmediate(callback, null, postData); + } postData.content = String(postData.content || ''); var cache = require('./cache'); if (postData.pid && cache.has(String(postData.pid))) { diff --git a/src/posts/summary.js b/src/posts/summary.js index f9dfe7f182..189efb7408 100644 --- a/src/posts/summary.js +++ b/src/posts/summary.js @@ -63,11 +63,8 @@ module.exports = function (Posts) { post.user = results.users[post.uid]; post.topic = results.topics[post.tid]; post.category = post.topic && results.categories[post.topic.cid]; - post.isMainPost = post.topic && parseInt(post.pid, 10) === parseInt(post.topic.mainPid, 10); - post.deleted = parseInt(post.deleted, 10) === 1; - post.upvotes = parseInt(post.upvotes, 10) || 0; - post.downvotes = parseInt(post.downvotes, 10) || 0; - post.votes = post.upvotes - post.downvotes; + post.isMainPost = post.topic && post.pid === post.topic.mainPid; + post.deleted = post.deleted === 1; post.timestampISO = utils.toISOString(post.timestamp); }); @@ -114,16 +111,7 @@ module.exports = function (Posts) { }, function (_topicsData, next) { topicsData = _topicsData; - var cids = topicsData.map(function (topic) { - if (topic) { - topic.title = String(topic.title); - topic.deleted = parseInt(topic.deleted, 10) === 1; - } - return topic && parseInt(topic.cid, 10); - }); - - cids = _.uniq(cids); - + var cids = _.uniq(topicsData.map(topic => topic && topic.cid)); categories.getCategoriesFields(cids, ['cid', 'name', 'icon', 'slug', 'parentCid', 'bgColor', 'color'], next); }, function (categoriesData, next) { diff --git a/src/privileges/posts.js b/src/privileges/posts.js index 78181b3cdb..a28a12378b 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -123,7 +123,7 @@ module.exports = function (privileges) { pids = postData.filter(function (post) { return post.topic && cidsSet.has(post.topic.cid) && - ((parseInt(post.topic.deleted, 10) !== 1 && parseInt(post.deleted, 10) !== 1) || results.isAdmin || isModOf[post.cid]); + ((!post.topic.deleted && !post.deleted) || results.isAdmin || isModOf[post.cid]); }).map(post => post.pid); plugins.fireHook('filter:privileges.posts.filter', { @@ -184,11 +184,11 @@ module.exports = function (privileges) { } var postDeleteDuration = meta.config.postDeleteDuration; - if (postDeleteDuration && (Date.now() - parseInt(postData.timestamp, 10) > postDeleteDuration * 1000)) { + if (postDeleteDuration && (Date.now() - postData.timestamp > postDeleteDuration * 1000)) { return next(null, { flag: false, message: '[[error:post-delete-duration-expired, ' + meta.config.postDeleteDuration + ']]' }); } - var deleterUid = parseInt(postData.deleterUid, 10) || 0; - var flag = results.isOwner && (deleterUid === 0 || deleterUid === parseInt(postData.uid, 10)); + var deleterUid = postData.deleterUid; + var flag = results.isOwner && (deleterUid === 0 || deleterUid === postData.uid); next(null, { flag: flag, message: '[[error:no-privileges]]' }); }, ], callback); diff --git a/src/privileges/topics.js b/src/privileges/topics.js index e7fcbb32bc..7a1e2f4195 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -100,7 +100,7 @@ module.exports = function (privileges) { tids = topicsData.filter(function (topic) { return cidsSet.has(topic.cid) && - (parseInt(topic.deleted, 10) !== 1 || results.isAdmin || isModOf[topic.cid]); + (!topic.deleted || results.isAdmin || isModOf[topic.cid]); }).map(topic => topic.tid); plugins.fireHook('filter:privileges.topics.filter', { diff --git a/src/routes/feeds.js b/src/routes/feeds.js index db1d394de2..ce1598b2f7 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -97,7 +97,7 @@ function generateForTopic(req, res, callback) { }, next); }, function (results, next) { - if (!results.topic || (parseInt(results.topic.deleted, 10) && !results.privileges.view_deleted)) { + if (!results.topic || (results.topic.deleted && !results.privileges.view_deleted)) { return controllers404.send404(req, res); } userPrivileges = results.privileges; diff --git a/src/search.js b/src/search.js index 75032ba1ab..7d8a6f3e09 100644 --- a/src/search.js +++ b/src/search.js @@ -87,9 +87,7 @@ function searchInContent(data, callback) { topics.getMainPids(results.tids, next); }, function (mainPids, next) { - pids = mainPids.concat(pids).map(function (pid) { - return pid && pid.toString(); - }).filter(Boolean); + pids = mainPids.concat(pids).filter(Boolean); privileges.posts.filter('read', pids, data.uid, next); }, @@ -144,9 +142,7 @@ function filterAndSort(pids, data, callback) { plugins.fireHook('filter:search.filterAndSort', { pids: pids, posts: posts, data: data }, next); }, function (result, next) { - pids = result.posts.map(function (post) { - return post && post.pid; - }); + pids = result.posts.map(post => post && post.pid); next(null, pids); }, @@ -163,25 +159,18 @@ function getMatchedPosts(pids, data, callback) { } } - var posts; + var postsData; async.waterfall([ function (next) { - var keys = pids.map(function (pid) { - return 'post:' + pid; - }); - db.getObjectsFields(keys, postFields, next); + posts.getPostsFields(pids, postFields, next); }, - function (_posts, next) { - posts = _posts.filter(function (post) { - return post && parseInt(post.deleted, 10) !== 1; - }); + function (_postsData, next) { + postsData = _postsData.filter(post => post && !post.deleted); async.parallel({ users: function (next) { if (data.sortBy && data.sortBy.startsWith('user')) { - var uids = posts.map(function (post) { - return post.uid; - }); + var uids = postsData.map(post => post.uid); user.getUsersFields(uids, ['username'], next); } else { next(); @@ -189,22 +178,17 @@ function getMatchedPosts(pids, data, callback) { }, topics: function (next) { var topicsData; + const tids = postsData.map(post => post.tid); async.waterfall([ function (next) { - var topicKeys = posts.map(function (post) { - return 'topic:' + post.tid; - }); - db.getObjects(topicKeys, next); + topics.getTopicsData(tids, next); }, function (_topics, next) { topicsData = _topics; - async.parallel({ teasers: function (next) { if (data.sortBy && data.sortBy.startsWith('teaser')) { - var teaserKeys = topicsData.map(function (topic) { - return 'post:' + topic.teaserPid; - }); + var teaserKeys = topicsData.map(topic => 'post:' + topic.teaserPid); db.getObjectsFields(teaserKeys, ['timestamp'], next); } else { next(); @@ -214,16 +198,11 @@ function getMatchedPosts(pids, data, callback) { if (!categoryFields.length) { return next(); } - var cids = topicsData.map(function (topic) { - return 'category:' + topic.cid; - }); + var cids = topicsData.map(topic => 'category:' + topic.cid); db.getObjectsFields(cids, categoryFields, next); }, tags: function (next) { if (Array.isArray(data.hasTags) && data.hasTags.length) { - var tids = posts.map(function (post) { - return post && post.tid; - }); topics.getTopicsTags(tids, next); } else { setImmediate(next); @@ -251,7 +230,7 @@ function getMatchedPosts(pids, data, callback) { }, next); }, function (results, next) { - posts.forEach(function (post, index) { + postsData.forEach(function (post, index) { if (results.topics && results.topics[index]) { post.topic = results.topics[index]; if (results.topics[index].category) { @@ -267,11 +246,8 @@ function getMatchedPosts(pids, data, callback) { } }); - posts = posts.filter(function (post) { - return post && post.topic && parseInt(post.topic.deleted, 10) !== 1; - }); - - next(null, posts); + postsData = postsData.filter(post => post && post.topic && !post.topic.deleted); + next(null, postsData); }, ], callback); } @@ -412,9 +388,7 @@ function getChildrenCids(cids, uid, callback) { childrenCategories.forEach(function (childrens) { categories.flattenCategories(allCategories, childrens); - childrenCids = childrenCids.concat(allCategories.map(function (category) { - return category && category.cid; - })); + childrenCids = childrenCids.concat(allCategories.map(category => category && category.cid)); }); next(null, childrenCids); diff --git a/src/topics/data.js b/src/topics/data.js index 842722d38a..8e813bde28 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -10,7 +10,7 @@ var translator = require('../translator'); const intFields = [ 'tid', 'cid', 'uid', 'mainPid', 'deleted', 'locked', 'pinned', - 'timestamp', + 'timestamp', 'upvotes', 'downvotes', ]; module.exports = function (Topics) { @@ -88,7 +88,7 @@ module.exports = function (Topics) { function escapeTitle(topicData) { if (topicData) { if (topicData.title) { - topicData.title = translator.escape(validator.escape(topicData.title.toString())); + topicData.title = translator.escape(validator.escape(String(topicData.title))); } if (topicData.titleRaw) { topicData.titleRaw = translator.escape(topicData.titleRaw); @@ -117,12 +117,6 @@ function modifyTopic(topic) { topic.lastposttimeISO = utils.toISOString(topic.lastposttime); } - if (topic.hasOwnProperty('upvotes')) { - topic.upvotes = parseInt(topic.upvotes, 10) || 0; - } - if (topic.hasOwnProperty('upvotes')) { - topic.downvotes = parseInt(topic.downvotes, 10) || 0; - } if (topic.hasOwnProperty('upvotes') && topic.hasOwnProperty('downvotes')) { topic.votes = topic.upvotes - topic.downvotes; } diff --git a/test/posts.js b/test/posts.js index af11c52e9b..b85f45d7db 100644 --- a/test/posts.js +++ b/test/posts.js @@ -251,7 +251,7 @@ describe('Post\'s', function () { assert.ifError(err); posts.getPostField(replyPid, 'deleted', function (err, isDeleted) { assert.ifError(err); - assert.equal(parseInt(isDeleted, 10), 1); + assert.strictEqual(isDeleted, 1); done(); }); }); @@ -262,7 +262,7 @@ describe('Post\'s', function () { assert.ifError(err); posts.getPostField(replyPid, 'deleted', function (err, isDeleted) { assert.ifError(err); - assert.equal(parseInt(isDeleted, 10), 0); + assert.strictEqual(isDeleted, 0); done(); }); }); @@ -591,6 +591,14 @@ describe('Post\'s', function () { }); describe('parse', function () { + it('should not crash and return falsy if post data is falsy', function (done) { + posts.parsePost(null, function (err, postData) { + assert.ifError(err); + assert.strictEqual(postData, null); + done(); + }); + }); + it('should store post content in cache', function (done) { var oldValue = global.env; global.env = 'production'; diff --git a/test/topics.js b/test/topics.js index 8928f30a7e..27f867e7d3 100644 --- a/test/topics.js +++ b/test/topics.js @@ -218,7 +218,18 @@ describe('Topic\'s', function () { it('should not receive errors', function (done) { - topics.getTopicData(newTopic.tid, done); + topics.getTopicData(newTopic.tid, function (err, topicData) { + assert.ifError(err); + assert(typeof topicData.tid === 'number'); + assert(typeof topicData.uid === 'number'); + assert(typeof topicData.cid === 'number'); + assert(typeof topicData.mainPid === 'number'); + assert(typeof topicData.deleted === 'number'); + assert(typeof topicData.locked === 'number'); + assert(typeof topicData.pinned === 'number'); + assert(typeof topicData.timestamp === 'number'); + done(); + }); }); it('should get topic title by pid', function (done) {