From 0c22b15bbad4007e804cb687d792165f3ddfa3cd Mon Sep 17 00:00:00 2001 From: Dominik Henneke Date: Wed, 14 Sep 2022 16:18:51 +0200 Subject: [PATCH] Implement MSC3869: Read event relations with the Widget API (#9210) * Add an action to read relations according to MSC3869 Signed-off-by: Dominik Henneke * Apply review comments Signed-off-by: Dominik Henneke * Fix test Signed-off-by: Dominik Henneke * Update matrix-widget-api to 1.1.1 Signed-off-by: Dominik Henneke Signed-off-by: Dominik Henneke --- package.json | 2 +- src/stores/widgets/StopGapWidgetDriver.ts | 45 ++++++++ .../widgets/StopGapWidgetDriver-test.ts | 100 +++++++++++++++++- yarn.lock | 8 +- 4 files changed, 148 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 082ffb66ea..d3e6fde6b9 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "^0.0.1-beta.7", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", - "matrix-widget-api": "^1.0.0", + "matrix-widget-api": "^1.1.1", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", "pako": "^2.0.3", diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index 8fe18dbc8c..9fbf5e4c56 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -21,6 +21,7 @@ import { IOpenIDUpdate, ISendEventDetails, ITurnServer, + IReadEventRelationsResult, IRoomEvent, MatrixCapabilities, OpenIDRequestState, @@ -37,6 +38,7 @@ import { IContent, IEvent, MatrixEvent } from "matrix-js-sdk/src/models/event"; import { Room } from "matrix-js-sdk/src/models/room"; import { logger } from "matrix-js-sdk/src/logger"; import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread"; +import { Direction } from "matrix-js-sdk/src/matrix"; import { iterableDiff, iterableIntersection } from "../../utils/iterables"; import { MatrixClientPeg } from "../../MatrixClientPeg"; @@ -366,4 +368,47 @@ export class StopGapWidgetDriver extends WidgetDriver { client.off(ClientEvent.TurnServersError, onTurnServersError); } } + + public async readEventRelations( + eventId: string, + roomId?: string, + relationType?: string, + eventType?: string, + from?: string, + to?: string, + limit?: number, + direction?: 'f' | 'b', + ): Promise { + const client = MatrixClientPeg.get(); + const dir = direction as Direction; + roomId = roomId ?? RoomViewStore.instance.getRoomId() ?? undefined; + + if (typeof roomId !== "string") { + throw new Error('Error while reading the current room'); + } + + const { + originalEvent, + events, + nextBatch, + prevBatch, + } = await client.relations( + roomId, + eventId, + relationType ?? null, + eventType ?? null, + { + from, + to, + limit, + direction: dir, + }); + + return { + originalEvent: originalEvent?.getEffectiveEvent(), + chunk: events.map(e => e.getEffectiveEvent()), + nextBatch, + prevBatch, + }; + } } diff --git a/test/stores/widgets/StopGapWidgetDriver-test.ts b/test/stores/widgets/StopGapWidgetDriver-test.ts index 7904629428..dccd203850 100644 --- a/test/stores/widgets/StopGapWidgetDriver-test.ts +++ b/test/stores/widgets/StopGapWidgetDriver-test.ts @@ -15,11 +15,13 @@ limitations under the License. */ import { mocked, MockedObject } from "jest-mock"; -import { Widget, WidgetKind, WidgetDriver, ITurnServer } from "matrix-widget-api"; -import { MatrixClient, ClientEvent, ITurnServer as IClientTurnServer } from "matrix-js-sdk/src/client"; +import { ClientEvent, ITurnServer as IClientTurnServer, MatrixClient } from "matrix-js-sdk/src/client"; import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo"; +import { Direction, MatrixEvent } from "matrix-js-sdk/src/matrix"; +import { ITurnServer, Widget, WidgetDriver, WidgetKind } from "matrix-widget-api"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; +import { RoomViewStore } from "../../../src/stores/RoomViewStore"; import { StopGapWidgetDriver } from "../../../src/stores/widgets/StopGapWidgetDriver"; import { stubClient } from "../../test-utils"; @@ -131,4 +133,98 @@ describe("StopGapWidgetDriver", () => { await servers.return(undefined); }); }); + + describe("readEventRelations", () => { + it('reads related events from the current room', async () => { + jest.spyOn(RoomViewStore.instance, 'getRoomId').mockReturnValue('!this-room-id'); + + client.relations.mockResolvedValue({ + originalEvent: new MatrixEvent(), + events: [], + }); + + await expect(driver.readEventRelations('$event')).resolves.toEqual({ + originalEvent: expect.objectContaining({ content: {} }), + chunk: [], + nextBatch: undefined, + prevBatch: undefined, + }); + + expect(client.relations).toBeCalledWith('!this-room-id', '$event', null, null, {}); + }); + + it('reads related events if the original event is missing', async () => { + client.relations.mockResolvedValue({ + // the relations function can return an undefined event, even + // though the typings don't permit an undefined value. + originalEvent: undefined as any, + events: [], + }); + + await expect(driver.readEventRelations('$event', '!room-id')).resolves.toEqual({ + originalEvent: undefined, + chunk: [], + nextBatch: undefined, + prevBatch: undefined, + }); + + expect(client.relations).toBeCalledWith('!room-id', '$event', null, null, {}); + }); + + it('reads related events from a selected room', async () => { + client.relations.mockResolvedValue({ + originalEvent: new MatrixEvent(), + events: [new MatrixEvent(), new MatrixEvent()], + nextBatch: 'next-batch-token', + }); + + await expect(driver.readEventRelations('$event', '!room-id')).resolves.toEqual({ + originalEvent: expect.objectContaining({ content: {} }), + chunk: [ + expect.objectContaining({ content: {} }), + expect.objectContaining({ content: {} }), + ], + nextBatch: 'next-batch-token', + prevBatch: undefined, + }); + + expect(client.relations).toBeCalledWith('!room-id', '$event', null, null, {}); + }); + + it('reads related events with custom parameters', async () => { + client.relations.mockResolvedValue({ + originalEvent: new MatrixEvent(), + events: [], + }); + + await expect(driver.readEventRelations( + '$event', + '!room-id', + 'm.reference', + 'm.room.message', + 'from-token', + 'to-token', + 25, + 'f', + )).resolves.toEqual({ + originalEvent: expect.objectContaining({ content: {} }), + chunk: [], + nextBatch: undefined, + prevBatch: undefined, + }); + + expect(client.relations).toBeCalledWith( + '!room-id', + '$event', + 'm.reference', + 'm.room.message', + { + limit: 25, + from: 'from-token', + to: 'to-token', + direction: Direction.Forward, + }, + ); + }); + }); }); diff --git a/yarn.lock b/yarn.lock index aae0dc19f3..b05ebda552 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6815,10 +6815,10 @@ matrix-web-i18n@^1.3.0: "@babel/traverse" "^7.18.5" walk "^2.3.15" -matrix-widget-api@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.0.0.tgz#0cde6839cca66ad817ab12aca3490ccc8bac97d1" - integrity sha512-cy8p/8EteRPTFIAw7Q9EgPUJc2jD19ZahMR8bMKf2NkILDcjuPMC0UWnsJyB3fSnlGw+VbGepttRpULM31zX8Q== +matrix-widget-api@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.1.1.tgz#d3fec45033d0cbc14387a38ba92dac4dbb1be962" + integrity sha512-gNSgmgSwvOsOcWK9k2+tOhEMYBiIMwX95vMZu0JqY7apkM02xrOzUBuPRProzN8CnbIALH7e3GAhatF6QCNvtA== dependencies: "@types/events" "^3.0.0" events "^3.2.0"