Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 78 additions & 85 deletions src/groups/search.js
Original file line number Diff line number Diff line change
@@ -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;
140 changes: 140 additions & 0 deletions src/groups/search.ts
Original file line number Diff line number Diff line change
@@ -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<Groups[]>;
ephemeralGroups: string[];
BANNED_USERS: string;
getGroupsAndMembers: (groupNames: string[]) => Promise<Groups[]>;
getGroupsData: (groupNames: string[]) => Promise<Groups[]>;
sort: (strategy: string, groups: Groups[]) => Groups[];
searchMembers: (data: { query: string; groupName: string; uid?: number }) => Promise<SearchResults>;
getOwnersAndMembers: (groupName: string, uid?: number, start?: number, stop?: number) => Promise<User[]>;
ownership: {
isOwners: (uids: number[], groupName: string) => Promise<boolean[]>;
};
}

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<Groups[]> {
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<SearchResults> {
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
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"allowJs": false,
"target": "es6",
"target": "es2017",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
Expand Down