import type { ILivechatDepartment, ILivechatDepartmentAgents } from '@rocket.chat/core-typings'; import { LivechatDepartment, LivechatDepartmentAgents } from '@rocket.chat/models'; import { applyDepartmentRestrictions } from '@rocket.chat/omni-core'; import type { PaginatedResult } from '@rocket.chat/rest-typings'; import { escapeRegExp } from '@rocket.chat/tools'; import type { Document, Filter, FilterOperators, FindOptions } from 'mongodb'; import { hasPermissionAsync } from '../../../../lib/authorization/hasPermission'; type Pagination = { pagination: { offset: number; count: number; sort: FindOptions['sort'] } }; type FindDepartmentParams = { userId: string; onlyMyDepartments?: boolean; text?: string; enabled?: boolean; excludeDepartmentId?: string; showArchived?: boolean; } & Pagination; type FindDepartmentByIdParams = { userId: string; departmentId: string; includeAgents?: boolean; onlyMyDepartments?: boolean; }; type FindDepartmentToAutocompleteParams = { uid: string; selector: { exceptions: string[]; conditions: Filter; term: string; }; onlyMyDepartments?: boolean; showArchived?: boolean; }; type FindDepartmentAgentsParams = { userId: string; departmentId: string; } & Pagination; export async function findDepartments({ userId, onlyMyDepartments = false, text, enabled, excludeDepartmentId, showArchived = false, pagination: { offset, count, sort }, }: FindDepartmentParams): Promise> { let query: FilterOperators = { $or: [{ type: { $eq: 'd' } }, { type: { $exists: false } }], ...(!showArchived && { archived: { $ne: !showArchived } }), ...(enabled && { enabled: Boolean(enabled) }), ...(text && { name: new RegExp(escapeRegExp(text), 'i') }), ...(excludeDepartmentId && { _id: { $ne: excludeDepartmentId } }), }; if (onlyMyDepartments) { query = await applyDepartmentRestrictions(query, userId); } const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { sort: sort || { name: 1 }, skip: offset, limit: count, }); const [departments, total] = await Promise.all([cursor.toArray(), totalCount]); return { departments, count: departments.length, offset, total, }; } export async function findArchivedDepartments({ userId, onlyMyDepartments = false, text, excludeDepartmentId, pagination: { offset, count, sort }, }: FindDepartmentParams): Promise> { let query: FilterOperators = { $or: [{ type: { $eq: 'd' } }, { type: { $exists: false } }], archived: { $eq: true }, ...(text && { name: new RegExp(escapeRegExp(text), 'i') }), ...(excludeDepartmentId && { _id: { $ne: excludeDepartmentId } }), }; if (onlyMyDepartments) { query = await applyDepartmentRestrictions(query, userId); } const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { sort: sort || { name: 1 }, skip: offset, limit: count, }); const [departments, total] = await Promise.all([cursor.toArray(), totalCount]); return { departments, count: departments.length, offset, total, }; } export async function findDepartmentById({ userId, departmentId, includeAgents = true, onlyMyDepartments = false, }: FindDepartmentByIdParams): Promise<{ department: ILivechatDepartment | null; agents?: ILivechatDepartmentAgents[]; }> { const canViewLivechatDepartments = includeAgents && (await hasPermissionAsync(userId, 'view-livechat-departments')); let query: FilterOperators = { _id: departmentId }; if (onlyMyDepartments) { query = await applyDepartmentRestrictions(query, userId); } const result = { department: await LivechatDepartment.findOne(query), ...(includeAgents && canViewLivechatDepartments && { agents: await LivechatDepartmentAgents.findByDepartmentId(departmentId).toArray(), }), }; return result; } export async function findDepartmentsToAutocomplete({ uid, selector, onlyMyDepartments = false, showArchived = false, }: FindDepartmentToAutocompleteParams): Promise<{ items: Pick[] }> { const { exceptions = [] } = selector; let { conditions = {} } = selector; if (onlyMyDepartments) { conditions = await applyDepartmentRestrictions(conditions, uid); } const conditionsWithArchived = { archived: { $ne: !showArchived }, ...conditions }; const items = await LivechatDepartment.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditionsWithArchived, { projection: { _id: 1, name: 1, }, sort: { name: 1, }, }).toArray(); return { items, }; } export async function findDepartmentAgents({ departmentId, pagination: { offset, count, sort }, }: FindDepartmentAgentsParams): Promise> { const { cursor, totalCount } = LivechatDepartmentAgents.findAgentsByDepartmentId(departmentId, { sort: sort || { username: 1 }, skip: offset, limit: count, }); const [agents, total] = await Promise.all([cursor.toArray(), totalCount]); return { agents, count: agents.length, offset, total, }; } export async function findDepartmentsBetweenIds({ ids, fields, }: { ids: string[]; fields: Record; }): Promise<{ departments: ILivechatDepartment[] }> { const departments = await LivechatDepartment.findInIds(ids, { projection: fields }).toArray(); return { departments }; }