about summary refs log tree commit diff
path: root/MatrixUtils.Web/Pages/Tools/Room
diff options
context:
space:
mode:
Diffstat (limited to 'MatrixUtils.Web/Pages/Tools/Room')
-rw-r--r--MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor51
-rw-r--r--MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor204
-rw-r--r--MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor8
3 files changed, 259 insertions, 4 deletions
diff --git a/MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor b/MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor
new file mode 100644

index 0000000..208cd19 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor
@@ -0,0 +1,51 @@ +@page "/Tools/Room/DropPowerlevel" +@using ArcaneLibs.Extensions +@using LibMatrix.EventTypes.Spec.State.RoomInfo +<h3>DropPowerlevel</h3> +<hr/> + +<span>User ID: </span><FancyTextBox @bind-Value="@UserId"/><br/> +<span>Room ID: </span><FancyTextBox @bind-Value="@RoomId"/><br/> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> + +<pre>@Result</pre> + +@code { + private AuthenticatedHomeserverGeneric? Homeserver { get; set; } = null!; + + [Parameter, SupplyParameterFromQuery(Name = "RoomId")] + public string RoomId { get; set; } = ""; + + [Parameter, SupplyParameterFromQuery(Name = "UserId")] + public string UserId { get; set; } = ""; + + private string Result { get; set; } = ""; + + protected override async Task OnInitializedAsync() { + Homeserver = await sessionStore.GetCurrentHomeserver(); + Result = "I am: " + Homeserver.WhoAmI.ToJson() + "\n"; + StateHasChanged(); + } + + private async Task Execute() { + try { + if (Homeserver is not AuthenticatedHomeserverGeneric hs) { + Result = "Not authenticated"; + return; + } + + var room = hs.GetRoom(RoomId); + + var powerlevels = await room.GetPowerLevelsAsync(); + powerlevels.Users.Remove(UserId); + Result = (await room.SendStateEventAsync(RoomPowerLevelEventContent.EventId, powerlevels)).ToJson(); + } + catch (Exception e) { + Result = e.Message; + } + finally { + StateHasChanged(); + } + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor b/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor new file mode 100644
index 0000000..a47d7f5 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor
@@ -0,0 +1,204 @@ +@page "/Tools/Room/SpacePermissions" +@using ArcaneLibs.Extensions +@using LibMatrix.EventTypes.Spec.State.RoomInfo +@using LibMatrix.RoomTypes +@using MatrixUtils.Web.Pages.Rooms +<h3>Space Permissions</h3> +<hr/> +<span>Space ID: </span> +<FancyTextBox @bind-Value="@SpaceId"/> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> +<br/> +<InputCheckbox @bind-Value="@AutoRecurseSpaces"/> +<span> Auto-recurse into child spaces</span> +<br/> + +@if (RoomPowerLevels.Count == 0) { + <p>No data loaded.</p> +} +else { + <span>Loaded @LoadedSpaceRooms.Count spaces.</span> + <br/> + @if (SpaceRooms.Count > 0) { + <h3>Load more spaces:</h3> + @foreach (var room in SpaceRooms) { + <LinkButton OnClickAsync="@(() => LoadSpaceAsync(room.Key))">@room.Value</LinkButton> + } + } + + <h3>By event type:</h3> + <table class="table-striped table-hover table-bordered align-middle"> + <thead> + <td>Room</td> + @foreach (var key in OrderedEventTypes) { + <td>@key.Key + <br/> + ~ @Math.Round(key.Value, 2) + </td> + } + </thead> + <tbody> + @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Events!.Values.Average())) { + <tr> + <td>@roomName</td> + @foreach (var eventType in OrderedEventTypes) { + if (!powerLevels.Events!.ContainsKey(eventType.Key)) { + <td style="background-color: #ff000044;">-</td> + continue; + } + + <td>@(powerLevels.Events![eventType.Key])</td> + } + </tr> + } + </tbody> + </table> + <br/> + <h3>By user:</h3> + <table class="table-striped table-hover table-bordered align-middle"> + <thead> + <td>Room</td> + @foreach (var key in OrderedUsers) { + <td>@key.Key + <br/> + ~ @Math.Round(key.Value, 2) + </td> + } + </thead> + <tbody> + @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Users!.Values.Average())) { + <tr> + <td>@roomName</td> + @foreach (var eventType in OrderedUsers) { + if (!powerLevels.Users!.ContainsKey(eventType.Key)) { + <td style="background-color: #ff000044;">-</td> + continue; + } + + <td>@(powerLevels.Users![eventType.Key])</td> + } + </tr> + } + </tbody> + </table> +} + +@code { + + [Parameter, SupplyParameterFromQuery] + public string? SpaceId { get; set; } + + [Parameter, SupplyParameterFromQuery] + public bool AutoRecurseSpaces { get; set; } + + private AuthenticatedHomeserverGeneric? Homeserver { get; set; } + private List<AuthenticatedHomeserverGeneric> AllHomeservers { get; set; } = []; + private Dictionary<string, List<GenericRoom>> JoinedHomeserversByRoom { get; set; } = []; + + private Dictionary<string, RoomPowerLevelEventContent> RoomPowerLevels { get; set; } = []; + private Dictionary<string, string> SpaceRooms { get; set; } = []; + private List<string> LoadedSpaceRooms { get; set; } = []; + + private Dictionary<string, double> OrderedEventTypes { get; set; } = new(); + private Dictionary<string, double> 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<GenericRoom> 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; + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor b/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor
index 80a03f2..d6ae945 100644 --- a/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor +++ b/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor
@@ -1,6 +1,6 @@ @page "/Tools/Room/SpaceRestrictedJoins" @using System.Collections.ObjectModel -@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.EventTypes.Spec.State.RoomInfo <h3>Allow space to restricted join children</h3> <hr/> @@ -10,7 +10,7 @@ <p><InputCheckbox @bind-Value="@ChangeKnocking"/> Change knock access: <InputCheckbox @bind-Value="@Knocking"/></p> <br/> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> <br/> @@ -31,7 +31,7 @@ protected override async Task OnInitializedAsync() { log.CollectionChanged += (sender, args) => StateHasChanged(); - hs = await RMUStorage.GetCurrentSessionOrNavigate(); + hs = await sessionStore.GetCurrentHomeserver(navigateOnFailure: true); if (hs is null) return; StateHasChanged(); @@ -40,7 +40,7 @@ } private async Task Execute() { - var space = hs.GetRoom(RoomId).AsSpace; + var space = hs.GetRoom(RoomId).AsSpace(); await foreach (var room in space.GetChildrenAsync()) { log.Add($"Got room {room.RoomId}"); if (ChangeGuestAccess) {