diff --git a/.changeset/stupid-rats-work.md b/.changeset/stupid-rats-work.md new file mode 100644 index 0000000000000..a1b5b2e6586f8 --- /dev/null +++ b/.changeset/stupid-rats-work.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/apps-engine': minor +'@rocket.chat/meteor': minor +--- + +Adds a filter option to include or exclude threads in the Apps Engine room read/unread messages bridge, enhancing flexibility in message retrieval. diff --git a/apps/meteor/app/apps/server/bridges/rooms.ts b/apps/meteor/app/apps/server/bridges/rooms.ts index 4743d72457d86..d88881330a17d 100644 --- a/apps/meteor/app/apps/server/bridges/rooms.ts +++ b/apps/meteor/app/apps/server/bridges/rooms.ts @@ -108,13 +108,15 @@ export class AppRoomBridge extends RoomBridge { protected async getMessages(roomId: string, options: GetMessagesOptions, appId: string): Promise { this.orch.debugLog(`The App ${appId} is getting the messages of the room: "${roomId}" with options:`, options); - const { limit, skip = 0, sort: _sort } = options; + const { limit, skip = 0, sort: _sort, showThreadMessages } = options; const messageConverter = this.orch.getConverters()?.get('messages'); if (!messageConverter) { throw new Error('Message converter not found'); } + const threadFilterQuery = showThreadMessages ? {} : { tmid: { $exists: false } }; + // We support only one field for now const sort: Sort | undefined = _sort?.createdAt ? { ts: _sort.createdAt } : undefined; @@ -128,6 +130,7 @@ export class AppRoomBridge extends RoomBridge { rid: roomId, _hidden: { $ne: true }, t: { $exists: false }, + ...threadFilterQuery, }; const cursor = Messages.find(query, messageQueryOptions); @@ -268,10 +271,18 @@ export class AppRoomBridge extends RoomBridge { const sort: Sort = options.sort?.createdAt ? { ts: options.sort.createdAt } : { ts: 1 }; - const cursor = Messages.findVisibleByRoomIdBetweenTimestampsNotContainingTypes(roomId, lastSeen, new Date(), [], { - ...options, - sort, - }); + const cursor = Messages.findVisibleByRoomIdBetweenTimestampsNotContainingTypes( + roomId, + lastSeen, + new Date(), + [], + { + limit: options.limit, + skip: options.skip, + sort, + }, + options.showThreadMessages, + ); const messages = await cursor.toArray(); return Promise.all(messages.map((msg) => messageConverter.convertMessageRaw(msg))); diff --git a/apps/meteor/app/apps/server/converters/messages.js b/apps/meteor/app/apps/server/converters/messages.js index 89ef2454d8956..704dde1850490 100644 --- a/apps/meteor/app/apps/server/converters/messages.js +++ b/apps/meteor/app/apps/server/converters/messages.js @@ -47,6 +47,7 @@ export class AppMessagesConverter { editor: 'editedBy', attachments: getAttachments, sender: 'u', + threadMsgCount: 'tcount', }; return transformMappedData(message, map); diff --git a/packages/apps-engine/src/definition/accessors/IRoomRead.ts b/packages/apps-engine/src/definition/accessors/IRoomRead.ts index dd7fa1b2a6846..8a21c27156b3a 100644 --- a/packages/apps-engine/src/definition/accessors/IRoomRead.ts +++ b/packages/apps-engine/src/definition/accessors/IRoomRead.ts @@ -48,6 +48,7 @@ export interface IRoomRead { * - limit: The maximum number of messages to retrieve. Maximum 100 * - skip: The number of messages to skip (for pagination). * - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either "asc" for ascending order or "desc" for descending order. + * - showThreadMessages: Whether to include thread messages in the results. Defaults to true. * @returns A Promise that resolves to an array of IMessage objects representing the messages in the room. */ getMessages(roomId: string, options?: Partial): Promise>; @@ -100,6 +101,7 @@ export interface IRoomRead { * - limit: The maximum number of messages to retrieve. If more than 100 is passed, it defaults to 100. * - skip: The number of messages to skip (for pagination). * - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either 'asc' for ascending order or 'desc' for descending order. + * - showThreadMessages: Whether to include thread messages in the results. Defaults to true. * @returns A Promise that resolves to an array of IMessage objects representing the unread messages for the specified user in the specified room. */ getUnreadByUser(roomId: string, uid: string, options?: Partial): Promise; diff --git a/packages/apps-engine/src/server/accessors/RoomRead.ts b/packages/apps-engine/src/server/accessors/RoomRead.ts index 7577daa9e8512..efe84eedbbd84 100644 --- a/packages/apps-engine/src/server/accessors/RoomRead.ts +++ b/packages/apps-engine/src/server/accessors/RoomRead.ts @@ -33,6 +33,7 @@ export class RoomRead implements IRoomRead { } options.limit ??= 100; + options.showThreadMessages ??= true; if (options.sort) { this.validateSort(options.sort); @@ -62,7 +63,7 @@ export class RoomRead implements IRoomRead { } public async getUnreadByUser(roomId: string, uid: string, options: Partial = {}): Promise { - const { limit = 100, sort = { createdAt: 'asc' }, skip = 0 } = options; + const { limit = 100, sort = { createdAt: 'asc' }, skip = 0, showThreadMessages = true } = options; if (typeof roomId !== 'string' || roomId.trim().length === 0) { throw new Error('Invalid roomId: must be a non-empty string'); @@ -74,7 +75,7 @@ export class RoomRead implements IRoomRead { this.validateSort(sort); - const completeOptions: GetMessagesOptions = { limit, sort, skip }; + const completeOptions: GetMessagesOptions = { limit, sort, skip, showThreadMessages }; return this.roomBridge.doGetUnreadByUser(roomId, uid, completeOptions, this.appId); } diff --git a/packages/apps-engine/src/server/bridges/RoomBridge.ts b/packages/apps-engine/src/server/bridges/RoomBridge.ts index 155c85ba4689a..814c943c94b1f 100644 --- a/packages/apps-engine/src/server/bridges/RoomBridge.ts +++ b/packages/apps-engine/src/server/bridges/RoomBridge.ts @@ -12,6 +12,7 @@ export type GetMessagesOptions = { limit: number; skip: number; sort: Record<(typeof GetMessagesSortableFields)[number], 'asc' | 'desc'>; + showThreadMessages: boolean; }; export abstract class RoomBridge extends BaseBridge {