-
Notifications
You must be signed in to change notification settings - Fork 13.5k
refactor: Migrate custom-user-status API to standardized format #39805
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 all commits
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 | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,17 +1,19 @@ | ||||||||||||||||||||||||||
| import type { ICustomUserStatus } from '@rocket.chat/core-typings'; | ||||||||||||||||||||||||||
| import { CustomUserStatus } from '@rocket.chat/models'; | ||||||||||||||||||||||||||
| import { ajv, ajvQuery, validateUnauthorizedErrorResponse, validateBadRequestErrorResponse } from '@rocket.chat/rest-typings'; | ||||||||||||||||||||||||||
| import { ajv, ajvQuery, validateUnauthorizedErrorResponse, validateBadRequestErrorResponse, isCustomUserStatusCreateProps, isCustomUserStatusDeleteProps, isCustomUserStatusUpdateProps } from '@rocket.chat/rest-typings'; | ||||||||||||||||||||||||||
| import type { PaginatedRequest, PaginatedResult } from '@rocket.chat/rest-typings'; | ||||||||||||||||||||||||||
| import { escapeRegExp } from '@rocket.chat/string-helpers'; | ||||||||||||||||||||||||||
| import { Match, check } from 'meteor/check'; | ||||||||||||||||||||||||||
| // import { Match, check } from 'meteor/check'; // No longer needed | ||||||||||||||||||||||||||
| import { Meteor } from 'meteor/meteor'; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import { deleteCustomUserStatus } from '../../../user-status/server/methods/deleteCustomUserStatus'; | ||||||||||||||||||||||||||
| import { insertOrUpdateUserStatus } from '../../../user-status/server/methods/insertOrUpdateUserStatus'; | ||||||||||||||||||||||||||
| import type { ExtractRoutesFromAPI } from '../ApiClass'; | ||||||||||||||||||||||||||
| import { API } from '../api'; | ||||||||||||||||||||||||||
| import { getPaginationItems } from '../helpers/getPaginationItems'; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // This file has been migrated to use modern API registration patterns and AJV validation. | ||||||||||||||||||||||||||
| // Redundant local type definitions and module augmentations have been removed to resolve | ||||||||||||||||||||||||||
| // a TypeScript circular reference error, relying on the source of truth in `@rocket.chat/rest-typings`. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| type CustomUserStatusListProps = PaginatedRequest<{ name?: string; _id?: string; query?: string }>; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const CustomUserStatusListSchema = { | ||||||||||||||||||||||||||
|
|
@@ -48,7 +50,7 @@ const CustomUserStatusListSchema = { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const isCustomUserStatusListProps = ajvQuery.compile<CustomUserStatusListProps>(CustomUserStatusListSchema); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const customUserStatusEndpoints = API.v1.get( | ||||||||||||||||||||||||||
| API.v1.get( | ||||||||||||||||||||||||||
| 'custom-user-status.list', | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| authRequired: true, | ||||||||||||||||||||||||||
|
|
@@ -120,95 +122,237 @@ const customUserStatusEndpoints = API.v1.get( | |||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| API.v1.addRoute( | ||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * @openapi | ||||||||||||||||||||||||||
| * /api/v1/custom-user-status.update: | ||||||||||||||||||||||||||
| * post: | ||||||||||||||||||||||||||
| * description: Update an existing custom user status | ||||||||||||||||||||||||||
| * security: | ||||||||||||||||||||||||||
| * - cookieAuth: [] | ||||||||||||||||||||||||||
| * - x-user-id: [] | ||||||||||||||||||||||||||
| * - x-auth-token: [] | ||||||||||||||||||||||||||
| * requestBody: | ||||||||||||||||||||||||||
| * content: | ||||||||||||||||||||||||||
| * application/json: | ||||||||||||||||||||||||||
| * schema: | ||||||||||||||||||||||||||
| * type: object | ||||||||||||||||||||||||||
| * properties: | ||||||||||||||||||||||||||
| * _id: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * name: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * statusType: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * required: | ||||||||||||||||||||||||||
| * - _id | ||||||||||||||||||||||||||
| * - name | ||||||||||||||||||||||||||
| * responses: | ||||||||||||||||||||||||||
| * 200: | ||||||||||||||||||||||||||
| * description: The updated custom user status | ||||||||||||||||||||||||||
| * content: | ||||||||||||||||||||||||||
| * application/json: | ||||||||||||||||||||||||||
| * schema: | ||||||||||||||||||||||||||
| * $ref: '#/components/schemas/ApiSuccessV1' | ||||||||||||||||||||||||||
| * default: | ||||||||||||||||||||||||||
| * $ref: '#/components/schemas/ApiErrorsV1' | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
|
Comment on lines
+125
to
+158
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. The OpenAPI blocks are out of sync with the handlers. The create and delete handlers are both documented as Also applies to: 201-234, 264-297 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| API.v1.post( | ||||||||||||||||||||||||||
| 'custom-user-status.create', | ||||||||||||||||||||||||||
| { authRequired: true }, | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| async post() { | ||||||||||||||||||||||||||
| check(this.bodyParams, { | ||||||||||||||||||||||||||
| name: String, | ||||||||||||||||||||||||||
| statusType: Match.Maybe(String), | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const userStatusData = { | ||||||||||||||||||||||||||
| name: this.bodyParams.name, | ||||||||||||||||||||||||||
| statusType: this.bodyParams.statusType || '', | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| await insertOrUpdateUserStatus(this.userId, userStatusData); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const customUserStatus = await CustomUserStatus.findOneByName(userStatusData.name); | ||||||||||||||||||||||||||
| if (!customUserStatus) { | ||||||||||||||||||||||||||
| throw new Meteor.Error('error-creating-custom-user-status', 'Error creating custom user status'); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return API.v1.success({ | ||||||||||||||||||||||||||
| customUserStatus, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| authRequired: true, | ||||||||||||||||||||||||||
| body: isCustomUserStatusCreateProps, | ||||||||||||||||||||||||||
| response: { | ||||||||||||||||||||||||||
| 200: ajv.compile<{ customUserStatus: ICustomUserStatus }>({ | ||||||||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||||||||
| properties: { | ||||||||||||||||||||||||||
| customUserStatus: { | ||||||||||||||||||||||||||
| $ref: '#/components/schemas/ICustomUserStatus', | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| success: { | ||||||||||||||||||||||||||
| type: 'boolean', | ||||||||||||||||||||||||||
| enum: [true], | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| required: ['success', 'customUserStatus'], | ||||||||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||
| 400: validateBadRequestErrorResponse, | ||||||||||||||||||||||||||
| 401: validateUnauthorizedErrorResponse, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| async function () { | ||||||||||||||||||||||||||
| const userStatusData = { | ||||||||||||||||||||||||||
| name: this.bodyParams.name, | ||||||||||||||||||||||||||
| statusType: this.bodyParams.statusType || '', | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| await insertOrUpdateUserStatus(this.userId, userStatusData); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| API.v1.addRoute( | ||||||||||||||||||||||||||
| const customUserStatus = await CustomUserStatus.findOneByName(userStatusData.name); | ||||||||||||||||||||||||||
| if (!customUserStatus) { | ||||||||||||||||||||||||||
| throw new Meteor.Error('error-creating-custom-user-status', 'Error creating custom user status'); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return API.v1.success({ | ||||||||||||||||||||||||||
| customUserStatus, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * @openapi | ||||||||||||||||||||||||||
| * /api/v1/custom-user-status.update: | ||||||||||||||||||||||||||
| * post: | ||||||||||||||||||||||||||
| * description: Update an existing custom user status | ||||||||||||||||||||||||||
| * security: | ||||||||||||||||||||||||||
| * - cookieAuth: [] | ||||||||||||||||||||||||||
| * - x-user-id: [] | ||||||||||||||||||||||||||
| * - x-auth-token: [] | ||||||||||||||||||||||||||
| * requestBody: | ||||||||||||||||||||||||||
| * content: | ||||||||||||||||||||||||||
| * application/json: | ||||||||||||||||||||||||||
| * schema: | ||||||||||||||||||||||||||
| * type: object | ||||||||||||||||||||||||||
| * properties: | ||||||||||||||||||||||||||
| * _id: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * name: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * statusType: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * required: | ||||||||||||||||||||||||||
| * - _id | ||||||||||||||||||||||||||
| * - name | ||||||||||||||||||||||||||
| * responses: | ||||||||||||||||||||||||||
| * 200: | ||||||||||||||||||||||||||
| * description: The updated custom user status | ||||||||||||||||||||||||||
| * content: | ||||||||||||||||||||||||||
| * application/json: | ||||||||||||||||||||||||||
| * schema: | ||||||||||||||||||||||||||
| * $ref: '#/components/schemas/ApiSuccessV1' | ||||||||||||||||||||||||||
| * default: | ||||||||||||||||||||||||||
| * $ref: '#/components/schemas/ApiErrorsV1' | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| API.v1.post( | ||||||||||||||||||||||||||
| 'custom-user-status.delete', | ||||||||||||||||||||||||||
| { authRequired: true }, | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| async post() { | ||||||||||||||||||||||||||
| const { customUserStatusId } = this.bodyParams; | ||||||||||||||||||||||||||
| if (!customUserStatusId) { | ||||||||||||||||||||||||||
| return API.v1.failure('The "customUserStatusId" params is required!'); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| authRequired: true, | ||||||||||||||||||||||||||
| body: isCustomUserStatusDeleteProps, | ||||||||||||||||||||||||||
| response: { | ||||||||||||||||||||||||||
| 200: ajv.compile<void>({ | ||||||||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||||||||
| properties: { | ||||||||||||||||||||||||||
| success: { | ||||||||||||||||||||||||||
| type: 'boolean', | ||||||||||||||||||||||||||
| enum: [true], | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| required: ['success'], | ||||||||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||
| 400: validateBadRequestErrorResponse, | ||||||||||||||||||||||||||
| 401: validateUnauthorizedErrorResponse, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| async function () { | ||||||||||||||||||||||||||
| const { customUserStatusId } = this.bodyParams; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| await deleteCustomUserStatus(this.userId, customUserStatusId); | ||||||||||||||||||||||||||
| await deleteCustomUserStatus(this.userId, customUserStatusId); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return API.v1.success(); | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| return API.v1.success(); | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| API.v1.addRoute( | ||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * @openapi | ||||||||||||||||||||||||||
| * /api/v1/custom-user-status.update: | ||||||||||||||||||||||||||
| * post: | ||||||||||||||||||||||||||
| * description: Update an existing custom user status | ||||||||||||||||||||||||||
| * security: | ||||||||||||||||||||||||||
| * - cookieAuth: [] | ||||||||||||||||||||||||||
| * - x-user-id: [] | ||||||||||||||||||||||||||
| * - x-auth-token: [] | ||||||||||||||||||||||||||
| * requestBody: | ||||||||||||||||||||||||||
| * content: | ||||||||||||||||||||||||||
| * application/json: | ||||||||||||||||||||||||||
| * schema: | ||||||||||||||||||||||||||
| * type: object | ||||||||||||||||||||||||||
| * properties: | ||||||||||||||||||||||||||
| * _id: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * name: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * statusType: | ||||||||||||||||||||||||||
| * type: string | ||||||||||||||||||||||||||
| * required: | ||||||||||||||||||||||||||
| * - _id | ||||||||||||||||||||||||||
| * - name | ||||||||||||||||||||||||||
| * responses: | ||||||||||||||||||||||||||
| * 200: | ||||||||||||||||||||||||||
| * description: The updated custom user status | ||||||||||||||||||||||||||
| * content: | ||||||||||||||||||||||||||
| * application/json: | ||||||||||||||||||||||||||
| * schema: | ||||||||||||||||||||||||||
| * $ref: '#/components/schemas/ApiSuccessV1' | ||||||||||||||||||||||||||
| * default: | ||||||||||||||||||||||||||
| * $ref: '#/components/schemas/ApiErrorsV1' | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| API.v1.post( | ||||||||||||||||||||||||||
| 'custom-user-status.update', | ||||||||||||||||||||||||||
| { authRequired: true }, | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| async post() { | ||||||||||||||||||||||||||
| check(this.bodyParams, { | ||||||||||||||||||||||||||
| _id: String, | ||||||||||||||||||||||||||
| name: String, | ||||||||||||||||||||||||||
| statusType: Match.Maybe(String), | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const userStatusData = { | ||||||||||||||||||||||||||
| _id: this.bodyParams._id, | ||||||||||||||||||||||||||
| name: this.bodyParams.name, | ||||||||||||||||||||||||||
| statusType: this.bodyParams.statusType, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| authRequired: true, | ||||||||||||||||||||||||||
| body: isCustomUserStatusUpdateProps, | ||||||||||||||||||||||||||
| response: { | ||||||||||||||||||||||||||
| 200: ajv.compile<{ customUserStatus: ICustomUserStatus }>({ | ||||||||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||||||||
| properties: { | ||||||||||||||||||||||||||
| customUserStatus: { | ||||||||||||||||||||||||||
| $ref: '#/components/schemas/ICustomUserStatus', | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| success: { | ||||||||||||||||||||||||||
| type: 'boolean', | ||||||||||||||||||||||||||
| enum: [true], | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| required: ['success', 'customUserStatus'], | ||||||||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||
| 400: validateBadRequestErrorResponse, | ||||||||||||||||||||||||||
| 401: validateUnauthorizedErrorResponse, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| async function () { | ||||||||||||||||||||||||||
| const { _id, name, statusType } = this.bodyParams; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const customUserStatusToUpdate = await CustomUserStatus.findOneById(userStatusData._id); | ||||||||||||||||||||||||||
| const customUserStatusToUpdate = await CustomUserStatus.findOneById(_id); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Ensure the message exists | ||||||||||||||||||||||||||
| if (!customUserStatusToUpdate) { | ||||||||||||||||||||||||||
| return API.v1.failure(`No custom user status found with the id of "${userStatusData._id}".`); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| // Ensure the message exists | ||||||||||||||||||||||||||
| if (!customUserStatusToUpdate) { | ||||||||||||||||||||||||||
| return API.v1.failure(`No custom user status found with the id of "${_id}".`); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| await insertOrUpdateUserStatus(this.userId, userStatusData); | ||||||||||||||||||||||||||
| await insertOrUpdateUserStatus(this.userId, { | ||||||||||||||||||||||||||
| _id, | ||||||||||||||||||||||||||
| name: name || customUserStatusToUpdate.name, | ||||||||||||||||||||||||||
| statusType: statusType || customUserStatusToUpdate.statusType, | ||||||||||||||||||||||||||
|
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. P2: Using Prompt for AI agents
Suggested change
|
||||||||||||||||||||||||||
| previousName: customUserStatusToUpdate.name, | ||||||||||||||||||||||||||
| previousStatusType: customUserStatusToUpdate.statusType, | ||||||||||||||||||||||||||
|
Comment on lines
+332
to
+337
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. Use
🔧 Proposed fix await insertOrUpdateUserStatus(this.userId, {
_id,
- name: name || customUserStatusToUpdate.name,
- statusType: statusType || customUserStatusToUpdate.statusType,
+ name: name ?? customUserStatusToUpdate.name,
+ statusType: statusType ?? customUserStatusToUpdate.statusType,
previousName: customUserStatusToUpdate.name,
previousStatusType: customUserStatusToUpdate.statusType,
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const customUserStatus = await CustomUserStatus.findOneById(userStatusData._id); | ||||||||||||||||||||||||||
| const customUserStatus = await CustomUserStatus.findOneById(_id); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (!customUserStatus) { | ||||||||||||||||||||||||||
| throw new Meteor.Error('error-updating-custom-user-status', 'Error updating custom user status'); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| if (!customUserStatus) { | ||||||||||||||||||||||||||
| throw new Meteor.Error('error-updating-custom-user-status', 'Error updating custom user status'); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return API.v1.success({ | ||||||||||||||||||||||||||
| customUserStatus, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| return API.v1.success({ | ||||||||||||||||||||||||||
| customUserStatus, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export type CustomUserStatusEndpoints = ExtractRoutesFromAPI<typeof customUserStatusEndpoints>; | ||||||||||||||||||||||||||
| // Note for Mentors: | ||||||||||||||||||||||||||
| // The circular reference error (Type alias 'CustomUserStatusEndpoints' circularly references itself) | ||||||||||||||||||||||||||
| // was resolved by removing the redundant server-side re-definition of CustomUserStatusEndpoints | ||||||||||||||||||||||||||
| // and the manual module augmentation. The endpoint types are now correctly resolved through the | ||||||||||||||||||||||||||
| // global `Endpoints` interface provided by the `@rocket.chat/rest-typings` package, following | ||||||||||||||||||||||||||
| // the project's modern API migration patterns. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| declare module '@rocket.chat/rest-typings' { | ||||||||||||||||||||||||||
| // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface | ||||||||||||||||||||||||||
| interface Endpoints extends CustomUserStatusEndpoints {} | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
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.
P1: OpenAPI annotation for create endpoint has incorrect path and description copied from update endpoint
Prompt for AI agents