Skip to content

Commit

Permalink
TCHAP: add message error for external users
Browse files Browse the repository at this point in the history
  • Loading branch information
marc.sirisak committed Dec 11, 2024
1 parent b8ab31b commit bfd1f37
Show file tree
Hide file tree
Showing 10 changed files with 439 additions and 0 deletions.
24 changes: 24 additions & 0 deletions modules/tchap-translations/tchap_translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -925,5 +925,29 @@
"user_info|demote_self_confirm_description_space": {
"en": "Before removing the admin role, verify that there is at least one admin in the space. Otherwise, this space won't be manageable anymore. Note that only an admin can reaffect this role to a user",
"fr": "Avant de retirer votre rôle d'administrateur, vérifiez qu'un autre administrateur est présent dans l'espace. Sans cela, l'espace ne pourra plus être géré. Notez que seul un administrateur pourra vous réattribuer ce rôle."
},
"room|error_join_generic_external": {
"en": "As an external user, you don't have access to this room.",
"fr": "En tant qu'invité externe, vous n'avez pas accès à ce salon."
},
"room|error_join_public_external": {
"en": "As an external user, you can not access public rooms",
"fr": "En tant qu'invité externe, vous n'avez pas accès aux salons publics"
},
"room|error_join_private_external": {
"en": "As an external user, you can not access private rooms. You can ask the room admin to invite",
"fr": "En tant qu'invité externe, vous n'avez pas accès aux salons privée. Demander à l'administrateur de vous inviter"
},
"room|error_create_room_external": {
"en": "As an external user, you can not create a private room.",
"fr": "En tant qu'invité externe, vous n'avez pas la possibilité de créer un salon privé."
},
"create_space|error_external": {
"en": "As an external user, you can not create a space.",
"fr": "En tant qu'invité externe, vous n'avez pas la possibilité de créer un espace"
},
"create_space|error_title": {
"en": "Impossible to create the space",
"fr": "Impossible de créer l'espace"
}
}
8 changes: 8 additions & 0 deletions patches/tchap-modifications.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,13 @@
"files": [
"src/Unread.ts"
]
},
"externals-error-messages": {
"issue": "https://github.com/tchapgouv/tchap-web-v4/issues/1164",
"files": [
"src/stores/RoomViewStore.tsx",
"src/components/views/spaces/SpaceCreateMenu.tsx",
"src/createRoom.ts"
]
}
}
3 changes: 3 additions & 0 deletions res/themes/tchap-light/css/_tchap_custom.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ $background-color_3: rgba(125, 125, 150, 0.65);
$background-color_4: #c7d5e4;
$border-color_1: #7e7ec4;

/* sometimes its red due to tchap red badge icon, so we force the green on the e2e verified color */
$e2e-verified-color: var(--confirmation-color);

.mx_SpacePanel {
.mx_SpaceButton.mx_SpaceButton_home {
.mx_SpaceButton_icon {
Expand Down
7 changes: 7 additions & 0 deletions src/components/views/spaces/SpaceCreateMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { Action } from "../../../dispatcher/actions";
import { Filter } from "../dialogs/spotlight/Filter";
import { OpenSpotlightPayload } from "../../../dispatcher/payloads/OpenSpotlightPayload.ts";
import TchapUrls from "~tchap-web/src/tchap/util/TchapUrls"; // :TCHAP: space-remove-public-and-subspace
import ExternalAccountHandler from "~tchap-web/src/tchap/lib/ExternalAccountHandler.ts";

export const createSpace = async (
client: MatrixClient,
Expand Down Expand Up @@ -262,6 +263,12 @@ const SpaceCreateMenu: React.FC<{

onFinished();
} catch (e) {
// :TCHAP: externals-error-messages
if (ExternalAccountHandler.isUserExternal(cli)) {
ExternalAccountHandler.createSpaceError();
return;
}
// end :TCHAP:
logger.error(e);
}
};
Expand Down
8 changes: 8 additions & 0 deletions src/createRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { waitForMember } from "./utils/membership";
import { PreferredRoomVersions } from "./utils/PreferredRoomVersions";
import SettingsStore from "./settings/SettingsStore";
import { MEGOLM_ENCRYPTION_ALGORITHM } from "./utils/crypto";
import ExternalAccountHandler from "./tchap/lib/ExternalAccountHandler";

// we define a number of interfaces which take their names from the js-sdk
/* eslint-disable camelcase */
Expand Down Expand Up @@ -381,6 +382,13 @@ export default async function createRoom(client: MatrixClient, opts: IOpts): Pro
action: Action.JoinRoomError,
roomId,
});

// :TCHAP: externals-error-messages
if (ExternalAccountHandler.isUserExternal(client)) {
ExternalAccountHandler.createRoomError();
return;
}
// end :TCHAP:
logger.error("Failed to create room " + roomId + " " + err);
let description = _t("create_room|generic_error");
if (err.errcode === "M_UNSUPPORTED_ROOM_VERSION") {
Expand Down
8 changes: 8 additions & 0 deletions src/stores/RoomViewStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { CancelAskToJoinPayload } from "../dispatcher/payloads/CancelAskToJoinPa
import { SubmitAskToJoinPayload } from "../dispatcher/payloads/SubmitAskToJoinPayload";
import { ModuleRunner } from "../modules/ModuleRunner";
import { setMarkedUnreadState } from "../utils/notifications";
import ExternalAccountHandler from "../tchap/lib/ExternalAccountHandler";

const NUM_JOIN_RETRY = 5;

Expand Down Expand Up @@ -619,6 +620,13 @@ export class RoomViewStore extends EventEmitter {
description = _t("Access possible only by invitation of a member of the room.");
}
/* end :TCHAP: */
// :TCHAP: externals-error-messages
const cli = MatrixClientPeg.safeGet();
if (ExternalAccountHandler.isUserExternal(cli)) {
ExternalAccountHandler.joinRoomError(cli.getRoom(roomId)!);
return;
}
// end :TCHAP:

if (err.name === "ConnectionError") {
description = _t("room|error_join_connection");
Expand Down
50 changes: 50 additions & 0 deletions src/tchap/lib/ExternalAccountHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import TchapRoomUtils from "../util/TchapRoomUtils";
import { TchapRoomType } from "../@types/tchap";
import { _t, _td } from "~tchap-web/src/languageHandler";
import ErrorDialog from "~tchap-web/src/components/views/dialogs/ErrorDialog";
import Modal from "~tchap-web/src/Modal";
import SdkConfig from "~tchap-web/src/SdkConfig";

class ExpiredAccountHandler {

public static isUserExternal(client: MatrixClient): boolean {
console.log('client.getDomain()',client.getDomain())
const hsList = SdkConfig.get()["homeserver_list"] ?? [];
const externesHs = hsList.find(hs => hs.server_name.includes("Externes"));
console.log('externesHs', externesHs)
console.log('externesHs includes', externesHs.base_url.includes(client.getDomain()))
return !!externesHs.base_url.includes(client.getDomain());
}

public static joinRoomError(room: Room): void{
if (!room) {
this.displayModal(_t("room|error_join_title"), _t("room|error_join_generic_external"));
return;
}

if (TchapRoomUtils.getTchapRoomType(room) == TchapRoomType.Forum) {
this.displayModal(_t("room|error_join_title"), _t("room|error_join_public_external"))
return;
}

this.displayModal(_t("room|error_join_title"), _t("room|error_join_private_external"))
}

public static createRoomError(): void {
this.displayModal(_t("create_room|error_title"), _t("room|error_create_room_external"))
}

public static createSpaceError(): void {
this.displayModal(_t("create_space|error_title"), _t("create_space|error_external"))
}

public static displayModal(title: string, description: string): void {
Modal.createDialog(ErrorDialog, {
title,
description,
});
}
}

export default ExpiredAccountHandler;
71 changes: 71 additions & 0 deletions test/unit-tests/tchap/createRoom-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import { mocked, Mocked } from "jest-mock";
import { MatrixClient } from "matrix-js-sdk/src/matrix";

import {
mockPlatformPeg,
getMockClientWithEventEmitter,
mockClientMethodsUser,
stubClient,
} from "~tchap-web/test/test-utils";
import createRoom from "~tchap-web/src/createRoom";
import ExternalAccountHandler from "~tchap-web/src/tchap/lib/ExternalAccountHandler";
import SdkConfig, { ConfigOptions } from "~tchap-web/src/SdkConfig";
import Modal from "~tchap-web/src/Modal";

jest.mock("~tchap-web/src/tchap/lib/ExternalAccountHandler.ts");

describe("createRoom", () => {
mockPlatformPeg();

let client: Mocked<MatrixClient>;

const config: ConfigOptions = {
homeserver_list: [
{
base_url: "https://matrix.dev01.tchap.incubateur.net",
server_name: "Agents 1",
},
{
base_url: "https://matrix.externes.com",
server_name: "Externes",
},
],
};
SdkConfig.put(config);

beforeEach(() => {
Modal.createDialog = jest.fn();
// @ts-ignore mock (type error because empty return)
mocked(Modal.createDialog).mockReturnValue({});

client = getMockClientWithEventEmitter({
...stubClient(),
...mockClientMethodsUser("@bob:externes.com"),
});
});

afterEach(() => jest.clearAllMocks());

it("doesn't create room when user is from external instance", async () => {
// we mock tht something wrong happened
jest.spyOn(client, "createRoom").mockRejectedValue(new Error("test") as never);

// don't know why isUserExternal is not returning true despite the setup we did for being an external user
// so we mock it, not the best...
jest.spyOn(ExternalAccountHandler, "isUserExternal").mockReturnValue(true);

await createRoom(client, {});

expect(ExternalAccountHandler.isUserExternal).toHaveBeenCalledTimes(1);

expect(ExternalAccountHandler.createRoomError).toHaveBeenCalledTimes(1);
});
});
90 changes: 90 additions & 0 deletions test/unit-tests/tchap/lib/ExternalAccountHandler-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { mocked, MockedObject } from "jest-mock";
import { MatrixClient } from "matrix-js-sdk/src/matrix";

import ExternalAccountHandler from "~tchap-web/src/tchap/lib/ExternalAccountHandler";
import Modal from "~tchap-web/src/Modal";
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "~tchap-web/test/test-utils";
import SdkConfig, { ConfigOptions } from "~tchap-web/src/SdkConfig";
import ErrorDialog from "~tchap-web/src/components/views/dialogs/ErrorDialog";
import { _t } from "~tchap-web/src/languageHandler";

describe("ExternalAccountHandler", () => {
let mockClient: MockedObject<MatrixClient>;

const userId = "@bob:externes.com";
const userIdNotExterne = "@bob:test.com";

beforeEach(() => {
Modal.createDialog = jest.fn();
// @ts-ignore mock (type error because empty return)
mocked(Modal.createDialog).mockReturnValue({});

const config: ConfigOptions = {
homeserver_list: [
{
base_url: "https://matrix.dev01.tchap.incubateur.net",
server_name: "Agents 1",
},
{
base_url: "https://matrix.externes.com",
server_name: "Externes",
},
],
};
SdkConfig.put(config);

mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(userId),
stopClient: jest.fn(),
removeAllListeners: jest.fn(),
});
});

afterEach(() => {
jest.clearAllMocks();
SdkConfig.reset();
});

it("should indicate the user as external", () => {
const isExternal = ExternalAccountHandler.isUserExternal(mockClient);
expect(isExternal).toBeTruthy();
});

it("should call modal join room error with generic message", () => {
ExternalAccountHandler.joinRoomError(null);
expect(Modal.createDialog).toHaveBeenCalledTimes(1);
expect(Modal.createDialog).toHaveBeenCalledWith(ErrorDialog, {
title: _t("room|error_join_title"),
description: _t("room|error_join_generic_external"),
});
});

it("should call modal create room error with public message", () => {
ExternalAccountHandler.createRoomError();
expect(Modal.createDialog).toHaveBeenCalledTimes(1);
expect(Modal.createDialog).toHaveBeenCalledWith(ErrorDialog, {
title: _t("create_room|error_title"),
description: _t("room|error_create_room_external"),
});
});

it("should call modal space error with private message", () => {
ExternalAccountHandler.createSpaceError();
expect(Modal.createDialog).toHaveBeenCalledTimes(1);
expect(Modal.createDialog).toHaveBeenCalledWith(ErrorDialog, {
title: _t("create_space|error_title"),
description: _t("create_space|error_external"),
});
});

it("should not indicate the user as external", () => {
mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(userIdNotExterne),
stopClient: jest.fn(),
removeAllListeners: jest.fn(),
});

const isExternal = ExternalAccountHandler.isUserExternal(mockClient);
expect(isExternal).toBeFalsy();
});
});
Loading

0 comments on commit bfd1f37

Please sign in to comment.