about summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
m---------LibMatrix0
-rw-r--r--MatrixUtils.LibDMSpace/DMSpaceRoom.cs6
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor3
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor50
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor.css35
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryResult.razor5
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor69
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor218
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor.css7
-rw-r--r--MatrixUtils.Web/Pages/HSAdmin/Synapse/SubTools/SynapseRoomStateResync.razor79
-rw-r--r--MatrixUtils.Web/Pages/Rooms/Space.razor4
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor2
-rw-r--r--MatrixUtils.Web/Program.cs3
-rw-r--r--MatrixUtils.Web/Shared/RoomListComponents/RoomListSpace.razor2
15 files changed, 321 insertions, 164 deletions
diff --git a/LibMatrix b/LibMatrix
-Subproject cacabe2b1a15bb7492e23d477ec653513e84d26
+Subproject 5121c355fa62a394b1090be67d48f972bcd5d4e
diff --git a/MatrixUtils.LibDMSpace/DMSpaceRoom.cs b/MatrixUtils.LibDMSpace/DMSpaceRoom.cs

index 646a3f3..89ab91b 100644 --- a/MatrixUtils.LibDMSpace/DMSpaceRoom.cs +++ b/MatrixUtils.LibDMSpace/DMSpaceRoom.cs
@@ -61,7 +61,7 @@ public class DMSpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomI }).ToAsyncEnumerable(); await foreach (var ((userId, dmRooms), layer) in layerTasks) { - var space = Homeserver.GetRoom(layer.SpaceId).AsSpace; + var space = Homeserver.GetRoom(layer.SpaceId).AsSpace(); foreach (var roomid in dmRooms) { var dri = new DMRoomInfo() { AttributedUser = userId @@ -122,7 +122,7 @@ public class DMSpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomI await foreach (var (layer, profile) in getProfileTasks) { if (profile is null) continue; var layerContent = layer.TypedContent as DMSpaceChildLayer; - var space = Homeserver.GetRoom(layerContent!.SpaceId).AsSpace; + var space = Homeserver.GetRoom(layerContent!.SpaceId).AsSpace(); try { await space.SendStateEventAsync(RoomAvatarEventContent.EventId, "", new RoomAvatarEventContent() { @@ -140,7 +140,7 @@ public class DMSpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomI private async Task UpdateLayer(DMSpaceChildLayer layer, string mxid) { UserProfileResponse? profile = null; - var space = Homeserver.GetRoom(layer.SpaceId).AsSpace; + var space = Homeserver.GetRoom(layer.SpaceId).AsSpace(); if (string.IsNullOrWhiteSpace(layer.OverrideAvatar) || string.IsNullOrWhiteSpace(layer.OverrideName)) { try { diff --git a/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor b/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor
index e1b46e2..03d3ad1 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor +++ b/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor
@@ -11,7 +11,8 @@ else { <h4>Synapse tools</h4> <hr/> <a href="/HSAdmin/Synapse/RoomQuery">Query rooms</a><br/> - <a href="/HSAdmin/Synapse/BlockMedia">Block media</a> + <a href="/HSAdmin/Synapse/BlockMedia">Block media</a><br/> + <a href="/HSAdmin/Synapse/BackgroundJobs">View running background jobs</a><br/> } else if (Homeserver is AuthenticatedHomeserverHSE) { <h4>Rory&amp;::LibMatrix.HomeserverEmulator tools</h4> diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor new file mode 100644
index 0000000..eb168f4 --- /dev/null +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor
@@ -0,0 +1,50 @@ +@using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Filters +<div style="margin-left: 8px; margin-bottom: 8px;"> + <u style="display: block;">String contains</u> + <span class="tile tile280">Room ID: <FancyTextBox @bind-Value="@Filter.RoomIdContains"></FancyTextBox></span> + <span class="tile tile280">Room name: <FancyTextBox @bind-Value="@Filter.NameContains"></FancyTextBox></span> + <span class="tile tile280">Canonical alias: <FancyTextBox @bind-Value="@Filter.CanonicalAliasContains"></FancyTextBox></span> + <span class="tile tile280">Creator: <FancyTextBox @bind-Value="@Filter.CreatorContains"></FancyTextBox></span> + <span class="tile tile280">Room version: <FancyTextBox @bind-Value="@Filter.VersionContains"></FancyTextBox></span> + <span class="tile tile280">Encryption algorithm: <FancyTextBox @bind-Value="@Filter.EncryptionContains"></FancyTextBox></span> + <span class="tile tile280">Join rules: <FancyTextBox @bind-Value="@Filter.JoinRulesContains"></FancyTextBox></span> + <span class="tile tile280">Guest access: <FancyTextBox @bind-Value="@Filter.GuestAccessContains"></FancyTextBox></span> + <span class="tile tile280">History visibility: <FancyTextBox @bind-Value="@Filter.HistoryVisibilityContains"></FancyTextBox></span> + + <u style="display: block;">Optional checks</u> + <span class="tile tile150"> + <InputCheckbox @bind-Value="@Filter.CheckFederation"></InputCheckbox> Is federated: + @if (Filter.CheckFederation) { + <InputCheckbox @bind-Value="@Filter.Federatable"></InputCheckbox> + } + </span> + <span class="tile tile150"> + <InputCheckbox @bind-Value="@Filter.CheckPublic"></InputCheckbox> Is public: + @if (Filter.CheckPublic) { + <InputCheckbox @bind-Value="@Filter.Public"></InputCheckbox> + } + </span> + + <u style="display: block;">Ranges</u> + <span class="tile center-children"> + <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.StateEventsGreaterThan"/> + <span class="range-sep">state events</span> + <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.StateEventsLessThan"/> + </span> + <span class="tile center-children"> + <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedMembersGreaterThan"></InputNumber><span class="range-sep">members</span><InputNumber + max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedMembersLessThan"></InputNumber> + </span> + <span class="tile center-children"> + <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedLocalMembersGreaterThan"></InputNumber><span + class="range-sep">local members</span><InputNumber max="@int.MaxValue" class="int-input" TValue="int" + @bind-Value="@Filter.JoinedLocalMembersLessThan"></InputNumber> + </span> +</div> + +@code { + + [Parameter] + public required SynapseAdminLocalRoomQueryFilter Filter { get; set; } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor.css b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor.css new file mode 100644
index 0000000..83ce426 --- /dev/null +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryFilter.razor.css
@@ -0,0 +1,35 @@ +.int-input { + width: 128px; +} + +.tile { + display: inline-block; + padding: 4px; + border: 1px solid #ffffff22; +} + +.tile280 { + min-width: 280px; +} + +.tile150 { + min-width: 150px; +} + +.range-sep { + display: inline-block; + padding: 4px; + width: 150px; +} + +.range-sep::before { + content: "< "; +} + +.range-sep::after { + content: " <"; +} + +.center-children { + text-align: center; +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryResult.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryResult.razor new file mode 100644
index 0000000..5591072 --- /dev/null +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/RoomQuery/SynapseRoomQueryResult.razor
@@ -0,0 +1,5 @@ +<h3>SynapseRoomQueryResult</h3> + +@code { + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor
index d5daf75..124d073 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/Components/SynapseRoomShutdownWindowContent.razor
@@ -2,35 +2,6 @@ @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Requests @if (string.IsNullOrWhiteSpace(Context.DeleteId)) { - <b>Media options</b> - <br/> - <hr/> - <span>Quarantine local media: </span> - <InputCheckbox @bind-Value="@Context.ExtraOptions.QuarantineLocalMedia"/> - <br/> - <span>Quarantine remote media: </span> - <InputCheckbox @bind-Value="@Context.ExtraOptions.QuarantineRemoteMedia"/> - <br/> - <span>Delete remote media: </span> - <InputCheckbox @bind-Value="@Context.ExtraOptions.DeleteRemoteMedia"/> - <br/> - - <b>User options</b> - <br/> - <hr/> - <span>Suspend local users: </span> - <InputCheckbox @bind-Value="@Context.ExtraOptions.SuspendLocalUsers"></InputCheckbox> - <br/> - <span>Quarantine <b>ALL</b> local user media: </span> - <InputCheckbox @bind-Value="@Context.ExtraOptions.QuarantineLocalUserMedia"></InputCheckbox> - <br/> - <span>Delete <b>ALL</b> local user media: </span> - <InputCheckbox @bind-Value="@Context.ExtraOptions.DeleteLocalUserMedia"></InputCheckbox> - <br/> - - <b>Room deletion options</b> - <br/> - <hr/> <span>Block room: </span> <InputCheckbox @bind-Value="@Context.DeleteRequest.Block"/> <br/> @@ -40,17 +11,43 @@ <span>Force purge room (unsafe): </span> <InputCheckbox @bind-Value="@Context.DeleteRequest.ForcePurge"></InputCheckbox> <br/> - <span>Warning room User ID (optional): </span> - <FancyTextBox @bind-Value="@Context.DeleteRequest.NewRoomUserId"/> - <br/> - @if (!string.IsNullOrWhiteSpace(Context.DeleteRequest.NewRoomUserId)) { + <details> + <summary>Media</summary> + <span>Quarantine local media: </span> + <InputCheckbox @bind-Value="@Context.ExtraOptions.QuarantineLocalMedia"/> + <br/> + <span>Quarantine remote media: </span> + <InputCheckbox @bind-Value="@Context.ExtraOptions.QuarantineRemoteMedia"/> + <br/> + <span>Delete remote media: </span> + <InputCheckbox @bind-Value="@Context.ExtraOptions.DeleteRemoteMedia"/> + </details> + + <details> + <summary>Local users</summary> + <span>Suspend local users: </span> + <InputCheckbox @bind-Value="@Context.ExtraOptions.SuspendLocalUsers"></InputCheckbox> + <br/> + <span>Quarantine <b>ALL</b> local user media: </span> + <InputCheckbox @bind-Value="@Context.ExtraOptions.QuarantineLocalUserMedia"></InputCheckbox> + <br/> + <span>Delete <b>ALL</b> local user media: </span> + <InputCheckbox @bind-Value="@Context.ExtraOptions.DeleteLocalUserMedia"></InputCheckbox> + </details> + + <details> + <summary>Issue warning to local members (optional)</summary> + <b>All fields are required if used!</b><br/> + <span>Warning room User ID: </span> + <FancyTextBox @bind-Value="@Context.DeleteRequest.NewRoomUserId"/> + <br/> <span>Warning room name: </span> <FancyTextBox @bind-Value="@Context.DeleteRequest.RoomName"/> <br/> <span>Warning room message (plaintext): </span> <FancyTextBox Multiline="true" @bind-Value="@Context.DeleteRequest.Message"/> <br/> - } + </details> <LinkButton OnClick="@DeleteRoom">Execute</LinkButton> } @@ -107,7 +104,7 @@ public async Task DeleteRoom() { await TaskMap.SetValueAsync(Context.RoomId, Context); } - + private static readonly SemaphoreSlim OnCompleteLock = new(1, 1); - + } \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor
index 79e7357..5c29909 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor
@@ -2,9 +2,10 @@ @using Microsoft.AspNetCore.WebUtilities @using ArcaneLibs.Extensions @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Filters -@using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Requests @using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Responses @using MatrixUtils.Web.Pages.HSAdmin.Synapse.Components +@using MatrixUtils.Web.Pages.HSAdmin.Synapse.Components.RoomQuery +@inject ILogger<RoomQuery> Logger <h3>Homeserver Administration - Room Query</h3> @@ -21,93 +22,52 @@ <details> <summary> <span>Local filtering (slow)</span> - </summary> - <div style="margin-left: 8px; margin-bottom: 8px;"> - <u style="display: block;">String contains</u> - <span class="tile tile280">Room ID: <FancyTextBox @bind-Value="@Filter.RoomIdContains"></FancyTextBox></span> - <span class="tile tile280">Room name: <FancyTextBox @bind-Value="@Filter.NameContains"></FancyTextBox></span> - <span class="tile tile280">Canonical alias: <FancyTextBox @bind-Value="@Filter.CanonicalAliasContains"></FancyTextBox></span> - <span class="tile tile280">Creator: <FancyTextBox @bind-Value="@Filter.CreatorContains"></FancyTextBox></span> - <span class="tile tile280">Room version: <FancyTextBox @bind-Value="@Filter.VersionContains"></FancyTextBox></span> - <span class="tile tile280">Encryption algorithm: <FancyTextBox @bind-Value="@Filter.EncryptionContains"></FancyTextBox></span> - <span class="tile tile280">Join rules: <FancyTextBox @bind-Value="@Filter.JoinRulesContains"></FancyTextBox></span> - <span class="tile tile280">Guest access: <FancyTextBox @bind-Value="@Filter.GuestAccessContains"></FancyTextBox></span> - <span class="tile tile280">History visibility: <FancyTextBox @bind-Value="@Filter.HistoryVisibilityContains"></FancyTextBox></span> - - <u style="display: block;">Optional checks</u> - <span class="tile tile150"> - <InputCheckbox @bind-Value="@Filter.CheckFederation"></InputCheckbox> Is federated: - @if (Filter.CheckFederation) { - <InputCheckbox @bind-Value="@Filter.Federatable"></InputCheckbox> - } - </span> - <span class="tile tile150"> - <InputCheckbox @bind-Value="@Filter.CheckPublic"></InputCheckbox> Is public: - @if (Filter.CheckPublic) { - <InputCheckbox @bind-Value="@Filter.Public"></InputCheckbox> - } - </span> - - <u style="display: block;">Ranges</u> - <span class="tile center-children"> - <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.StateEventsGreaterThan"></InputNumber><span class="range-sep">state events</span><InputNumber - max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.StateEventsLessThan"></InputNumber> - </span> - <span class="tile center-children"> - <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedMembersGreaterThan"></InputNumber><span class="range-sep">members</span><InputNumber - max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedMembersLessThan"></InputNumber> - </span> - <span class="tile center-children"> - <InputNumber max="@int.MaxValue" class="int-input" TValue="int" @bind-Value="@Filter.JoinedLocalMembersGreaterThan"></InputNumber><span - class="range-sep">local members</span><InputNumber max="@int.MaxValue" class="int-input" TValue="int" - @bind-Value="@Filter.JoinedLocalMembersLessThan"></InputNumber> - </span> - </div> + <SynapseRoomQueryFilter Filter="@Filter"/> </details> <button class="btn btn-primary" @onclick="Search">Search</button> <br/> @if (Results.Count > 0) { <p>Found @Results.Count rooms</p> - <details> - <summary>TSV data (copy/paste)</summary> - <pre style="font-size: 0.6em;"> - <table> - @foreach (var res in Results) { - <tr> - <td style="padding: 8px;">@res.RoomId@("\t")</td> - <td style="padding: 8px;">@res.CanonicalAlias@("\t")</td> - <td style="padding: 8px;">@res.Creator@("\t")</td> - <td style="padding: 8px;">@res.Name</td> - </tr> - } - </table> - </pre> - </details> + @* <details> *@ + @* <summary>TSV data (copy/paste)</summary> *@ + @* <pre style="font-size: 0.6em;"> *@ + @* <table> *@ + @* @foreach (var res in Results) { *@ + @* <tr> *@ + @* <td style="padding: 8px;">@res.RoomId@("\t")</td> *@ + @* <td style="padding: 8px;">@res.CanonicalAlias@("\t")</td> *@ + @* <td style="padding: 8px;">@res.Creator@("\t")</td> *@ + @* <td style="padding: 8px;">@res.Name</td> *@ + @* </tr> *@ + @* } *@ + @* </table> *@ + @* </pre> *@ + @* </details> *@ } @foreach (var res in Results) { - <div style="background-color: #ffffff11; border-radius: 0.5em; display: block; margin-top: 4px; padding: 4px;"> + <div class="room-list-item"> @* <RoomListItem RoomName="@res.Name" RoomId="@res.RoomId"></RoomListItem> *@ <p> @if (!string.IsNullOrWhiteSpace(res.CanonicalAlias)) { - <span>@res.CanonicalAlias - @res.RoomId (@res.Name)</span> - <br/> + <span>@res.CanonicalAlias - </span> } - else { - <span>@res.RoomId (@res.Name)</span> - <br/> + <span>@res.RoomId</span> + @if (!string.IsNullOrWhiteSpace(res.Name)) { + <span> (@res.Name)</span> } + <br/> + @if (!string.IsNullOrWhiteSpace(res.Creator)) { - @* <span>Created by <InlineUserItem UserId="@res.Creator"></InlineUserItem></span> *@ <span>Created by @res.Creator</span> <br/> } </p> <p> <LinkButton OnClick="@(() => { - DeleteRequests.Add(res.RoomId, new() { + DeleteRequests.TryAdd(res.RoomId, new() { RoomId = res.RoomId, DeleteRequest = new() { Block = true, @@ -115,18 +75,65 @@ ForcePurge = false } }); - + StateHasChanged(); + return Task.CompletedTask; })">Delete room </LinkButton> + <LinkButton target="_blank" href="@($"/HSAdmin/Synapse/ResyncState?roomId={res.RoomId}&via={res.RoomId.Split(':', 2)[1]}")">Resync state</LinkButton> </p> - <span>@res.StateEvents state events</span><br/> - @if (res.LocalMembers is null) { - <span>@res.JoinedMembers members, of which @res.JoinedLocalMembers are on this server</span> + + @{ + List<string?> flags = []; + if (res.JoinedLocalMembers > 0) { + flags.Add(res.JoinRules switch { + "public" => "Public", + "invite" => "Invite only", + "knock" => "Knock", + "restricted" => "Restricted", + "knock_restricted" => "Knock + restricted", + // TODO: default? + null => null, + "" => null, + _ => "unknown join rule: " + res.JoinRules + }); + if (!string.IsNullOrWhiteSpace(res.Encryption)) flags.Add("encrypted"); + if (!res.Federatable) flags.Add("unfederated"); + + flags.Add(res.HistoryVisibility switch { + "world_readable" => "world readable history", + "shared" => "shared history", + "invited" => "history since invite", + "joined" => "history since join", + // TODO: default? + null => null, + "" => null, + _ => "unknown history setting: " + res.HistoryVisibility + }); + + flags.Add(res.GuestAccess switch { + "can_join" => "guests allowed", + "forbidden" => null, + // TODO: default? + null => null, + "" => null, + _ => "unknown guest access: " + res.GuestAccess, + }); + + flags = flags.Where(x => x != null).ToList(); + } } - else { - <span>@res.JoinedMembers members, of which @res.JoinedLocalMembers are on this server: @(string.Join(", ", res.LocalMembers))</span> + <span>@string.Join(", ", flags)</span><br/> + + <span>@res.StateEvents state events, room version @(res.Version ?? "1")</span><br/> + + @{ + var memberSummary = $"{res.JoinedMembers} members, of which {res.JoinedLocalMembers} are on this server"; + if (res.LocalMembers is not null) { + memberSummary += $": {string.Join(", ", res.LocalMembers)}"; + } } + <span>@memberSummary</span> <details> <summary>Full result data</summary> <pre>@res.ToJson(ignoreNull: true)</pre> @@ -146,46 +153,14 @@ @* </ModalWindow> *@ @* } *@ -@foreach(var (roomId, deleteRequest) in DeleteRequests) { - <SynapseRoomShutdownWindowContent Context="deleteRequest" Homeserver="Homeserver"/> +@foreach (var (roomId, deleteRequest) in DeleteRequests) { + <ModalWindow Title="@($"Delete room {roomId}")" OnCloseClicked="@(() => { DeleteRequests.Remove(roomId); StateHasChanged(); })"> + <SynapseRoomShutdownWindowContent Context="deleteRequest" Homeserver="Homeserver"/> + </ModalWindow> } <style> - .int-input { - width: 128px; - } - - .tile { - display: inline-block; - padding: 4px; - border: 1px solid #ffffff22; - } - - .tile280 { - min-width: 280px; - } - - .tile150 { - min-width: 150px; - } - - .range-sep { - display: inline-block; - padding: 4px; - width: 150px; - } - - .range-sep::before { - content: "@("<") "; - } - - .range-sep::after { - content: " @("<")"; - } - .center-children { - text-align: center; - } </style> @code { @@ -200,7 +175,7 @@ [Parameter] [SupplyParameterFromQuery(Name = "ascending")] - public bool Ascending { get; set; } + public bool Ascending { get; set; } = true; private List<RoomInfo> Results { get; set; } = new(); @@ -215,8 +190,6 @@ // private Dictionary<string, SynapseAdminRoomDeleteStatus> DeleteStatuses { get; set; } = new(); protected override Task OnParametersSetAsync() { - if (Ascending == null) - Ascending = true; OrderBy ??= "name"; var execute = false; @@ -300,9 +273,6 @@ while (await searchRooms.MoveNextAsync()) { var room = searchRooms.Current; - if (Results.Count < 100) - Console.WriteLine("Hit: " + room.ToJson(false)); - var roomInfo = new RoomInfo { RoomId = room.RoomId, Name = room.Name, @@ -322,14 +292,24 @@ Results.Add(roomInfo); - if (room.JoinedLocalMembers is > 0 and < 100) - roomInfo.LocalMembers = (await synapse.Admin.GetRoomMembersAsync(room.RoomId)).Members.Where(x => x.EndsWith(":" + synapse.ServerName)).ToList(); - - if (Results.Count < 200 || Results.Count % 1000 == 0) { + if ((Results.Count <= 200 && Results.Count % 10 == 0) || Results.Count % 1000 == 0) { StateHasChanged(); await Task.Yield(); + await Task.Delay(1); } } + + StateHasChanged(); + + var tasks = Results + .Where(x => x.JoinedLocalMembers is > 0 and < 100) + .Select(async r => { + var members = (await synapse.Admin.GetRoomMembersAsync(r.RoomId)).Members.Where(x => x.EndsWith(":" + synapse.ServerName)).ToList(); + r.LocalMembers = members; + } + ); + await Task.WhenAll(tasks); + //Logger.LogWarning($"Found {tasks.Count} rooms with >0, <100 local members"); } StateHasChanged(); @@ -416,5 +396,5 @@ private class RoomInfo : SynapseAdminRoomListResult.SynapseAdminRoomListResultRoom { public List<string>? LocalMembers { get; set; } } - + } diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor.css b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor.css
index e69de29..62941e5 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor.css +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor.css
@@ -0,0 +1,7 @@ +.room-list-item { + background-color: #ffffff11; + border-radius: 0.5em; + display: block; + margin-top: 4px; + padding: 4px; +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/HSAdmin/Synapse/SubTools/SynapseRoomStateResync.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/SubTools/SynapseRoomStateResync.razor new file mode 100644
index 0000000..05a4bbc --- /dev/null +++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/SubTools/SynapseRoomStateResync.razor
@@ -0,0 +1,79 @@ +@page "/HSAdmin/Synapse/ResyncState" +@using ArcaneLibs.Extensions +@using LibMatrix.Homeservers.ImplementationDetails.Synapse.Models.Requests + +<h3>Resync room state with other server</h3> +<hr/> +<span>Room ID: </span> +<InputText @bind-Value="@RoomId"></InputText><br/> +<span>Via: </span> +<InputText @bind-Value="@Via"></InputText><br/> +<LinkButton OnClick="@Execute">Execute</LinkButton> + +@if (Executing) { + <p>Execution in progress. DO NOT CLOSE THIS PAGE!</p> + @* stage 1 *@ + @if (Members is null) { + <p>Loading members...</p> + } + else { + <p>Got @Members.Count local members</p> + } + + @* stage 2 *@ + @if (DeleteStatus is not null) { + <p>Purging room, please wait...</p> + <pre>@DeleteStatus.ToJson(ignoreNull: true)</pre> + } + else { + <p>Purging room...</p> + <pre>@DeleteStatus!.ToJson(ignoreNull: true)</pre> + } + + @* stage 3 *@ +} +@if (Done) { + <p>Execution finished. You may now close the page :)</p> +} + + +@code { + + [Parameter] + [SupplyParameterFromQuery] + public string? RoomId { get; set; } + + [Parameter] + [SupplyParameterFromQuery(Name = "via")] + public string? Via { get; set; } + + private bool Executing { get; set; } + private bool Done { get; set; } + + private List<string?>? Members { get; set; } + + private AuthenticatedHomeserverSynapse? Homeserver { get; set; } + private SynapseAdminRoomDeleteStatus? DeleteStatus { get; set; } + + protected override async Task OnInitializedAsync() { + if (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true) is not AuthenticatedHomeserverSynapse hs) return; + Homeserver = hs; + + StateHasChanged(); + } + + private async Task Execute() { + if (string.IsNullOrWhiteSpace(RoomId)) return; + if (string.IsNullOrWhiteSpace(Via)) return; + Executing = true; + StateHasChanged(); + + Members = (await Homeserver.Admin.GetRoomMembersAsync(RoomId)) + .Members.Where(m => m.EndsWith(Homeserver.ServerName)) + .ToList(); + StateHasChanged(); + + + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Rooms/Space.razor b/MatrixUtils.Web/Pages/Rooms/Space.razor
index 46e39ed..86a4c13 100644 --- a/MatrixUtils.Web/Pages/Rooms/Space.razor +++ b/MatrixUtils.Web/Pages/Rooms/Space.razor
@@ -126,7 +126,7 @@ var ce = await room.GetCreateEventAsync(); if(ce is null) continue; if (ce.Type == "m.space") { - var children = room.AsSpace.GetChildrenAsync(false); + var children = room.AsSpace().GetChildrenAsync(false); await foreach (var child in children) { JoinRecursive(child.RoomId); } @@ -142,7 +142,7 @@ private async Task AddNewRoom() { if (string.IsNullOrWhiteSpace(NewRoomId)) return; - await Room.AsSpace.AddChildByIdAsync(NewRoomId); + await Room.AsSpace().AddChildByIdAsync(NewRoomId); } } diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor b/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor
index 736e59a..e407de4 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor
@@ -158,7 +158,7 @@ } public async Task AppendSet(string spaceId, List<GenericRoom> rooms) { - var space = hs.GetRoom(spaceId).AsSpace; + var space = hs.GetRoom(spaceId).AsSpace(); Log.Add($"Found space {spaceId}"); var roomIdsEnum = space.GetChildrenAsync(true); List<Task> tasks = new(); diff --git a/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor b/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor
index ac3c651..5d5ca20 100644 --- a/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor +++ b/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor
@@ -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) { diff --git a/MatrixUtils.Web/Program.cs b/MatrixUtils.Web/Program.cs
index 14cf2fc..57fe03d 100644 --- a/MatrixUtils.Web/Program.cs +++ b/MatrixUtils.Web/Program.cs
@@ -3,6 +3,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using Blazored.LocalStorage; using Blazored.SessionStorage; +using LibMatrix.Extensions; using LibMatrix.Services; using MatrixUtils.Web; using MatrixUtils.Web.Classes; @@ -77,6 +78,8 @@ builder.Services.AddScoped<TieredStorageService>(x => ) ); +MatrixHttpClient.LogRequests = false; + builder.Services.AddRoryLibMatrixServices(); builder.Services.AddScoped<RmuSessionStore>(); // await builder.Build().RunAsync(); diff --git a/MatrixUtils.Web/Shared/RoomListComponents/RoomListSpace.razor b/MatrixUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
index 27f0499..471f586 100644 --- a/MatrixUtils.Web/Shared/RoomListComponents/RoomListSpace.razor +++ b/MatrixUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
@@ -45,7 +45,7 @@ if (Breadcrumbs == null) throw new ArgumentNullException(nameof(Breadcrumbs)); if (Homeserver is null) throw new ArgumentNullException(nameof(Homeserver)); await Task.Delay(Random.Shared.Next(1000, 10000)); - var rooms = Space.Room.AsSpace.GetChildrenAsync(); + var rooms = Space.Room.AsSpace().GetChildrenAsync(); var joinedRooms = await Homeserver.GetJoinedRooms(); await foreach (var room in rooms) { if (Breadcrumbs.Contains(room.RoomId)) continue;