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
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 = ajvQuery.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 = ajvQuery.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