Skip to content

Commit 3eca1de

Browse files
committed
Update for compatibility with v12 rooms
Stop using powerLevelNorm and reading PL events manually. To support matrix-org/matrix-js-sdk#4937
1 parent ab6ef2f commit 3eca1de

File tree

4 files changed

+50
-36
lines changed

4 files changed

+50
-36
lines changed

src/components/structures/MatrixChat.tsx

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ import { type OpenForwardDialogPayload } from "../../dispatcher/payloads/OpenFor
141141
import { ShareFormat, type SharePayload } from "../../dispatcher/payloads/SharePayload";
142142
import Markdown from "../../Markdown";
143143
import { sanitizeHtmlParams } from "../../Linkify";
144+
import { isOnlyAdmin } from "../../utils/membership";
144145

145146
// legacy export
146147
export { default as Views } from "../../Views";
@@ -1255,29 +1256,21 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
12551256

12561257
const client = MatrixClientPeg.get();
12571258
if (client && roomToLeave) {
1258-
const plEvent = roomToLeave.currentState.getStateEvents(EventType.RoomPowerLevels, "");
1259-
const plContent = plEvent ? plEvent.getContent() : {};
1260-
const userLevels = plContent.users || {};
1261-
const currentUserLevel = userLevels[client.getUserId()!];
1262-
const userLevelValues = Object.values(userLevels);
1263-
if (userLevelValues.every((x) => typeof x === "number")) {
1264-
const maxUserLevel = Math.max(...(userLevelValues as number[]));
1265-
// If the user is the only user with highest power level
1266-
if (
1267-
maxUserLevel === currentUserLevel &&
1268-
userLevelValues.lastIndexOf(maxUserLevel) == userLevelValues.indexOf(maxUserLevel)
1269-
) {
1270-
const warning =
1271-
maxUserLevel >= 100
1272-
? _t("leave_room_dialog|room_leave_admin_warning")
1273-
: _t("leave_room_dialog|room_leave_mod_warning");
1274-
warnings.push(
1275-
<strong className="warning" key="last_admin_warning">
1276-
{" " /* Whitespace, otherwise the sentences get smashed together */}
1277-
{warning}
1278-
</strong>,
1279-
);
1280-
}
1259+
const userLevelValues = roomToLeave.getMembers().map((m) => m.powerLevel);
1260+
1261+
const maxUserLevel = Math.max(...(userLevelValues as number[]));
1262+
// If the user is the only user with highest power level
1263+
if (isOnlyAdmin(roomToLeave, client)) {
1264+
const warning =
1265+
maxUserLevel >= 100
1266+
? _t("leave_room_dialog|room_leave_admin_warning")
1267+
: _t("leave_room_dialog|room_leave_mod_warning");
1268+
warnings.push(
1269+
<strong className="warning" key="last_admin_warning">
1270+
{" " /* Whitespace, otherwise the sentences get smashed together */}
1271+
{warning}
1272+
</strong>,
1273+
);
12811274
}
12821275
}
12831276

src/components/views/dialogs/LeaveSpaceDialog.tsx

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,13 @@ import BaseDialog from "../dialogs/BaseDialog";
1515
import SpaceStore from "../../../stores/spaces/SpaceStore";
1616
import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker";
1717
import { filterBoolean } from "../../../utils/arrays";
18+
import { isOnlyAdmin } from "../../../utils/membership";
1819

1920
interface IProps {
2021
space: Room;
2122
onFinished(leave: boolean, rooms?: Room[]): void;
2223
}
2324

24-
const isOnlyAdmin = (room: Room): boolean => {
25-
const userId = room.client.getSafeUserId();
26-
if (room.getMember(userId)?.powerLevelNorm !== 100) {
27-
return false; // user is not an admin
28-
}
29-
return room.getJoinedMembers().every((member) => {
30-
// return true if every other member has a lower power level (we are highest)
31-
return member.userId === userId || member.powerLevelNorm < 100;
32-
});
33-
};
34-
3525
const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
3626
const spaceChildren = useMemo(() => {
3727
const roomSet = new Set(SpaceStore.instance.getSpaceFilteredRoomIds(space.roomId));
@@ -53,11 +43,13 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
5343
rejoinWarning = _t("space|leave_dialog_public_rejoin_warning");
5444
}
5545

46+
const isOnlyAdminWrapper = (r: Room): boolean => isOnlyAdmin(r, r.client);
47+
5648
let onlyAdminWarning;
57-
if (isOnlyAdmin(space)) {
49+
if (isOnlyAdmin(space, space.client)) {
5850
onlyAdminWarning = _t("space|leave_dialog_only_admin_warning");
5951
} else {
60-
const numChildrenOnlyAdminIn = roomsToLeave.filter(isOnlyAdmin).length;
52+
const numChildrenOnlyAdminIn = roomsToLeave.filter(isOnlyAdminWrapper).length;
6153
if (numChildrenOnlyAdminIn > 0) {
6254
onlyAdminWarning = _t("space|leave_dialog_only_admin_room_warning");
6355
}

src/utils/membership.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,16 @@ export async function waitForMember(
131131
client.removeListener(RoomStateEvent.NewMember, handler);
132132
});
133133
}
134+
135+
export function isOnlyAdmin(room: Room, client: MatrixClient): boolean {
136+
const currentUserLevel = room.getMember(client.getUserId()!)?.powerLevel;
137+
138+
const userLevelValues = room.getMembers().map((m) => m.powerLevel);
139+
140+
const maxUserLevel = Math.max(...userLevelValues.filter((x) => typeof x === "number"));
141+
// If the user is the only user with highest power level
142+
return (
143+
maxUserLevel === currentUserLevel &&
144+
userLevelValues.lastIndexOf(maxUserLevel) == userLevelValues.indexOf(maxUserLevel)
145+
);
146+
}

test/unit-tests/components/structures/MatrixChat-test.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,22 @@ describe("<MatrixChat />", () => {
775775
),
776776
).toBeInTheDocument();
777777
});
778+
it("should warn when user is the last admin", async () => {
779+
jest.spyOn(room, "getMembers").mockReturnValue([
780+
{ powerLevel: 100 } as unknown as MatrixJs.RoomMember,
781+
{ powerLevel: 0 } as unknown as MatrixJs.RoomMember,
782+
]);
783+
jest.spyOn(room, "getMember").mockReturnValue({
784+
powerLevel: 100,
785+
} as unknown as MatrixJs.RoomMember);
786+
dispatchAction();
787+
await screen.findByRole("dialog");
788+
expect(
789+
screen.getByText(
790+
"You're the only administrator in this room. If you leave, nobody will be able to change room settings or take other important actions.",
791+
),
792+
).toBeInTheDocument();
793+
});
778794
it("should do nothing on cancel", async () => {
779795
dispatchAction();
780796
const dialog = await screen.findByRole("dialog");

0 commit comments

Comments
 (0)