Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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 = ajv.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