feat: search in bookmarks on search page

This commit is contained in:
Barış Soner Uşaklı
2024-01-12 14:02:28 -05:00
parent 1b094b80f1
commit 5213e22a6e
5 changed files with 62 additions and 5 deletions

View File

@@ -7,6 +7,7 @@
"in-titles": "In titles",
"in-titles-posts": "In titles and posts",
"in-posts": "In posts",
"in-bookmarks": "In bookmarks",
"in-categories": "In categories",
"in-users": "In users",
"in-tags": "In tags",

View File

@@ -119,7 +119,7 @@ define('forum/search', [
in: $('#search-in').val(),
};
searchData.term = $('#search-input').val();
if (searchData.in === 'posts' || searchData.in === 'titlesposts' || searchData.in === 'titles') {
if (['posts', 'titlesposts', 'titles', 'bookmarks'].includes(searchData.in)) {
searchData.matchWords = form.find('#match-words-filter').val();
searchData.by = selectedUsers.length ? selectedUsers.map(u => u.username) : undefined;
searchData.categories = selectedCids.length ? selectedCids : undefined;
@@ -143,7 +143,7 @@ define('forum/search', [
}
function updateFormItemVisiblity(searchIn) {
const hideTitlePostFilters = !searchIn.includes('posts') && !searchIn.includes('titles');
const hideTitlePostFilters = !['posts', 'titles', 'bookmarks'].some(token => searchIn.includes(token));
$('.post-search-item').toggleClass('hidden', hideTitlePostFilters);
}
@@ -252,6 +252,7 @@ define('forum/search', [
function categoryFilterDropdown(_selectedCids) {
ajaxify.data.allCategoriesUrl = '';
selectedCids = _selectedCids || [];
const dropdownEl = $('[component="category/filter"]');
categoryFilter.init(dropdownEl, {
selectedCids: _selectedCids,
@@ -290,6 +291,7 @@ define('forum/search', [
}
function userFilterDropdown(el, _selectedUsers) {
selectedUsers = _selectedUsers || [];
userFilter.init(el, {
selectedUsers: _selectedUsers,
template: 'partials/search-filters',

View File

@@ -36,7 +36,7 @@ searchController.search = async function (req, res, next) {
let allowed = (req.query.in === 'users' && userPrivileges['search:users']) ||
(req.query.in === 'tags' && userPrivileges['search:tags']) ||
(req.query.in === 'categories') ||
(['titles', 'titlesposts', 'posts'].includes(req.query.in) && userPrivileges['search:content']);
(['titles', 'titlesposts', 'posts', 'bookmarks'].includes(req.query.in) && userPrivileges['search:content']);
({ allowed } = await plugins.hooks.fire('filter:search.isAllowed', {
uid: req.uid,
query: req.query,

View File

@@ -261,4 +261,21 @@ module.exports = function (Posts) {
}
});
}
Posts.filterPidsByUid = async function (pids, uids) {
if (!uids) {
return pids;
}
if (!Array.isArray(uids) || uids.length === 1) {
return await filterPidsBySingleUid(pids, uids);
}
const pidsArr = await Promise.all(uids.map(uid => Posts.filterPidsByUid(pids, uid)));
return _.union(...pidsArr);
};
async function filterPidsBySingleUid(pids, uid) {
const isMembers = await db.isSortedSetMembers(`uid:${parseInt(uid, 10)}:posts`, pids);
return pids.filter((pid, index) => pid && isMembers[index]);
}
};

View File

@@ -3,6 +3,7 @@
const _ = require('lodash');
const db = require('./database');
const batch = require('./batch');
const posts = require('./posts');
const topics = require('./topics');
const categories = require('./categories');
@@ -18,7 +19,7 @@ search.search = async function (data) {
data.sortBy = data.sortBy || 'relevance';
let result;
if (data.searchIn === 'posts' || data.searchIn === 'titles' || data.searchIn === 'titlesposts') {
if (['posts', 'titles', 'titlesposts', 'bookmarks'].includes(data.searchIn)) {
result = await searchInContent(data);
} else if (data.searchIn === 'users') {
result = await user.search(data);
@@ -68,6 +69,8 @@ async function searchInContent(data) {
const tid = inTopic[1];
const cleanedTerm = data.query.replace(inTopic[0], '');
pids = await topics.search(tid, cleanedTerm);
} else if (data.searchIn === 'bookmarks') {
pids = await searchInBookmarks(data, searchCids, searchUids);
} else {
[pids, tids] = await Promise.all([
doSearch('post', ['posts', 'titlesposts']),
@@ -115,8 +118,42 @@ async function searchInContent(data) {
return Object.assign(returnData, metadata);
}
async function searchInBookmarks(data, searchCids, searchUids) {
const { uid, query, matchWords } = data;
const allPids = [];
await batch.processSortedSet(`uid:${uid}:bookmarks`, async (pids) => {
if (Array.isArray(searchCids) && searchCids.length) {
pids = await posts.filterPidsByCid(pids, searchCids);
}
if (Array.isArray(searchUids) && searchUids.length) {
pids = await posts.filterPidsByUid(pids, searchUids);
}
if (query) {
const tokens = String(query).split(' ');
const postData = await db.getObjectsFields(pids.map(pid => `post:${pid}`), ['content']);
pids = pids.filter((pid, i) => {
const content = String(postData[i].content);
if (matchWords === 'any') {
return tokens.some(t => content.includes(t));
}
return tokens.every(t => content.includes(t));
});
}
allPids.push(...pids);
}, {
batch: 500,
});
return allPids;
}
async function filterAndSort(pids, data) {
if (data.sortBy === 'relevance' && !data.replies && !data.timeRange && !data.hasTags && !plugins.hooks.hasListeners('filter:search.filterAndSort')) {
if (data.sortBy === 'relevance' &&
!data.replies &&
!data.timeRange &&
!data.hasTags &&
data.searchIn !== 'bookmarks' &&
!plugins.hooks.hasListeners('filter:search.filterAndSort')) {
return pids;
}
let postsData = await getMatchedPosts(pids, data);