feat: adds new model function for aggregated agents by department (#36541)

This commit is contained in:
Lucas Pelegrino 2025-07-30 12:41:40 -03:00 committed by GitHub
parent fc1270c3ef
commit 84f7c43a72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 91 additions and 39 deletions

View File

@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/model-typings": minor
"@rocket.chat/models": minor
---
Adds user object in department/:deparmentId/agents with username and name.

View File

@ -168,18 +168,24 @@ export async function findDepartmentsToAutocomplete({
export async function findDepartmentAgents({
departmentId,
pagination: { offset, count, sort },
}: FindDepartmentAgentsParams): Promise<PaginatedResult<{ agents: ILivechatDepartmentAgents[] }>> {
const { cursor, totalCount } = LivechatDepartmentAgents.findAgentsByDepartmentId<ILivechatDepartmentAgents>(departmentId, {
}: FindDepartmentAgentsParams): Promise<
PaginatedResult<{ agents: (ILivechatDepartmentAgents & { user: { _id: string; username: string; name: string } })[] }>
> {
const cursor = LivechatDepartmentAgents.findAgentsByDepartmentId(departmentId, {
sort: sort || { username: 1 },
skip: offset,
limit: count,
});
const [agents, total] = await Promise.all([cursor.toArray(), totalCount]);
const [
{
result,
totalCount: [{ total } = { total: 0 }],
},
] = await cursor.toArray();
return {
agents,
count: agents.length,
agents: result,
count: result.length,
offset,
total,
};

View File

@ -841,6 +841,10 @@ import { IS_EE } from '../../../e2e/config/constants';
expect(res.body.agents[0]).to.have.property('_id');
expect(res.body.agents[0]).to.have.property('departmentId', dep._id);
expect(res.body.agents[0]).to.have.property('departmentEnabled', true);
expect(res.body.agents[0]).to.have.property('user');
expect(res.body.agents[0].user).to.have.property('_id');
expect(res.body.agents[0].user).to.have.property('username');
expect(res.body.agents[0].user).to.have.property('name');
expect(res.body.count).to.be.equal(1);
await deleteDepartment(dep._id);
});

View File

@ -1,7 +1,7 @@
import type { AvailableAgentsAggregation, ILivechatDepartmentAgents } from '@rocket.chat/core-typings';
import type { DeleteResult, FindCursor, FindOptions, Document, UpdateResult, Filter, AggregationCursor } from 'mongodb';
import type { FindPaginated, IBaseModel } from './IBaseModel';
import type { IBaseModel } from './IBaseModel';
export interface ILivechatDepartmentAgentsModel extends IBaseModel<ILivechatDepartmentAgents> {
findUsersInQueue(usersList: string[]): FindCursor<ILivechatDepartmentAgents>;
@ -22,22 +22,13 @@ export interface ILivechatDepartmentAgentsModel extends IBaseModel<ILivechatDepa
): FindCursor<ILivechatDepartmentAgents> | FindCursor<P>;
findByAgentId(agentId: string, options?: FindOptions<ILivechatDepartmentAgents>): FindCursor<ILivechatDepartmentAgents>;
findAgentsByDepartmentId(departmentId: string): FindPaginated<FindCursor<ILivechatDepartmentAgents>>;
findAgentsByDepartmentId(
departmentId: string,
options: FindOptions<ILivechatDepartmentAgents>,
): FindPaginated<FindCursor<ILivechatDepartmentAgents>>;
findAgentsByDepartmentId<P extends Document>(
departmentId: string,
options: FindOptions<P extends ILivechatDepartmentAgents ? ILivechatDepartmentAgents : P>,
): FindPaginated<FindCursor<P>>;
findAgentsByDepartmentId(
departmentId: string,
options?: undefined | FindOptions<ILivechatDepartmentAgents>,
): FindPaginated<FindCursor<ILivechatDepartmentAgents>>;
options?: FindOptions<ILivechatDepartmentAgents>,
): AggregationCursor<{
result: (ILivechatDepartmentAgents & { user: { _id: string; username: string; name: string } })[];
totalCount: { _id: null; total: number }[];
}>;
findByDepartmentIds(departmentIds: string[], options?: Record<string, any>): FindCursor<ILivechatDepartmentAgents>;
findAgentsByAgentIdAndBusinessHourId(_agentId: string, _businessHourId: string): Promise<ILivechatDepartmentAgents[]>;

View File

@ -1,5 +1,5 @@
import type { AvailableAgentsAggregation, ILivechatDepartmentAgents, RocketChatRecordDeleted } from '@rocket.chat/core-typings';
import type { FindPaginated, ILivechatDepartmentAgentsModel } from '@rocket.chat/model-typings';
import type { ILivechatDepartmentAgentsModel } from '@rocket.chat/model-typings';
import type {
Collection,
FindCursor,
@ -15,6 +15,7 @@ import type {
} from 'mongodb';
import { Users } from '../index';
import { readSecondaryPreferred } from '../readSecondaryPreferred';
import { BaseRaw } from './BaseRaw';
export class LivechatDepartmentAgentsRaw extends BaseRaw<ILivechatDepartmentAgents> implements ILivechatDepartmentAgentsModel {
@ -87,29 +88,72 @@ export class LivechatDepartmentAgentsRaw extends BaseRaw<ILivechatDepartmentAgen
return this.find({ agentId }, options);
}
findAgentsByDepartmentId(departmentId: string): FindPaginated<FindCursor<ILivechatDepartmentAgents>>;
findAgentsByDepartmentId(
departmentId: string,
options: FindOptions<ILivechatDepartmentAgents>,
): FindPaginated<FindCursor<ILivechatDepartmentAgents>>;
options?: FindOptions<ILivechatDepartmentAgents>,
): AggregationCursor<{
result: (ILivechatDepartmentAgents & { user: { _id: string; username: string; name: string } })[];
totalCount: { _id: null; total: number }[];
}> {
const lookup = {
$lookup: {
from: 'users',
let: {
agentId: '$agentId',
},
pipeline: [
{
$match: {
$expr: {
$eq: ['$_id', '$$agentId'],
},
},
},
{
$project: {
_id: 1,
username: 1,
name: 1,
},
},
],
as: 'user',
},
};
const unwind = { $unwind: { path: '$user' } };
findAgentsByDepartmentId<P extends Document>(
departmentId: string,
options: FindOptions<P extends ILivechatDepartmentAgents ? ILivechatDepartmentAgents : P>,
): FindPaginated<FindCursor<P>>;
const sort: Document = { $sort: options?.sort || { username: 1 } };
const pagination = [sort];
findAgentsByDepartmentId(
departmentId: string,
options?: undefined | FindOptions<ILivechatDepartmentAgents>,
): FindPaginated<FindCursor<ILivechatDepartmentAgents>> {
const query = { departmentId };
if (options === undefined) {
return this.findPaginated(query);
if (options?.skip) {
pagination.push({ $skip: options.skip });
}
return this.findPaginated(query, options);
if (options?.limit) {
pagination.push({ $limit: options.limit });
}
const facet = {
$facet: {
result: pagination,
totalCount: [{ $group: { _id: null, total: { $sum: 1 } } }],
},
};
return this.col.aggregate<{
result: (ILivechatDepartmentAgents & { user: { _id: string; username: string; name: string } })[];
totalCount: { _id: null; total: number }[];
}>(
[
{
$match: { departmentId },
},
lookup,
unwind,
facet,
],
{ readPreference: readSecondaryPreferred(), allowDiskUse: true },
);
}
findByDepartmentIds(departmentIds: string[], options = {}): FindCursor<ILivechatDepartmentAgents> {