-
Notifications
You must be signed in to change notification settings - Fork 13.5k
refactor(chat): migrate chat.syncMessages to typed REST endpoint #39682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7a4f496
66cedf7
d46be85
62f683d
917c41f
f438aeb
de5bc73
2696bd2
113d96f
356eb82
52a987c
00a59eb
2662b80
0deb0cb
b9b111f
2694b01
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@rocket.chat/rest-typings': minor | ||
| '@rocket.chat/meteor': minor | ||
| --- | ||
|
|
||
| Migrated chat.syncMessages exisiting REST APIs to the new typed REST(openApi) structure. |
| 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, IThreadMainMessage, IRoom } from '@rocket.chat/core-typings'; | ||||||||||||||||||||||||||||||
| import { MessageTypes } from '@rocket.chat/message-types'; | ||||||||||||||||||||||||||||||
| import { Messages, Users, Rooms, Subscriptions } from '@rocket.chat/models'; | ||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||
|
|
@@ -9,7 +9,6 @@ import { | |||||||||||||||||||||||||||||
| isChatUpdateProps, | ||||||||||||||||||||||||||||||
| isChatGetThreadsListProps, | ||||||||||||||||||||||||||||||
| isChatDeleteProps, | ||||||||||||||||||||||||||||||
| isChatSyncMessagesProps, | ||||||||||||||||||||||||||||||
| isChatGetMessageProps, | ||||||||||||||||||||||||||||||
| isChatPostMessageProps, | ||||||||||||||||||||||||||||||
| isChatSearchProps, | ||||||||||||||||||||||||||||||
|
|
@@ -168,50 +167,6 @@ API.v1.addRoute( | |||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| API.v1.addRoute( | ||||||||||||||||||||||||||||||
| 'chat.syncMessages', | ||||||||||||||||||||||||||||||
| { authRequired: true, validateParams: isChatSyncMessagesProps }, | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| async get() { | ||||||||||||||||||||||||||||||
| const { roomId, lastUpdate, count, next, previous, type } = this.queryParams; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!roomId) { | ||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-param-required', 'The required "roomId" query param is missing'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!lastUpdate && !type) { | ||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-param-required', 'The "type" or "lastUpdate" parameters must be provided'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (lastUpdate && isNaN(Date.parse(lastUpdate))) { | ||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-lastUpdate-param-invalid', 'The "lastUpdate" query parameter must be a valid date'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const getMessagesQuery = { | ||||||||||||||||||||||||||||||
| ...(lastUpdate && { lastUpdate: new Date(lastUpdate) }), | ||||||||||||||||||||||||||||||
| ...(next && { next }), | ||||||||||||||||||||||||||||||
| ...(previous && { previous }), | ||||||||||||||||||||||||||||||
| ...(count && { count }), | ||||||||||||||||||||||||||||||
| ...(type && { type }), | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const result = await getMessageHistory(roomId, this.userId, getMessagesQuery); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!result) { | ||||||||||||||||||||||||||||||
| return API.v1.failure(); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return API.v1.success({ | ||||||||||||||||||||||||||||||
| result: { | ||||||||||||||||||||||||||||||
| updated: 'updated' in result ? await normalizeMessagesForUser(result.updated, this.userId) : [], | ||||||||||||||||||||||||||||||
| deleted: 'deleted' in result ? result.deleted : [], | ||||||||||||||||||||||||||||||
| cursor: 'cursor' in result ? result.cursor : undefined, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| API.v1.addRoute( | ||||||||||||||||||||||||||||||
| 'chat.getMessage', | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
|
|
@@ -275,6 +230,99 @@ const isChatPinMessageProps = ajv.compile<ChatPinMessage>(ChatPinMessageSchema); | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const isChatUnpinMessageProps = ajv.compile<ChatUnpinMessage>(ChatUnpinMessageSchema); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| type ChatSyncMessages = { | ||||||||||||||||||||||||||||||
| roomId: IRoom['_id']; | ||||||||||||||||||||||||||||||
| lastUpdate?: string; | ||||||||||||||||||||||||||||||
| count?: number; | ||||||||||||||||||||||||||||||
| next?: string; | ||||||||||||||||||||||||||||||
| previous?: string; | ||||||||||||||||||||||||||||||
| type?: 'UPDATED' | 'DELETED'; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const ChatSyncMessagesSchema = { | ||||||||||||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||||||||||||
| properties: { | ||||||||||||||||||||||||||||||
| roomId: { | ||||||||||||||||||||||||||||||
| type: 'string', | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| lastUpdate: { | ||||||||||||||||||||||||||||||
| type: 'string', | ||||||||||||||||||||||||||||||
| nullable: true, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| count: { | ||||||||||||||||||||||||||||||
| type: 'number', | ||||||||||||||||||||||||||||||
| nullable: true, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| next: { | ||||||||||||||||||||||||||||||
| type: 'string', | ||||||||||||||||||||||||||||||
| nullable: true, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| previous: { | ||||||||||||||||||||||||||||||
| type: 'string', | ||||||||||||||||||||||||||||||
| nullable: true, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| type: { | ||||||||||||||||||||||||||||||
| type: 'string', | ||||||||||||||||||||||||||||||
| enum: ['UPDATED', 'DELETED'], | ||||||||||||||||||||||||||||||
| nullable: true, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| required: ['roomId'], | ||||||||||||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const isChatSyncMessagesLocalProps = ajv.compile<ChatSyncMessages>(ChatSyncMessagesSchema); | ||||||||||||||||||||||||||||||
cubic-dev-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
Harxhit marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const isSyncMessagesResponse = ajv.compile<{ | ||||||||||||||||||||||||||||||
| result: { | ||||||||||||||||||||||||||||||
| updated: IMessage[]; | ||||||||||||||||||||||||||||||
| deleted: IMessage[]; | ||||||||||||||||||||||||||||||
| cursor?: { | ||||||||||||||||||||||||||||||
| next: string | null; | ||||||||||||||||||||||||||||||
| previous: string | null; | ||||||||||||||||||||||||||||||
| } | null; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
| }>({ | ||||||||||||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||||||||||||
| properties: { | ||||||||||||||||||||||||||||||
| result: { | ||||||||||||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||||||||||||
| properties: { | ||||||||||||||||||||||||||||||
| updated: { | ||||||||||||||||||||||||||||||
| type: 'array', | ||||||||||||||||||||||||||||||
| items: { $ref: '#/components/schemas/IMessage' }, | ||||||||||||||||||||||||||||||
cubic-dev-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| deleted: { | ||||||||||||||||||||||||||||||
Harxhit marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
| type: 'array', | ||||||||||||||||||||||||||||||
| items: { $ref: '#/components/schemas/IMessage' }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| cursor: { | ||||||||||||||||||||||||||||||
| oneOf: [ | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| type: 'object', | ||||||||||||||||||||||||||||||
| properties: { | ||||||||||||||||||||||||||||||
| next: { type: 'string', nullable: true }, | ||||||||||||||||||||||||||||||
| previous: { type: 'string', nullable: true }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| required: ['next', 'previous'], | ||||||||||||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| { type: 'null' }, | ||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| required: ['updated', 'deleted'], | ||||||||||||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| success: { | ||||||||||||||||||||||||||||||
| type: 'boolean', | ||||||||||||||||||||||||||||||
| enum: [true], | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| required: ['result', 'success'], | ||||||||||||||||||||||||||||||
| additionalProperties: false, | ||||||||||||||||||||||||||||||
| });; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const chatEndpoints = API.v1 | ||||||||||||||||||||||||||||||
| .post( | ||||||||||||||||||||||||||||||
| 'chat.pinMessage', | ||||||||||||||||||||||||||||||
|
|
@@ -558,6 +606,55 @@ const chatEndpoints = API.v1 | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return API.v1.success(); | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| .get( | ||||||||||||||||||||||||||||||
| 'chat.syncMessages', | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| authRequired: true, | ||||||||||||||||||||||||||||||
| query: isChatSyncMessagesLocalProps, | ||||||||||||||||||||||||||||||
| response: { | ||||||||||||||||||||||||||||||
| 400: validateBadRequestErrorResponse, | ||||||||||||||||||||||||||||||
| 401: validateUnauthorizedErrorResponse, | ||||||||||||||||||||||||||||||
| 200: isSyncMessagesResponse, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| async function action() { | ||||||||||||||||||||||||||||||
| const { roomId, lastUpdate, count, next, previous, type } = this.queryParams; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!roomId) { | ||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-param-required', 'The required "roomId" query param is missing'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!lastUpdate && !type) { | ||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-param-required', 'The "type" or "lastUpdate" parameters must be provided'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (lastUpdate && isNaN(Date.parse(lastUpdate))) { | ||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-lastUpdate-param-invalid', 'The "lastUpdate" query parameter must be a valid date'); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const getMessagesQuery = { | ||||||||||||||||||||||||||||||
| ...(lastUpdate && { lastUpdate: new Date(lastUpdate) }), | ||||||||||||||||||||||||||||||
| ...(next && { next }), | ||||||||||||||||||||||||||||||
| ...(previous && { previous }), | ||||||||||||||||||||||||||||||
| ...(count && { count }), | ||||||||||||||||||||||||||||||
| ...(type && { type }), | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
Comment on lines
+636
to
+642
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserve explicit Line 633 uses a truthy check, so Suggested fix const getMessagesQuery = {
...(lastUpdate && { lastUpdate: new Date(lastUpdate) }),
...(next && { next }),
...(previous && { previous }),
- ...(count && { count }),
+ ...(typeof count === 'number' && { count }),
...(type && { type }),
};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the suggestion. As per maintainer guidance, I’m preserving the current behavior for now. If needed, I can update this to explicitly handle
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🧠 Learnings used |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const result = await getMessageHistory(roomId, this.userId, getMessagesQuery); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!result) { | ||||||||||||||||||||||||||||||
| return API.v1.failure(); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return API.v1.success({ | ||||||||||||||||||||||||||||||
| result: { | ||||||||||||||||||||||||||||||
| updated: 'updated' in result ? await normalizeMessagesForUser(result.updated, this.userId) : [], | ||||||||||||||||||||||||||||||
| deleted: 'deleted' in result ? result.deleted : [], | ||||||||||||||||||||||||||||||
cubic-dev-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
| cursor: 'cursor' in result ? result.cursor : undefined, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| API.v1.addRoute( | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.