Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ad25650
chore: adds new endpoint to replace meteor methods
lucas-a-pelegrino Sep 16, 2025
4ef8aae
chore: adds new endpoint for deleting livechat rooms
lucas-a-pelegrino Sep 16, 2025
cf7f67e
chore: replaces depracted method usage with new endpoint
lucas-a-pelegrino Sep 16, 2025
56a24dd
chore: adds deprecation warning to meteor method
lucas-a-pelegrino Sep 16, 2025
f033349
docs: adds changeset
lucas-a-pelegrino Sep 16, 2025
3a72cb4
chore: fixes return type mismatch
lucas-a-pelegrino Sep 16, 2025
122a98c
Merge remote-tracking branch 'origin/chore/v7/CTZ-60' into chore/v7/C…
lucas-a-pelegrino Sep 16, 2025
8f68940
fix: merge conflicts
lucas-a-pelegrino Sep 16, 2025
db2051c
fix: rest-typings imports
lucas-a-pelegrino Sep 16, 2025
78d1b67
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into chor…
lucas-a-pelegrino Sep 16, 2025
2d33020
fix: merge conflicts
lucas-a-pelegrino Sep 17, 2025
0a8c639
fix: fix linting errors
lucas-a-pelegrino Sep 17, 2025
edc7e12
fix: fix linting errors
lucas-a-pelegrino Sep 17, 2025
7288a9c
Merge remote-tracking branch 'origin/chore/v7/CTZ-60' into chore/v7/C…
lucas-a-pelegrino Sep 17, 2025
040b44f
fix: fix linting errors #2
lucas-a-pelegrino Sep 17, 2025
c387257
fix: fix linting errors 2
lucas-a-pelegrino Sep 17, 2025
a68b10c
Merge remote-tracking branch 'origin/chore/v7/CTZ-60' into chore/v7/C…
lucas-a-pelegrino Sep 17, 2025
fa8c42a
fix: correct method on depracation warning
lucas-a-pelegrino Sep 17, 2025
8797f67
chore: adds minor improvements to the rooms.delete endpoint
lucas-a-pelegrino Sep 22, 2025
cb8cf64
Merge branch 'develop' into chore/v7/CTZ-60
lucas-a-pelegrino Sep 22, 2025
7332d8c
fix: linting error
lucas-a-pelegrino Sep 22, 2025
4c226f2
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into chor…
lucas-a-pelegrino Sep 24, 2025
447c6cc
fix: removes component misconfig
lucas-a-pelegrino Sep 25, 2025
5b9097c
chore: removes extra line break
lucas-a-pelegrino Sep 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/three-turkeys-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/rest-typings": patch
---

Adds deprecation warning on `livechat:removeRoom` with new endpoint replacing it; `livechat/rooms.delete`
78 changes: 56 additions & 22 deletions apps/meteor/app/livechat/server/api/v1/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import {
isPOSTLivechatRoomCloseByUserParams,
isPOSTLivechatRoomsCloseAll,
isPOSTLivechatRoomsCloseAllSuccessResponse,
POSTLivechatRemoveRoomSuccess,
isPOSTLivechatRemoveRoomParams,
validateBadRequestErrorResponse,
validateUnauthorizedErrorResponse,
validateForbiddenErrorResponse,
} from '@rocket.chat/rest-typings';
import { check } from 'meteor/check';

Expand Down Expand Up @@ -438,32 +443,61 @@ API.v1.addRoute(
},
);

const livechatRoomsEndpoints = API.v1.post(
'livechat/rooms.removeAllClosedRooms',
{
response: {
200: isPOSTLivechatRoomsCloseAllSuccessResponse,
const livechatRoomsEndpoints = API.v1
.post(
'livechat/rooms.delete',
{
response: {
200: POSTLivechatRemoveRoomSuccess,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
403: validateForbiddenErrorResponse,
},
authRequired: true,
permissionsRequired: ['remove-closed-livechat-room'],
body: isPOSTLivechatRemoveRoomParams,
},
authRequired: true,
permissionsRequired: ['remove-closed-livechat-rooms'],
body: isPOSTLivechatRoomsCloseAll,
},
async function action() {
livechatLogger.info(`User ${this.userId} is removing all closed rooms`);
async function action() {
const { roomId } = this.bodyParams;

try {
await removeOmnichannelRoom(roomId);
return API.v1.success();
} catch (error: unknown) {
if (error instanceof Meteor.Error) {
return API.v1.failure(error.reason);
}

return API.v1.failure('error-removing-room');
}
},
)
.post(
'livechat/rooms.removeAllClosedRooms',
{
response: {
200: isPOSTLivechatRoomsCloseAllSuccessResponse,
},
authRequired: true,
permissionsRequired: ['remove-closed-livechat-rooms'],
body: isPOSTLivechatRoomsCloseAll,
},
async function action() {
livechatLogger.info(`User ${this.userId} is removing all closed rooms`);

const params = this.bodyParams;
const params = this.bodyParams;

const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}, { userId: this.userId });
const promises: Promise<void>[] = [];
await LivechatRooms.findClosedRooms(params?.departmentIds, {}, extraQuery).forEach(({ _id }: IOmnichannelRoom) => {
promises.push(removeOmnichannelRoom(_id));
});
await Promise.all(promises);
const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}, { userId: this.userId });
const promises: Promise<void>[] = [];
await LivechatRooms.findClosedRooms(params?.departmentIds, {}, extraQuery).forEach(({ _id }: IOmnichannelRoom) => {
promises.push(removeOmnichannelRoom(_id));
});
await Promise.all(promises);

livechatLogger.info(`User ${this.userId} removed ${promises.length} closed rooms`);
return API.v1.success({ removedRooms: promises.length });
},
);
livechatLogger.info(`User ${this.userId} removed ${promises.length} closed rooms`);
return API.v1.success({ removedRooms: promises.length });
},
);

type LivechatRoomsEndpoints = ExtractRoutesFromAPI<typeof livechatRoomsEndpoints>;

Expand Down
9 changes: 9 additions & 0 deletions apps/meteor/app/livechat/server/lib/rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
IOmnichannelRoom,
TransferData,
} from '@rocket.chat/core-typings';
import { isOmnichannelRoom } from '@rocket.chat/core-typings';
import {
LivechatRooms,
LivechatContacts,
Expand Down Expand Up @@ -262,6 +263,14 @@ export async function removeOmnichannelRoom(rid: string) {
throw new Meteor.Error('error-invalid-room', 'Invalid room');
}

if (!isOmnichannelRoom(room)) {
throw new Meteor.Error('error-this-is-not-a-livechat-room');
}

if (room.open) {
throw new Meteor.Error('error-room-is-not-closed');
}

const inquiry = await LivechatInquiry.findOneByRoomId(rid);

const result = await Promise.allSettled([
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/app/livechat/server/methods/removeRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,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 { removeOmnichannelRoom } from '../lib/rooms';

declare module '@rocket.chat/ddp-client' {
Expand All @@ -15,6 +16,7 @@ declare module '@rocket.chat/ddp-client' {

Meteor.methods<ServerMethods>({
async 'livechat:removeRoom'(rid) {
methodDeprecationLogger.method('livechat:removeRoom', '8.0.0', '/v1/livechat/rooms.delete');
const user = Meteor.userId();
if (!user || !(await hasPermissionAsync(user, 'remove-closed-livechat-room'))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeRoom' });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
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 { useQueryClient, useMutation } from '@tanstack/react-query';

export const useRemoveCurrentChatMutation = (
options?: Omit<UseMutationOptions<void, Error, IRoom['_id']>, 'mutationFn'>,
): UseMutationResult<void, Error, IRoom['_id']> => {
const removeRoom = useMethod('livechat:removeRoom');
options?: Omit<UseMutationOptions<null, Error, IRoom['_id']>, 'mutationFn'>,
): UseMutationResult<null, Error, IRoom['_id']> => {
const removeRoom = useEndpoint('POST', '/v1/livechat/rooms.delete');
const queryClient = useQueryClient();

return useMutation({
mutationFn: (rid) => removeRoom(rid),
mutationFn: (rid) => removeRoom({ roomId: rid }),
...options,

onSuccess: (...args) => {
Expand Down
9 changes: 1 addition & 8 deletions apps/meteor/tests/e2e/utils/omnichannel/rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,7 @@ export const createRoom = async (api: BaseTest['api'], { visitorToken, agentId }
data: room,
async delete() {
await closeRoom(api, { roomId: room._id, visitorToken });
return api.post('/method.call/livechat:removeRoom', {
message: JSON.stringify({
msg: 'method',
id: '16',
method: 'livechat:removeRoom',
params: [room._id],
}),
});
return api.post('/livechat/rooms.delete', { roomId: room._id });
},
};
};
Expand Down
64 changes: 47 additions & 17 deletions packages/rest-typings/src/v1/omnichannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4067,6 +4067,53 @@ export const isPOSTLivechatRoomsCloseAllSuccessResponse = ajv.compile<{ removedR
POSTLivechatRoomsCloseAllSuccessResponseSchema,
);

type POSTLivechatRemoveRoomParams = {
roomId: string;
};

const POSTLivechatRemoveRoomParamsSchema = {
type: 'object',
properties: {
roomId: {
type: 'string',
},
},
required: ['roomId'],
additionalProperties: false,
};

export const isPOSTLivechatRemoveRoomParams = ajv.compile<POSTLivechatRemoveRoomParams>(POSTLivechatRemoveRoomParamsSchema);

const POSTLivechatRemoveRoomSuccessSchema = {
type: 'object',
properties: {
success: {
type: 'boolean',
enum: [true],
},
},
additionalProperties: false,
};

export const POSTLivechatRemoveRoomSuccess = ajv.compile<void>(POSTLivechatRemoveRoomSuccessSchema);

type POSTLivechatRemoveCustomFields = {
customFieldId: string;
};

const POSTLivechatRemoveCustomFieldsSchema = {
type: 'object',
properties: {
customFieldId: {
type: 'string',
},
},
required: ['customFieldId'],
additionalProperties: false,
};

export const isPOSTLivechatRemoveCustomFields = ajv.compile<POSTLivechatRemoveCustomFields>(POSTLivechatRemoveCustomFieldsSchema);

const POSTLivechatSaveCustomFieldsSchema = {
type: 'object',
properties: {
Expand Down Expand Up @@ -4186,23 +4233,6 @@ export const POSTLivechatSaveCustomFieldSuccess = ajv.compile<{ customField: ILi
POSTLivechatSaveCustomFieldSuccessSchema,
);

type POSTLivechatRemoveCustomFields = {
customFieldId: string;
};

const POSTLivechatRemoveCustomFieldsSchema = {
type: 'object',
properties: {
customFieldId: {
type: 'string',
},
},
required: ['customFieldId'],
additionalProperties: false,
};

export const isPOSTLivechatRemoveCustomFields = ajv.compile<POSTLivechatRemoveCustomFields>(POSTLivechatRemoveCustomFieldsSchema);

const POSTLivechatRemoveCustomFieldSuccessSchema = {
type: 'object',
properties: {
Expand Down
Loading