|
|
|
@ -1,6 +1,8 @@
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
var async = require('async'),
|
|
|
|
|
|
|
|
|
|
db = require('./database'),
|
|
|
|
|
posts = require('./posts'),
|
|
|
|
|
topics = require('./topics'),
|
|
|
|
|
categories = require('./categories'),
|
|
|
|
@ -19,8 +21,8 @@ search.search = function(data, callback) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.search_query = query;
|
|
|
|
|
result[searchIn] = data;
|
|
|
|
|
result.matchCount = data.length;
|
|
|
|
|
result[searchIn] = data.matches;
|
|
|
|
|
result.matchCount = data.matchCount;
|
|
|
|
|
result.hidePostedBy = searchIn !== 'posts';
|
|
|
|
|
result.time = (process.elapsedTimeSince(start) / 1000).toFixed(2);
|
|
|
|
|
callback(null, result);
|
|
|
|
@ -65,8 +67,9 @@ function searchInPosts(query, data, callback) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var matchCount = 0;
|
|
|
|
|
if (!results || (!results.pids.length && !results.tids.length)) {
|
|
|
|
|
return callback(null, []);
|
|
|
|
|
return callback(null, {matches: [], matchCount: matchCount});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async.waterfall([
|
|
|
|
@ -82,31 +85,162 @@ function searchInPosts(query, data, callback) {
|
|
|
|
|
privileges.posts.filter('read', mainPids, data.uid, next);
|
|
|
|
|
},
|
|
|
|
|
function(pids, next) {
|
|
|
|
|
filterAndSort(pids, data, results.searchCategories, next);
|
|
|
|
|
},
|
|
|
|
|
function(pids, next) {
|
|
|
|
|
matchCount = pids.length;
|
|
|
|
|
if (data.page) {
|
|
|
|
|
var start = Math.max(0, (data.page - 1)) * 10;
|
|
|
|
|
pids = pids.slice(start, start + 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
posts.getPostSummaryByPids(pids, data.uid, {stripTags: true, parse: false}, next);
|
|
|
|
|
},
|
|
|
|
|
function(posts, next) {
|
|
|
|
|
posts = filterPosts(data, results.searchCategories, posts);
|
|
|
|
|
next(null, posts);
|
|
|
|
|
next(null, {matches: posts, matchCount: matchCount});
|
|
|
|
|
}
|
|
|
|
|
], callback);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filterPosts(data, searchCategories, posts) {
|
|
|
|
|
var postedBy = data.postedBy;
|
|
|
|
|
var isAtLeast = data.repliesFilter === 'atleast';
|
|
|
|
|
data.replies = parseInt(data.replies, 10);
|
|
|
|
|
if (postedBy || searchCategories.length || data.replies) {
|
|
|
|
|
function filterAndSort(pids, data, searchCategories, callback) {
|
|
|
|
|
var postFields = ['pid', 'tid', 'timestamp'];
|
|
|
|
|
var topicFields = [];
|
|
|
|
|
|
|
|
|
|
if (data.postedBy) {
|
|
|
|
|
postFields.push('uid');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (searchCategories.length) {
|
|
|
|
|
topicFields.push('cid');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data.replies) {
|
|
|
|
|
topicFields.push('postcount');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async.parallel({
|
|
|
|
|
posts: function(next) {
|
|
|
|
|
getMatchedPosts(pids, postFields, topicFields, next);
|
|
|
|
|
},
|
|
|
|
|
postedByUid: function(next) {
|
|
|
|
|
if (data.postedBy) {
|
|
|
|
|
user.getUidByUsername(data.postedBy, next);
|
|
|
|
|
} else {
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, function(err, results) {
|
|
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
if (!results.posts) {
|
|
|
|
|
return callback(null, pids);
|
|
|
|
|
}
|
|
|
|
|
var posts = results.posts.filter(Boolean);
|
|
|
|
|
|
|
|
|
|
posts = filterByUser(posts, results.postedByUid);
|
|
|
|
|
posts = filterByCategories(posts, searchCategories);
|
|
|
|
|
posts = filterByPostcount(posts, data.replies, data.repliesFilter);
|
|
|
|
|
posts = filterByTimerange(posts, data.timeRange, data.timeFilter);
|
|
|
|
|
|
|
|
|
|
sortPosts(posts, data);
|
|
|
|
|
|
|
|
|
|
pids = posts.map(function(post) {
|
|
|
|
|
return post && post.pid;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
callback(null, pids);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getMatchedPosts(pids, postFields, topicFields, callback) {
|
|
|
|
|
var keys = pids.map(function(pid) {
|
|
|
|
|
return 'post:' + pid;
|
|
|
|
|
});
|
|
|
|
|
var posts;
|
|
|
|
|
async.waterfall([
|
|
|
|
|
function(next) {
|
|
|
|
|
db.getObjectsFields(keys, postFields, next);
|
|
|
|
|
},
|
|
|
|
|
function(_posts, next) {
|
|
|
|
|
posts = _posts;
|
|
|
|
|
if (!topicFields.length) {
|
|
|
|
|
return callback(null, posts);
|
|
|
|
|
}
|
|
|
|
|
var topicKeys = posts.map(function(post) {
|
|
|
|
|
return 'topic:' + post.tid;
|
|
|
|
|
});
|
|
|
|
|
db.getObjectsFields(topicKeys, topicFields, next);
|
|
|
|
|
},
|
|
|
|
|
function(topics, next) {
|
|
|
|
|
posts.forEach(function(post, index) {
|
|
|
|
|
post.topic = topics[index];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
next(null, posts);
|
|
|
|
|
}
|
|
|
|
|
], callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filterByUser(posts, postedByUid) {
|
|
|
|
|
if (postedByUid) {
|
|
|
|
|
postedByUid = parseInt(postedByUid, 10);
|
|
|
|
|
posts = posts.filter(function(post) {
|
|
|
|
|
return parseInt(post.uid, 10) === postedByUid;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return posts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filterByCategories(posts, searchCategories) {
|
|
|
|
|
if (searchCategories.length) {
|
|
|
|
|
posts = posts.filter(function(post) {
|
|
|
|
|
return post &&
|
|
|
|
|
(postedBy ? post.user && (post.user.username === postedBy) : true) &&
|
|
|
|
|
(searchCategories.length ? (post.category && searchCategories.indexOf(post.category.cid) !== -1) : true) &&
|
|
|
|
|
(data.replies ? (isAtLeast ? post.topic.postcount >= data.replies : post.topic.postcount <= data.replies) : true);
|
|
|
|
|
return post.topic && searchCategories.indexOf(post.topic.cid) !== -1;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return posts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filterByPostcount(posts, postCount, repliesFilter) {
|
|
|
|
|
postCount = parseInt(postCount, 10);
|
|
|
|
|
if (postCount) {
|
|
|
|
|
if (repliesFilter === 'atleast') {
|
|
|
|
|
posts = posts.filter(function(post) {
|
|
|
|
|
return post.topic && post.topic.postcount >= postCount;
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
posts = posts.filter(function(post) {
|
|
|
|
|
return post.topic && post.topic.postcount <= postCount;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return posts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filterByTimerange(posts, timeRange, timeFilter) {
|
|
|
|
|
timeRange = parseInt(timeRange) * 1000;
|
|
|
|
|
if (timeRange) {
|
|
|
|
|
var time = Date.now() - timeRange;
|
|
|
|
|
if (timeFilter === 'newer') {
|
|
|
|
|
posts = posts.filter(function(post) {
|
|
|
|
|
return post.timestamp >= time;
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
posts = posts.filter(function(post) {
|
|
|
|
|
return post.timestamp <= time;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return posts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function sortPosts(posts, data) {
|
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
|
return p2.timestamp - p1.timestamp;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSearchCategories(data, callback) {
|
|
|
|
|
if (!Array.isArray(data.categories) || !data.categories.length || data.categories.indexOf('all') !== -1) {
|
|
|
|
|
return callback(null, []);
|
|
|
|
@ -159,12 +293,21 @@ function getChildrenCids(cids, uid, callback) {
|
|
|
|
|
|
|
|
|
|
function searchInUsers(query, callback) {
|
|
|
|
|
user.search({query: query}, function(err, results) {
|
|
|
|
|
callback(err, results ? results.users : null);
|
|
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
callback(null, {matches: results.users, matchCount: results.matchCount});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function searchInTags(query, callback) {
|
|
|
|
|
topics.searchAndLoadTags({query: query}, callback);
|
|
|
|
|
topics.searchAndLoadTags({query: query}, function(err, tags) {
|
|
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback(null, {matches: tags, matchCount: tags.length});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getMainPids(tids, callback) {
|
|
|
|
|