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 930e9cd8168cb..b5f7552ce37eb 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, @@ -887,48 +885,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; @@ -947,6 +903,14 @@ type RoomsLeave = roomName: string; }; +type RoomsHideProps = { + roomId: string; +}; + +type RoomsOpenProps = { + roomId: string; +}; + const isRoomGetRolesPropsSchema = { type: 'object', properties: { @@ -1000,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); +const isRoomsHideProps = ajv.compile(roomsHideSchema); export const roomEndpoints = API.v1 .get( @@ -1207,6 +1197,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/apps/meteor/tests/end-to-end/api/rooms.ts b/apps/meteor/tests/end-to-end/api/rooms.ts index 8bf1bb3ab08c7..cf90b339ad65a 100644 --- a/apps/meteor/tests/end-to-end/api/rooms.ts +++ b/apps/meteor/tests/end-to-end/api/rooms.ts @@ -4215,6 +4215,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) => { diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index 5afad26ca5817..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'; @@ -841,20 +805,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; };