-
Notifications
You must be signed in to change notification settings - Fork 13.5k
chore: migrate rooms.hide and rooms.open to OpenAPI-compliant pattern #39072
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 20 commits
7144ed7
7a9f808
eefea4e
4b3767f
5fc1d43
00bcd97
c260039
651dd01
5f70334
16a23c5
9fa1c10
96c0f83
e05c7cb
7591ff7
a025ef0
7aa1adc
4277e92
4150fad
eb263ba
f4a4021
cb7d370
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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<RoomsFavorite>(RoomsFavoriteSchema); | ||||||
| const isRoomsLeaveProps = ajv.compile<RoomsLeave>(isRoomsLeavePropsSchema); | ||||||
| const isRoomsOpenProps = ajv.compile<RoomsOpenProps>(roomsOpenSchema); | ||||||
| export const isRoomsHideProps = ajv.compile<RoomsHideProps>(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<void>({ | ||||||
| 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 } }); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo in projection option: MongoDB/Mongoose uses Proposed fix- const user = await Users.findOneById(this.userId, { projections: { _id: 1 } });
+ const user = await Users.findOneById(this.userId, { projection: { _id: 1 } });📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isnt this outoff the scoop for this PR?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: Length of output: 59 🏁 Script executed: Length of output: 408 🏁 Script executed: Length of output: 354
I checked the original implementation on the Per the migration guidelines, this PR should maintain behavioral parity with the original implementation, even if that includes pre-existing bugs. The typo should be addressed in a separate bug-fix PR. My apologies for flagging this during a migration-focused review. Would you like me to open a follow-up issue to track fixing this typo across the codebase? 🧠 Learnings used |
||||||
|
|
||||||
| 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<void>({ | ||||||
| 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(); | ||||||
| }, | ||||||
| ); | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 }) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test was sending a request with no body and no credentials, which caused AJV validation to run first and return 400 (missing roomId) before the auth middleware could return 401. Adding .send({ roomId: roomA._id }) ensures the request body is valid so that authentication is the only failing condition, making the test correctly assert the 401 behavior.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
make sense |
||
| .expect('Content-Type', 'application/json') | ||
| .expect(401) | ||
| .expect((res) => { | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you forget to remove RoomsOpenProps and RoomsHideProps from rest-typings and move them into the corresponding API file apps/meteor/app/api/server/v1/rooms.ts
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just seeing this now, I've immediately done this and pushed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you export isRoomsHideProps? is it necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was an oversight
Updating it now