import type { IRoom, IRoomAbacRedaction, ISubscription, RoomAdminFieldsType, RoomType } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions } from '@rocket.chat/models'; import type { FindOptions, Sort } from 'mongodb'; import { scopeAdminRoomsForAbac } from './scopeAdminRoomsForAbac'; import { adminFields } from '../../../lib/rooms/adminFields'; import { hasAtLeastOnePermissionAsync, hasPermissionAsync } from '../../lib/authorization/hasPermission'; import { stripABACManagedFieldsForAdmin } from '../../lib/authorization/isABACManagedRoom'; export async function findAdminRooms({ uid, filter, types = [], pagination: { offset, count, sort }, }: { uid: string; filter: string; types: Array; pagination: { offset: number; count: number; sort: Sort }; }): Promise<{ rooms: Array & IRoomAbacRedaction>; count: number; offset: number; total: number; }> { if (!(await hasPermissionAsync(uid, 'view-room-administration'))) { throw new Error('error-not-authorized'); } const name = filter?.trim(); const discussion = types?.includes('discussions'); const includeTeams = types?.includes('teams'); const typesToRemove = ['discussions', 'teams']; const showTypes = Array.isArray(types) ? types.filter((type): type is RoomType => !typesToRemove.includes(type)) : []; const options: FindOptions = { projection: adminFields, skip: offset, limit: count, }; const result = Rooms.findByNameOrFnameContainingAndTypes(name, showTypes, discussion, includeTeams, options); const { cursor, totalCount } = result; const [rooms, total] = await Promise.all([ cursor .sort(sort || { default: -1, name: 1 }) .map(stripABACManagedFieldsForAdmin) .toArray(), totalCount, ]); return { rooms: await scopeAdminRoomsForAbac(rooms, uid), count: rooms.length, offset, total, }; } export async function findAdminRoom({ uid, rid, }: { uid: string; rid: string; }): Promise<(Pick & IRoomAbacRedaction) | null> { if (!(await hasPermissionAsync(uid, 'view-room-administration'))) { throw new Error('error-not-authorized'); } const room = await Rooms.findOneById(rid, { projection: adminFields }); if (!room) { return null; } const [scoped] = await scopeAdminRoomsForAbac([stripABACManagedFieldsForAdmin(room)], uid); return scoped ?? null; } export async function findChannelAndPrivateAutocomplete({ uid, selector }: { uid: string; selector: { name: string } }): Promise<{ items: IRoom[]; }> { const options: FindOptions = { projection: { _id: 1, fname: 1, name: 1, t: 1, avatarETag: 1, encrypted: 1, }, limit: 10, sort: { name: 1, }, }; const userRoomsIds = (await Subscriptions.findByUserId(uid, { projection: { rid: 1 } }).toArray()).map( (item: Pick) => item.rid, ); const rooms = await Rooms.findRoomsWithoutDiscussionsByRoomIds(selector.name, userRoomsIds, options).toArray(); return { items: rooms, }; } export async function findAdminRoomsAutocomplete({ uid, selector }: { uid: string; selector: { name: string } }): Promise<{ items: IRoom[]; }> { if (!(await hasAtLeastOnePermissionAsync(uid, ['view-room-administration', 'can-audit']))) { throw new Error('error-not-authorized'); } const options: FindOptions = { projection: { _id: 1, fname: 1, name: 1, t: 1, avatarETag: 1, encrypted: 1, }, limit: 10, sort: { name: 1, }, }; const rooms = await Rooms.findRoomsByNameOrFnameStarting(selector.name, options).toArray(); return { items: rooms, }; } export async function findChannelAndPrivateAutocompleteWithPagination({ uid, selector, pagination: { offset, count, sort }, }: { uid: string; selector: { name: string }; pagination: { offset: number; count: number; sort: Sort }; }): Promise<{ items: IRoom[]; total: number; }> { const userRoomsIds = (await Subscriptions.findByUserId(uid, { projection: { rid: 1 } }).toArray()).map( (item: Pick) => item.rid, ); const options: FindOptions = { projection: { _id: 1, fname: 1, name: 1, t: 1, avatarETag: 1, }, sort: sort || { name: 1 }, skip: offset, limit: count, }; const { cursor, totalCount } = Rooms.findPaginatedRoomsWithoutDiscussionsByRoomIds(selector.name, userRoomsIds, options); const [rooms, total] = await Promise.all([cursor.toArray(), totalCount]); return { items: rooms, total, }; } export async function findRoomsAvailableForTeams({ uid, name }: { uid: string; name?: string }): Promise<{ items: IRoom[]; }> { const options: FindOptions = { projection: { _id: 1, fname: 1, name: 1, t: 1, avatarETag: 1, }, limit: 10, sort: { name: 1, }, }; const userRooms = ( (await Subscriptions.findByUserIdAndRoles(uid, ['owner'], { projection: { rid: 1 } }).toArray()) as Pick[] ).map((item) => item.rid); const rooms = await Rooms.findChannelAndGroupListWithoutTeamsByNameStartingByOwner(name, userRooms, options).toArray(); return { items: rooms, }; }