@page "/Tools/Room/SpacePermissions" @using ArcaneLibs.Extensions @using LibMatrix.EventTypes.Spec.State.RoomInfo @using LibMatrix.RoomTypes @using MatrixUtils.Web.Pages.Rooms

Space Permissions


Space ID: Execute
Auto-recurse into child spaces
@if (RoomPowerLevels.Count == 0) {

No data loaded.

} else { Loaded @LoadedSpaceRooms.Count spaces.
@if (SpaceRooms.Count > 0) {

Load more spaces:

@foreach (var room in SpaceRooms) { @room.Value } }

By event type:

@foreach (var key in OrderedEventTypes) { } @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Events!.Values.Average())) { @foreach (var eventType in OrderedEventTypes) { if (!powerLevels.Events!.ContainsKey(eventType.Key)) { continue; } } }
Room@key.Key
~ @Math.Round(key.Value, 2)
@roomName-@(powerLevels.Events![eventType.Key])

By user:

@foreach (var key in OrderedUsers) { } @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Users!.Values.Average())) { @foreach (var eventType in OrderedUsers) { if (!powerLevels.Users!.ContainsKey(eventType.Key)) { continue; } } }
Room@key.Key
~ @Math.Round(key.Value, 2)
@roomName-@(powerLevels.Users![eventType.Key])
} @code { [Parameter, SupplyParameterFromQuery] public string? SpaceId { get; set; } [Parameter, SupplyParameterFromQuery] public bool AutoRecurseSpaces { get; set; } private AuthenticatedHomeserverGeneric? Homeserver { get; set; } private List AllHomeservers { get; set; } = []; private Dictionary> JoinedHomeserversByRoom { get; set; } = []; private Dictionary RoomPowerLevels { get; set; } = []; private Dictionary SpaceRooms { get; set; } = []; private List LoadedSpaceRooms { get; set; } = []; private Dictionary OrderedEventTypes { get; set; } = new(); private Dictionary OrderedUsers { get; set; } = new(); protected override async Task OnInitializedAsync() { if (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true) is not AuthenticatedHomeserverGeneric hs) return; Homeserver = hs; await foreach (var server in sessionStore.TryGetAllHomeservers()) { AllHomeservers.Add(server); var joinedRooms = await server.GetJoinedRooms(); foreach (var room in joinedRooms) { if (!JoinedHomeserversByRoom.ContainsKey(room.RoomId)) { JoinedHomeserversByRoom[room.RoomId] = []; } JoinedHomeserversByRoom[room.RoomId].Add(room); } } if (!string.IsNullOrWhiteSpace(SpaceId)) { await Execute(); } } private async Task Execute() { RoomPowerLevels = []; SpaceRooms = []; await LoadSpaceAsync(SpaceId); } private async Task GetJoinedRoomAsync(string roomId) { var room = Homeserver.GetRoom(roomId); if (await room.IsJoinedAsync()) return room; if (JoinedHomeserversByRoom.TryGetValue(roomId, out var rooms)) { foreach (var r in rooms) { if (await r.IsJoinedAsync()) return r; } } foreach (var hs in AllHomeservers) { if (hs == Homeserver) continue; room = hs.GetRoom(roomId); if (await room.IsJoinedAsync()) return room; } Console.WriteLine($"Not joined to room {roomId} on any known homeserver."); return room; // not null, in case we can preview the room } private async Task LoadSpaceAsync(string spaceId) { LoadedSpaceRooms.Add(spaceId); SpaceRooms.Remove(spaceId); var space = (await GetJoinedRoomAsync(spaceId)).AsSpace(); RoomPowerLevels[await space.GetNameOrFallbackAsync()] = AddFakeEvents(await space.GetPowerLevelsAsync()); var children = space.GetChildrenAsync(); await foreach (var childRoom in children) { var child = await GetJoinedRoomAsync(childRoom.RoomId); try { var powerlevels = await child.GetPowerLevelsAsync(); RoomPowerLevels[await child.GetNameOrFallbackAsync()] = AddFakeEvents(powerlevels!); if (await child.GetRoomType() == SpaceRoom.TypeName) { if (AutoRecurseSpaces) await LoadSpaceAsync(child.RoomId); else SpaceRooms.Add(child.RoomId, await child.GetNameOrFallbackAsync()); } OrderedEventTypes = RoomPowerLevels .SelectMany(x => x.Value.Events!) .GroupBy(x => x.Key) .ToDictionary(x => x.Key, x => x.Average(y => y.Value)) .OrderByDescending(x => x.Value) .ToDictionary(x => x.Key, x => x.Value); OrderedUsers = RoomPowerLevels .SelectMany(x => x.Value.Users!) .GroupBy(x => x.Key) .ToDictionary(x => x.Key, x => x.Average(y => y.Value)) .OrderByDescending(x => x.Value) .ToDictionary(x => x.Key, x => x.Value); StateHasChanged(); } catch (Exception ex) { Console.WriteLine($"Failed to get power levels for room {child.RoomId}: {ex}"); } } } private RoomPowerLevelEventContent AddFakeEvents(RoomPowerLevelEventContent powerlevels) { powerlevels.Events ??= []; powerlevels.Events["[user_default]"] = powerlevels.UsersDefault ?? 0; powerlevels.Events["[event_default]"] = powerlevels.EventsDefault ?? 0; powerlevels.Events["[state_default]"] = powerlevels.StateDefault ?? 100; powerlevels.Events["[ban]"] = powerlevels.Ban ?? 100; powerlevels.Events["[invite]"] = powerlevels.Invite ?? 100; powerlevels.Events["[kick]"] = powerlevels.Kick ?? 100; powerlevels.Events["[ping_room]"] = powerlevels.NotificationsPl?.Room ?? 100; powerlevels.Events["[redact]"] = powerlevels.Redact ?? 100; return powerlevels; } }