diff --git a/src/groups/search.js b/src/groups/search.js index 3e0dfd2def..c77525e7c1 100644 --- a/src/groups/search.js +++ b/src/groups/search.js @@ -1,86 +1,79 @@ -'use strict'; - -const user = require('../user'); -const db = require('../database'); - -module.exports = function (Groups) { - Groups.search = async function (query, options) { - if (!query) { - return []; - } - query = String(query).toLowerCase(); - let groupNames = Object.values(await db.getObject('groupslug:groupname')); - if (!options.hideEphemeralGroups) { - groupNames = Groups.ephemeralGroups.concat(groupNames); - } - groupNames = groupNames.filter( - name => name.toLowerCase().includes(query) && name !== Groups.BANNED_USERS // hide banned-users in searches - ); - groupNames = groupNames.slice(0, 100); - - let groupsData; - if (options.showMembers) { - groupsData = await Groups.getGroupsAndMembers(groupNames); - } else { - groupsData = await Groups.getGroupsData(groupNames); - } - groupsData = groupsData.filter(Boolean); - if (options.filterHidden) { - groupsData = groupsData.filter(group => !group.hidden); - } - return Groups.sort(options.sort, groupsData); - }; - - Groups.sort = function (strategy, groups) { - switch (strategy) { - case 'count': - groups.sort((a, b) => a.slug > b.slug) - .sort((a, b) => b.memberCount - a.memberCount); - break; - - case 'date': - groups.sort((a, b) => b.createtime - a.createtime); - break; - - case 'alpha': // intentional fall-through - default: - groups.sort((a, b) => (a.slug > b.slug ? 1 : -1)); - } - - return groups; - }; - - Groups.searchMembers = async function (data) { - if (!data.query) { - const users = await Groups.getOwnersAndMembers(data.groupName, data.uid, 0, 19); - const matchCount = users.length; - const timing = '0.00'; - return { users, matchCount, timing }; - } - - const results = await user.search({ - ...data, - paginate: false, - hardCap: -1, - }); - - const uids = results.users.map(user => user && user.uid); - const isOwners = await Groups.ownership.isOwners(uids, data.groupName); - - results.users.forEach((user, index) => { - if (user) { - user.isOwner = isOwners[index]; - } - }); - - results.users.sort((a, b) => { - if (a.isOwner && !b.isOwner) { - return -1; - } else if (!a.isOwner && b.isOwner) { - return 1; - } - return 0; - }); - return results; - }; +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call +const user_1 = __importDefault(require("../user")); +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call +const database_1 = __importDefault(require("../database")); +function attachSearchFunctions(Groups) { + Groups.search = async function (query, options = {}) { + if (!query) { + return []; + } + query = query.toLowerCase(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + let groupNames = Object.values(await database_1.default.getObject('groupslug:groupname')); + if (!options.hideEphemeralGroups) { + groupNames = Groups.ephemeralGroups.concat(groupNames); + } + groupNames = groupNames.filter((name) => name.toLowerCase().includes(query) && name !== Groups.BANNED_USERS); + groupNames = groupNames.slice(0, 100); + let groupsData; + if (options.showMembers) { + groupsData = await Groups.getGroupsAndMembers(groupNames); + } + else { + groupsData = await Groups.getGroupsData(groupNames); + } + groupsData = groupsData.filter(Boolean); + if (options.filterHidden) { + groupsData = groupsData.filter(group => !group.hidden); + } + return Groups.sort(options.sort, groupsData) || []; // Ensure non-empty array return + }; + Groups.sort = function (strategy, groups) { + switch (strategy) { + case 'count': + groups.sort((a, b) => a.slug.localeCompare(b.slug)) + .sort((a, b) => b.memberCount - a.memberCount); + break; + case 'date': + groups.sort((a, b) => b.createtime - a.createtime); + break; + case 'alpha': // intentional fall-through + default: + groups.sort((a, b) => (a.slug > b.slug ? 1 : -1)); + } + return groups; + }; + Groups.searchMembers = async function (data) { + if (!data.query) { + const users = await Groups.getOwnersAndMembers(data.groupName, data.uid, 0, 19); + const matchCount = users.length; + const timing = '0.00'; + return { users, matchCount, timing }; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + const results = await user_1.default.search(Object.assign(Object.assign({}, data), { paginate: false, hardCap: -1 })); + const uids = results.users.map(user => user === null || user === void 0 ? void 0 : user.uid); + const isOwners = await Groups.ownership.isOwners(uids, data.groupName); + results.users.forEach((user, index) => { + if (user) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + user.isOwner = isOwners[index]; + } + }); + results.users.sort((a, b) => { + if ((a === null || a === void 0 ? void 0 : a.isOwner) && !(b === null || b === void 0 ? void 0 : b.isOwner)) { + return -1; + } + else if (!(a === null || a === void 0 ? void 0 : a.isOwner) && (b === null || b === void 0 ? void 0 : b.isOwner)) { + return 1; + } + return 0; + }); + return results; + }; +} +module.exports = attachSearchFunctions; diff --git a/src/groups/search.ts b/src/groups/search.ts new file mode 100644 index 0000000000..25af4327b3 --- /dev/null +++ b/src/groups/search.ts @@ -0,0 +1,140 @@ + +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call +import user from '../user'; +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call +import db from '../database'; + + +interface Groups { + slug: string; + memberCount: number; + hidden: boolean; + createtime: number; + search: (query: string, options: SearchOptions) => Promise; + ephemeralGroups: string[]; + BANNED_USERS: string; + getGroupsAndMembers: (groupNames: string[]) => Promise; + getGroupsData: (groupNames: string[]) => Promise; + sort: (strategy: string, groups: Groups[]) => Groups[]; + searchMembers: (data: { query: string; groupName: string; uid?: number }) => Promise; + getOwnersAndMembers: (groupName: string, uid?: number, start?: number, stop?: number) => Promise; + ownership: { + isOwners: (uids: number[], groupName: string) => Promise; + }; +} + +interface SearchOptions { + hideEphemeralGroups?: boolean; + showMembers?: boolean; + filterHidden?: boolean; + sort?: string; +} + +interface SearchResults { + users: User[]; + matchCount: number; + timing: string; +} + +interface User { + uid: number; + isOwner?: boolean; +} + + +function attachSearchFunctions(Groups: Groups) { + Groups.search = async function (query: string, options: SearchOptions = {}): Promise { + if (!query) { + return []; + } + query = query.toLowerCase(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + let groupNames = Object.values(await db.getObject('groupslug:groupname') as Groups); + if (!options.hideEphemeralGroups) { + groupNames = Groups.ephemeralGroups.concat(groupNames as string[]); + } + groupNames = groupNames.filter( + (name: string) => name.toLowerCase().includes(query) && name !== Groups.BANNED_USERS + ); + groupNames = groupNames.slice(0, 100); + + let groupsData: Groups[] | undefined; + if (options.showMembers) { + groupsData = await Groups.getGroupsAndMembers(groupNames as string[]); + } else { + groupsData = await Groups.getGroupsData(groupNames as string[]); + } + groupsData = groupsData.filter(Boolean); + if (options.filterHidden) { + groupsData = groupsData.filter(group => !group.hidden); + } + return Groups.sort(options.sort, groupsData) || []; // Ensure non-empty array return + }; + + Groups.sort = function (strategy: string, groups: Groups[]): Groups[] { + switch (strategy) { + case 'count': + groups.sort((a, b) => a.slug.localeCompare(b.slug)) + .sort((a, b) => b.memberCount - a.memberCount); + break; + + case 'date': + groups.sort((a, b) => b.createtime - a.createtime); + break; + + case 'alpha': // intentional fall-through + default: + groups.sort((a, b) => (a.slug > b.slug ? 1 : -1)); + } + + return groups; + }; + Groups.searchMembers = async function (data: { + query: string; + groupName: string; + uid?: number; + }): Promise { + if (!data.query) { + const users = await Groups.getOwnersAndMembers( + data.groupName, + data.uid, + 0, + 19 + ); + const matchCount = users.length; + const timing = '0.00'; + return { users, matchCount, timing }; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + const results: SearchResults = await user.search({ + ...data, + paginate: false, + hardCap: -1, + }) as SearchResults; + + const uids = results.users.map(user => user?.uid); + const isOwners = await Groups.ownership.isOwners( + uids, + data.groupName + ); + + results.users.forEach((user, index) => { + if (user) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + user.isOwner = isOwners[index]; + } + }); + + results.users.sort((a, b) => { + if (a?.isOwner && !b?.isOwner) { + return -1; + } else if (!a?.isOwner && b?.isOwner) { + return 1; + } + return 0; + }); + return results; + }; +} + +export = attachSearchFunctions diff --git a/tsconfig.json b/tsconfig.json index 10aeeef7e6..c15cb37711 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "allowJs": false, - "target": "es6", + "target": "es2017", "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true,