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
7 changes: 7 additions & 0 deletions .changeset/migrate-chat-getDeletedMessages-to-AJV.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@rocket.chat/core-typings': minor
'@rocket.chat/rest-typings': minor
'@rocket.chat/meteor': minor
---

Migrate chat.getDeletedMessages endpoint to make it openAPI and AJV compatible
130 changes: 98 additions & 32 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 { ICustomMessage, 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 @@ -18,14 +18,14 @@ import {
isChatGetPinnedMessagesProps,
isChatGetMentionedMessagesProps,
isChatReactProps,
isChatGetDeletedMessagesProps,
isChatSyncThreadsListProps,
isChatGetThreadMessagesProps,
isChatSyncThreadMessagesProps,
isChatGetStarredMessagesProps,
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,42 @@ const ChatUnfollowMessageLocalSchema = {
additionalProperties: false,
};

//chat.getDeletedMessages starts
type ChatGetDeletedMessages = PaginatedRequest<{
roomId: IRoom['_id'];
since: string;
}>;

const ChatGetDeletedMessagesSchema = {
type: 'object',
properties: {
roomId: {
type: 'string',
minLength: 1,
},
since: {
type: 'string',
minLength: 1,
format: 'iso-date-time',
},
count: {
type: 'number',
nullable: true,
},
offset: {
type: 'number',
nullable: true,
},
sort: {
type: 'string',
nullable: true,
},
},
required: ['roomId', 'since'],
additionalProperties: false,
};
//chat.getDeletedMessages ends

const isChatStarMessageLocalProps = ajv.compile<ChatStarMessageLocal>(ChatStarMessageLocalSchema);

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

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

const isChatGetDeletedMessagesLocalProps = ajv.compile<ChatGetDeletedMessages>(ChatGetDeletedMessagesSchema);

API.v1.addRoute(
'chat.delete',
{ authRequired: true, validateParams: isChatDeleteProps },
Expand Down Expand Up @@ -558,6 +596,64 @@ const chatEndpoints = API.v1

return API.v1.success();
},
)
.get(
'chat.getDeletedMessages',
{
authRequired: true,
query: isChatGetDeletedMessagesLocalProps,
response: {
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
200: ajv.compile<{ messages: ICustomMessage[] }>({
type: 'object',
properties: {
messages: {
type: 'array',
items: { $ref: '#/components/schemas/ICustomMessage' },
},
Comment on lines +611 to +614
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why you didnt use the ref?

Copy link
Copy Markdown
Author

@CodeMatrix1 CodeMatrix1 Mar 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the trashfind query only returned message ids with projection: { _id: 1 }, this has incomplete info for the ref, so, when I ran swagger ui request and the test, it returned a 400 bad request, but this change in schema passed the checks

count: {
type: 'number',
},
offset: {
type: 'number',
},
total: {
type: 'number',
},
success: {
type: 'boolean',
enum: [true],
},
},
required: ['messages', 'count', 'offset', 'total', 'success'],
additionalProperties: false,
}),
},
},
async function action() {
const { roomId, since } = this.queryParams;
const { offset, count } = await getPaginationItems(this.queryParams);

const { cursor, totalCount } = Messages.trashFindPaginatedDeletedAfter(
new Date(since),
{ rid: roomId },
{
skip: offset,
limit: count,
projection: { _id: 1 },
},
);

const [messages, total] = await Promise.all([cursor.toArray(), totalCount]);

return API.v1.success({
messages,
count: messages.length,
offset,
total,
});
},
);

API.v1.addRoute(
Expand Down Expand Up @@ -723,36 +819,6 @@ API.v1.addRoute(
},
);

API.v1.addRoute(
'chat.getDeletedMessages',
{ authRequired: true, validateParams: isChatGetDeletedMessagesProps },
{
async get() {
const { roomId, since } = this.queryParams;
const { offset, count } = await getPaginationItems(this.queryParams);

const { cursor, totalCount } = Messages.trashFindPaginatedDeletedAfter(
new Date(since),
{ rid: roomId },
{
skip: offset,
limit: count,
projection: { _id: 1 },
},
);

const [messages, total] = await Promise.all([cursor.toArray(), totalCount]);

return API.v1.success({
messages,
count: messages.length,
offset,
total,
});
},
},
);

API.v1.addRoute(
'chat.getPinnedMessages',
{ authRequired: true, validateParams: isChatGetPinnedMessagesProps },
Expand Down
2 changes: 2 additions & 0 deletions packages/core-typings/src/Ajv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { IBanner } from './IBanner';
import type { ICalendarEvent } from './ICalendarEvent';
import type { CallHistoryItem } from './ICallHistoryItem';
import type { CloudConfirmationPollData, CloudRegistrationIntentData, CloudRegistrationStatus } from './ICloud';
import type { ICustomMessage } from './ICustomMessage';
import type { ICustomSound } from './ICustomSound';
import type { ICustomUserStatus } from './ICustomUserStatus';
import type { IEmailInbox } from './IEmailInbox';
Expand All @@ -28,6 +29,7 @@ export const schemas = typia.json.schemas<
| ISubscription
| IInvite
| ICustomSound
| ICustomMessage
| IMessage
| IOAuthApps
| IPermission
Expand Down
3 changes: 3 additions & 0 deletions packages/core-typings/src/ICustomMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { IMessage } from './IMessage';

export type ICustomMessage = Pick<IMessage, '_id'>;
1 change: 1 addition & 0 deletions packages/core-typings/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export type * from './ICredentialToken';
export type * from './IAvatar';
export type * from './ICustomUserStatus';
export type * from './IEmailMessageHistory';
export type * from './ICustomMessage';

export type * from './IReadReceipt';
export type * from './MessageReads';
Expand Down
44 changes: 0 additions & 44 deletions packages/rest-typings/src/v1/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,42 +703,6 @@ const ChatGetThreadMessagesSchema = {

export const isChatGetThreadMessagesProps = ajv.compile<ChatGetThreadMessages>(ChatGetThreadMessagesSchema);

type ChatGetDeletedMessages = PaginatedRequest<{
roomId: IRoom['_id'];
since: string;
}>;

const ChatGetDeletedMessagesSchema = {
type: 'object',
properties: {
roomId: {
type: 'string',
minLength: 1,
},
since: {
type: 'string',
minLength: 1,
format: 'iso-date-time',
},
count: {
type: 'number',
nullable: true,
},
offset: {
type: 'number',
nullable: true,
},
sort: {
type: 'string',
nullable: true,
},
},
required: ['roomId', 'since'],
additionalProperties: false,
};

export const isChatGetDeletedMessagesProps = ajv.compile<ChatGetDeletedMessages>(ChatGetDeletedMessagesSchema);

type ChatPostMessage =
| {
roomId: string | string[];
Expand Down Expand Up @@ -1005,14 +969,6 @@ export type ChatEndpoints = {
total: number;
};
};
'/v1/chat.getDeletedMessages': {
GET: (params: ChatGetDeletedMessages) => {
messages: IMessage[];
count: number;
offset: number;
total: number;
};
};
'/v1/chat.getURLPreview': {
GET: (params: ChatGetURLPreview) => { urlPreview: MessageUrl };
};
Expand Down