From f9150748c5f924a35b8607657529fd4f78c2e63d Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 14:59:40 -0300 Subject: [PATCH 01/16] chore: adds a new endpoint to replace deprecated method --- .../livechat/imports/server/rest/inquiries.ts | 52 ++++++++++++++++++- packages/rest-typings/src/v1/omnichannel.ts | 39 ++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index 2432e55054f52..f86ca8b1c7a47 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -1,16 +1,24 @@ import { LivechatInquiryStatus } from '@rocket.chat/core-typings'; -import { LivechatInquiry, LivechatDepartment, Users } from '@rocket.chat/models'; +import { LivechatInquiry, LivechatDepartment, Users, LivechatRooms } from '@rocket.chat/models'; import { isGETLivechatInquiriesListParams, isPOSTLivechatInquiriesTakeParams, isGETLivechatInquiriesQueuedForUserParams, isGETLivechatInquiriesGetOneParams, + validateBadRequestErrorResponse, + validateUnauthorizedErrorResponse, + validateForbiddenErrorResponse, + isPOSTLivechatInquiriesReturnAsInquiry, + POSTLivechatInquiriesReturnAsInquirySuccessResponse, } from '@rocket.chat/rest-typings'; import { API } from '../../../../api/server'; import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems'; import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries'; import { takeInquiry } from '../../../server/methods/takeInquiry'; +import { ExtractRoutesFromAPI } from '/app/api/server/ApiClass'; +import { Omnichannel } from '@rocket.chat/core-services'; +import { returnRoomAsInquiry } from '/app/livechat/server/lib/rooms'; API.v1.addRoute( 'livechat/inquiries.list', @@ -108,3 +116,45 @@ API.v1.addRoute( }, }, ); + +const livechatInquiriesEndpoints = API.v1.post( + 'livechat/inquiries.returnAsInquiry', + { + response: { + 200: POSTLivechatInquiriesReturnAsInquirySuccessResponse, + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + 403: validateForbiddenErrorResponse, + }, + authRequired: true, + permissionsRequired: ['view-l-room'], + body: isPOSTLivechatInquiriesReturnAsInquiry, + }, + async function action() { + const { roomId, departmentId } = this.bodyParams; + + const room = await LivechatRooms.findOneById(roomId); + if (!room || room.t !== 'l') { + return API.v1.failure('invalid-room'); + } + + if (!room.open) { + return API.v1.failure('room-closed'); + } + + if (!(await Omnichannel.isWithinMACLimit(room))) { + return API.v1.failure('mac-limit-reached'); + } + + await returnRoomAsInquiry(room, departmentId); + + return API.v1.success(); + }, +); + +type LivechatInquiriesEndpoints = ExtractRoutesFromAPI + +declare module '@rocket.chat/rest-typings' { + // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface + interface Endpoints extends LivechatInquiriesEndpoints {} +} diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index e5db53a53a785..212fbbaacc038 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -3389,6 +3389,45 @@ const GETLivechatInquiriesGetOneParamsSchema = { export const isGETLivechatInquiriesGetOneParams = ajv.compile(GETLivechatInquiriesGetOneParamsSchema); +type POSTLivechatInquiriesReturnAsInquiry = { + roomId: string; + departmentId?: string; +}; + +const POSTLivechatInquiriesReturnAsInquirySchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + departmentId: { + type: 'string', + nullable: true, + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isPOSTLivechatInquiriesReturnAsInquiry = ajv.compile( + POSTLivechatInquiriesReturnAsInquirySchema, +); + +const POSTLivechatInquiriesReturnAsInquirySuccessResponseSchema = { + type: 'object', + properties: { + success: { + type: 'boolean', + enum: [true], + }, + }, + additionalProperties: false, +}; + +export const POSTLivechatInquiriesReturnAsInquirySuccessResponse = ajv.compile( + POSTLivechatInquiriesReturnAsInquirySuccessResponseSchema, +); + type GETDashboardTotalizers = { start: string; end: string; From c34fd1ddb7b73110fd4d0cc8dec422168e057c8e Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 15:00:03 -0300 Subject: [PATCH 02/16] chore: replaces deprecated method by the new endpoint --- .../QuickActions/hooks/useReturnChatToQueueMutation.ts | 6 +++--- .../QuickActions/hooks/useReturnChatToQueueMutation.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts index 00d990d97cc19..73d9379dd6534 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts +++ b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts @@ -1,5 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { useMethod } from '@rocket.chat/ui-contexts'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query'; @@ -8,13 +8,13 @@ import { roomsQueryKeys, subscriptionsQueryKeys } from '../../../../../../lib/qu export const useReturnChatToQueueMutation = ( options?: Omit, 'mutationFn'>, ): UseMutationResult => { - const returnChatToQueue = useMethod('livechat:returnAsInquiry'); + const returnChatToQueue = useEndpoint('POST', '/v1/livechat/inquiries.returnAsInquiry'); const queryClient = useQueryClient(); return useMutation({ mutationFn: async (rid) => { - await returnChatToQueue(rid); + await returnChatToQueue({ roomId: rid }); }, ...options, onSuccess: async (data, rid, context) => { diff --git a/apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts b/apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts index 00d990d97cc19..73d9379dd6534 100644 --- a/apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts +++ b/apps/meteor/client/views/room/HeaderV2/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts @@ -1,5 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { useMethod } from '@rocket.chat/ui-contexts'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query'; @@ -8,13 +8,13 @@ import { roomsQueryKeys, subscriptionsQueryKeys } from '../../../../../../lib/qu export const useReturnChatToQueueMutation = ( options?: Omit, 'mutationFn'>, ): UseMutationResult => { - const returnChatToQueue = useMethod('livechat:returnAsInquiry'); + const returnChatToQueue = useEndpoint('POST', '/v1/livechat/inquiries.returnAsInquiry'); const queryClient = useQueryClient(); return useMutation({ mutationFn: async (rid) => { - await returnChatToQueue(rid); + await returnChatToQueue({ roomId: rid }); }, ...options, onSuccess: async (data, rid, context) => { From ab170833c021a0ab634a849a8a2be3ef775c6e86 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 16:11:15 -0300 Subject: [PATCH 03/16] tests: updates tests to use the new endpoint --- .../livechat/imports/server/rest/inquiries.ts | 4 +- .../end-to-end/api/livechat/05-inquiries.ts | 114 +++++------------- packages/rest-typings/src/v1/omnichannel.ts | 5 +- 3 files changed, 39 insertions(+), 84 deletions(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index f86ca8b1c7a47..88ba3e6debcec 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -146,9 +146,9 @@ const livechatInquiriesEndpoints = API.v1.post( return API.v1.failure('mac-limit-reached'); } - await returnRoomAsInquiry(room, departmentId); + const result = await returnRoomAsInquiry(room, departmentId); - return API.v1.success(); + return API.v1.success({ result }); }, ); diff --git a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts index 66b5e19c753da..a09dabedea859 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts @@ -4,7 +4,7 @@ import { expect } from 'chai'; import { before, describe, it, after } from 'mocha'; import type { Response } from 'supertest'; -import { getCredentials, api, request, credentials, methodCall } from '../../../data/api-data'; +import { getCredentials, api, request, credentials } from '../../../data/api-data'; import { deleteDepartment } from '../../../data/livechat/department'; import { closeOmnichannelRoom, @@ -19,7 +19,7 @@ import { startANewLivechatRoomAndTakeIt, takeInquiry, } from '../../../data/livechat/rooms'; -import { parseMethodResponse, sleep } from '../../../data/livechat/utils'; +import { sleep } from '../../../data/livechat/utils'; import { removePermissionFromAllRoles, restorePermissionToRoles, @@ -324,7 +324,7 @@ describe('LIVECHAT - inquiries', () => { }); }); - describe('livechat:returnAsInquiry', () => { + describe('livechat/inquiries.returnAsInquiry', () => { let testUser: { user: IUser; credentials: Credentials }; before(async () => { const user = await createUser(); @@ -344,59 +344,39 @@ describe('LIVECHAT - inquiries', () => { it('should throw an error if user doesnt have view-l-room permission', async () => { await removePermissionFromAllRoles('view-l-room'); const { body } = await request - .post(methodCall('livechat:returnAsInquiry')) + .post(api('livechat/inquiries.returnAsInquiry')) .set(credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:returnAsInquiry', - params: ['test'], - id: 'id', - msg: 'method', - }), - }) + .send({ roomId: 'test' }) .expect('Content-Type', 'application/json') - .expect(200); - - const response = parseMethodResponse(body); + .expect(403); - expect(response.error.error).to.be.equal('error-not-allowed'); + expect(body).to.have.property('success', false); + expect(body.error).to.have.equal('User does not have the permissions required for this action [error-unauthorized]'); }); it('should fail if provided room doesnt exists', async () => { await restorePermissionToRoles('view-l-room'); const { body } = await request - .post(methodCall('livechat:returnAsInquiry')) + .post(api('livechat/inquiries.returnAsInquiry')) .set(credentials) .send({ - message: JSON.stringify({ - method: 'livechat:returnAsInquiry', - params: ['test'], - id: 'id', - msg: 'method', - }), + roomId: 'test', }) .expect('Content-Type', 'application/json') - .expect(200); + .expect(400); - const response = parseMethodResponse(body); - expect(response.error.error).to.be.equal('error-invalid-room'); + expect(body).to.have.property('success', false); + expect(body).to.have.property('error', 'invalid-room'); }); it('should fail if room is not a livechat room', async () => { const { body } = await request - .post(methodCall('livechat:returnAsInquiry')) + .post(api('livechat/inquiries.returnAsInquiry')) .set(credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:returnAsInquiry', - params: ['GENERAL'], - id: 'id', - msg: 'method', - }), - }) + .send({ roomId: 'GENERAL' }) .expect('Content-Type', 'application/json') - .expect(200); + .expect(400); - const response = parseMethodResponse(body); - expect(response.error.error).to.be.equal('error-invalid-room'); + expect(body).to.have.property('success', false); + expect(body).to.have.property('error', 'invalid-room'); }); it('should fail if room is closed', async () => { const visitor = await createVisitor(); @@ -404,21 +384,14 @@ describe('LIVECHAT - inquiries', () => { await closeOmnichannelRoom(room._id); const { body } = await request - .post(methodCall('livechat:returnAsInquiry')) + .post(api('livechat/inquiries.returnAsInquiry')) .set(credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:returnAsInquiry', - params: [room._id], - id: 'id', - msg: 'method', - }), - }) + .send({ roomId: room._id }) .expect('Content-Type', 'application/json') - .expect(200); + .expect(400); - const response = parseMethodResponse(body); - expect(response.error.error).to.be.equal('room-closed'); + expect(body).to.have.property('success', false); + expect(body).to.have.property('error', 'room-closed'); }); describe('no serving', () => { let room: IOmnichannelRoom; @@ -431,21 +404,14 @@ describe('LIVECHAT - inquiries', () => { }); it('should fail if no one is serving the room', async () => { const { body } = await request - .post(methodCall('livechat:returnAsInquiry')) + .post(api('livechat/inquiries.returnAsInquiry')) .set(credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:returnAsInquiry', - params: [room._id], - id: 'id', - msg: 'method', - }), - }) + .send({ roomId: room._id }) .expect('Content-Type', 'application/json') .expect(200); - const response = parseMethodResponse(body); - expect(response.result).to.be.false; + expect(body).to.have.property('success', true); + expect(body).to.have.property('result', false); }); }); @@ -460,21 +426,14 @@ describe('LIVECHAT - inquiries', () => { await takeInquiry(inq._id, testUser.credentials); const { body } = await request - .post(methodCall('livechat:returnAsInquiry')) + .post(api('livechat/inquiries.returnAsInquiry')) .set(testUser.credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:returnAsInquiry', - params: [room._id], - id: 'id', - msg: 'method', - }), - }) + .send({ roomId: room._id }) .expect('Content-Type', 'application/json') .expect(200); - const response = parseMethodResponse(body); - expect(response.result).to.be.true; + expect(body).to.have.property('success', true); + expect(body).to.have.property('result', true); }); (IS_EE ? it : it.skip)('should appear on users queued elements', async () => { const { body } = await request @@ -554,16 +513,9 @@ describe('LIVECHAT - inquiries', () => { await request.post(api('livechat/message')).send({ token: visitor.token, rid: room._id, msg: msgText }).expect(200); await request - .post(methodCall('livechat:returnAsInquiry')) + .post(api('livechat/inquiries.returnAsInquiry')) .set(credentials) - .send({ - message: JSON.stringify({ - method: 'livechat:returnAsInquiry', - params: [room._id], - id: 'id', - msg: 'method', - }), - }) + .send({ roomId: room._id }) .expect('Content-Type', 'application/json') .expect(200); diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index 212fbbaacc038..a725742ca4505 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -3416,6 +3416,9 @@ export const isPOSTLivechatInquiriesReturnAsInquiry = ajv.compile( +export const POSTLivechatInquiriesReturnAsInquirySuccessResponse = ajv.compile<{ result: boolean }>( POSTLivechatInquiriesReturnAsInquirySuccessResponseSchema, ); From dbb86b0635869914c46ba1c09d4fded1ab904ca4 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 16:12:52 -0300 Subject: [PATCH 04/16] chore: adds deprecation warning --- apps/meteor/app/livechat/server/methods/returnAsInquiry.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts b/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts index df4f4f2a5f76b..e9c5018920723 100644 --- a/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts +++ b/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts @@ -5,6 +5,7 @@ import { LivechatRooms } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; import { returnRoomAsInquiry } from '../lib/rooms'; declare module '@rocket.chat/ddp-client' { @@ -16,6 +17,7 @@ declare module '@rocket.chat/ddp-client' { Meteor.methods({ async 'livechat:returnAsInquiry'(rid, departmentId) { + methodDeprecationLogger.method('livechat:returnAsInquiry', '8.0.0', '/v1/livechat/inquiries.returnAsInquiry'); const uid = Meteor.userId(); if (!uid || !(await hasPermissionAsync(uid, 'view-l-room'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { From 6c23a2a7d0a051a2d3ed76ad95861a961c1994b2 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 16:41:54 -0300 Subject: [PATCH 05/16] fix: lint import errors --- apps/meteor/app/livechat/imports/server/rest/inquiries.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index 88ba3e6debcec..42142606286ee 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -1,3 +1,4 @@ +import { Omnichannel } from '@rocket.chat/core-services'; import { LivechatInquiryStatus } from '@rocket.chat/core-typings'; import { LivechatInquiry, LivechatDepartment, Users, LivechatRooms } from '@rocket.chat/models'; import { @@ -16,9 +17,8 @@ import { API } from '../../../../api/server'; import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems'; import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries'; import { takeInquiry } from '../../../server/methods/takeInquiry'; -import { ExtractRoutesFromAPI } from '/app/api/server/ApiClass'; -import { Omnichannel } from '@rocket.chat/core-services'; -import { returnRoomAsInquiry } from '/app/livechat/server/lib/rooms'; +import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass'; +import { returnRoomAsInquiry } from '../../../server/lib/rooms'; API.v1.addRoute( 'livechat/inquiries.list', @@ -152,7 +152,7 @@ const livechatInquiriesEndpoints = API.v1.post( }, ); -type LivechatInquiriesEndpoints = ExtractRoutesFromAPI +type LivechatInquiriesEndpoints = ExtractRoutesFromAPI; declare module '@rocket.chat/rest-typings' { // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface From e1370357de11550b8d25eaaf4f639ea2bfe41782 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 17:06:07 -0300 Subject: [PATCH 06/16] fix: import paths --- apps/meteor/app/livechat/imports/server/rest/inquiries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index 42142606286ee..6fc19027e33d7 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -14,11 +14,11 @@ import { } from '@rocket.chat/rest-typings'; import { API } from '../../../../api/server'; +import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass'; import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems'; import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries'; -import { takeInquiry } from '../../../server/methods/takeInquiry'; -import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass'; import { returnRoomAsInquiry } from '../../../server/lib/rooms'; +import { takeInquiry } from '../../../server/methods/takeInquiry'; API.v1.addRoute( 'livechat/inquiries.list', From 46fe17405d0a3a5ca3b3cfcd7f6635577dd73112 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 18:35:44 -0300 Subject: [PATCH 07/16] docs: adds changeset --- .changeset/calm-hounds-look.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/calm-hounds-look.md diff --git a/.changeset/calm-hounds-look.md b/.changeset/calm-hounds-look.md new file mode 100644 index 0000000000000..5bbc19ad8667a --- /dev/null +++ b/.changeset/calm-hounds-look.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/rest-typings": patch +--- + +Adds deprecation warning on `livechat:returnAsInquiry` with new endpoint replacing it; `livechat/inquiries.returnAsInquiry` From 19ac582278e437dc905f25cfde70d0f6ea58de7f Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Wed, 17 Sep 2025 18:56:01 -0300 Subject: [PATCH 08/16] chore: adds trycatch to handle meteor errors thrown by service function --- .../app/livechat/imports/server/rest/inquiries.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index 6fc19027e33d7..55e4dc7af9542 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -146,9 +146,17 @@ const livechatInquiriesEndpoints = API.v1.post( return API.v1.failure('mac-limit-reached'); } - const result = await returnRoomAsInquiry(room, departmentId); + try { + const result = await returnRoomAsInquiry(room, departmentId); - return API.v1.success({ result }); + return API.v1.success({ result }); + } catch (error) { + if (error instanceof Meteor.Error) { + return API.v1.failure(error.reason); + } + + return API.v1.failure('error-returning-inquiry'); + } }, ); From 0a255f7ccd381d1d6656d0a1e6457b1b94213f63 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Mon, 22 Sep 2025 14:13:48 -0300 Subject: [PATCH 09/16] chore: adds minor improvements to returnAsInquiry --- .../livechat/imports/server/rest/inquiries.ts | 19 +++++-------------- apps/meteor/app/livechat/server/lib/rooms.ts | 12 +++++++++++- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index 55e4dc7af9542..9a421ef25e230 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -1,4 +1,3 @@ -import { Omnichannel } from '@rocket.chat/core-services'; import { LivechatInquiryStatus } from '@rocket.chat/core-typings'; import { LivechatInquiry, LivechatDepartment, Users, LivechatRooms } from '@rocket.chat/models'; import { @@ -133,20 +132,12 @@ const livechatInquiriesEndpoints = API.v1.post( async function action() { const { roomId, departmentId } = this.bodyParams; - const room = await LivechatRooms.findOneById(roomId); - if (!room || room.t !== 'l') { - return API.v1.failure('invalid-room'); - } - - if (!room.open) { - return API.v1.failure('room-closed'); - } - - if (!(await Omnichannel.isWithinMACLimit(room))) { - return API.v1.failure('mac-limit-reached'); - } - try { + const room = await LivechatRooms.findOneById(roomId); + if (!room) { + return API.v1.failure('error-room-not-found'); + } + const result = await returnRoomAsInquiry(room, departmentId); return API.v1.success({ result }); diff --git a/apps/meteor/app/livechat/server/lib/rooms.ts b/apps/meteor/app/livechat/server/lib/rooms.ts index b52dc76b25f64..7e68df744f8b9 100644 --- a/apps/meteor/app/livechat/server/lib/rooms.ts +++ b/apps/meteor/app/livechat/server/lib/rooms.ts @@ -1,5 +1,5 @@ import { AppEvents, Apps } from '@rocket.chat/apps'; -import type { +import { ILivechatVisitor, IMessage, IOmnichannelRoomInfo, @@ -7,6 +7,7 @@ import type { IOmnichannelRoomExtraData, IOmnichannelRoom, TransferData, + isOmnichannelRoom, } from '@rocket.chat/core-typings'; import { LivechatRooms, @@ -41,6 +42,7 @@ import { } from '../../../lib/server/lib/notifyListener'; import { settings } from '../../../settings/server'; import { i18n } from '../../../utils/lib/i18n'; +import { Omnichannel } from '@rocket.chat/core-services'; export async function getRoom( guest: ILivechatVisitor, @@ -218,6 +220,14 @@ export async function returnRoomAsInquiry(room: IOmnichannelRoom, departmentId?: throw new Meteor.Error('error-room-onHold'); } + if (!isOmnichannelRoom(room)) { + throw new Meteor.Error('error-invalid-room-type'); + } + + if (!(await Omnichannel.isWithinMACLimit(room))) { + throw new Meteor.Error('error-mac-limit-exceeded'); + } + if (!room.servedBy) { return false; } From f2f7684c96d8e82a20321f1e9f39f07cf6a15959 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Mon, 22 Sep 2025 14:34:53 -0300 Subject: [PATCH 10/16] fix: lint errors --- apps/meteor/app/livechat/server/lib/rooms.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/rooms.ts b/apps/meteor/app/livechat/server/lib/rooms.ts index 7e68df744f8b9..724c52c6a11d1 100644 --- a/apps/meteor/app/livechat/server/lib/rooms.ts +++ b/apps/meteor/app/livechat/server/lib/rooms.ts @@ -1,5 +1,6 @@ import { AppEvents, Apps } from '@rocket.chat/apps'; -import { +import { Omnichannel } from '@rocket.chat/core-services'; +import type { ILivechatVisitor, IMessage, IOmnichannelRoomInfo, @@ -7,8 +8,8 @@ import { IOmnichannelRoomExtraData, IOmnichannelRoom, TransferData, - isOmnichannelRoom, } from '@rocket.chat/core-typings'; +import { isOmnichannelRoom } from '@rocket.chat/core-typings' import { LivechatRooms, LivechatContacts, @@ -42,7 +43,6 @@ import { } from '../../../lib/server/lib/notifyListener'; import { settings } from '../../../settings/server'; import { i18n } from '../../../utils/lib/i18n'; -import { Omnichannel } from '@rocket.chat/core-services'; export async function getRoom( guest: ILivechatVisitor, From 5b01542de9dd64bb11b9ef3a69d794e560842a91 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Mon, 22 Sep 2025 14:34:53 -0300 Subject: [PATCH 11/16] fix: lint errors --- apps/meteor/app/livechat/server/lib/rooms.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/rooms.ts b/apps/meteor/app/livechat/server/lib/rooms.ts index 7e68df744f8b9..6c6eb175cf553 100644 --- a/apps/meteor/app/livechat/server/lib/rooms.ts +++ b/apps/meteor/app/livechat/server/lib/rooms.ts @@ -1,5 +1,6 @@ import { AppEvents, Apps } from '@rocket.chat/apps'; -import { +import { Omnichannel } from '@rocket.chat/core-services'; +import type { ILivechatVisitor, IMessage, IOmnichannelRoomInfo, @@ -7,8 +8,8 @@ import { IOmnichannelRoomExtraData, IOmnichannelRoom, TransferData, - isOmnichannelRoom, } from '@rocket.chat/core-typings'; +import { isOmnichannelRoom } from '@rocket.chat/core-typings'; import { LivechatRooms, LivechatContacts, @@ -42,7 +43,6 @@ import { } from '../../../lib/server/lib/notifyListener'; import { settings } from '../../../settings/server'; import { i18n } from '../../../utils/lib/i18n'; -import { Omnichannel } from '@rocket.chat/core-services'; export async function getRoom( guest: ILivechatVisitor, From 505efbce42d234e13452beec1a337bed391415d3 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Mon, 22 Sep 2025 15:46:51 -0300 Subject: [PATCH 12/16] fix: error message validation --- apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts index a09dabedea859..743b06e327836 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts @@ -365,7 +365,7 @@ describe('LIVECHAT - inquiries', () => { .expect(400); expect(body).to.have.property('success', false); - expect(body).to.have.property('error', 'invalid-room'); + expect(body).to.have.property('error', 'error-room-not-found'); }); it('should fail if room is not a livechat room', async () => { const { body } = await request From a669247bbfc571d769d36ef4a8aed8ffc4dc00af Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Mon, 22 Sep 2025 18:31:45 -0300 Subject: [PATCH 13/16] fix: invalid message in api test --- apps/meteor/app/livechat/server/lib/rooms.ts | 5 ----- apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/rooms.ts b/apps/meteor/app/livechat/server/lib/rooms.ts index 6c6eb175cf553..2464456afcc17 100644 --- a/apps/meteor/app/livechat/server/lib/rooms.ts +++ b/apps/meteor/app/livechat/server/lib/rooms.ts @@ -9,7 +9,6 @@ import type { IOmnichannelRoom, TransferData, } from '@rocket.chat/core-typings'; -import { isOmnichannelRoom } from '@rocket.chat/core-typings'; import { LivechatRooms, LivechatContacts, @@ -220,10 +219,6 @@ export async function returnRoomAsInquiry(room: IOmnichannelRoom, departmentId?: throw new Meteor.Error('error-room-onHold'); } - if (!isOmnichannelRoom(room)) { - throw new Meteor.Error('error-invalid-room-type'); - } - if (!(await Omnichannel.isWithinMACLimit(room))) { throw new Meteor.Error('error-mac-limit-exceeded'); } diff --git a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts index 743b06e327836..271b50acb3332 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts @@ -376,7 +376,7 @@ describe('LIVECHAT - inquiries', () => { .expect(400); expect(body).to.have.property('success', false); - expect(body).to.have.property('error', 'invalid-room'); + expect(body).to.have.property('error', 'error-room-not-found'); }); it('should fail if room is closed', async () => { const visitor = await createVisitor(); From 25bab34741c447e31390d87adc88e96e3faaf090 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Tue, 23 Sep 2025 11:28:04 -0300 Subject: [PATCH 14/16] fix: error message patterns --- apps/meteor/app/livechat/imports/server/rest/inquiries.ts | 4 ++-- apps/meteor/app/livechat/server/lib/rooms.ts | 2 +- apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index 9a421ef25e230..dfd671e65669f 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -142,8 +142,8 @@ const livechatInquiriesEndpoints = API.v1.post( return API.v1.success({ result }); } catch (error) { - if (error instanceof Meteor.Error) { - return API.v1.failure(error.reason); + if (error instanceof Meteor.Error && typeof error.error === 'string') { + return API.v1.failure(error.error as string); } return API.v1.failure('error-returning-inquiry'); diff --git a/apps/meteor/app/livechat/server/lib/rooms.ts b/apps/meteor/app/livechat/server/lib/rooms.ts index 2464456afcc17..1b576d8d103e2 100644 --- a/apps/meteor/app/livechat/server/lib/rooms.ts +++ b/apps/meteor/app/livechat/server/lib/rooms.ts @@ -212,7 +212,7 @@ export async function saveRoomInfo( export async function returnRoomAsInquiry(room: IOmnichannelRoom, departmentId?: string, overrideTransferData: Partial = {}) { livechatLogger.debug({ msg: `Transfering room to ${departmentId ? 'department' : ''} queue`, room }); if (!room.open) { - throw new Meteor.Error('room-closed'); + throw new Meteor.Error('error-room-closed'); } if (room.onHold) { diff --git a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts index 271b50acb3332..6019cfec656f3 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts @@ -391,7 +391,7 @@ describe('LIVECHAT - inquiries', () => { .expect(400); expect(body).to.have.property('success', false); - expect(body).to.have.property('error', 'room-closed'); + expect(body).to.have.property('error', 'error-room-closed'); }); describe('no serving', () => { let room: IOmnichannelRoom; From 8dcbf1bd97ca3599972d0c437243585ea5e0a299 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Tue, 23 Sep 2025 14:43:57 -0300 Subject: [PATCH 15/16] chore: adds minor changes requested from code review --- apps/meteor/app/livechat/server/lib/rooms.ts | 4 ++-- .../app/livechat/server/methods/returnAsInquiry.ts | 9 --------- .../meteor/tests/end-to-end/api/livechat/05-inquiries.ts | 2 +- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/rooms.ts b/apps/meteor/app/livechat/server/lib/rooms.ts index 1b576d8d103e2..00ede94ce8a93 100644 --- a/apps/meteor/app/livechat/server/lib/rooms.ts +++ b/apps/meteor/app/livechat/server/lib/rooms.ts @@ -212,7 +212,7 @@ export async function saveRoomInfo( export async function returnRoomAsInquiry(room: IOmnichannelRoom, departmentId?: string, overrideTransferData: Partial = {}) { livechatLogger.debug({ msg: `Transfering room to ${departmentId ? 'department' : ''} queue`, room }); if (!room.open) { - throw new Meteor.Error('error-room-closed'); + throw new Meteor.Error('room-closed', 'Room closed'); } if (room.onHold) { @@ -220,7 +220,7 @@ export async function returnRoomAsInquiry(room: IOmnichannelRoom, departmentId?: } if (!(await Omnichannel.isWithinMACLimit(room))) { - throw new Meteor.Error('error-mac-limit-exceeded'); + throw new Meteor.Error('error-mac-limit-reached'); } if (!room.servedBy) { diff --git a/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts b/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts index e9c5018920723..40a1714955e49 100644 --- a/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts +++ b/apps/meteor/app/livechat/server/methods/returnAsInquiry.ts @@ -1,4 +1,3 @@ -import { Omnichannel } from '@rocket.chat/core-services'; import type { ILivechatDepartment, IRoom } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { LivechatRooms } from '@rocket.chat/models'; @@ -32,14 +31,6 @@ Meteor.methods({ }); } - if (!(await Omnichannel.isWithinMACLimit(room))) { - throw new Meteor.Error('error-mac-limit-reached', 'MAC limit reached', { method: 'livechat:returnAsInquiry' }); - } - - if (!room.open) { - throw new Meteor.Error('room-closed', 'Room closed', { method: 'livechat:returnAsInquiry' }); - } - return returnRoomAsInquiry(room, departmentId); }, }); diff --git a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts index 6019cfec656f3..271b50acb3332 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts @@ -391,7 +391,7 @@ describe('LIVECHAT - inquiries', () => { .expect(400); expect(body).to.have.property('success', false); - expect(body).to.have.property('error', 'error-room-closed'); + expect(body).to.have.property('error', 'room-closed'); }); describe('no serving', () => { let room: IOmnichannelRoom; From a5f47435309c8ed92d6b68ea65483bae8af86b7e Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Thu, 25 Sep 2025 10:54:18 -0300 Subject: [PATCH 16/16] fix: import order --- apps/meteor/app/livechat/imports/server/rest/inquiries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index a76e40b59aaad..a69604bd083ec 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -16,8 +16,8 @@ import { API } from '../../../../api/server'; import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass'; import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems'; import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries'; -import { takeInquiry } from '../../../server/lib/takeInquiry'; import { returnRoomAsInquiry } from '../../../server/lib/rooms'; +import { takeInquiry } from '../../../server/lib/takeInquiry'; API.v1.addRoute( 'livechat/inquiries.list',