ability to filter search by tags

v1.18.x
barisusakli 8 years ago
parent fef239d97a
commit 1fed01fe43

@ -13,8 +13,8 @@
"start": "node loader.js",
"lint": "eslint --cache .",
"pretest": "npm run lint",
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec",
"coveralls": "istanbul cover _mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
"test": "istanbul cover node_modules/mocha/bin/_mocha -- -R dot",
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
},
"dependencies": {
"async": "~1.5.0",

@ -8,6 +8,7 @@
"posted-by": "Posted by",
"in-categories": "In Categories",
"search-child-categories": "Search child categories",
"has-tags": "Has tags",
"reply-count": "Reply Count",
"at-least": "At least",
"at-most": "At most",

@ -12,8 +12,6 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc
var searchIn = $('#search-in');
fillOutForm();
searchIn.on('change', function () {
updateFormItemVisiblity(searchIn.val());
});
@ -31,6 +29,8 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc
handleSavePreferences();
enableAutoComplete();
fillOutForm();
};
function getSearchData() {
@ -43,6 +43,7 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc
searchData.by = form.find('#posted-by-user').val();
searchData.categories = form.find('#posted-in-categories').val();
searchData.searchChildren = form.find('#search-children').is(':checked');
searchData.hasTags = form.find('#has-tags').tagsinput('items');
searchData.replies = form.find('#reply-count').val();
searchData.repliesFilter = form.find('#reply-count-filter').val();
searchData.timeFilter = form.find('#post-time-filter').val();
@ -79,7 +80,6 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc
$('#posted-by-user').val(formData.by);
}
if (formData.categories) {
$('#posted-in-categories').val(formData.categories);
}
@ -88,6 +88,13 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc
$('#search-children').prop('checked', true);
}
if (formData.hasTags) {
formData.hasTags = Array.isArray(formData.hasTags) ? formData.hasTags : [formData.hasTags];
formData.hasTags.forEach(function (tag) {
$('#has-tags').tagsinput('add', tag);
});
}
if (formData.replies) {
$('#reply-count').val(formData.replies);
$('#reply-count-filter').val(formData.repliesFilter);
@ -157,6 +164,14 @@ define('forum/search', ['search', 'autocomplete'], function (searchModule, autoc
function enableAutoComplete() {
autocomplete.user($('#posted-by-user'));
var tagEl = $('#has-tags');
tagEl.tagsinput({
confirmKeys: [13, 44],
trimValue: true
});
autocomplete.tag($('#has-tags').siblings('.bootstrap-tagsinput').find('input'));
}
return Search;

@ -75,5 +75,40 @@ define('autocomplete', function () {
});
};
module.tag = function (input, onselect) {
app.loadJQueryUI(function () {
input.autocomplete({
delay: 100,
open: function () {
$(this).autocomplete('widget').css('z-index', 20000);
},
select: function (event, ui) {
onselect = onselect || function () {};
var e = jQuery.Event('keypress');
e.which = 13;
e.keyCode = 13;
setTimeout(function () {
input.trigger(e);
}, 100);
onselect(event, ui);
},
source: function (request, response) {
socket.emit('topics.autocompleteTags', {
query: request.term,
cid: ajaxify.data.cid || 0
}, function (err, tags) {
if (err) {
return app.alertError(err.message);
}
if (tags) {
response(tags);
}
$('.ui-autocomplete a').attr('data-ajaxify', 'false');
});
}
});
});
};
return module;
});

@ -53,6 +53,10 @@ define('search', ['navigator', 'translator'], function (nav, translator) {
}
}
if (data.hasTags && data.hasTags.length) {
query.hasTags = data.hasTags;
}
if (parseInt(data.replies, 10) > 0) {
query.replies = data.replies;
query.repliesFilter = data.repliesFilter || 'atleast';

@ -33,6 +33,7 @@ searchController.search = function (req, res, next) {
postedBy: req.query.by,
categories: req.query.categories,
searchChildren: req.query.searchChildren,
hasTags: req.query.hasTags,
replies: req.query.replies,
repliesFilter: req.query.repliesFilter,
timeRange: req.query.timeRange,

@ -41,6 +41,7 @@ module.exports = function (Meta) {
next(true);
}
} catch(e) {
console.log(e);
process.stdout.write('[' + 'missing'.red + '] ' + module.bold + ' is a required dependency but could not be found\n');
depsMissing = true;
next(true);

@ -126,6 +126,7 @@ function filterAndSort(pids, data, callback) {
posts = filterByPostcount(posts, data.replies, data.repliesFilter);
posts = filterByTimerange(posts, data.timeRange, data.timeFilter);
posts = filterByTags(posts, data.hasTags);
sortPosts(posts, data);
@ -166,6 +167,7 @@ function getMatchedPosts(pids, data, callback) {
var keys = pids.map(function (pid) {
return 'post:' + pid;
});
db.getObjectsFields(keys, postFields, next);
},
function (_posts, next) {
@ -185,7 +187,7 @@ function getMatchedPosts(pids, data, callback) {
}
},
topics: function (next) {
var topics;
var topicsData;
async.waterfall([
function (next) {
var topicKeys = posts.map(function (post) {
@ -194,12 +196,12 @@ function getMatchedPosts(pids, data, callback) {
db.getObjectsFields(topicKeys, topicFields, next);
},
function (_topics, next) {
topics = _topics;
topicsData = _topics;
async.parallel({
teasers: function (next) {
if (topicFields.indexOf('teaserPid') !== -1) {
var teaserKeys = topics.map(function (topic) {
var teaserKeys = topicsData.map(function (topic) {
return 'post:' + topic.teaserPid;
});
db.getObjectsFields(teaserKeys, ['timestamp'], next);
@ -211,10 +213,20 @@ function getMatchedPosts(pids, data, callback) {
if (!categoryFields.length) {
return next();
}
var cids = topics.map(function (topic) {
var cids = topicsData.map(function (topic) {
return 'category:' + topic.cid;
});
db.getObjectsFields(cids, categoryFields, next);
},
tags: function (next) {
if (data.hasTags && data.hasTags.length) {
var tids = posts.map(function (post) {
return post && post.tid;
});
topics.getTopicsTags(tids, next);
} else {
setImmediate(next);
}
}
}, next);
}
@ -223,16 +235,19 @@ function getMatchedPosts(pids, data, callback) {
return next(err);
}
topics.forEach(function (topic, index) {
topicsData.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];
}
if (topic && results.tags && results.tags[index]) {
topic.tags = results.tags[index];
}
});
next(null, topics);
next(null, topicsData);
});
}
}, next);
@ -297,6 +312,21 @@ function filterByTimerange(posts, timeRange, timeFilter) {
return posts;
}
function filterByTags(posts, hasTags) {
if (hasTags && hasTags.length) {
posts = posts.filter(function (post) {
var hasAllTags = false;
if (post && post.topic && post.topic.tags && post.topic.tags.length) {
hasAllTags = hasTags.every(function (tag) {
return post.topic.tags.indexOf(tag) !== -1;
});
}
return hasAllTags;
});
}
return posts;
}
function sortPosts(posts, data) {
if (!posts.length || !data.sortBy) {
return;

@ -203,6 +203,13 @@ module.exports = function (Topics) {
db.getSetMembers('topic:' + tid + ':tags', callback);
};
Topics.getTopicsTags = function (tids, callback) {
var keys = tids.map(function (tid) {
return 'topic:' + tid + ':tags';
});
db.getSetsMembers(keys, callback);
};
Topics.getTopicTagsObjects = function (tid, callback) {
Topics.getTopicsTagsObjects([tid], function (err, data) {
callback(err, Array.isArray(data) && data.length ? data[0] : []);

@ -61,7 +61,7 @@ describe('Search', function () {
cid: cid1,
title: 'nodebb mongodb bugs',
content: 'avocado cucumber apple orange fox',
tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin']
tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin', 'jquery']
}, next);
},
function (results, next) {
@ -73,7 +73,7 @@ describe('Search', function () {
cid: cid2,
title: 'java mongodb redis',
content: 'avocado cucumber carrot armadillo',
tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin']
tags: ['nodebb', 'bug', 'plugin', 'nodebb-plugin', 'javascript']
}, next);
},
function (results, next) {
@ -155,6 +155,18 @@ describe('Search', function () {
});
});
it('should search with tags filter', function (done) {
search.search({
query: 'mongodb',
searchIn: 'titles',
hasTags: ['nodebb', 'javascript']
}, function (err, data) {
assert.ifError(err);
assert.equal(data.posts[0].tid, topic2Data.tid);
done();
});
});
after(function (done) {
db.emptydb(done);
});

Loading…
Cancel
Save