diff --git a/.changeset/migrate-chat-star-unstar-message.md b/.changeset/migrate-chat-star-unstar-message.md new file mode 100644 index 0000000000000..395b6422747a5 --- /dev/null +++ b/.changeset/migrate-chat-star-unstar-message.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/rest-typings": minor +--- + +Add OpenAPI support for the chat.starMessage and chat.unStarMessage API endpoints by migrating to a modern chained route definition syntax and utilizing AJV schemas for body and response validation. diff --git a/apps/meteor/app/api/server/v1/chat.ts b/apps/meteor/app/api/server/v1/chat.ts index c9fc2ce6925ec..00f4c0e2de4e1 100644 --- a/apps/meteor/app/api/server/v1/chat.ts +++ b/apps/meteor/app/api/server/v1/chat.ts @@ -14,8 +14,6 @@ import { isChatPostMessageProps, isChatSearchProps, isChatSendMessageProps, - isChatStarMessageProps, - isChatUnstarMessageProps, isChatIgnoreUserProps, isChatGetPinnedMessagesProps, isChatFollowMessageProps, @@ -59,6 +57,42 @@ import { API } from '../api'; import { getPaginationItems } from '../helpers/getPaginationItems'; import { findDiscussionsFromRoom, findMentionedMessages, findStarredMessages } from '../lib/messages'; +type ChatStarMessageLocal = { + messageId: IMessage['_id']; +}; + +type ChatUnstarMessageLocal = { + messageId: IMessage['_id']; +}; + +const ChatStarMessageLocalSchema = { + type: 'object', + properties: { + messageId: { + type: 'string', + minLength: 1, + }, + }, + required: ['messageId'], + additionalProperties: false, +}; + +const ChatUnstarMessageLocalSchema = { + type: 'object', + properties: { + messageId: { + type: 'string', + minLength: 1, + }, + }, + required: ['messageId'], + additionalProperties: false, +}; + +const isChatStarMessageLocalProps = ajv.compile(ChatStarMessageLocalSchema); + +const isChatUnstarMessageLocalProps = ajv.compile(ChatUnstarMessageLocalSchema); + API.v1.addRoute( 'chat.delete', { authRequired: true, validateParams: isChatDeleteProps }, @@ -350,6 +384,80 @@ const chatEndpoints = API.v1 message, }); }, + ) + .post( + 'chat.starMessage', + { + authRequired: true, + body: isChatStarMessageLocalProps, + response: { + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + 200: ajv.compile({ + type: 'object', + properties: { + success: { + type: 'boolean', + enum: [true], + }, + }, + required: ['success'], + additionalProperties: false, + }), + }, + }, + async function action() { + const msg = await Messages.findOneById(this.bodyParams.messageId); + + if (!msg) { + throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.'); + } + + await starMessage(this.user, { + _id: msg._id, + rid: msg.rid, + starred: true, + }); + + return API.v1.success(); + }, + ) + .post( + 'chat.unStarMessage', + { + authRequired: true, + body: isChatUnstarMessageLocalProps, + response: { + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + 200: ajv.compile({ + type: 'object', + properties: { + success: { + type: 'boolean', + enum: [true], + }, + }, + required: ['success'], + additionalProperties: false, + }), + }, + }, + async function action() { + const msg = await Messages.findOneById(this.bodyParams.messageId); + + if (!msg) { + throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.'); + } + + await starMessage(this.user, { + _id: msg._id, + rid: msg.rid, + starred: false, + }); + + return API.v1.success(); + }, ); API.v1.addRoute( @@ -445,50 +553,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'chat.starMessage', - { authRequired: true, validateParams: isChatStarMessageProps }, - { - async post() { - const msg = await Messages.findOneById(this.bodyParams.messageId); - - if (!msg) { - throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.'); - } - - await starMessage(this.user, { - _id: msg._id, - rid: msg.rid, - starred: true, - }); - - return API.v1.success(); - }, - }, -); - -API.v1.addRoute( - 'chat.unStarMessage', - { authRequired: true, validateParams: isChatUnstarMessageProps }, - { - async post() { - const msg = await Messages.findOneById(this.bodyParams.messageId); - - if (!msg) { - throw new Meteor.Error('error-message-not-found', 'The provided "messageId" does not match any existing message.'); - } - - await starMessage(this.user, { - _id: msg._id, - rid: msg.rid, - starred: false, - }); - - return API.v1.success(); - }, - }, -); - API.v1.addRoute( 'chat.react', { authRequired: true, validateParams: isChatReactProps }, diff --git a/packages/rest-typings/src/v1/chat.ts b/packages/rest-typings/src/v1/chat.ts index 71fd745d7f95c..7a1065ee84964 100644 --- a/packages/rest-typings/src/v1/chat.ts +++ b/packages/rest-typings/src/v1/chat.ts @@ -133,40 +133,6 @@ const ChatGetMessageSchema = { export const isChatGetMessageProps = ajv.compile(ChatGetMessageSchema); -type ChatStarMessage = { - messageId: IMessage['_id']; -}; - -const ChatStarMessageSchema = { - type: 'object', - properties: { - messageId: { - type: 'string', - }, - }, - required: ['messageId'], - additionalProperties: false, -}; - -export const isChatStarMessageProps = ajv.compile(ChatStarMessageSchema); - -type ChatUnstarMessage = { - messageId: IMessage['_id']; -}; - -const ChatUnstarMessageSchema = { - type: 'object', - properties: { - messageId: { - type: 'string', - }, - }, - required: ['messageId'], - additionalProperties: false, -}; - -export const isChatUnstarMessageProps = ajv.compile(ChatUnstarMessageSchema); - type ChatGetDiscussions = PaginatedRequest<{ roomId: IRoom['_id']; text?: string; @@ -973,12 +939,6 @@ export type ChatEndpoints = { '/v1/chat.unfollowMessage': { POST: (params: ChatUnfollowMessage) => void; }; - '/v1/chat.starMessage': { - POST: (params: ChatStarMessage) => void; - }; - '/v1/chat.unStarMessage': { - POST: (params: ChatUnstarMessage) => void; - }; '/v1/chat.reportMessage': { POST: (params: ChatReportMessage) => void; };