Skip to content

Commit

Permalink
[IMPROVE] Improve searchChats endpoint to have source filter support (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
KevLehman authored and MartinSchoeler committed Nov 28, 2022
1 parent af61cd3 commit 7518f79
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 4 deletions.
13 changes: 13 additions & 0 deletions apps/meteor/app/livechat/imports/server/rest/rooms.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isGETLivechatRoomsParams } from '@rocket.chat/rest-typings';
import { LivechatRooms } from '@rocket.chat/models';

import { API } from '../../../../api/server';
import { findRooms } from '../../../server/api/lib/rooms';
Expand Down Expand Up @@ -72,3 +73,15 @@ API.v1.addRoute(
},
},
);

API.v1.addRoute(
'livechat/rooms/filters',
{ authRequired: true, permissionsRequired: ['view-l-room'] },
{
async get() {
return API.v1.success({
filters: (await LivechatRooms.findAvailableSources().toArray())[0].fullTypes,
});
},
},
);
3 changes: 2 additions & 1 deletion apps/meteor/app/livechat/imports/server/rest/visitors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ API.v1.addRoute(
{
async get() {
const { roomId, visitorId } = this.urlParams;
const { searchText, closedChatsOnly, servedChatsOnly } = this.queryParams;
const { searchText, closedChatsOnly, servedChatsOnly, source } = this.queryParams;
const { offset, count } = this.getPaginationItems();
const { sort } = this.parseJsonQuery();
const history = await searchChats({
Expand All @@ -102,6 +102,7 @@ API.v1.addRoute(
searchText,
closedChatsOnly,
servedChatsOnly,
source,
pagination: {
offset,
count,
Expand Down
4 changes: 4 additions & 0 deletions apps/meteor/app/livechat/server/api/lib/visitors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export async function searchChats({
searchText,
closedChatsOnly,
servedChatsOnly: served,
source,
pagination: { offset, count, sort },
}: {
userId: IUser['_id'];
Expand All @@ -92,6 +93,7 @@ export async function searchChats({
searchText?: string;
closedChatsOnly?: string;
servedChatsOnly?: string;
source?: string;
pagination: { offset: number; count: number; sort: FindOptions<IOmnichannelRoom>['sort'] };
}) {
const room = await LivechatRooms.findOneById(roomId);
Expand All @@ -115,13 +117,15 @@ export async function searchChats({
served: served === 'true',
searchText,
onlyCount: true,
source,
}).toArray();
const cursor = await LivechatRooms.findRoomsByVisitorIdAndMessageWithCriteria({
visitorId,
open: closedChatsOnly !== 'true',
served: served === 'true',
searchText,
options,
source,
});

const history = await cursor.toArray();
Expand Down
51 changes: 49 additions & 2 deletions apps/meteor/server/models/raw/LivechatRooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -931,12 +931,15 @@ export class LivechatRoomsRaw extends BaseRaw {
return this.findPaginated(query, options);
}

findRoomsByVisitorIdAndMessageWithCriteria({ visitorId, searchText, open, served, onlyCount = false, options = {} }) {
findRoomsByVisitorIdAndMessageWithCriteria({ visitorId, searchText, open, served, onlyCount = false, source, options = {} }) {
const match = {
$match: {
'v._id': visitorId,
...(open !== undefined && { open: { $exists: open } }),
...(served !== undefined && { servedBy: { $exists: served } }),
...(source && {
$or: [{ 'source.type': new RegExp(escapeRegExp(source), 'i') }, { 'source.alias': new RegExp(escapeRegExp(source), 'i') }],
}),
},
};
const lookup = {
Expand All @@ -948,7 +951,7 @@ export class LivechatRoomsRaw extends BaseRaw {
},
};
const matchMessages = searchText && {
$match: { 'messages.msg': { $regex: `.*${searchText}.*` } },
$match: { 'messages.msg': { $regex: `.*${escapeRegExp(searchText)}.*` } },
};

const params = [match, lookup];
Expand Down Expand Up @@ -1237,4 +1240,48 @@ export class LivechatRoomsRaw extends BaseRaw {

return this.updateOne(query, update);
}

findAvailableSources() {
return this.col.aggregate([
{
$group: {
_id: 0,
types: {
$addToSet: {
$cond: {
if: {
$eq: ['$source.type', 'app'],
},
then: '$$REMOVE',
else: { type: '$source.type' },
},
},
},
apps: {
$addToSet: {
$cond: {
if: {
$eq: ['$source.type', 'app'],
},
else: '$$REMOVE',
then: {
type: '$source.type',
id: '$source.id',
alias: '$source.alias',
sidebarIcon: '$source.sidebarIcon',
defaultIcon: '$source.defaultIcon',
},
},
},
},
},
},
{
$project: {
_id: 0,
fullTypes: { $setUnion: ['$types', '$apps'] },
},
},
]);
}
}
13 changes: 13 additions & 0 deletions apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1433,4 +1433,17 @@ describe('LIVECHAT - rooms', function () {
.expect(400);
});
});

describe('livechat/rooms/filters', () => {
it('should fail if user doesnt have view-l-room permission', async () => {
await updatePermission('view-l-room', []);
await request.get(api('livechat/rooms/filters')).set(credentials).expect(403);
});
it('should return a list of available source filters', async () => {
await updatePermission('view-l-room', ['admin']);
const response = await request.get(api('livechat/rooms/filters')).set(credentials).expect(200);
expect(response.body).to.have.property('filters').and.to.be.an('array');
expect(response.body.filters.find((f: IOmnichannelRoom['source']) => f.type === 'api')).to.not.be.undefined;
});
});
});
33 changes: 33 additions & 0 deletions apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,39 @@ describe('LIVECHAT - visitors', function () {
.then(() => done())
.catch(done);
});

it('should return a list of chats when filtered by ', (done) => {
updatePermission('view-l-room', ['admin', 'livechat-agent'])
.then(() => updateSetting('Livechat_Routing_Method', 'Manual_Selection'))
.then(() => createVisitor())
.then((createdVisitor: ILivechatVisitor) => Promise.all([createLivechatRoom(createdVisitor.token), createdVisitor]))
.then(([room, visitor]: [IOmnichannelRoom, ILivechatVisitor]) => Promise.all([createAgent(), room, visitor]))
.then(([agent, room, visitor]: [ILivechatAgent, IOmnichannelRoom, ILivechatVisitor]) => {
return Promise.all([room, visitor, takeInquiry(room._id, agent._id)]);
})
.then(([room, visitor]: [IOmnichannelRoom, ILivechatVisitor, any]) => {
request
.get(api(`livechat/visitors.searchChats/room/${room._id}/visitor/${visitor._id}?source=api`))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res: Response) => {
console.log(res.body);
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('history');
expect(res.body.history).to.be.an('array');
expect(res.body.history).to.have.length.of.at.least(1);
expect(res.body.history[0]).to.have.property('_id');
expect(res.body.history[0]).to.have.property('name');
expect(res.body.history[0]).to.have.property('createdAt');
expect(res.body.history[0]).to.have.property('endedAt');
expect(res.body.history[0]).to.have.property('status');
expect(res.body.history[0]).to.have.property('visitor');
});
})
.then(() => done())
.catch(done);
});
});

describe('livechat/visitor.status', () => {
Expand Down
5 changes: 4 additions & 1 deletion packages/model-typings/src/models/ILivechatRoomsModel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { IOmnichannelRoom } from '@rocket.chat/core-typings';
import type { FindCursor, UpdateResult } from 'mongodb';
import type { FindCursor, UpdateResult, AggregationCursor, Document } from 'mongodb';

import type { FindPaginated } from '..';
import type { IBaseModel } from './IBaseModel';
Expand Down Expand Up @@ -73,6 +73,7 @@ export interface ILivechatRoomsModel extends IBaseModel<IOmnichannelRoom> {
served: any;
onlyCount?: boolean;
options?: any;
source?: string;
}): any;

findRoomsWithCriteria(params: {
Expand Down Expand Up @@ -106,4 +107,6 @@ export interface ILivechatRoomsModel extends IBaseModel<IOmnichannelRoom> {
unsetAutoTransferOngoingById(roomId: string): Promise<UpdateResult>;

setAutoTransferredAtById(roomId: string): Promise<UpdateResult>;

findAvailableSources(): AggregationCursor<Document>;
}
8 changes: 8 additions & 0 deletions packages/rest-typings/src/v1/omnichannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2240,6 +2240,7 @@ type GETLivechatVisitorsSearchChatsRoomRoomIdVisitorVisitorIdParams = PaginatedR
searchText?: string;
closedChatsOnly?: string;
servedChatsOnly?: string;
source?: string;
}>;

const GETLivechatVisitorsSearchChatsRoomRoomIdVisitorVisitorIdParamsSchema = {
Expand Down Expand Up @@ -2269,6 +2270,10 @@ const GETLivechatVisitorsSearchChatsRoomRoomIdVisitorVisitorIdParamsSchema = {
type: 'string',
nullable: true,
},
source: {
type: 'string',
nullable: true,
},
},
additionalProperties: false,
};
Expand Down Expand Up @@ -3223,6 +3228,9 @@ export type OmnichannelEndpoints = {
'/v1/livechat/analytics/dashboards/charts/agents-status': {
GET: (params: GETDashboardsAgentStatusParams) => { offline: number; away: number; busy: number; available: number };
};
'/v1/livechat/rooms/filters': {
GET: () => { filters: IOmnichannelRoom['source'][] };
};
} & {
// EE
'/v1/livechat/analytics/agents/average-service-time': {
Expand Down

0 comments on commit 7518f79

Please sign in to comment.