From 7144ed79bb6ffe8473988568e3597ceb4e8a6b3a Mon Sep 17 00:00:00 2001 From: Verifieddanny Date: Tue, 24 Feb 2026 00:17:54 +0100 Subject: [PATCH 1/9] feat: migrate rooms.leave to openAPI format --- .changeset/migrate-rooms-leave-endpoint.md | 5 ++ apps/meteor/app/api/server/v1/rooms.ts | 79 +++++++++++++++++----- packages/rest-typings/src/v1/rooms.ts | 5 -- 3 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 .changeset/migrate-rooms-leave-endpoint.md diff --git a/.changeset/migrate-rooms-leave-endpoint.md b/.changeset/migrate-rooms-leave-endpoint.md new file mode 100644 index 0000000000000..48f018ab6c3bc --- /dev/null +++ b/.changeset/migrate-rooms-leave-endpoint.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Migrated rooms.leave endpoint to new OpenAPI pattern with AJV validation diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index 988e60002eef9..70875e47fedd9 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -390,23 +390,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'rooms.leave', - { authRequired: true }, - { - async post() { - const room = await findRoomByIdOrName({ params: this.bodyParams }); - const user = await Users.findOneById(this.userId); - if (!user) { - return API.v1.failure('Invalid user'); - } - await leaveRoomMethod(user, room._id); - - return API.v1.success(); - }, - }, -); - /* TO-DO: 8.0.0 should use the ajv validation which will change this endpoint's @@ -935,6 +918,14 @@ type RoomsFavorite = favorite: boolean; }; +type RoomsLeave = + | { + roomId: string; + } + | { + roomName: string; + }; + const isRoomGetRolesPropsSchema = { type: 'object', properties: { @@ -967,7 +958,29 @@ const RoomsFavoriteSchema = { ], }; +const isRoomsLeavePropsSchema = { + anyOf: [ + { + type: 'object', + properties: { + roomId: { type: 'string' }, + }, + required: ['roomId'], + additionalProperties: false, + }, + { + type: 'object', + properties: { + roomName: { type: 'string' }, + }, + required: ['roomName'], + additionalProperties: false, + }, + ], +}; + const isRoomsFavoriteProps = ajv.compile(RoomsFavoriteSchema); +const isRoomsLeaveProps = ajv.compile(isRoomsLeavePropsSchema); export const roomEndpoints = API.v1 .get( @@ -1141,6 +1154,38 @@ export const roomEndpoints = API.v1 await toggleFavoriteMethod(this.userId, room._id, favorite); + return API.v1.success(); + }, + ) + .post( + 'rooms.leave', + { + authRequired: true, + body: isRoomsLeaveProps, + response: { + 200: ajv.compile({ + type: 'object', + properties: { + success: { type: 'boolean', enum: [true] }, + }, + required: ['success'], + additionalProperties: false, + }), + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + }, + }, + async function action() { + const room = await findRoomByIdOrName({ params: this.bodyParams }); + + const user = await Users.findOneById(this.userId); + + if (!user) { + return API.v1.failure('error-invalid-user'); + } + + await leaveRoomMethod(user, room._id); + return API.v1.success(); }, ); diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index 18c4574f7bb23..be2314d65bd41 100644 --- a/packages/rest-typings/src/v1/rooms.ts +++ b/packages/rest-typings/src/v1/rooms.ts @@ -90,7 +90,6 @@ export const isRoomsAutocompleteAdminRoomsPayload = ajv.compile void; - }; - '/v1/rooms.getDiscussions': { GET: (params: RoomsGetDiscussionsProps) => PaginatedResult<{ discussions: IRoom[]; From 5fc1d43702e67e5298e4b11d63e1e63c385b4f12 Mon Sep 17 00:00:00 2001 From: Verifieddanny Date: Tue, 24 Feb 2026 14:48:10 +0100 Subject: [PATCH 2/9] ix: Added rest typing --- .changeset/migrate-rooms-leave-endpoint.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.changeset/migrate-rooms-leave-endpoint.md b/.changeset/migrate-rooms-leave-endpoint.md index 48f018ab6c3bc..c003ca512e59d 100644 --- a/.changeset/migrate-rooms-leave-endpoint.md +++ b/.changeset/migrate-rooms-leave-endpoint.md @@ -1,5 +1,6 @@ --- '@rocket.chat/meteor': patch +'@rocket.chat/rest-typings': patch --- Migrated rooms.leave endpoint to new OpenAPI pattern with AJV validation From 651dd01ee8ccb38b74fa8227c7133f9bb8feaa2b Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 24 Feb 2026 10:51:55 -0300 Subject: [PATCH 3/9] Apply suggestion from @ggazzo --- .changeset/migrate-rooms-leave-endpoint.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/migrate-rooms-leave-endpoint.md b/.changeset/migrate-rooms-leave-endpoint.md index c003ca512e59d..4f9a6263a9a19 100644 --- a/.changeset/migrate-rooms-leave-endpoint.md +++ b/.changeset/migrate-rooms-leave-endpoint.md @@ -1,6 +1,6 @@ --- -'@rocket.chat/meteor': patch -'@rocket.chat/rest-typings': patch +'@rocket.chat/meteor': minor +'@rocket.chat/rest-typings': minor --- Migrated rooms.leave endpoint to new OpenAPI pattern with AJV validation From 5f70334cc724ca8f03e5bdd851d0ede6637210e8 Mon Sep 17 00:00:00 2001 From: Verifieddanny Date: Tue, 24 Feb 2026 14:56:37 +0100 Subject: [PATCH 4/9] Fix: applied changeset suggestion --- .changeset/migrate-rooms-leave-endpoint.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/migrate-rooms-leave-endpoint.md b/.changeset/migrate-rooms-leave-endpoint.md index c003ca512e59d..4f9a6263a9a19 100644 --- a/.changeset/migrate-rooms-leave-endpoint.md +++ b/.changeset/migrate-rooms-leave-endpoint.md @@ -1,6 +1,6 @@ --- -'@rocket.chat/meteor': patch -'@rocket.chat/rest-typings': patch +'@rocket.chat/meteor': minor +'@rocket.chat/rest-typings': minor --- Migrated rooms.leave endpoint to new OpenAPI pattern with AJV validation From e05c7cb7d6a0fbab0aecb1239b863e47af67e610 Mon Sep 17 00:00:00 2001 From: Verifieddanny Date: Thu, 26 Feb 2026 01:06:48 +0100 Subject: [PATCH 5/9] chore: migrate rooms.hide and rooms.open to OpenAPI-compliant pattern --- .../chore-mirgrate-room-hide-room-open.md | 8 ++ apps/meteor/app/api/server/v1/rooms.ts | 108 +++++++++++------- packages/rest-typings/src/v1/rooms.ts | 8 -- 3 files changed, 74 insertions(+), 50 deletions(-) create mode 100644 .changeset/chore-mirgrate-room-hide-room-open.md diff --git a/.changeset/chore-mirgrate-room-hide-room-open.md b/.changeset/chore-mirgrate-room-hide-room-open.md new file mode 100644 index 0000000000000..d917823054313 --- /dev/null +++ b/.changeset/chore-mirgrate-room-hide-room-open.md @@ -0,0 +1,8 @@ +--- +'@rocket.chat/meteor': minor +'@rocket.chat/rest-typings': minor +--- + +Migrated `rooms.hide` and `rooms.open` endpoints to new OpenAPI-compliant pattern with AJV validation and response schemas. + +Tracking PR: https://github.com/RocketChat/Rocket.Chat-Open-API/pull/150 diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index 70875e47fedd9..35bf2bdaad13e 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -866,48 +866,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'rooms.open', - { authRequired: true, validateParams: isRoomsOpenProps }, - { - async post() { - const { roomId } = this.bodyParams; - - await openRoom(this.userId, roomId); - - return API.v1.success(); - }, - }, -); - -API.v1.addRoute( - 'rooms.hide', - { authRequired: true, validateParams: isRoomsHideProps }, - { - async post() { - const { roomId } = this.bodyParams; - - if (!(await canAccessRoomIdAsync(roomId, this.userId))) { - return API.v1.unauthorized(); - } - - const user = await Users.findOneById(this.userId, { projections: { _id: 1 } }); - - if (!user) { - return API.v1.failure('error-invalid-user'); - } - - const modCount = await hideRoomMethod(this.userId, roomId); - - if (!modCount) { - return API.v1.failure('error-room-already-hidden'); - } - - return API.v1.success(); - }, - }, -); - type RoomsFavorite = | { roomId: string; @@ -1186,6 +1144,72 @@ export const roomEndpoints = API.v1 await leaveRoomMethod(user, room._id); + return API.v1.success(); + }, + ) + .post( + 'rooms.hide', + { + authRequired: true, + body: isRoomsHideProps, + response: { + 200: ajv.compile({ + type: 'object', + properties: { + success: { type: 'boolean', enum: [true] }, + }, + required: ['success'], + additionalProperties: false, + }), + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + }, + }, + async function action() { + const { roomId } = this.bodyParams; + + if (!(await canAccessRoomIdAsync(roomId, this.userId))) { + return API.v1.unauthorized('Unauthorized'); + } + + const user = await Users.findOneById(this.userId, { projections: { _id: 1 } }); + + if (!user) { + return API.v1.failure('error-invalid-user'); + } + + const modCount = await hideRoomMethod(this.userId, roomId); + + if (!modCount) { + return API.v1.failure('error-room-already-hidden'); + } + + return API.v1.success(); + }, + ) + .post( + 'rooms.open', + { + authRequired: true, + body: isRoomsOpenProps, + response: { + 200: ajv.compile({ + type: 'object', + properties: { + success: { type: 'boolean', enum: [true] }, + }, + required: ['success'], + additionalProperties: false, + }), + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + }, + }, + async function action() { + const { roomId } = this.bodyParams; + + await openRoom(this.userId, roomId); + return API.v1.success(); }, ); diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index be2314d65bd41..a92a06f6efb4a 100644 --- a/packages/rest-typings/src/v1/rooms.ts +++ b/packages/rest-typings/src/v1/rooms.ts @@ -845,20 +845,12 @@ export type RoomsEndpoints = { }>; }; - '/v1/rooms.open': { - POST: (params: RoomsOpenProps) => void; - }; - '/v1/rooms.membersOrderedByRole': { GET: (params: RoomsMembersOrderedByRoleProps) => PaginatedResult<{ members: (IUser & { subscription: Pick })[]; }>; }; - '/v1/rooms.hide': { - POST: (params: RoomsHideProps) => void; - }; - '/v1/rooms.invite': { POST: (params: RoomsInviteProps) => void; }; From 4277e92356a35729474ecfada6668117d432d8dd Mon Sep 17 00:00:00 2001 From: Verifieddanny Date: Mon, 2 Mar 2026 18:28:16 +0100 Subject: [PATCH 6/9] Fix: test bug not sending roomId to run test --- apps/meteor/tests/end-to-end/api/rooms.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/meteor/tests/end-to-end/api/rooms.ts b/apps/meteor/tests/end-to-end/api/rooms.ts index f20b56e563df7..2c2e0c03793f1 100644 --- a/apps/meteor/tests/end-to-end/api/rooms.ts +++ b/apps/meteor/tests/end-to-end/api/rooms.ts @@ -4213,6 +4213,7 @@ describe('[Rooms]', () => { it('should return 401 if user is not logged in', async () => { await request .post(api('rooms.hide')) + .send({ roomId: roomA._id }) .expect('Content-Type', 'application/json') .expect(401) .expect((res) => { From eb263ba84a6e1e325236d03ede7b2b95b52efa3b Mon Sep 17 00:00:00 2001 From: Verifieddanny Date: Tue, 3 Mar 2026 21:31:31 +0100 Subject: [PATCH 7/9] Fix: moved RoomsOpenProps and RoomsHideProps from rest-typing --- apps/meteor/app/api/server/v1/rooms.ts | 36 ++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index cd6a168d53286..a1ea8b12af5d0 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -11,10 +11,8 @@ import { isRoomsExportProps, isRoomsIsMemberProps, isRoomsCleanHistoryProps, - isRoomsOpenProps, isRoomsMembersOrderedByRoleProps, isRoomsChangeArchivationStateProps, - isRoomsHideProps, isRoomsInviteProps, validateBadRequestErrorResponse, validateUnauthorizedErrorResponse, @@ -905,6 +903,14 @@ type RoomsLeave = roomName: string; }; +type RoomsHideProps = { + roomId: string; +}; + +type RoomsOpenProps = { + roomId: string; +}; + const isRoomGetRolesPropsSchema = { type: 'object', properties: { @@ -958,8 +964,34 @@ const isRoomsLeavePropsSchema = { ], }; +const roomsHideSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + minLength: 1, + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +const roomsOpenSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + minLength: 1, + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + const isRoomsFavoriteProps = ajv.compile(RoomsFavoriteSchema); const isRoomsLeaveProps = ajv.compile(isRoomsLeavePropsSchema); +const isRoomsOpenProps = ajv.compile(roomsOpenSchema); +export const isRoomsHideProps = ajv.compile(roomsHideSchema); export const roomEndpoints = API.v1 .get( From f4a40213b1ccf5cdb89a4d9a109a3b7acfc6d664 Mon Sep 17 00:00:00 2001 From: Verifieddanny Date: Wed, 4 Mar 2026 16:16:10 +0100 Subject: [PATCH 8/9] Fix: RoomsOpenProps and RoomsHideProps from rest-typings --- packages/rest-typings/src/v1/rooms.ts | 36 --------------------------- 1 file changed, 36 deletions(-) diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index 91e3057209b90..a1d9b725ea999 100644 --- a/packages/rest-typings/src/v1/rooms.ts +++ b/packages/rest-typings/src/v1/rooms.ts @@ -609,24 +609,6 @@ const roomsCleanHistorySchema = { export const isRoomsCleanHistoryProps = ajv.compile(roomsCleanHistorySchema); -type RoomsOpenProps = { - roomId: string; -}; - -const roomsOpenSchema = { - type: 'object', - properties: { - roomId: { - type: 'string', - minLength: 1, - }, - }, - required: ['roomId'], - additionalProperties: false, -}; - -export const isRoomsOpenProps = ajv.compile(roomsOpenSchema); - type MembersOrderedByRoleProps = { roomId?: IRoom['_id']; roomName?: IRoom['name']; @@ -669,24 +651,6 @@ const membersOrderedByRoleRolePropsSchema = { export const isRoomsMembersOrderedByRoleProps = ajv.compile(membersOrderedByRoleRolePropsSchema); -type RoomsHideProps = { - roomId: string; -}; - -const roomsHideSchema = { - type: 'object', - properties: { - roomId: { - type: 'string', - minLength: 1, - }, - }, - required: ['roomId'], - additionalProperties: false, -}; - -export const isRoomsHideProps = ajv.compile(roomsHideSchema); - type RoomsInviteProps = { roomId: string; action: 'accept' | 'reject'; From cb7d370e328b213d82ac787e8e71d3b15e6099c6 Mon Sep 17 00:00:00 2001 From: Daniel Nwachukwu Date: Wed, 4 Mar 2026 16:43:00 +0100 Subject: [PATCH 9/9] Fix: removed unnecessary export keyword --- apps/meteor/app/api/server/v1/rooms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index a1ea8b12af5d0..b5f7552ce37eb 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -991,7 +991,7 @@ const roomsOpenSchema = { const isRoomsFavoriteProps = ajv.compile(RoomsFavoriteSchema); const isRoomsLeaveProps = ajv.compile(isRoomsLeavePropsSchema); const isRoomsOpenProps = ajv.compile(roomsOpenSchema); -export const isRoomsHideProps = ajv.compile(roomsHideSchema); +const isRoomsHideProps = ajv.compile(roomsHideSchema); export const roomEndpoints = API.v1 .get(