diff --git a/src/lifecycles/WidgetLifecycle.ts b/src/lifecycles/WidgetLifecycle.ts new file mode 100644 index 0000000..b1e0647 --- /dev/null +++ b/src/lifecycles/WidgetLifecycle.ts @@ -0,0 +1,84 @@ +/* +Copyright 2023 Mikhail Aheichyk +Copyright 2023 Nordeck IT + Consulting GmbH. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export enum WidgetLifecycle { + CapabilitiesRequest = "capabilities_request", + PreLoadRequest = "preload_request", + IdentityRequest = "identity_request", +} + +export type CapabilitiesOpts = { + approvedCapabilities: Set | undefined; +}; + +export type ApprovalOpts = { + approved: boolean | undefined; +}; + +export type CapabilitiesListener = ( + capabilitiesOpts: CapabilitiesOpts, + widgetInfo: WidgetInfo, + requestedCapabilities: Set, +) => void; + +/** + * Listener for PreLoad and Identity requests + */ +export type ApprovalListener = ( + approvalOpts: ApprovalOpts, + widgetInfo: WidgetInfo +) => void; + +/** + * Represents the widget + */ +export interface WidgetInfo { + /** + * The user ID who created the widget. + */ + creatorUserId: string; + + /** + * The type of widget. + */ + type: string; + + /** + * The ID of the widget. + */ + id: string; + + /** + * The name of the widget, or null if not set. + */ + name: string | null; + + /** + * The title for the widget, or null if not set. + */ + title: string | null; + + /** + * The templated URL for the widget. + */ + templateUrl: string; + + /** + * The origin for this widget. + */ + origin: string; +} diff --git a/src/lifecycles/types.ts b/src/lifecycles/types.ts index 3f0a98e..72c3a34 100644 --- a/src/lifecycles/types.ts +++ b/src/lifecycles/types.ts @@ -15,7 +15,9 @@ limitations under the License. */ import { RoomViewLifecycle } from "./RoomViewLifecycle"; +import { WidgetLifecycle } from "./WidgetLifecycle"; export type AnyLifecycle = | RoomViewLifecycle + | WidgetLifecycle ; diff --git a/test/lifecycles/WidgetLifecycle.test.ts b/test/lifecycles/WidgetLifecycle.test.ts new file mode 100644 index 0000000..439458c --- /dev/null +++ b/test/lifecycles/WidgetLifecycle.test.ts @@ -0,0 +1,80 @@ +/* +Copyright 2023 Mikhail Aheichyk +Copyright 2023 Nordeck IT + Consulting GmbH. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { + ApprovalListener, ApprovalOpts, + CapabilitiesListener, + CapabilitiesOpts, + WidgetInfo, WidgetLifecycle, +} from "../../src/lifecycles/WidgetLifecycle"; +import { RuntimeModule } from "../../src/RuntimeModule"; + +describe("WidgetLifecycle", () => { + const mockWidget: WidgetInfo = { + creatorUserId: "@user-id", + type: "m.custom", + id: "widget-id", + name: null, + title: null, + templateUrl: "https://example.com/some_path", + origin: "https://example.com", + }; + + let module: RuntimeModule; + + beforeAll(() => { + module = new class extends RuntimeModule { + constructor() { + super(undefined); + + this.on(WidgetLifecycle.CapabilitiesRequest, this.capabilitiesListener); + this.on(WidgetLifecycle.PreLoadRequest, this.preloadListener); + this.on(WidgetLifecycle.IdentityRequest, this.identityListener); + } + + protected capabilitiesListener: CapabilitiesListener = ( + capabilitiesOpts: CapabilitiesOpts, + widgetInfo: WidgetInfo, + requestedCapabilities: Set, + ) => { + capabilitiesOpts.approvedCapabilities = requestedCapabilities; + }; + + protected preloadListener: ApprovalListener = (approvalOpts: ApprovalOpts, widgetInfo: WidgetInfo) => { + approvalOpts.approved = true; + }; + + protected identityListener: ApprovalListener = (approvalOpts: ApprovalOpts, widgetInfo: WidgetInfo) => { + approvalOpts.approved = false; + }; + }; + }); + + it('should handle widget permissions requests', () => { + const capabilitiesOpts: CapabilitiesOpts = {approvedCapabilities: new Set()}; + module.emit(WidgetLifecycle.CapabilitiesRequest, capabilitiesOpts, mockWidget, new Set(["org.matrix.msc2931.navigate"])); + expect(capabilitiesOpts.approvedCapabilities).toEqual(new Set(["org.matrix.msc2931.navigate"])); + + const preloadOpts: ApprovalOpts = {approved: undefined}; + module.emit(WidgetLifecycle.PreLoadRequest, preloadOpts, mockWidget); + expect(preloadOpts.approved).toBe(true); + + const identityOpts: ApprovalOpts = {approved: undefined}; + module.emit(WidgetLifecycle.IdentityRequest, identityOpts, mockWidget); + expect(identityOpts.approved).toBe(false); + }); +});