Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/migrate-chat-search-to-AJV.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/meteor': minor
'@rocket.chat/rest-typings': minor
---

Migrate chat.search endpoint to make openAPI and AJV compatible
121 changes: 87 additions & 34 deletions apps/meteor/app/api/server/v1/chat.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -12,7 +12,6 @@ import {
isChatSyncMessagesProps,
isChatGetMessageProps,
isChatPostMessageProps,
isChatSearchProps,
isChatSendMessageProps,
isChatIgnoreUserProps,
isChatGetPinnedMessagesProps,
Expand All @@ -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';
Expand Down Expand Up @@ -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<ChatStarMessageLocal>(ChatStarMessageLocalSchema);

const isChatUnstarMessageLocalProps = ajv.compile<ChatUnstarMessageLocal>(ChatUnstarMessageLocalSchema);
Expand All @@ -127,6 +156,8 @@ const isChatFollowMessageLocalProps = ajv.compile<ChatFollowMessageLocal>(ChatFo

const isChatUnfollowMessageLocalProps = ajv.compile<ChatUnfollowMessageLocal>(ChatUnfollowMessageLocalSchema);

const isChatSearchLocalProps = ajv.compile<ChatSearch>(ChatSearchSchema);

API.v1.addRoute(
'chat.delete',
{ authRequired: true, validateParams: isChatDeleteProps },
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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.
Expand Down
34 changes: 0 additions & 34 deletions packages/rest-typings/src/v1/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,35 +323,6 @@ const ChatIgnoreUserSchema = {

export const isChatIgnoreUserProps = ajv.compile<ChatIgnoreUser>(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<ChatSearch>(ChatSearchSchema);

interface IChatUpdate {
roomId: IRoom['_id'];
msgId: string;
Expand Down Expand Up @@ -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;
Expand Down