Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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-ignoreUser-to-openapi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/meteor': minor
'@rocket.chat/rest-typings': minor
---

Migrated chat.ignoreUser endpoint to new OpenAPI pattern with AJV validation
143 changes: 95 additions & 48 deletions apps/meteor/app/api/server/v1/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { MessageTypes } from '@rocket.chat/message-types';
import { Messages, Users, Rooms, Subscriptions } from '@rocket.chat/models';
import {
ajv,
isChatReportMessageProps,
isChatGetURLPreviewProps,
isChatUpdateProps,
isChatGetThreadsListProps,
Expand All @@ -14,7 +13,6 @@ import {
isChatPostMessageProps,
isChatSearchProps,
isChatSendMessageProps,
isChatIgnoreUserProps,
isChatGetPinnedMessagesProps,
isChatGetMentionedMessagesProps,
isChatReactProps,
Expand Down Expand Up @@ -275,6 +273,51 @@ const isChatPinMessageProps = ajv.compile<ChatPinMessage>(ChatPinMessageSchema);

const isChatUnpinMessageProps = ajv.compile<ChatUnpinMessage>(ChatUnpinMessageSchema);

type ChatReportMessage = {
messageId: IMessage['_id'];
description: string;
};

const ChatReportMessageSchema = {
type: 'object',
properties: {
messageId: { type: 'string', minLength: 1 },
description: { type: 'string', minLength: 1 },
},
required: ['messageId', 'description'],
additionalProperties: false,
};

const isChatReportMessageLocalProps = ajv.compile<ChatReportMessage>(ChatReportMessageSchema);

type ChatIgnoreUser = {
rid: string;
userId: string;
ignore: string;
};

const ChatIgnoreUserSchema = {
type: 'object',
properties: {
rid: {
type: 'string',
minLength: 1,
},
userId: {
type: 'string',
minLength: 1,
},
ignore: {
type: 'string',
minLength: 1,
},
},
required: ['rid', 'userId', 'ignore'],
additionalProperties: false,
};

export const isChatIgnoreUserLocalProps = ajv.compile<ChatIgnoreUser>(ChatIgnoreUserSchema);

const chatEndpoints = API.v1
.post(
'chat.pinMessage',
Expand Down Expand Up @@ -419,6 +462,30 @@ const chatEndpoints = API.v1
});
},
)
.post(
'chat.reportMessage',
{
authRequired: true,
body: isChatReportMessageLocalProps,
response: {
200: ajv.compile<void>({
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
},
required: ['success'],
additionalProperties: false,
}),
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const { messageId, description } = this.bodyParams;
await reportMessage(messageId, description, this.userId);
return API.v1.success();
},
)
.post(
'chat.starMessage',
{
Expand Down Expand Up @@ -555,6 +622,32 @@ const chatEndpoints = API.v1
}

await unfollowMessage(this.user, { mid });
return API.v1.success();
},
)
.get(
'chat.ignoreUser',
{
authRequired: true,
query: isChatIgnoreUserLocalProps,
response: {
200: ajv.compile<void>({
type: 'object',
properties: { success: { type: 'boolean', enum: [true] } },
required: ['success'],
additionalProperties: false,
}),
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const { rid, userId } = this.queryParams;
const { ignore = 'true' } = this.queryParams;

const ignoreBool = typeof ignore === 'string' ? /true|1/.test(ignore) : ignore;

await ignoreUser(this.userId, { rid, userId, ignore: ignoreBool });

return API.v1.success();
},
Expand Down Expand Up @@ -677,52 +770,6 @@ API.v1.addRoute(
},
);

API.v1.addRoute(
'chat.reportMessage',
{ authRequired: true, validateParams: isChatReportMessageProps },
{
async post() {
const { messageId, description } = this.bodyParams;
if (!messageId) {
return API.v1.failure('The required "messageId" param is missing.');
}

if (!description) {
return API.v1.failure('The required "description" param is missing.');
}

await reportMessage(messageId, description, this.userId);

return API.v1.success();
},
},
);

API.v1.addRoute(
'chat.ignoreUser',
{ authRequired: true, validateParams: isChatIgnoreUserProps },
{
async get() {
const { rid, userId } = this.queryParams;
let { ignore = true } = this.queryParams;

ignore = typeof ignore === 'string' ? /true|1/.test(ignore) : ignore;

if (!rid?.trim()) {
throw new Meteor.Error('error-room-id-param-not-provided', 'The required "rid" param is missing.');
}

if (!userId?.trim()) {
throw new Meteor.Error('error-user-id-param-not-provided', 'The required "userId" param is missing.');
}

await ignoreUser(this.userId, { rid, userId, ignore });

return API.v1.success();
},
},
);

API.v1.addRoute(
'chat.getDeletedMessages',
{ authRequired: true, validateParams: isChatGetDeletedMessagesProps },
Expand Down
35 changes: 0 additions & 35 deletions packages/rest-typings/src/v1/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,38 +291,6 @@ const ChatReactSchema = {

export const isChatReactProps = ajv.compile<ChatReact>(ChatReactSchema);

/**
* The param `ignore` cannot be boolean, since this is a GET method. Use strings 'true' or 'false' instead.
* @param {string} ignore
*/
type ChatIgnoreUser = {
rid: string;
userId: string;
ignore: string;
};

const ChatIgnoreUserSchema = {
type: 'object',
properties: {
rid: {
type: 'string',
minLength: 1,
},
userId: {
type: 'string',
minLength: 1,
},
ignore: {
type: 'string',
minLength: 1,
},
},
required: ['rid', 'userId', 'ignore'],
additionalProperties: false,
};

export const isChatIgnoreUserProps = ajv.compile<ChatIgnoreUser>(ChatIgnoreUserSchema);

type ChatSearch = PaginatedRequest<{
roomId: IRoom['_id'];
searchText: string;
Expand Down Expand Up @@ -930,9 +898,6 @@ export type ChatEndpoints = {
'/v1/chat.react': {
POST: (params: ChatReact) => void;
};
'/v1/chat.ignoreUser': {
GET: (params: ChatIgnoreUser) => void;
};
'/v1/chat.search': {
GET: (params: ChatSearch) => {
messages: IMessage[];
Expand Down