From cd495fb8422e846554a0428a6082a0c8bbb16609 Mon Sep 17 00:00:00 2001 From: Anuja Date: Sun, 29 Sep 2024 15:36:18 -0400 Subject: [PATCH 1/3] passing linter, removed trailing spaces etc --- src/api/search.js | 233 +++++++++++++++++++++++----------------------- 1 file changed, 115 insertions(+), 118 deletions(-) diff --git a/src/api/search.js b/src/api/search.js index 4d2e3ce650..1b0b2899bd 100644 --- a/src/api/search.js +++ b/src/api/search.js @@ -2,10 +2,10 @@ const _ = require('lodash'); -const db = require('../database'); -const user = require('../user'); +// const db = require('../database'); +// const user = require('../user'); const categories = require('../categories'); -const messaging = require('../messaging'); +// const messaging = require('../messaging'); const privileges = require('../privileges'); const meta = require('../meta'); const plugins = require('../plugins'); @@ -16,127 +16,124 @@ const searchApi = module.exports; // Main function for handling category searches searchApi.categories = async (caller, data) => { - // Placeholder arrays for category IDs (cids) and matched category IDs (matchedCids) - let cids = []; - let matchedCids = []; - - // Default privilege to check if not provided - const privilege = data.privilege || 'topics:read'; - - // Setting up watch states (e.g., watching, tracking, etc.) - data.states = (data.states || ['watching', 'tracking', 'notwatching', 'ignoring']).map( - state => categories.watchStates[state] - ); - - // Default parent category ID (cid) - data.parentCid = parseInt(data.parentCid || 0, 10); - - // Check if there is a search query - if (data.search) { - // If there is a search query, find matched categories based on the search - ({ cids, matchedCids } = await findMatchedCids(caller.uid, data)); - } else { - // If no search query, load all categories normally - cids = await loadCids(caller.uid, data.parentCid); - } - - // Get visible categories based on user's privileges and states - const visibleCategories = await controllersHelpers.getVisibleCategories({ - cids, // Category IDs to check visibility - uid: caller.uid, // User ID - states: data.states, // Watch states (e.g., watching, tracking) - privilege, // The privilege to check (default is 'topics:read') - showLinks: data.showLinks, - parentCid: data.parentCid, - }); - - // Handle selected categories from the UI if provided - if (Array.isArray(data.selectedCids)) { - data.selectedCids = data.selectedCids.map(cid => parseInt(cid, 10)); - } - - // Build the final category data array - let categoriesData = categories.buildForSelectCategories(visibleCategories, ['disabledClass'], data.parentCid); - categoriesData = categoriesData.slice(0, 200); // Limit to 200 categories - - // Mark selected and matched categories in the result - categoriesData.forEach((category) => { - category.selected = data.selectedCids ? data.selectedCids.includes(category.cid) : false; - if (matchedCids.includes(category.cid)) { - category.match = true; // Mark matched categories - } - }); - - // Fire a plugin hook in case any other plugins want to modify the category data - const result = await plugins.hooks.fire('filter:categories.categorySearch', { - categories: categoriesData, // The category data - ...data, // Spread in any additional data passed - uid: caller.uid, // The user ID - }); - - return { categories: result.categories }; // Return the final category result + // Placeholder arrays for category IDs (cids) and matched category IDs (matchedCids) + let cids = []; + let matchedCids = []; + // Default privilege to check if not provided + const privilege = data.privilege || 'topics:read'; + // Setting up watch states (e.g., watching, tracking, etc.) + data.states = (data.states || ['watching', 'tracking', 'notwatching', 'ignoring']).map( + state => categories.watchStates[state] + ); + + // Default parent category ID (cid) + data.parentCid = parseInt(data.parentCid || 0, 10); + + // Check if there is a search query + if (data.search) { + // If there is a search query, find matched categories based on the search + ({ cids, matchedCids } = await findMatchedCids(caller.uid, data)); + } else { + // If no search query, load all categories normally + cids = await loadCids(caller.uid, data.parentCid); + } + + // Get visible categories based on user's privileges and states + const visibleCategories = await controllersHelpers.getVisibleCategories({ + cids, // Category IDs to check visibility + uid: caller.uid, // User ID + states: data.states, // Watch states (e.g., watching, tracking) + privilege, // The privilege to check (default is 'topics:read') + showLinks: data.showLinks, + parentCid: data.parentCid, + }); + // Handle selected categories from the UI if provided + if (Array.isArray(data.selectedCids)) { + data.selectedCids = data.selectedCids.map(cid => parseInt(cid, 10)); + } + + // Build the final category data array + let categoriesData = categories.buildForSelectCategories(visibleCategories, ['disabledClass'], data.parentCid); + categoriesData = categoriesData.slice(0, 200); // Limit to 200 categories + + // Mark selected and matched categories in the result + categoriesData.forEach((category) => { + category.selected = data.selectedCids ? data.selectedCids.includes(category.cid) : false; + if (matchedCids.includes(category.cid)) { + category.match = true; // Mark matched categories + } + }); + + // Fire a plugin hook in case any other plugins want to modify the category data + const result = await plugins.hooks.fire('filter:categories.categorySearch', { + categories: categoriesData, // The category data + ...data, // Spread in any additional data passed + uid: caller.uid, // The user ID + }); + + return { categories: result.categories }; // Return the final category result }; // Function to find matching categories based on the search query async function findMatchedCids(uid, data) { - // Use the search function in the 'categories' module to search for categories - const result = await categories.search({ - uid: uid, // User ID for permission checks - query: data.search, // The search query entered by the user - qs: data.query, // Additional query parameters - paginate: false, // No pagination for now - }); - - // Extract matching category IDs - let matchedCids = result.categories.map(c => c.cid); - - // If not all watch states are selected, filter by watch state - const filterByWatchState = !Object.values(categories.watchStates) - .every(state => data.states.includes(state)); - - if (filterByWatchState) { - // Get watch states for the matched categories and filter based on those - const states = await categories.getWatchState(matchedCids, uid); - matchedCids = matchedCids.filter((cid, index) => data.states.includes(states[index])); - } - - // Get the parent and child category IDs for each matched category - const rootCids = _.uniq(_.flatten(await Promise.all(matchedCids.map(categories.getParentCids)))); - const allChildCids = _.uniq(_.flatten(await Promise.all(matchedCids.map(categories.getChildrenCids)))); - - // Return both the matched category IDs and the expanded list of categories - return { - cids: _.uniq(rootCids.concat(allChildCids).concat(matchedCids)), // Combined parent, child, and matched categories - matchedCids: matchedCids, // Only the matched categories - }; + // Use the search function in the 'categories' module to search for categories + const result = await categories.search({ + uid: uid, // User ID for permission checks + query: data.search, // The search query entered by the user + qs: data.query, // Additional query parameters + paginate: false, // No pagination for now + }); + + // Extract matching category IDs + let matchedCids = result.categories.map(c => c.cid); + + // If not all watch states are selected, filter by watch state + const filterByWatchState = !Object.values(categories.watchStates) + .every(state => data.states.includes(state)); + + if (filterByWatchState) { + // Get watch states for the matched categories and filter based on those + const states = await categories.getWatchState(matchedCids, uid); + matchedCids = matchedCids.filter((cid, index) => data.states.includes(states[index])); + } + + // Get the parent and child category IDs for each matched category + const rootCids = _.uniq(_.flatten(await Promise.all(matchedCids.map(categories.getParentCids)))); + const allChildCids = _.uniq(_.flatten(await Promise.all(matchedCids.map(categories.getChildrenCids)))); + + // Return both the matched category IDs and the expanded list of categories + return { + cids: _.uniq(rootCids.concat(allChildCids).concat(matchedCids)), // Combined parent, child, and matched categories + matchedCids: matchedCids, // Only the matched categories + }; } // Function to load category IDs if no search query is provided async function loadCids(uid, parentCid) { - let resultCids = []; - - // Recursive function to gather child categories - async function getCidsRecursive(cids) { - const categoryData = await categories.getCategoriesFields(cids, ['subCategoriesPerPage']); - const cidToData = _.zipObject(cids, categoryData); - - await Promise.all(cids.map(async (cid) => { - const allChildCids = await categories.getAllCidsFromSet(`cid:${cid}:children`); - if (allChildCids.length) { - const childCids = await privileges.categories.filterCids('find', allChildCids, uid); - resultCids.push(...childCids.slice(0, cidToData[cid].subCategoriesPerPage)); - await getCidsRecursive(childCids); - } - })); - } - - // Get the root categories for the parent category - const allRootCids = await categories.getAllCidsFromSet(`cid:${parentCid}:children`); - const rootCids = await privileges.categories.filterCids('find', allRootCids, uid); - const pageCids = rootCids.slice(0, meta.config.categoriesPerPage); - resultCids = pageCids; - - // Recursively get child categories - await getCidsRecursive(pageCids); - return resultCids; // Return the list of category IDs + let resultCids = []; + + // Recursive function to gather child categories + async function getCidsRecursive(cids) { + const categoryData = await categories.getCategoriesFields(cids, ['subCategoriesPerPage']); + const cidToData = _.zipObject(cids, categoryData); + + await Promise.all(cids.map(async (cid) => { + const allChildCids = await categories.getAllCidsFromSet(`cid:${cid}:children`); + if (allChildCids.length) { + const childCids = await privileges.categories.filterCids('find', allChildCids, uid); + resultCids.push(...childCids.slice(0, cidToData[cid].subCategoriesPerPage)); + await getCidsRecursive(childCids); + } + })); + } + + // Get the root categories for the parent category + const allRootCids = await categories.getAllCidsFromSet(`cid:${parentCid}:children`); + const rootCids = await privileges.categories.filterCids('find', allRootCids, uid); + const pageCids = rootCids.slice(0, meta.config.categoriesPerPage); + resultCids = pageCids; + + // Recursively get child categories + await getCidsRecursive(pageCids); + return resultCids; // Return the list of category IDs } From 1872b1aeadaf144e8bee466de84b28591eeac5ad Mon Sep 17 00:00:00 2001 From: Anuja Date: Mon, 7 Oct 2024 16:22:15 -0400 Subject: [PATCH 2/3] reverting changes from search bar to experiment on test passing --- src/api/search.js | 153 +++++++++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 62 deletions(-) diff --git a/src/api/search.js b/src/api/search.js index 1b0b2899bd..448f420635 100644 --- a/src/api/search.js +++ b/src/api/search.js @@ -2,10 +2,10 @@ const _ = require('lodash'); -// const db = require('../database'); -// const user = require('../user'); +const db = require('../database'); +const user = require('../user'); const categories = require('../categories'); -// const messaging = require('../messaging'); +const messaging = require('../messaging'); const privileges = require('../privileges'); const meta = require('../meta'); const plugins = require('../plugins'); @@ -14,109 +14,70 @@ const controllersHelpers = require('../controllers/helpers'); const searchApi = module.exports; -// Main function for handling category searches searchApi.categories = async (caller, data) => { - // Placeholder arrays for category IDs (cids) and matched category IDs (matchedCids) + // used by categorySearch module let cids = []; let matchedCids = []; - // Default privilege to check if not provided const privilege = data.privilege || 'topics:read'; - // Setting up watch states (e.g., watching, tracking, etc.) data.states = (data.states || ['watching', 'tracking', 'notwatching', 'ignoring']).map( state => categories.watchStates[state] ); - - // Default parent category ID (cid) data.parentCid = parseInt(data.parentCid || 0, 10); - - // Check if there is a search query if (data.search) { - // If there is a search query, find matched categories based on the search ({ cids, matchedCids } = await findMatchedCids(caller.uid, data)); } else { - // If no search query, load all categories normally cids = await loadCids(caller.uid, data.parentCid); } - - // Get visible categories based on user's privileges and states const visibleCategories = await controllersHelpers.getVisibleCategories({ - cids, // Category IDs to check visibility - uid: caller.uid, // User ID - states: data.states, // Watch states (e.g., watching, tracking) - privilege, // The privilege to check (default is 'topics:read') - showLinks: data.showLinks, - parentCid: data.parentCid, + cids, uid: caller.uid, states: data.states, privilege, showLinks: data.showLinks, parentCid: data.parentCid, }); - // Handle selected categories from the UI if provided if (Array.isArray(data.selectedCids)) { data.selectedCids = data.selectedCids.map(cid => parseInt(cid, 10)); } - - // Build the final category data array let categoriesData = categories.buildForSelectCategories(visibleCategories, ['disabledClass'], data.parentCid); - categoriesData = categoriesData.slice(0, 200); // Limit to 200 categories - - // Mark selected and matched categories in the result + categoriesData = categoriesData.slice(0, 200); categoriesData.forEach((category) => { category.selected = data.selectedCids ? data.selectedCids.includes(category.cid) : false; if (matchedCids.includes(category.cid)) { - category.match = true; // Mark matched categories + category.match = true; } }); - - // Fire a plugin hook in case any other plugins want to modify the category data const result = await plugins.hooks.fire('filter:categories.categorySearch', { - categories: categoriesData, // The category data - ...data, // Spread in any additional data passed - uid: caller.uid, // The user ID + categories: categoriesData, + ...data, + uid: caller.uid, }); - - return { categories: result.categories }; // Return the final category result + return { categories: result.categories }; }; -// Function to find matching categories based on the search query async function findMatchedCids(uid, data) { - // Use the search function in the 'categories' module to search for categories const result = await categories.search({ - uid: uid, // User ID for permission checks - query: data.search, // The search query entered by the user - qs: data.query, // Additional query parameters - paginate: false, // No pagination for now + uid: uid, + query: data.search, + qs: data.query, + paginate: false, }); - - // Extract matching category IDs let matchedCids = result.categories.map(c => c.cid); - - // If not all watch states are selected, filter by watch state + // no need to filter if all 3 states are used const filterByWatchState = !Object.values(categories.watchStates) .every(state => data.states.includes(state)); - if (filterByWatchState) { - // Get watch states for the matched categories and filter based on those const states = await categories.getWatchState(matchedCids, uid); matchedCids = matchedCids.filter((cid, index) => data.states.includes(states[index])); } - - // Get the parent and child category IDs for each matched category const rootCids = _.uniq(_.flatten(await Promise.all(matchedCids.map(categories.getParentCids)))); const allChildCids = _.uniq(_.flatten(await Promise.all(matchedCids.map(categories.getChildrenCids)))); - - // Return both the matched category IDs and the expanded list of categories return { - cids: _.uniq(rootCids.concat(allChildCids).concat(matchedCids)), // Combined parent, child, and matched categories - matchedCids: matchedCids, // Only the matched categories + cids: _.uniq(rootCids.concat(allChildCids).concat(matchedCids)), + matchedCids: matchedCids, }; } -// Function to load category IDs if no search query is provided async function loadCids(uid, parentCid) { let resultCids = []; - - // Recursive function to gather child categories async function getCidsRecursive(cids) { const categoryData = await categories.getCategoriesFields(cids, ['subCategoriesPerPage']); const cidToData = _.zipObject(cids, categoryData); - await Promise.all(cids.map(async (cid) => { const allChildCids = await categories.getAllCidsFromSet(`cid:${cid}:children`); if (allChildCids.length) { @@ -126,14 +87,82 @@ async function loadCids(uid, parentCid) { } })); } - - // Get the root categories for the parent category const allRootCids = await categories.getAllCidsFromSet(`cid:${parentCid}:children`); const rootCids = await privileges.categories.filterCids('find', allRootCids, uid); const pageCids = rootCids.slice(0, meta.config.categoriesPerPage); resultCids = pageCids; - - // Recursively get child categories await getCidsRecursive(pageCids); - return resultCids; // Return the list of category IDs + return resultCids; } +searchApi.roomUsers = async (caller, { query, roomId }) => { + const [isAdmin, inRoom, isRoomOwner] = await Promise.all([ + user.isAdministrator(caller.uid), + messaging.isUserInRoom(caller.uid, roomId), + messaging.isRoomOwner(caller.uid, roomId), + ]); + if (!isAdmin && !inRoom) { + throw new Error('[[error:no-privileges]]'); + } + const results = await user.search({ + query, + paginate: false, + hardCap: -1, + uid: caller.uid, + }); + const { users } = results; + const foundUids = users.map(user => user && user.uid); + const isUidInRoom = _.zipObject( + foundUids, + await messaging.isUsersInRoom(foundUids, roomId) + ); + const roomUsers = users.filter(user => isUidInRoom[user.uid]); + const isOwners = await messaging.isRoomOwner(roomUsers.map(u => u.uid), roomId); + roomUsers.forEach((user, index) => { + if (user) { + user.isOwner = isOwners[index]; + user.canKick = isRoomOwner && (parseInt(user.uid, 10) !== parseInt(caller.uid, 10)); + } + }); + roomUsers.sort((a, b) => { + if (a.isOwner && !b.isOwner) { + return -1; + } else if (!a.isOwner && b.isOwner) { + return 1; + } + return 0; + }); + return { users: roomUsers }; +}; +searchApi.roomMessages = async (caller, { query, roomId, uid }) => { + const [roomData, inRoom] = await Promise.all([ + messaging.getRoomData(roomId), + messaging.isUserInRoom(caller.uid, roomId), + ]); + if (!roomData) { + throw new Error('[[error:no-room]]'); + } + if (!inRoom) { + throw new Error('[[error:no-privileges]]'); + } + const { ids } = await plugins.hooks.fire('filter:messaging.searchMessages', { + content: query, + roomId: [roomId], + uid: [uid], + matchWords: 'any', + ids: [], + }); + let userjoinTimestamp = 0; + if (!roomData.public) { + userjoinTimestamp = await db.sortedSetScore(`chat:room:${roomId}:uids`, caller.uid); + } + let messageData = await messaging.getMessagesData(ids, caller.uid, roomId, false); + messageData = messageData + .map((msg) => { + if (msg) { + msg.newSet = true; + } + return msg; + }) + .filter(msg => msg && !msg.deleted && msg.timestamp > userjoinTimestamp); + return { messages: messageData }; +}; \ No newline at end of file From 93c04792bfa1fd6bec6ffb0cd8b16194e68f7a5c Mon Sep 17 00:00:00 2001 From: Anuja Date: Mon, 7 Oct 2024 16:27:18 -0400 Subject: [PATCH 3/3] lint space fix --- src/api/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/search.js b/src/api/search.js index 448f420635..c90ba7369f 100644 --- a/src/api/search.js +++ b/src/api/search.js @@ -165,4 +165,4 @@ searchApi.roomMessages = async (caller, { query, roomId, uid }) => { }) .filter(msg => msg && !msg.deleted && msg.timestamp > userjoinTimestamp); return { messages: messageData }; -}; \ No newline at end of file +};