|
|
@ -8,7 +8,8 @@ var async = require('async'),
|
|
|
|
categories = require('./categories'),
|
|
|
|
categories = require('./categories'),
|
|
|
|
user = require('./user'),
|
|
|
|
user = require('./user'),
|
|
|
|
plugins = require('./plugins'),
|
|
|
|
plugins = require('./plugins'),
|
|
|
|
privileges = require('./privileges');
|
|
|
|
privileges = require('./privileges'),
|
|
|
|
|
|
|
|
utils = require('../public/src/utils');
|
|
|
|
|
|
|
|
|
|
|
|
var search = {};
|
|
|
|
var search = {};
|
|
|
|
|
|
|
|
|
|
|
@ -21,6 +22,9 @@ search.search = function(data, callback) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result.search_query = query;
|
|
|
|
result.search_query = query;
|
|
|
|
|
|
|
|
if (searchIn === 'titles' || searchIn === 'titlesposts') {
|
|
|
|
|
|
|
|
searchIn = 'posts';
|
|
|
|
|
|
|
|
}
|
|
|
|
result[searchIn] = data.matches;
|
|
|
|
result[searchIn] = data.matches;
|
|
|
|
result.matchCount = data.matchCount;
|
|
|
|
result.matchCount = data.matchCount;
|
|
|
|
result.hidePostedBy = searchIn !== 'posts';
|
|
|
|
result.hidePostedBy = searchIn !== 'posts';
|
|
|
@ -31,7 +35,7 @@ search.search = function(data, callback) {
|
|
|
|
var start = process.hrtime();
|
|
|
|
var start = process.hrtime();
|
|
|
|
|
|
|
|
|
|
|
|
var query = data.query;
|
|
|
|
var query = data.query;
|
|
|
|
var searchIn = data.searchIn || 'posts';
|
|
|
|
var searchIn = data.searchIn || 'titlesposts';
|
|
|
|
|
|
|
|
|
|
|
|
var result = {
|
|
|
|
var result = {
|
|
|
|
posts: [],
|
|
|
|
posts: [],
|
|
|
@ -39,8 +43,8 @@ search.search = function(data, callback) {
|
|
|
|
tags: []
|
|
|
|
tags: []
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (searchIn === 'posts') {
|
|
|
|
if (searchIn === 'posts' || searchIn === 'titles' || searchIn === 'titlesposts') {
|
|
|
|
searchInPosts(query, data, done);
|
|
|
|
searchInContent(query, data, done);
|
|
|
|
} else if (searchIn === 'users') {
|
|
|
|
} else if (searchIn === 'users') {
|
|
|
|
searchInUsers(query, data.uid, done);
|
|
|
|
searchInUsers(query, data.uid, done);
|
|
|
|
} else if (searchIn === 'tags') {
|
|
|
|
} else if (searchIn === 'tags') {
|
|
|
@ -50,14 +54,22 @@ search.search = function(data, callback) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
function searchInPosts(query, data, callback) {
|
|
|
|
function searchInContent(query, data, callback) {
|
|
|
|
data.uid = data.uid || 0;
|
|
|
|
data.uid = data.uid || 0;
|
|
|
|
async.parallel({
|
|
|
|
async.parallel({
|
|
|
|
pids: function(next) {
|
|
|
|
pids: function(next) {
|
|
|
|
searchQuery('post', query, next);
|
|
|
|
if (data.searchIn === 'posts' || data.searchIn === 'titlesposts') {
|
|
|
|
|
|
|
|
searchQuery('post', query, next);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
next(null, []);
|
|
|
|
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
tids: function(next) {
|
|
|
|
tids: function(next) {
|
|
|
|
searchQuery('topic', query, next);
|
|
|
|
if (data.searchIn === 'titles' || data.searchIn === 'titlesposts') {
|
|
|
|
|
|
|
|
searchQuery('topic', query, next);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
next(null, []);
|
|
|
|
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
searchCategories: function(next) {
|
|
|
|
searchCategories: function(next) {
|
|
|
|
getSearchCategories(data, next);
|
|
|
|
getSearchCategories(data, next);
|
|
|
@ -104,24 +116,9 @@ function searchInPosts(query, data, callback) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function filterAndSort(pids, data, searchCategories, callback) {
|
|
|
|
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({
|
|
|
|
async.parallel({
|
|
|
|
posts: function(next) {
|
|
|
|
posts: function(next) {
|
|
|
|
getMatchedPosts(pids, postFields, topicFields, next);
|
|
|
|
getMatchedPosts(pids, data, searchCategories, next);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
postedByUid: function(next) {
|
|
|
|
postedByUid: function(next) {
|
|
|
|
if (data.postedBy) {
|
|
|
|
if (data.postedBy) {
|
|
|
@ -154,28 +151,130 @@ function filterAndSort(pids, data, searchCategories, callback) {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getMatchedPosts(pids, postFields, topicFields, callback) {
|
|
|
|
function getMatchedPosts(pids, data, searchCategories, callback) {
|
|
|
|
var keys = pids.map(function(pid) {
|
|
|
|
var postFields = ['pid', 'tid', 'timestamp'];
|
|
|
|
return 'post:' + pid;
|
|
|
|
var topicFields = [];
|
|
|
|
});
|
|
|
|
var categoryFields = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (data.postedBy) {
|
|
|
|
|
|
|
|
postFields.push('uid');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (searchCategories.length || (data.sortBy && data.sortBy.startsWith('category.'))) {
|
|
|
|
|
|
|
|
topicFields.push('cid');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (data.replies) {
|
|
|
|
|
|
|
|
topicFields.push('postcount');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (data.sortBy) {
|
|
|
|
|
|
|
|
if (data.sortBy.startsWith('topic.')) {
|
|
|
|
|
|
|
|
topicFields.push(data.sortBy.split('.')[1]);
|
|
|
|
|
|
|
|
} else if (data.sortBy.startsWith('user.')) {
|
|
|
|
|
|
|
|
postFields.push('uid');
|
|
|
|
|
|
|
|
} else if (data.sortBy.startsWith('category.')) {
|
|
|
|
|
|
|
|
categoryFields.push(data.sortBy.split('.')[1]);
|
|
|
|
|
|
|
|
} else if (data.sortBy.startsWith('teaser')) {
|
|
|
|
|
|
|
|
topicFields.push('teaserPid');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var posts;
|
|
|
|
var posts;
|
|
|
|
async.waterfall([
|
|
|
|
async.waterfall([
|
|
|
|
function(next) {
|
|
|
|
function(next) {
|
|
|
|
|
|
|
|
var keys = pids.map(function(pid) {
|
|
|
|
|
|
|
|
return 'post:' + pid;
|
|
|
|
|
|
|
|
});
|
|
|
|
db.getObjectsFields(keys, postFields, next);
|
|
|
|
db.getObjectsFields(keys, postFields, next);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
function(_posts, next) {
|
|
|
|
function(_posts, next) {
|
|
|
|
posts = _posts;
|
|
|
|
posts = _posts;
|
|
|
|
if (!topicFields.length) {
|
|
|
|
|
|
|
|
return callback(null, posts);
|
|
|
|
async.parallel({
|
|
|
|
}
|
|
|
|
users: function(next) {
|
|
|
|
var topicKeys = posts.map(function(post) {
|
|
|
|
if (data.sortBy && data.sortBy.startsWith('user')) {
|
|
|
|
return 'topic:' + post.tid;
|
|
|
|
var uids = posts.map(function(post) {
|
|
|
|
});
|
|
|
|
return post.uid;
|
|
|
|
db.getObjectsFields(topicKeys, topicFields, next);
|
|
|
|
});
|
|
|
|
|
|
|
|
user.getMultipleUserFields(uids, ['username'], next);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
next();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
topics: function(next) {
|
|
|
|
|
|
|
|
if (!topicFields.length) {
|
|
|
|
|
|
|
|
return next();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var topics;
|
|
|
|
|
|
|
|
async.waterfall([
|
|
|
|
|
|
|
|
function(next) {
|
|
|
|
|
|
|
|
var topicKeys = posts.map(function(post) {
|
|
|
|
|
|
|
|
return 'topic:' + post.tid;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
db.getObjectsFields(topicKeys, topicFields, next);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
function(_topics, next) {
|
|
|
|
|
|
|
|
topics = _topics;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async.parallel({
|
|
|
|
|
|
|
|
teasers: function(next) {
|
|
|
|
|
|
|
|
if (topicFields.indexOf('teaserPid') !== -1) {
|
|
|
|
|
|
|
|
var teaserKeys = topics.map(function(topic) {
|
|
|
|
|
|
|
|
return 'post:' + topic.teaserPid;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
db.getObjectsFields(teaserKeys, ['timestamp'], next);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
next();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
categories: function(next) {
|
|
|
|
|
|
|
|
if (!categoryFields.length) {
|
|
|
|
|
|
|
|
return next();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
var cids = topics.map(function(topic) {
|
|
|
|
|
|
|
|
return 'category:' + topic.cid;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
db.getObjectsFields(cids, categoryFields, next);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, next);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
], function(err, results) {
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
|
|
|
|
return next(err);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
topics.forEach(function(topic, index) {
|
|
|
|
|
|
|
|
if (topic && results.categories && results.categories[index]) {
|
|
|
|
|
|
|
|
topic.category = results.categories[index];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (topic && results.teasers && results.teasers[index]) {
|
|
|
|
|
|
|
|
topic.teaser = results.teasers[index];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
next(null, topics);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, next);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
function(topics, next) {
|
|
|
|
function(results, next) {
|
|
|
|
|
|
|
|
|
|
|
|
posts.forEach(function(post, index) {
|
|
|
|
posts.forEach(function(post, index) {
|
|
|
|
post.topic = topics[index];
|
|
|
|
if (results.topics && results.topics[index]) {
|
|
|
|
|
|
|
|
post.topic = results.topics[index];
|
|
|
|
|
|
|
|
if (results.topics[index].category) {
|
|
|
|
|
|
|
|
post.category = results.topics[index].category;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (results.topics[index].teaser) {
|
|
|
|
|
|
|
|
post.teaser = results.topics[index].teaser;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (results.users && results.users[index]) {
|
|
|
|
|
|
|
|
post.user = results.users[index];
|
|
|
|
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
next(null, posts);
|
|
|
|
next(null, posts);
|
|
|
@ -236,8 +335,75 @@ function filterByTimerange(posts, timeRange, timeFilter) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function sortPosts(posts, data) {
|
|
|
|
function sortPosts(posts, data) {
|
|
|
|
|
|
|
|
if (!posts.length) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
data.sortBy = data.sortBy || 'timestamp';
|
|
|
|
|
|
|
|
data.sortDirection = data.sortDirection || 'desc';
|
|
|
|
|
|
|
|
if (data.sortBy === 'timestamp') {
|
|
|
|
|
|
|
|
if (data.sortDirection === 'desc') {
|
|
|
|
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
|
|
|
|
return p2.timestamp - p1.timestamp;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
|
|
|
|
return p1.timestamp - p2.timestamp;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var firstPost = posts[0];
|
|
|
|
|
|
|
|
var fields = data.sortBy.split('.');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!fields || fields.length !== 2 || !firstPost[fields[0]] || !firstPost[fields[0]][fields[1]]) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var value = firstPost[fields[0]][fields[1]];
|
|
|
|
|
|
|
|
var isNumeric = utils.isNumber(value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isNumeric) {
|
|
|
|
|
|
|
|
if (data.sortDirection === 'desc') {
|
|
|
|
|
|
|
|
sortDescendingNumeric(posts, fields);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
sortAscendingNumeric(posts, fields);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (data.sortDirection === 'desc') {
|
|
|
|
|
|
|
|
sortDescendingAlpha(posts, fields);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
sortAscendingAlpha(posts, fields);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function sortAscendingNumeric(posts, fields) {
|
|
|
|
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
|
|
|
|
return p1[fields[0]][fields[1]] - p2[fields[0]][fields[1]];
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function sortDescendingNumeric(posts, fields) {
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
return p2.timestamp - p1.timestamp;
|
|
|
|
return p2[fields[0]][fields[1]] - p1[fields[0]][fields[1]];
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function sortAscendingAlpha(posts, fields) {
|
|
|
|
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
|
|
|
|
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return -1;
|
|
|
|
|
|
|
|
if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function sortDescendingAlpha(posts, fields) {
|
|
|
|
|
|
|
|
posts.sort(function(p1, p2) {
|
|
|
|
|
|
|
|
if (p1[fields[0]][fields[1]] < p2[fields[0]][fields[1]]) return -1;
|
|
|
|
|
|
|
|
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -311,6 +477,10 @@ function searchInTags(query, callback) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getMainPids(tids, callback) {
|
|
|
|
function getMainPids(tids, callback) {
|
|
|
|
|
|
|
|
if (!Array.isArray(tids) || !tids.length) {
|
|
|
|
|
|
|
|
return callback(null, []);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
topics.getTopicsFields(tids, ['mainPid'], function(err, topics) {
|
|
|
|
topics.getTopicsFields(tids, ['mainPid'], function(err, topics) {
|
|
|
|
if (err) {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
return callback(err);
|
|
|
|