diff --git a/.changeset/migrate-chat-search-to-AJV.md b/.changeset/migrate-chat-search-to-AJV.md new file mode 100644 index 0000000000000..af292c1e8624f --- /dev/null +++ b/.changeset/migrate-chat-search-to-AJV.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/meteor': minor +'@rocket.chat/rest-typings': minor +--- + +Migrate chat.search endpoint to make openAPI and AJV compatible diff --git a/apps/meteor/app/api/server/v1/chat.ts b/apps/meteor/app/api/server/v1/chat.ts index a00d57e46ae72..8797bf447982e 100644 --- a/apps/meteor/app/api/server/v1/chat.ts +++ b/apps/meteor/app/api/server/v1/chat.ts @@ -1,5 +1,5 @@ import { Message } from '@rocket.chat/core-services'; -import type { IMessage, IThreadMainMessage } from '@rocket.chat/core-typings'; +import type { IMessage, IRoom, IThreadMainMessage } from '@rocket.chat/core-typings'; import { MessageTypes } from '@rocket.chat/message-types'; import { Messages, Users, Rooms, Subscriptions } from '@rocket.chat/models'; import { @@ -12,7 +12,6 @@ import { isChatSyncMessagesProps, isChatGetMessageProps, isChatPostMessageProps, - isChatSearchProps, isChatSendMessageProps, isChatIgnoreUserProps, isChatGetPinnedMessagesProps, @@ -26,6 +25,7 @@ import { isChatGetDiscussionsProps, validateBadRequestErrorResponse, validateUnauthorizedErrorResponse, + type PaginatedRequest, } from '@rocket.chat/rest-typings'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import { Meteor } from 'meteor/meteor'; @@ -119,6 +119,35 @@ const ChatUnfollowMessageLocalSchema = { additionalProperties: false, }; +//chat.search starts +type ChatSearch = PaginatedRequest<{ + roomId: IRoom['_id']; + searchText: string; +}>; + +const ChatSearchSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + searchText: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + }, + required: ['roomId', 'searchText'], + additionalProperties: false, +}; +//chat.search ends + const isChatStarMessageLocalProps = ajv.compile(ChatStarMessageLocalSchema); const isChatUnstarMessageLocalProps = ajv.compile(ChatUnstarMessageLocalSchema); @@ -127,6 +156,8 @@ const isChatFollowMessageLocalProps = ajv.compile(ChatFo const isChatUnfollowMessageLocalProps = ajv.compile(ChatUnfollowMessageLocalSchema); +const isChatSearchLocalProps = ajv.compile(ChatSearchSchema); + API.v1.addRoute( 'chat.delete', { authRequired: true, validateParams: isChatDeleteProps }, @@ -558,6 +589,60 @@ const chatEndpoints = API.v1 return API.v1.success(); }, + ) + .get( + 'chat.search', + { + authRequired: true, + query: isChatSearchLocalProps, + response: { + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + 200: ajv.compile({ + type: 'object', + properties: { + messages: { + type: 'array', + items: { $ref: '#/components/schemas/IMessage' }, + }, + success: { + type: 'boolean', + enum: [true], + }, + }, + required: ['messages', 'success'], + additionalProperties: false, + }), + }, + }, + async function action() { + const { roomId, searchText } = this.queryParams; + const { offset, count } = await getPaginationItems(this.queryParams); + + if (!roomId) { + throw new Meteor.Error('error-roomId-param-not-provided', 'The required "roomId" query param is missing.'); + } + + if (!searchText) { + throw new Meteor.Error('error-searchText-param-not-provided', 'The required "searchText" query param is missing.'); + } + + const searchResult = await messageSearch(this.userId, searchText, roomId, count, offset); + + if (searchResult === false) { + return API.v1.failure(); + } + + if (!searchResult.message) { + return API.v1.failure(); + } + + const result = searchResult.message.docs; + + return API.v1.success({ + messages: await normalizeMessagesForUser(result, this.userId), + }); + }, ); API.v1.addRoute( @@ -597,38 +682,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'chat.search', - { authRequired: true, validateParams: isChatSearchProps }, - { - async get() { - const { roomId, searchText } = this.queryParams; - const { offset, count } = await getPaginationItems(this.queryParams); - - if (!roomId) { - throw new Meteor.Error('error-roomId-param-not-provided', 'The required "roomId" query param is missing.'); - } - - if (!searchText) { - throw new Meteor.Error('error-searchText-param-not-provided', 'The required "searchText" query param is missing.'); - } - - const searchResult = await messageSearch(this.userId, searchText, roomId, count, offset); - if (searchResult === false) { - return API.v1.failure(); - } - if (!searchResult.message) { - return API.v1.failure(); - } - const result = searchResult.message.docs; - - return API.v1.success({ - messages: await normalizeMessagesForUser(result, this.userId), - }); - }, - }, -); - // The difference between `chat.postMessage` and `chat.sendMessage` is that `chat.sendMessage` allows // for passing a value for `_id` and the other one doesn't. Also, `chat.sendMessage` only sends it to // one channel whereas the other one allows for sending to more than one channel at a time. diff --git a/packages/rest-typings/src/v1/chat.ts b/packages/rest-typings/src/v1/chat.ts index f3a6e61f677b0..fe26531201589 100644 --- a/packages/rest-typings/src/v1/chat.ts +++ b/packages/rest-typings/src/v1/chat.ts @@ -323,35 +323,6 @@ const ChatIgnoreUserSchema = { export const isChatIgnoreUserProps = ajv.compile(ChatIgnoreUserSchema); -type ChatSearch = PaginatedRequest<{ - roomId: IRoom['_id']; - searchText: string; -}>; - -const ChatSearchSchema = { - type: 'object', - properties: { - roomId: { - type: 'string', - }, - searchText: { - type: 'string', - }, - count: { - type: 'number', - nullable: true, - }, - offset: { - type: 'number', - nullable: true, - }, - }, - required: ['roomId', 'searchText'], - additionalProperties: false, -}; - -export const isChatSearchProps = ajvQuery.compile(ChatSearchSchema); - interface IChatUpdate { roomId: IRoom['_id']; msgId: string; @@ -933,11 +904,6 @@ export type ChatEndpoints = { '/v1/chat.ignoreUser': { GET: (params: ChatIgnoreUser) => void; }; - '/v1/chat.search': { - GET: (params: ChatSearch) => { - messages: IMessage[]; - }; - }; '/v1/chat.update': { POST: (params: ChatUpdate) => { message: IMessage;