Store refactor: convert WidgetPermissionStore (#9458)

* Store refactor: convert WidgetPermissionStore

Add Jest tests as well.

* More tests

* Review comments
This commit is contained in:
kegsay 2022-10-19 21:00:53 +01:00 committed by GitHub
parent 7d0af1dca4
commit 17c3fb89c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 129 additions and 17 deletions

View file

@ -21,10 +21,11 @@ import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../languageHandler";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { OIDCState, WidgetPermissionStore } from "../../../stores/widgets/WidgetPermissionStore";
import { OIDCState } from "../../../stores/widgets/WidgetPermissionStore";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
import { SdkContextClass } from '../../../contexts/SDKContext';
interface IProps extends IDialogProps {
widget: Widget;
@ -57,7 +58,7 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<I
if (this.state.rememberSelection) {
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,
allowed ? OIDCState.Allowed : OIDCState.Denied,
);

View file

@ -27,6 +27,7 @@ import { RoomViewStore } from "../stores/RoomViewStore";
import SpaceStore, { SpaceStoreClass } from "../stores/spaces/SpaceStore";
import TypingStore from "../stores/TypingStore";
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
import { WidgetPermissionStore } from "../stores/widgets/WidgetPermissionStore";
import WidgetStore from "../stores/WidgetStore";
export const SDKContext = createContext<SdkContextClass>(undefined);
@ -51,6 +52,7 @@ export class SdkContextClass {
public client?: MatrixClient;
// All protected fields to make it easier to derive test stores
protected _WidgetPermissionStore?: WidgetPermissionStore;
protected _RightPanelStore?: RightPanelStore;
protected _RoomNotificationStateStore?: RoomNotificationStateStore;
protected _RoomViewStore?: RoomViewStore;
@ -102,6 +104,12 @@ export class SdkContextClass {
}
return this._WidgetLayoutStore;
}
public get widgetPermissionStore(): WidgetPermissionStore {
if (!this._WidgetPermissionStore) {
this._WidgetPermissionStore = new WidgetPermissionStore(this);
}
return this._WidgetPermissionStore;
}
public get widgetStore(): WidgetStore {
if (!this._WidgetStore) {
this._WidgetStore = WidgetStore.instance;

View file

@ -47,7 +47,7 @@ import Modal from "../../Modal";
import WidgetOpenIDPermissionsDialog from "../../components/views/dialogs/WidgetOpenIDPermissionsDialog";
import WidgetCapabilitiesPromptDialog from "../../components/views/dialogs/WidgetCapabilitiesPromptDialog";
import { WidgetPermissionCustomisations } from "../../customisations/WidgetPermissions";
import { OIDCState, WidgetPermissionStore } from "./WidgetPermissionStore";
import { OIDCState } from "./WidgetPermissionStore";
import { WidgetType } from "../../widgets/WidgetType";
import { CHAT_EFFECTS } from "../../effects";
import { containsEmoji } from "../../effects/utils";
@ -350,7 +350,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
}
public async askOpenID(observer: SimpleObservable<IOpenIDUpdate>) {
const oidcState = WidgetPermissionStore.instance.getOIDCState(
const oidcState = SdkContextClass.instance.widgetPermissionStore.getOIDCState(
this.forWidget, this.forWidgetKind, this.inRoomId,
);

View file

@ -17,8 +17,8 @@
import { Widget, WidgetKind } from "matrix-widget-api";
import SettingsStore from "../../settings/SettingsStore";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { SettingLevel } from "../../settings/SettingLevel";
import { SdkContextClass } from "../../contexts/SDKContext";
export enum OIDCState {
Allowed, // user has set the remembered value as allowed
@ -27,16 +27,7 @@ export enum OIDCState {
}
export class WidgetPermissionStore {
private static internalInstance: WidgetPermissionStore;
private constructor() {
}
public static get instance(): WidgetPermissionStore {
if (!WidgetPermissionStore.internalInstance) {
WidgetPermissionStore.internalInstance = new WidgetPermissionStore();
}
return WidgetPermissionStore.internalInstance;
public constructor(private readonly context: SdkContextClass) {
}
// 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 {
let location = roomId;
if (kind !== WidgetKind.Room) {
location = MatrixClientPeg.get().getUserId();
location = this.context.client?.getUserId();
}
if (kind === WidgetKind.Modal) {
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) {
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.deny) currentValues.deny = [];

View file

@ -22,6 +22,7 @@ import RightPanelStore from "../src/stores/right-panel/RightPanelStore";
import { RoomViewStore } from "../src/stores/RoomViewStore";
import { SpaceStoreClass } from "../src/stores/spaces/SpaceStore";
import { WidgetLayoutStore } from "../src/stores/widgets/WidgetLayoutStore";
import { WidgetPermissionStore } from "../src/stores/widgets/WidgetPermissionStore";
import WidgetStore from "../src/stores/WidgetStore";
/**
@ -32,6 +33,7 @@ export class TestSdkContext extends SdkContextClass {
public _RightPanelStore?: RightPanelStore;
public _RoomNotificationStateStore?: RoomNotificationStateStore;
public _RoomViewStore?: RoomViewStore;
public _WidgetPermissionStore?: WidgetPermissionStore;
public _WidgetLayoutStore?: WidgetLayoutStore;
public _WidgetStore?: WidgetStore;
public _PosthogAnalytics?: PosthogAnalytics;

View 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);
});
});