diff --git a/deno-runtime/handlers/listener/handler.ts b/deno-runtime/handlers/listener/handler.ts index b2258860f..1e6de2053 100644 --- a/deno-runtime/handlers/listener/handler.ts +++ b/deno-runtime/handlers/listener/handler.ts @@ -12,6 +12,7 @@ import { RoomBuilder } from '../../lib/accessors/builders/RoomBuilder.ts'; import { AppAccessors, AppAccessorsInstance } from '../../lib/accessors/mod.ts'; import { require } from '../../lib/require.ts'; import createRoom from '../../lib/roomFactory.ts'; +import { Room } from "../../lib/room.ts"; const { AppsEngineException } = require('@rocket.chat/apps-engine/definition/exceptions/AppsEngineException.js') as { AppsEngineException: typeof _AppsEngineException; @@ -46,6 +47,7 @@ export default async function handleListener(evtInterface: string, params: unkno return JsonRpcError.internalError({ message: e.message }); } + } export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMethod: string, params: unknown[]): unknown[] { @@ -62,7 +64,9 @@ export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMetho let context = param1; - if (evtMethod.endsWith('RoomUserJoined') || evtMethod.endsWith('RoomUserLeave')) { + if (evtMethod.includes('Message')) { + context = hydrateMessageObjects(context) as Record; + } else if (evtMethod.endsWith('RoomUserJoined') || evtMethod.endsWith('RoomUserLeave')) { (context as Record).room = createRoom((context as Record).room as IRoom, AppAccessorsInstance.getSenderFn()); } else if (evtMethod.includes('PreRoom')) { context = createRoom(context as IRoom, AppAccessorsInstance.getSenderFn()); @@ -74,7 +78,7 @@ export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMetho if (evtMethod.startsWith('check')) { // "checkPostMessageDeleted" has an extra param - (context, reader, http, extraContext) if (param2) { - args.push(param2); + args.push(hydrateMessageObjects(param2)); } return args; @@ -114,8 +118,33 @@ export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMetho throw JsonRpcError.invalidParams(null); } - args.push(param2); + args.push(hydrateMessageObjects(param2)); } return args; } + +/** + * Hydrate the context object with the correct IMessage + * + * Some information is lost upon serializing the data from listeners through the pipes, + * so here we hydrate the complete object as necessary + */ +function hydrateMessageObjects(context: unknown): unknown { + if (objectIsRawMessage(context)) { + context.room = createRoom(context.room as IRoom, AppAccessorsInstance.getSenderFn()); + } else if ((context as Record)?.message) { + (context as Record).message = hydrateMessageObjects((context as Record).message); + } + + return context; +} + +function objectIsRawMessage(value: unknown): value is IMessage { + if (!value) return false; + + const { id, room, sender, createdAt } = value as Record; + + // Check if we have the fields of a message and the room hasn't already been hydrated + return !!(id && room && sender && createdAt) && !(room instanceof Room); +} diff --git a/deno-runtime/handlers/tests/listener-handler.test.ts b/deno-runtime/handlers/tests/listener-handler.test.ts index 3da9250b1..3e3663b06 100644 --- a/deno-runtime/handlers/tests/listener-handler.test.ts +++ b/deno-runtime/handlers/tests/listener-handler.test.ts @@ -50,7 +50,15 @@ describe('handlers > listeners', () => { it('correctly parses the arguments for a request to trigger the "checkPreRoomCreateExtend" method', () => { const evtMethod = 'checkPreRoomCreateExtend'; // For the 'checkPreRoomCreateExtend' method, the context will be a room in a real scenario - const evtArgs = [{ __type: 'context' }]; + const evtArgs = [ + { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }, + ]; const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); @@ -136,7 +144,15 @@ describe('handlers > listeners', () => { it('correctly parses the arguments for a request to trigger the "executePostRoomUserJoined" method', () => { const evtMethod = 'executePostRoomUserJoined'; // For the 'executePostRoomUserJoined' method, the context will be a room in a real scenario - const evtArgs = [{ __type: 'context', room: { __type: 'room' } }]; + const room = { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }; + + const evtArgs = [{ __type: 'context', room }]; const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); @@ -151,7 +167,15 @@ describe('handlers > listeners', () => { it('correctly parses the arguments for a request to trigger the "executePostRoomUserLeave" method', () => { const evtMethod = 'executePostRoomUserLeave'; // For the 'executePostRoomUserLeave' method, the context will be a room in a real scenario - const evtArgs = [{ __type: 'context', room: { __type: 'room' } }]; + const room = { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }; + + const evtArgs = [{ __type: 'context', room }]; const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); @@ -178,4 +202,33 @@ describe('handlers > listeners', () => { assertEquals(params[4], { __type: 'modifier' }); assertEquals(params[5], { __type: 'extraContext' }); }); + + it('correctly parses the arguments for a request to trigger the "executePostMessageSent" method', () => { + const evtMethod = 'executePostMessageSent'; + // For the 'executePostMessageDeleted' method, the context will be a message in a real scenario + const evtArgs = [ + { + id: 'fake', + sender: 'fake', + createdAt: Date.now(), + room: { + id: 'fake-room', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }, + }, + ]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + assertObjectMatch((params[0] as Record), { id: 'fake' }); + assertInstanceOf((params[0] as any).room, Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + }); });