From be0fa6da7b35ff0cb797eefcb50a4f4694bef297 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 25 Oct 2021 14:06:00 +0100 Subject: [PATCH] Fix removing a room from a Space and interaction with `m.space.parent` (#6944) --- src/components/structures/SpaceHierarchy.tsx | 10 ++++++++ src/stores/SpaceStore.ts | 25 +++++++++++++------- test/stores/SpaceStore-test.ts | 2 +- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/components/structures/SpaceHierarchy.tsx b/src/components/structures/SpaceHierarchy.tsx index 5846ed766d..e97ba54a83 100644 --- a/src/components/structures/SpaceHierarchy.tsx +++ b/src/components/structures/SpaceHierarchy.tsx @@ -545,9 +545,19 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu onClick={async () => { setRemoving(true); try { + const userId = cli.getUserId(); for (const [parentId, childId] of selectedRelations) { await cli.sendStateEvent(parentId, EventType.SpaceChild, {}, childId); + // remove the child->parent relation too, if we have permission to. + const childRoom = cli.getRoom(childId); + const parentRelation = childRoom?.currentState.getStateEvents(EventType.SpaceParent, parentId); + if (childRoom?.currentState.maySendStateEvent(EventType.SpaceParent, userId) && + Array.isArray(parentRelation?.getContent().via) + ) { + await cli.sendStateEvent(childId, EventType.SpaceParent, {}, parentId); + } + hierarchy.removeRelation(parentId, childId); } } catch (e) { diff --git a/src/stores/SpaceStore.ts b/src/stores/SpaceStore.ts index 4ba1081325..bc05ca738b 100644 --- a/src/stores/SpaceStore.ts +++ b/src/stores/SpaceStore.ts @@ -307,16 +307,23 @@ export class SpaceStoreClass extends AsyncStoreWithClient { return room?.currentState.getStateEvents(EventType.SpaceParent) .map(ev => { const content = ev.getContent(); - if (Array.isArray(content?.via) && (!canonicalOnly || content?.canonical)) { - const parent = this.matrixClient.getRoom(ev.getStateKey()); - // only respect the relationship if the sender has sufficient permissions in the parent to set - // child relations, as per MSC1772. - // https://github.com/matrix-org/matrix-doc/blob/main/proposals/1772-groups-as-rooms.md#relationship-between-rooms-and-spaces - if (parent?.currentState.maySendStateEvent(EventType.SpaceChild, userId)) { - return parent; - } + if (!Array.isArray(content.via) || (canonicalOnly && !content.canonical)) { + return; // skip } - // else implicit undefined which causes this element to be filtered out + + // only respect the relationship if the sender has sufficient permissions in the parent to set + // child relations, as per MSC1772. + // https://github.com/matrix-org/matrix-doc/blob/main/proposals/1772-groups-as-rooms.md#relationship-between-rooms-and-spaces + const parent = this.matrixClient.getRoom(ev.getStateKey()); + const relation = parent.currentState.getStateEvents(EventType.SpaceChild, roomId); + if (!parent?.currentState.maySendStateEvent(EventType.SpaceChild, userId) || + // also skip this relation if the parent had this child added but then since removed it + (relation && !Array.isArray(relation.getContent().via)) + ) { + return; // skip + } + + return parent; }) .filter(Boolean) || []; } diff --git a/test/stores/SpaceStore-test.ts b/test/stores/SpaceStore-test.ts index cdc3e58a4f..ccbf0af402 100644 --- a/test/stores/SpaceStore-test.ts +++ b/test/stores/SpaceStore-test.ts @@ -281,7 +281,7 @@ describe("SpaceStore", () => { mkSpace(space1, [fav1, room1]); mkSpace(space2, [fav1, fav2, fav3, room1]); mkSpace(space3, [invite2]); - // client.getRoom.mockImplementation(roomId => rooms.find(room => room.roomId === roomId)); + client.getRoom.mockImplementation(roomId => rooms.find(room => room.roomId === roomId)); [fav1, fav2, fav3].forEach(roomId => { client.getRoom(roomId).tags = {