about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-05-15 08:18:38 +0200
committerRory& <root@rory.gay>2025-05-16 14:51:47 +0200
commit5839b404416b59b271793858777a01a2eed401f6 (patch)
tree5adcdf3f9e7a3d2bd273016d92301b52cf9c1231
parentUpdate LibMatrix (diff)
downloadMatrixUtils-dev/synapse-resync-state.tar.xz
Clean up later... dev/synapse-resync-state
-rw-r--r--.idea/.idea.MatrixUtils/.idea/indexLayout.xml1
m---------LibMatrix0
-rw-r--r--MatrixUtils.Web.Server/Program.cs6
-rw-r--r--MatrixUtils.Web/Pages/Rooms/PolicyList.razor11
-rw-r--r--MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor140
-rw-r--r--MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor.css15
-rw-r--r--MatrixUtils.Web/wwwroot/index.html10
-rw-r--r--MatrixUtils.sln12
8 files changed, 145 insertions, 50 deletions
diff --git a/.idea/.idea.MatrixUtils/.idea/indexLayout.xml b/.idea/.idea.MatrixUtils/.idea/indexLayout.xml

index d166ec4..4520708 100644 --- a/.idea/.idea.MatrixUtils/.idea/indexLayout.xml +++ b/.idea/.idea.MatrixUtils/.idea/indexLayout.xml
@@ -2,7 +2,6 @@ <project version="4"> <component name="UserContentModel"> <attachedFolders> - <Path>LibMatrix/LibMatrix/Homeservers</Path> <Path>MatrixRoomUtils.Bot/bot_data</Path> <Path>MatrixRoomUtils.Desktop/bin/Debug/net7.0/mru-desktop</Path> </attachedFolders> diff --git a/LibMatrix b/LibMatrix -Subproject dae1a25664606415e054f3e3b20bbbfabdbb0e9 +Subproject e16e9f3093fab575f5f9323248e7b19fa6d5456 diff --git a/MatrixUtils.Web.Server/Program.cs b/MatrixUtils.Web.Server/Program.cs
index cad3878..59d450a 100644 --- a/MatrixUtils.Web.Server/Program.cs +++ b/MatrixUtils.Web.Server/Program.cs
@@ -1,3 +1,6 @@ +using LibMatrix.Services; +using MatrixUtils.Web.Classes; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. @@ -5,6 +8,9 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); +builder.Services.AddRoryLibMatrixServices(); +builder.Services.AddScoped<RmuSessionStore>(); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor
index b908e57..5f70187 100644 --- a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor +++ b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor
@@ -58,7 +58,11 @@ else { Console.WriteLine($"Rendered header in {renderSw.GetElapsedAndRestart()}"); - @foreach (var type in KnownPolicyTypes.Where(t => GetPolicyEventsByType(t).Count > 0).OrderByDescending(t => GetPolicyEventsByType(t).Count)) { + var renderSw2 = Stopwatch.StartNew(); + IOrderedEnumerable<Type> policiesByType = KnownPolicyTypes.Where(t => GetPolicyEventsByType(t).Count > 0).OrderByDescending(t => GetPolicyEventsByType(t).Count); + Console.WriteLine($"Ordered policy types by count in {renderSw2.GetElapsedAndRestart()}"); + + foreach (var type in policiesByType) { <details> <summary> <span> @@ -68,6 +72,7 @@ else { </summary> <table class="table table-striped table-hover"> @{ + var renderSw3 = Stopwatch.StartNew(); var policies = GetValidPolicyEventsByType(type); var invalidPolicies = GetInvalidPolicyEventsByType(type); // enumerate all properties with friendly name @@ -81,6 +86,7 @@ else { .Where(x => props.Any(y => y.Name == x.Name)) .ToFrozenSet(); Console.WriteLine($"{proxySafeProps?.Count} proxy safe props found in {policies.FirstOrDefault()?.TypedContent?.GetType()}"); + Console.WriteLine($"Filtered policies and got properties in {renderSw3.GetElapsedAndRestart()}"); } <thead> <tr> @@ -125,7 +131,8 @@ else { </LinkButton> @if (CurrentUserIsDraupnir) { <LinkButton Color="@(ActiveKicks.ContainsKey(policy) ? "#FF0000" : null)" OnClick="@(() => DraupnirKickMatching(policy))">Kick - users @(ActiveKicks.ContainsKey(policy) ? $"({ActiveKicks[policy]})" : null)</LinkButton> + users @(ActiveKicks.TryGetValue(policy, out var kick) ? $"({kick})" : null) + </LinkButton> } } } diff --git a/MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor b/MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor
index 4ab899c..f7bb200 100644 --- a/MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor +++ b/MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor
@@ -25,7 +25,7 @@ <br/> <span>Entities:</span><br/> - <InputTextArea @bind-Value="@Users" style="width: 500px;"></InputTextArea> + <FancyTextBox Multiline="true" @bind-Value="@Entities"></FancyTextBox> <br/> @@ -35,16 +35,43 @@ @* $1$ @PolicyEvent.ToJson(true, true) #1# *@ @* </pre> *@ @* </details> *@ - <LinkButton OnClick="@(() => { - OnClose.Invoke(); - return Task.CompletedTask; - })"> Cancel - </LinkButton> - <LinkButton OnClick="@(() => { - _ = Save(); - return Task.CompletedTask; - })"> Save - </LinkButton> + @if (!VerifyIntent) { + <LinkButton OnClick="@(() => { + OnClose.Invoke(); + return Task.CompletedTask; + })"> Cancel + </LinkButton> + <LinkButton OnClick="@(() => { + _ = Save(); + return Task.CompletedTask; + })"> Save + </LinkButton> + @if (!string.IsNullOrWhiteSpace(Response)) { + <pre style="color: red;">@Response</pre> + } + } + else { + <b class="blink">WARNING!!!</b> + <br/> + + @if (!string.IsNullOrWhiteSpace(Response)) { + <pre style="color: red;">@Response</pre> + } + + <span>Are you sure you want to do this?</span> + <LinkButton Color="#00FF00" OnClick="@(() => { + VerifyIntent = false; + Response = null; + StateHasChanged(); + return Task.CompletedTask; + })">No + </LinkButton> + <LinkButton Color="#FF0000" OnClick="@(() => { + _ = Save(force: true); + return Task.CompletedTask; + })"> Yes + </LinkButton> + } </ModalWindow> @@ -59,9 +86,20 @@ [Parameter] public required GenericRoom Room { get; set; } - public string Recommendation { get; set; } = "m.ban"; - public string Reason { get; set; } = "spam"; - public string Users { get; set; } = ""; + private string Recommendation { get; set; } = "m.ban"; + private string Reason { get; set; } = "spam"; + + private string Entities { get; set; } = ""; + + private string? Response { + get; + set { + field = value; + StateHasChanged(); + } + } + + private bool VerifyIntent { get; set; } private static FrozenSet<Type> KnownPolicyTypes = StateEvent.KnownStateEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent))).ToFrozenSet(); @@ -74,47 +112,75 @@ private string? MappedType { get; set; } - private async Task Save() { - try { - await DoActualSave(); - } - catch (Exception e) { - Console.WriteLine($"Failed to save: {e}"); - } - } - - private async Task DoActualSave() { + private async Task Save(bool force = false) { if (string.IsNullOrWhiteSpace(MappedType)) { - Console.WriteLine("No type selected"); + Response = "No type selected"; return; } - if (string.IsNullOrWhiteSpace(Users)) { - Console.WriteLine("No users selected"); + if (string.IsNullOrWhiteSpace(Entities)) { + Response = "No users selected"; return; } - Console.WriteLine($"Saving ---"); - Console.WriteLine($"Users = {Users}"); + Console.WriteLine("Saving ---"); - var users = Users.Split("\n") + var entities = Entities.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Select(x => x.Trim()) - .Where(x => x.StartsWith('@')) .Distinct() .ToList(); + + if (!force && !Validate(entities, PolicyTypes[MappedType])) { + List<string> distinctTypes = entities + .Select(GuessType) + .Where(x => x != null) + .Distinct() + .Select(x => x!.Name) + .ToList(); + + VerifyIntent = true; + Response = $"Invalid entities. Expected {PolicyTypes[MappedType].Name}, got:\n - " + + string.Join("\n - ", distinctTypes); + return; + } + + try { + await SaveAll(entities); + } + catch (Exception e) { + Response = $"Failed to save: {e}"; + } + } + + private bool Validate(List<string> entities, Type expectedType) { + return entities.All(x => GuessType(x) == expectedType); + } + + private Type? GuessType(string entity) { + var sigil = entity[0]; + return TypesBySigil.GetValueOrDefault(sigil.ToString(), typeof(ServerPolicyRuleEventContent)); + } + + private Dictionary<string, Type> TypesBySigil = new() { + { "@", typeof(UserPolicyRuleEventContent) }, + { "!", typeof(RoomPolicyRuleEventContent) }, + { "#", typeof(RoomPolicyRuleEventContent) } + }; + + private async Task SaveAll(List<string> entities) { await foreach (var evt in Room.GetFullStateAsync()) { if (evt is null || !AllKnownPolicyTypes.Contains(evt.Type) || !evt.TypedContent!.GetType().IsAssignableTo(PolicyTypes[MappedType!]) ) continue; - + if (evt.TypedContent is PolicyRuleEventContent content && content.Recommendation == Recommendation && content.Reason == Reason) { - if (content.Entity != null && users.Contains(content.Entity)) - users.Remove(content.Entity); + if (content.Entity != null && entities.Contains(content.Entity)) + entities.Remove(content.Entity); } } - - var tasks = users.Select(x => ExecuteBan(Room, x)).ToList(); + + var tasks = entities.Select(x => ExecuteBan(Room, x)).ToList(); await Task.WhenAll(tasks); OnSaved.Invoke(); @@ -124,7 +190,7 @@ bool success = false; while (!success) { try { - var content = Activator.CreateInstance(PolicyTypes[MappedType!]) as PolicyRuleEventContent; + var content = Activator.CreateInstance(PolicyTypes[MappedType!]) as PolicyRuleEventContent ?? throw new InvalidOperationException("Failed to create event content"); content.Recommendation = Recommendation; content.Reason = Reason; content.Entity = entity; diff --git a/MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor.css b/MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor.css new file mode 100644
index 0000000..49ab31b --- /dev/null +++ b/MatrixUtils.Web/Shared/PolicyEditorComponents/MassPolicyEditorModal.razor.css
@@ -0,0 +1,15 @@ +.blink { + animation: blinker 2s linear infinite; +} + +@keyframes blinker { + 0% { + opacity: 1; + } + 50% { + opacity: 0; + } + 100% { + opacity: 1; + } +} \ No newline at end of file diff --git a/MatrixUtils.Web/wwwroot/index.html b/MatrixUtils.Web/wwwroot/index.html
index 7425de2..f25d549 100644 --- a/MatrixUtils.Web/wwwroot/index.html +++ b/MatrixUtils.Web/wwwroot/index.html
@@ -29,16 +29,6 @@ <a class="dismiss">🗙</a> </div> <script> - function BlazorFocusElement(element) { - if (element == null) return; - if (element instanceof HTMLElement) { - console.log(element); - element.focus(); - } else if (element.hasOwnProperty("__internalId")) { - console.log("Element is not an HTMLElement", element); - } - } - function getWidth(element) { console.log("getWidth", element); if (element == null) return 0; diff --git a/MatrixUtils.sln b/MatrixUtils.sln
index 5fb0c1f..6b33671 100644 --- a/MatrixUtils.sln +++ b/MatrixUtils.sln
@@ -67,6 +67,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MxApiExtensions", "MxApiExt EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{CEECE820-1BA9-4E29-8668-25967B3E712B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixUtils.Web.Ssr", "MatrixUtils.Web.Ssr\MatrixUtils.Web.Ssr\MatrixUtils.Web.Ssr.csproj", "{35F510FD-98FC-4760-A53B-9176A53A33A2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixUtils.Web.Ssr.Client", "MatrixUtils.Web.Ssr\MatrixUtils.Web.Ssr.Client\MatrixUtils.Web.Ssr.Client.csproj", "{335DB9D5-FEEE-45E3-B76A-057D8BB48412}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -185,6 +189,14 @@ Global {CEECE820-1BA9-4E29-8668-25967B3E712B}.Debug|Any CPU.Build.0 = Debug|Any CPU {CEECE820-1BA9-4E29-8668-25967B3E712B}.Release|Any CPU.ActiveCfg = Release|Any CPU {CEECE820-1BA9-4E29-8668-25967B3E712B}.Release|Any CPU.Build.0 = Release|Any CPU + {35F510FD-98FC-4760-A53B-9176A53A33A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35F510FD-98FC-4760-A53B-9176A53A33A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35F510FD-98FC-4760-A53B-9176A53A33A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35F510FD-98FC-4760-A53B-9176A53A33A2}.Release|Any CPU.Build.0 = Release|Any CPU + {335DB9D5-FEEE-45E3-B76A-057D8BB48412}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {335DB9D5-FEEE-45E3-B76A-057D8BB48412}.Debug|Any CPU.Build.0 = Debug|Any CPU + {335DB9D5-FEEE-45E3-B76A-057D8BB48412}.Release|Any CPU.ActiveCfg = Release|Any CPU + {335DB9D5-FEEE-45E3-B76A-057D8BB48412}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {84BE90C4-2FDE-4A48-B154-58926EF24846} = {933DC8A6-8B1F-46BF-9046-4B636AA46469}