diff --git a/src/definition/accessors/IRoomRead.ts b/src/definition/accessors/IRoomRead.ts index 4e827507d..53550780d 100644 --- a/src/definition/accessors/IRoomRead.ts +++ b/src/definition/accessors/IRoomRead.ts @@ -1,4 +1,4 @@ -import type { IMessage } from '../messages/index'; +import type { IMessageRaw } from '../messages/index'; import type { IRoom } from '../rooms/index'; import type { IUser } from '../users/index'; @@ -56,7 +56,7 @@ export interface IRoomRead { skip: number; sort: Record; }>, - ): Promise; + ): Promise; /** * Gets an iterator for all of the users in the provided room. diff --git a/src/definition/messages/IMessageRaw.ts b/src/definition/messages/IMessageRaw.ts new file mode 100644 index 000000000..1706b2639 --- /dev/null +++ b/src/definition/messages/IMessageRaw.ts @@ -0,0 +1,40 @@ +import type { IBlock, Block } from '@rocket.chat/ui-kit'; + +import type { IRoom } from '../rooms'; +import type { IUserLookup } from '../users'; +import type { IMessageAttachment } from './IMessageAttachment'; +import type { IMessageFile } from './IMessageFile'; +import type { IMessageReactions } from './IMessageReaction'; + +/** + * The raw version of a message, without resolved information for relationship fields, i.e. + * `room`, `sender` and `editor` are not the complete entity like they are in `IMessage` + * + * This is used in methods that fetch multiple messages at the same time, as resolving the relationship + * fields require additional queries to the database and would hit the system's performance significantly. + */ +export interface IMessageRaw { + id: string; + roomId: IRoom['id']; + sender: IUserLookup; + createdAt: Date; + threadId?: string; + text?: string; + updatedAt?: Date; + editor?: IUserLookup; + editedAt?: Date; + emoji?: string; + avatarUrl?: string; + alias?: string; + file?: IMessageFile; + attachments?: Array; + reactions?: IMessageReactions; + groupable?: boolean; + parseUrls?: boolean; + customFields?: { [key: string]: any }; + blocks?: Array; + starred?: Array<{ _id: string }>; + pinned?: boolean; + pinnedAt?: Date; + pinnedBy?: IUserLookup; +} diff --git a/src/definition/messages/index.ts b/src/definition/messages/index.ts index a46a0310e..1ed02d7b2 100644 --- a/src/definition/messages/index.ts +++ b/src/definition/messages/index.ts @@ -8,6 +8,7 @@ import { IMessageDeleteContext } from './IMessageDeleteContext'; import { IMessageFile } from './IMessageFile'; import { IMessageFollowContext } from './IMessageFollowContext'; import { IMessagePinContext } from './IMessagePinContext'; +import { IMessageRaw } from './IMessageRaw'; import { IMessageReaction, IMessageReactions } from './IMessageReaction'; import { IMessageReactionContext } from './IMessageReactionContext'; import { IMessageReportContext } from './IMessageReportContext'; @@ -39,6 +40,7 @@ export { IMessageAttachmentField, IMessageAction, IMessageFile, + IMessageRaw, IMessageReactions, IMessageReaction, IPostMessageDeleted, diff --git a/src/definition/users/IUserLookup.ts b/src/definition/users/IUserLookup.ts index 271560b86..9b5f09b04 100644 --- a/src/definition/users/IUserLookup.ts +++ b/src/definition/users/IUserLookup.ts @@ -1,4 +1,5 @@ export interface IUserLookup { _id: string; username: string; + name?: string; } diff --git a/src/server/accessors/RoomRead.ts b/src/server/accessors/RoomRead.ts index d79a64028..efbc63bc5 100644 --- a/src/server/accessors/RoomRead.ts +++ b/src/server/accessors/RoomRead.ts @@ -1,5 +1,5 @@ import type { IRoomRead } from '../../definition/accessors'; -import type { IMessage } from '../../definition/messages'; +import type { IMessageRaw } from '../../definition/messages'; import type { IRoom } from '../../definition/rooms'; import type { IUser } from '../../definition/users'; import type { RoomBridge } from '../bridges'; @@ -30,7 +30,7 @@ export class RoomRead implements IRoomRead { skip: number; sort: Record; }>, - ): Promise { + ): Promise { return this.roomBridge.doGetMessages(roomId, { limit: 100, ...options }, this.appId); } diff --git a/src/server/bridges/RoomBridge.ts b/src/server/bridges/RoomBridge.ts index a1ec60952..ced6b3b6e 100644 --- a/src/server/bridges/RoomBridge.ts +++ b/src/server/bridges/RoomBridge.ts @@ -1,4 +1,4 @@ -import type { IMessage } from '../../definition/messages'; +import type { IMessage, IMessageRaw } from '../../definition/messages'; import type { IRoom } from '../../definition/rooms'; import type { IUser } from '../../definition/users'; import { PermissionDeniedError } from '../errors/PermissionDeniedError'; @@ -99,7 +99,7 @@ export abstract class RoomBridge extends BaseBridge { sort?: Record; }, appId: string, - ): Promise { + ): Promise { if (this.hasReadPermission(appId)) { return this.getMessages(roomId, options, appId); } @@ -145,7 +145,7 @@ export abstract class RoomBridge extends BaseBridge { sort?: Record; }, appId: string, - ): Promise; + ): Promise; private hasWritePermission(appId: string): boolean { if (AppPermissionManager.hasPermission(appId, AppPermissions.room.write)) { diff --git a/tests/server/accessors/RoomRead.spec.ts b/tests/server/accessors/RoomRead.spec.ts index f99eae19e..af1b22b82 100644 --- a/tests/server/accessors/RoomRead.spec.ts +++ b/tests/server/accessors/RoomRead.spec.ts @@ -5,14 +5,14 @@ import type { IUser } from '../../../src/definition/users'; import { RoomRead } from '../../../src/server/accessors'; import type { RoomBridge } from '../../../src/server/bridges'; import { TestData } from '../../test-data/utilities'; -import type { IMessage } from '../../../src/definition/messages'; +import type { IMessageRaw } from '../../../src/definition/messages'; export class RoomReadAccessorTestFixture { private room: IRoom; private user: IUser; - private messages: IMessage[]; + private messages: IMessageRaw[]; private mockRoomBridgeWithRoom: RoomBridge; @@ -20,7 +20,7 @@ export class RoomReadAccessorTestFixture { public setupFixture() { this.room = TestData.getRoom(); this.user = TestData.getUser(); - this.messages = ['507f1f77bcf86cd799439011', '507f191e810c19729de860ea'].map((id) => TestData.getMessage(id)); + this.messages = ['507f1f77bcf86cd799439011', '507f191e810c19729de860ea'].map((id) => TestData.getMessageRaw(id)); const theRoom = this.room; const theUser = this.user; @@ -44,7 +44,7 @@ export class RoomReadAccessorTestFixture { doGetMembers(name, appId): Promise> { return Promise.resolve([theUser]); }, - doGetMessages(roomId, appId, options): Promise { + doGetMessages(roomId, appId, options): Promise { return Promise.resolve(theMessages); }, } as RoomBridge; diff --git a/tests/test-data/bridges/roomBridge.ts b/tests/test-data/bridges/roomBridge.ts index 92a596f8e..600a3c5c6 100644 --- a/tests/test-data/bridges/roomBridge.ts +++ b/tests/test-data/bridges/roomBridge.ts @@ -1,4 +1,4 @@ -import type { IMessage } from '../../../src/definition/messages'; +import type { IMessage, IMessageRaw } from '../../../src/definition/messages'; import type { IRoom } from '../../../src/definition/rooms'; import type { IUser } from '../../../src/definition/users'; import { RoomBridge } from '../../../src/server/bridges'; @@ -32,7 +32,7 @@ export class TestsRoomBridge extends RoomBridge { throw new Error('Method not implemented.'); } - public getMessages(roomId: string, options: { limit: number; skip?: number; sort?: Record }, appId: string): Promise { + public getMessages(roomId: string, options: { limit: number; skip?: number; sort?: Record }, appId: string): Promise { throw new Error('Method not implemented.'); } diff --git a/tests/test-data/utilities.ts b/tests/test-data/utilities.ts index 5f3e714a0..3e75bf04e 100644 --- a/tests/test-data/utilities.ts +++ b/tests/test-data/utilities.ts @@ -1,6 +1,6 @@ import type { IHttp, IModify, IPersistence, IRead } from '../../src/definition/accessors'; import { HttpStatusCode } from '../../src/definition/accessors'; -import type { IMessage } from '../../src/definition/messages'; +import type { IMessage, IMessageAttachment, IMessageRaw } from '../../src/definition/messages'; import type { IRoom } from '../../src/definition/rooms'; import { RoomType } from '../../src/definition/rooms'; import type { ISetting } from '../../src/definition/settings'; @@ -61,6 +61,39 @@ export class TestInfastructureSetup { } const date = new Date(); + +const DEFAULT_ATTACHMENT = { + color: '#00b2b2', + collapsed: false, + text: 'Just an attachment that is used for testing', + timestampLink: 'https://google.com/', + thumbnailUrl: 'https://avatars0.githubusercontent.com/u/850391?s=88&v=4', + author: { + name: 'Author Name', + link: 'https://github.com/graywolf336', + icon: 'https://avatars0.githubusercontent.com/u/850391?s=88&v=4', + }, + title: { + value: 'Attachment Title', + link: 'https://github.com/RocketChat', + displayDownloadLink: false, + }, + imageUrl: 'https://rocket.chat/images/default/logo.svg', + audioUrl: 'http://www.w3schools.com/tags/horse.mp3', + videoUrl: 'http://www.w3schools.com/tags/movie.mp4', + fields: [ + { + short: true, + title: 'Test', + value: 'Testing out something or other', + }, + { + short: true, + title: 'Another Test', + value: '[Link](https://google.com/) something and this and that.', + }, + ], +}; export class TestData { public static getDate(): Date { return date; @@ -126,41 +159,42 @@ export class TestData { emoji: ':see_no_evil:', avatarUrl: 'https://avatars0.githubusercontent.com/u/850391?s=88&v=4', alias: 'Testing Bot', - attachments: [ - { - collapsed: false, - color: '#00b2b2', - text: 'Just an attachment that is used for testing', - timestamp: new Date(), - timestampLink: 'https://google.com/', - thumbnailUrl: 'https://avatars0.githubusercontent.com/u/850391?s=88&v=4', - author: { - name: 'Author Name', - link: 'https://github.com/graywolf336', - icon: 'https://avatars0.githubusercontent.com/u/850391?s=88&v=4', - }, - title: { - value: 'Attachment Title', - link: 'https://github.com/RocketChat', - displayDownloadLink: false, - }, - imageUrl: 'https://rocket.chat/images/default/logo.svg', - audioUrl: 'http://www.w3schools.com/tags/horse.mp3', - videoUrl: 'http://www.w3schools.com/tags/movie.mp4', - fields: [ - { - short: true, - title: 'Test', - value: 'Testing out something or other', - }, - { - short: true, - title: 'Another Test', - value: '[Link](https://google.com/) something and this and that.', - }, - ], - }, - ], + attachments: [this.createAttachment()], + }; + } + + public static getMessageRaw(id?: string, text?: string): IMessageRaw { + const editorUser = TestData.getUser(); + const senderUser = TestData.getUser(); + + return { + id: id || '4bShvoOXqB', + roomId: TestData.getRoom().id, + sender: { + _id: senderUser.id, + username: senderUser.username, + name: senderUser?.name, + }, + text: text || 'This is just a test, do not be alarmed', + createdAt: date, + updatedAt: new Date(), + editor: { + _id: editorUser.id, + username: editorUser.username, + }, + editedAt: new Date(), + emoji: ':see_no_evil:', + avatarUrl: 'https://avatars0.githubusercontent.com/u/850391?s=88&v=4', + alias: 'Testing Bot', + attachments: [this.createAttachment()], + }; + } + + private static createAttachment(attachment?: IMessageAttachment): IMessageAttachment { + attachment = attachment || DEFAULT_ATTACHMENT; + return { + timestamp: new Date(), + ...attachment, }; }