@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:
Room |
@foreach (var key in OrderedEventTypes) {
@key.Key
~ @Math.Round(key.Value, 2)
|
}
@foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Events!.Values.Average())) {
@roomName |
@foreach (var eventType in OrderedEventTypes) {
if (!powerLevels.Events!.ContainsKey(eventType.Key)) {
- |
continue;
}
@(powerLevels.Events![eventType.Key]) |
}
}
By user:
Room |
@foreach (var key in OrderedUsers) {
@key.Key
~ @Math.Round(key.Value, 2)
|
}
@foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Users!.Values.Average())) {
@roomName |
@foreach (var eventType in OrderedUsers) {
if (!powerLevels.Users!.ContainsKey(eventType.Key)) {
- |
continue;
}
@(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;
}
}