diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts index a762e5297..eb9ecd6d6 100644 --- a/src/api/routes/guilds/#guild_id/messages/search.ts +++ b/src/api/routes/guilds/#guild_id/messages/search.ts @@ -19,10 +19,10 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { route } from "@spacebar/api"; -import { Channel, FieldErrors, Message, getPermission } from "@spacebar/util"; +import { Channel, FieldErrors, Member, Message, Snowflake, getPermission } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; -import { FindManyOptions, In, Like } from "typeorm"; +import { Between, FindManyOptions, FindOptionsWhere, In, LessThan, Like, MoreThan } from "typeorm"; const router: Router = Router({ mergeParams: true }); @@ -43,16 +43,17 @@ router.get( }), async (req: Request, res: Response) => { const { - channel_id, content, // include_nsfw, // TODO offset, sort_order, // sort_by, // TODO: Handle 'relevance' limit, - author_id, + max_id, + min_id, } = req.query as Record; - + const { author_id } = req.query as Record; + let { channel_id, mentions } = req.query as Record; const parsedLimit = Number(limit) || 50; if (parsedLimit < 1 || parsedLimit > 100) throw new HTTPError("limit must be between 1 and 100", 422); @@ -65,43 +66,98 @@ router.get( }, }); // todo this is wrong } - - const permissions = await getPermission(req.user_id, req.params.guild_id as string, channel_id as string | undefined); - permissions.hasThrow("VIEW_CHANNEL"); - if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json({ messages: [], total_results: 0 }); + if (channel_id) { + const ids = new Set(channel_id instanceof Array ? channel_id : [channel_id]); + Promise.all( + [...ids].map(async (id) => { + const permissions = await getPermission(req.user_id, req.params.guild_id as string, id); + permissions.hasThrow("VIEW_CHANNEL"); + if (!permissions.has("READ_MESSAGE_HISTORY")) ids.delete(id); + }), + ); + if (ids.size === 0) { + res.json({ messages: [], total_results: 0 }); + } else if (ids.size === 1) { + channel_id = [...ids][0]; + } else { + channel_id = [...ids]; + } + } else { + const permissions = await getPermission(req.user_id, req.params.guild_id as string); + permissions.hasThrow("VIEW_CHANNEL"); + if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json({ messages: [], total_results: 0 }); + } + const minStamp = min_id ? Snowflake.deconstruct(min_id).timestamp : 0; + const maxStamp = max_id ? Snowflake.deconstruct(max_id).timestamp : 0; + const where: FindOptionsWhere = { + guild: { + id: req.params.guild_id as string, + }, + ...(content ? { content: Like(`%${content}%`) } : {}), + ...(author_id ? (author_id instanceof Array ? { author_id: In(author_id) } : { author_id }) : {}), + ...(channel_id + ? channel_id instanceof Array + ? { channel_id: In(channel_id) } + : { channel_id } + : { + channel_id: In( + ( + await Promise.all( + ( + await Channel.find({ + where: { guild_id: req.params.guild_id as string }, + select: { id: true }, + }) + ).map(async (channel) => { + const perm = await getPermission(req.user_id, req.params.guild_id as string, channel.id); + return perm.has("VIEW_CHANNEL") && perm.has("READ_MESSAGE_HISTORY") ? channel : undefined; + }), + ) + ) + .filter((_) => _ !== undefined) + .map(({ id }) => id), + ), + }), + ...(minStamp + ? maxStamp + ? { timestamp: Between(new Date(minStamp), new Date(maxStamp)) } + : { timestamp: MoreThan(new Date(minStamp)) } + : maxStamp + ? { timestamp: LessThan(new Date(maxStamp)) } + : {}), + }; + mentions = mentions instanceof Array ? mentions : mentions ? [mentions] : []; + let roleids = [] as string[]; + if (mentions) { + const ms = await Member.find({ where: { id: In(mentions), guild_id: req.params.guild_id as string }, relations: ["roles"] }); + const rSet = new Set(); + ms.forEach((memb) => { + memb.roles.forEach(({ id }) => rSet.add(id)); + }); + roleids = [...rSet]; + } const query: FindManyOptions = { order: { timestamp: sort_order ? (sort_order.toUpperCase() as "ASC" | "DESC") : "DESC", }, - where: { - guild: { - id: req.params.guild_id as string, - }, - ...(content ? { content: Like(`%${content}%`) } : {}), - ...(author_id ? { author_id } : {}), - ...(channel_id - ? { channel_id } - : { - channel_id: In( - ( - await Promise.all( - ( - await Channel.find({ - where: { guild_id: req.params.guild_id as string }, - select: { id: true }, - }) - ).map(async (channel) => { - const perm = await getPermission(req.user_id, req.params.guild_id as string, channel.id); - return perm.has("VIEW_CHANNEL") && perm.has("READ_MESSAGE_HISTORY") ? channel : undefined; - }), - ) - ) - .filter((_) => _ !== undefined) - .map(({ id }) => id), - ), - }), - }, + where: mentions.length + ? [ + { ...where, mention_everyone: true }, + { + ...where, + mentions: { + id: In(mentions), + }, + }, + { + ...where, + mention_roles: { + id: In(roleids), + }, + }, + ] + : where, relations: { author: true, webhook: true, application: true, mentions: true, mention_roles: true, mention_channels: true, sticker_items: true, attachments: true }, };