mirror of
https://github.com/element-hq/element-web
synced 2024-11-26 03:05:51 +03:00
Store refactor: convert WidgetPermissionStore (#9458)
* Store refactor: convert WidgetPermissionStore Add Jest tests as well. * More tests * Review comments
This commit is contained in:
parent
7d0af1dca4
commit
17c3fb89c1
6 changed files with 129 additions and 17 deletions
|
@ -21,10 +21,11 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
|
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
|
||||||
import { OIDCState, WidgetPermissionStore } from "../../../stores/widgets/WidgetPermissionStore";
|
import { OIDCState } from "../../../stores/widgets/WidgetPermissionStore";
|
||||||
import { IDialogProps } from "./IDialogProps";
|
import { IDialogProps } from "./IDialogProps";
|
||||||
import BaseDialog from "./BaseDialog";
|
import BaseDialog from "./BaseDialog";
|
||||||
import DialogButtons from "../elements/DialogButtons";
|
import DialogButtons from "../elements/DialogButtons";
|
||||||
|
import { SdkContextClass } from '../../../contexts/SDKContext';
|
||||||
|
|
||||||
interface IProps extends IDialogProps {
|
interface IProps extends IDialogProps {
|
||||||
widget: Widget;
|
widget: Widget;
|
||||||
|
@ -57,7 +58,7 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<I
|
||||||
if (this.state.rememberSelection) {
|
if (this.state.rememberSelection) {
|
||||||
logger.log(`Remembering ${this.props.widget.id} as allowed=${allowed} for OpenID`);
|
logger.log(`Remembering ${this.props.widget.id} as allowed=${allowed} for OpenID`);
|
||||||
|
|
||||||
WidgetPermissionStore.instance.setOIDCState(
|
SdkContextClass.instance.widgetPermissionStore.setOIDCState(
|
||||||
this.props.widget, this.props.widgetKind, this.props.inRoomId,
|
this.props.widget, this.props.widgetKind, this.props.inRoomId,
|
||||||
allowed ? OIDCState.Allowed : OIDCState.Denied,
|
allowed ? OIDCState.Allowed : OIDCState.Denied,
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { RoomViewStore } from "../stores/RoomViewStore";
|
||||||
import SpaceStore, { SpaceStoreClass } from "../stores/spaces/SpaceStore";
|
import SpaceStore, { SpaceStoreClass } from "../stores/spaces/SpaceStore";
|
||||||
import TypingStore from "../stores/TypingStore";
|
import TypingStore from "../stores/TypingStore";
|
||||||
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
||||||
|
import { WidgetPermissionStore } from "../stores/widgets/WidgetPermissionStore";
|
||||||
import WidgetStore from "../stores/WidgetStore";
|
import WidgetStore from "../stores/WidgetStore";
|
||||||
|
|
||||||
export const SDKContext = createContext<SdkContextClass>(undefined);
|
export const SDKContext = createContext<SdkContextClass>(undefined);
|
||||||
|
@ -51,6 +52,7 @@ export class SdkContextClass {
|
||||||
public client?: MatrixClient;
|
public client?: MatrixClient;
|
||||||
|
|
||||||
// All protected fields to make it easier to derive test stores
|
// All protected fields to make it easier to derive test stores
|
||||||
|
protected _WidgetPermissionStore?: WidgetPermissionStore;
|
||||||
protected _RightPanelStore?: RightPanelStore;
|
protected _RightPanelStore?: RightPanelStore;
|
||||||
protected _RoomNotificationStateStore?: RoomNotificationStateStore;
|
protected _RoomNotificationStateStore?: RoomNotificationStateStore;
|
||||||
protected _RoomViewStore?: RoomViewStore;
|
protected _RoomViewStore?: RoomViewStore;
|
||||||
|
@ -102,6 +104,12 @@ export class SdkContextClass {
|
||||||
}
|
}
|
||||||
return this._WidgetLayoutStore;
|
return this._WidgetLayoutStore;
|
||||||
}
|
}
|
||||||
|
public get widgetPermissionStore(): WidgetPermissionStore {
|
||||||
|
if (!this._WidgetPermissionStore) {
|
||||||
|
this._WidgetPermissionStore = new WidgetPermissionStore(this);
|
||||||
|
}
|
||||||
|
return this._WidgetPermissionStore;
|
||||||
|
}
|
||||||
public get widgetStore(): WidgetStore {
|
public get widgetStore(): WidgetStore {
|
||||||
if (!this._WidgetStore) {
|
if (!this._WidgetStore) {
|
||||||
this._WidgetStore = WidgetStore.instance;
|
this._WidgetStore = WidgetStore.instance;
|
||||||
|
|
|
@ -47,7 +47,7 @@ import Modal from "../../Modal";
|
||||||
import WidgetOpenIDPermissionsDialog from "../../components/views/dialogs/WidgetOpenIDPermissionsDialog";
|
import WidgetOpenIDPermissionsDialog from "../../components/views/dialogs/WidgetOpenIDPermissionsDialog";
|
||||||
import WidgetCapabilitiesPromptDialog from "../../components/views/dialogs/WidgetCapabilitiesPromptDialog";
|
import WidgetCapabilitiesPromptDialog from "../../components/views/dialogs/WidgetCapabilitiesPromptDialog";
|
||||||
import { WidgetPermissionCustomisations } from "../../customisations/WidgetPermissions";
|
import { WidgetPermissionCustomisations } from "../../customisations/WidgetPermissions";
|
||||||
import { OIDCState, WidgetPermissionStore } from "./WidgetPermissionStore";
|
import { OIDCState } from "./WidgetPermissionStore";
|
||||||
import { WidgetType } from "../../widgets/WidgetType";
|
import { WidgetType } from "../../widgets/WidgetType";
|
||||||
import { CHAT_EFFECTS } from "../../effects";
|
import { CHAT_EFFECTS } from "../../effects";
|
||||||
import { containsEmoji } from "../../effects/utils";
|
import { containsEmoji } from "../../effects/utils";
|
||||||
|
@ -350,7 +350,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async askOpenID(observer: SimpleObservable<IOpenIDUpdate>) {
|
public async askOpenID(observer: SimpleObservable<IOpenIDUpdate>) {
|
||||||
const oidcState = WidgetPermissionStore.instance.getOIDCState(
|
const oidcState = SdkContextClass.instance.widgetPermissionStore.getOIDCState(
|
||||||
this.forWidget, this.forWidgetKind, this.inRoomId,
|
this.forWidget, this.forWidgetKind, this.inRoomId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
import { Widget, WidgetKind } from "matrix-widget-api";
|
import { Widget, WidgetKind } from "matrix-widget-api";
|
||||||
|
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
|
||||||
import { SettingLevel } from "../../settings/SettingLevel";
|
import { SettingLevel } from "../../settings/SettingLevel";
|
||||||
|
import { SdkContextClass } from "../../contexts/SDKContext";
|
||||||
|
|
||||||
export enum OIDCState {
|
export enum OIDCState {
|
||||||
Allowed, // user has set the remembered value as allowed
|
Allowed, // user has set the remembered value as allowed
|
||||||
|
@ -27,16 +27,7 @@ export enum OIDCState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WidgetPermissionStore {
|
export class WidgetPermissionStore {
|
||||||
private static internalInstance: WidgetPermissionStore;
|
public constructor(private readonly context: SdkContextClass) {
|
||||||
|
|
||||||
private constructor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get instance(): WidgetPermissionStore {
|
|
||||||
if (!WidgetPermissionStore.internalInstance) {
|
|
||||||
WidgetPermissionStore.internalInstance = new WidgetPermissionStore();
|
|
||||||
}
|
|
||||||
return WidgetPermissionStore.internalInstance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (all functions here): Merge widgetKind with the widget definition
|
// TODO (all functions here): Merge widgetKind with the widget definition
|
||||||
|
@ -44,7 +35,7 @@ export class WidgetPermissionStore {
|
||||||
private packSettingKey(widget: Widget, kind: WidgetKind, roomId?: string): string {
|
private packSettingKey(widget: Widget, kind: WidgetKind, roomId?: string): string {
|
||||||
let location = roomId;
|
let location = roomId;
|
||||||
if (kind !== WidgetKind.Room) {
|
if (kind !== WidgetKind.Room) {
|
||||||
location = MatrixClientPeg.get().getUserId();
|
location = this.context.client?.getUserId();
|
||||||
}
|
}
|
||||||
if (kind === WidgetKind.Modal) {
|
if (kind === WidgetKind.Modal) {
|
||||||
location = '*MODAL*-' + location; // to guarantee differentiation from whatever spawned it
|
location = '*MODAL*-' + location; // to guarantee differentiation from whatever spawned it
|
||||||
|
@ -71,7 +62,10 @@ export class WidgetPermissionStore {
|
||||||
public setOIDCState(widget: Widget, kind: WidgetKind, roomId: string, newState: OIDCState) {
|
public setOIDCState(widget: Widget, kind: WidgetKind, roomId: string, newState: OIDCState) {
|
||||||
const settingsKey = this.packSettingKey(widget, kind, roomId);
|
const settingsKey = this.packSettingKey(widget, kind, roomId);
|
||||||
|
|
||||||
const currentValues = SettingsStore.getValue("widgetOpenIDPermissions");
|
let currentValues = SettingsStore.getValue("widgetOpenIDPermissions");
|
||||||
|
if (!currentValues) {
|
||||||
|
currentValues = {};
|
||||||
|
}
|
||||||
if (!currentValues.allow) currentValues.allow = [];
|
if (!currentValues.allow) currentValues.allow = [];
|
||||||
if (!currentValues.deny) currentValues.deny = [];
|
if (!currentValues.deny) currentValues.deny = [];
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import RightPanelStore from "../src/stores/right-panel/RightPanelStore";
|
||||||
import { RoomViewStore } from "../src/stores/RoomViewStore";
|
import { RoomViewStore } from "../src/stores/RoomViewStore";
|
||||||
import { SpaceStoreClass } from "../src/stores/spaces/SpaceStore";
|
import { SpaceStoreClass } from "../src/stores/spaces/SpaceStore";
|
||||||
import { WidgetLayoutStore } from "../src/stores/widgets/WidgetLayoutStore";
|
import { WidgetLayoutStore } from "../src/stores/widgets/WidgetLayoutStore";
|
||||||
|
import { WidgetPermissionStore } from "../src/stores/widgets/WidgetPermissionStore";
|
||||||
import WidgetStore from "../src/stores/WidgetStore";
|
import WidgetStore from "../src/stores/WidgetStore";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +33,7 @@ export class TestSdkContext extends SdkContextClass {
|
||||||
public _RightPanelStore?: RightPanelStore;
|
public _RightPanelStore?: RightPanelStore;
|
||||||
public _RoomNotificationStateStore?: RoomNotificationStateStore;
|
public _RoomNotificationStateStore?: RoomNotificationStateStore;
|
||||||
public _RoomViewStore?: RoomViewStore;
|
public _RoomViewStore?: RoomViewStore;
|
||||||
|
public _WidgetPermissionStore?: WidgetPermissionStore;
|
||||||
public _WidgetLayoutStore?: WidgetLayoutStore;
|
public _WidgetLayoutStore?: WidgetLayoutStore;
|
||||||
public _WidgetStore?: WidgetStore;
|
public _WidgetStore?: WidgetStore;
|
||||||
public _PosthogAnalytics?: PosthogAnalytics;
|
public _PosthogAnalytics?: PosthogAnalytics;
|
||||||
|
|
107
test/stores/widgets/WidgetPermissionStore-test.ts
Normal file
107
test/stores/widgets/WidgetPermissionStore-test.ts
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
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 { mocked } from "jest-mock";
|
||||||
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { Widget, WidgetKind } from "matrix-widget-api";
|
||||||
|
|
||||||
|
import { OIDCState, WidgetPermissionStore } from "../../../src/stores/widgets/WidgetPermissionStore";
|
||||||
|
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||||
|
import { TestSdkContext } from "../../TestSdkContext";
|
||||||
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
|
import { SdkContextClass } from "../../../src/contexts/SDKContext";
|
||||||
|
import { stubClient } from "../../test-utils";
|
||||||
|
|
||||||
|
jest.mock("../../../src/settings/SettingsStore");
|
||||||
|
|
||||||
|
describe("WidgetPermissionStore", () => {
|
||||||
|
let widgetPermissionStore: WidgetPermissionStore;
|
||||||
|
let mockClient: MatrixClient;
|
||||||
|
const userId = "@alice:localhost";
|
||||||
|
const roomId = "!room:localhost";
|
||||||
|
const w = new Widget({
|
||||||
|
id: "wid",
|
||||||
|
creatorUserId: userId,
|
||||||
|
type: "m.custom",
|
||||||
|
url: "https://invalid.address.here",
|
||||||
|
});
|
||||||
|
let settings = {}; // key value store
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
settings = {}; // clear settings
|
||||||
|
mocked(SettingsStore.getValue).mockImplementation((setting: string) => {
|
||||||
|
return settings[setting];
|
||||||
|
});
|
||||||
|
mocked(SettingsStore.setValue).mockImplementation((settingName: string,
|
||||||
|
roomId: string | null,
|
||||||
|
level: SettingLevel,
|
||||||
|
value: any,
|
||||||
|
): Promise<void> => {
|
||||||
|
// the store doesn't use any specific level or room ID (room IDs are packed into keys in `value`)
|
||||||
|
settings[settingName] = value;
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
mockClient = stubClient();
|
||||||
|
const context = new TestSdkContext();
|
||||||
|
context.client = mockClient;
|
||||||
|
widgetPermissionStore = new WidgetPermissionStore(context);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should persist OIDCState.Allowed for a widget", () => {
|
||||||
|
widgetPermissionStore.setOIDCState(w, WidgetKind.Account, null, OIDCState.Allowed);
|
||||||
|
// check it remembered the value
|
||||||
|
expect(
|
||||||
|
widgetPermissionStore.getOIDCState(w, WidgetKind.Account, null),
|
||||||
|
).toEqual(OIDCState.Allowed);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should persist OIDCState.Denied for a widget", () => {
|
||||||
|
widgetPermissionStore.setOIDCState(w, WidgetKind.Account, null, OIDCState.Denied);
|
||||||
|
// check it remembered the value
|
||||||
|
expect(
|
||||||
|
widgetPermissionStore.getOIDCState(w, WidgetKind.Account, null),
|
||||||
|
).toEqual(OIDCState.Denied);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should update OIDCState for a widget", () => {
|
||||||
|
widgetPermissionStore.setOIDCState(w, WidgetKind.Account, null, OIDCState.Allowed);
|
||||||
|
widgetPermissionStore.setOIDCState(w, WidgetKind.Account, null, OIDCState.Denied);
|
||||||
|
// check it remembered the latest value
|
||||||
|
expect(
|
||||||
|
widgetPermissionStore.getOIDCState(w, WidgetKind.Account, null),
|
||||||
|
).toEqual(OIDCState.Denied);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should scope the location for a widget when setting OIDC state", () => {
|
||||||
|
// allow this widget for this room
|
||||||
|
widgetPermissionStore.setOIDCState(w, WidgetKind.Room, roomId, OIDCState.Allowed);
|
||||||
|
// check it remembered the value
|
||||||
|
expect(
|
||||||
|
widgetPermissionStore.getOIDCState(w, WidgetKind.Room, roomId),
|
||||||
|
).toEqual(OIDCState.Allowed);
|
||||||
|
// check this is not the case for the entire account
|
||||||
|
expect(
|
||||||
|
widgetPermissionStore.getOIDCState(w, WidgetKind.Account, roomId),
|
||||||
|
).toEqual(OIDCState.Unknown);
|
||||||
|
});
|
||||||
|
it("is created once in SdkContextClass", () => {
|
||||||
|
const context = new SdkContextClass();
|
||||||
|
const store = context.widgetPermissionStore;
|
||||||
|
expect(store).toBeDefined();
|
||||||
|
const store2 = context.widgetPermissionStore;
|
||||||
|
expect(store2).toStrictEqual(store);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue