@using LibMatrix.EventTypes.Spec.State.Policy @using System.Reflection @using ArcaneLibs.Attributes @using LibMatrix @using System.Collections.Frozen @using LibMatrix.EventTypes @using LibMatrix.RoomTypes Policy type:
Reason:
Recommendation:
Entities:

@*
*@ @* JSON data *@ @*
 *@
    @*             $1$ @PolicyEvent.ToJson(true, true) #1# *@
    @*     
*@ @*
*@ @if (!VerifyIntent) { Cancel Save @if (!string.IsNullOrWhiteSpace(Response)) {
@Response
} } else { WARNING!!!
@if (!string.IsNullOrWhiteSpace(Response)) {
@Response
} Are you sure you want to do this? No Yes }
@code { [Parameter] public required Action OnClose { get; set; } [Parameter] public required Action OnSaved { get; set; } [Parameter] public required GenericRoom Room { 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 KnownPolicyTypes = MatrixEvent.KnownEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent))).ToFrozenSet(); private static Dictionary PolicyTypes = KnownPolicyTypes .ToDictionary(x => x.GetCustomAttributes().First(y => !string.IsNullOrWhiteSpace(y.EventName)).EventName, x => x); private static FrozenSet AllKnownPolicyTypes = KnownPolicyTypes .SelectMany(x => x.GetCustomAttributes().Select(y => y.EventName)) .ToFrozenSet(); private string? MappedType { get; set; } private async Task Save(bool force = false) { if (string.IsNullOrWhiteSpace(MappedType)) { Response = "No type selected"; return; } if (string.IsNullOrWhiteSpace(Entities)) { Response = "No users selected"; return; } Console.WriteLine("Saving ---"); var entities = Entities.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Select(x => x.Trim()) .Distinct() .ToList(); if (!force && !Validate(entities, PolicyTypes[MappedType])) { List 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 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 TypesBySigil = new() { { "@", typeof(UserPolicyRuleEventContent) }, { "!", typeof(RoomPolicyRuleEventContent) }, { "#", typeof(RoomPolicyRuleEventContent) } }; private async Task SaveAll(List 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 && entities.Contains(content.Entity)) entities.Remove(content.Entity); } } // var tasks = entities.Select(x => ExecuteBan(Room, x)).ToList(); // await Task.WhenAll(tasks); var events = entities.Select(entity => { 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; return new MatrixEvent() { Type = MappedType, TypedContent = content, StateKey = content.GetDraupnir2StateKey() }; }); foreach (var chunk in events.Chunk(50)) await Room.BulkSendEventsAsync(chunk); OnSaved.Invoke(); } private async Task ExecuteBan(GenericRoom room, string entity) { bool success = false; while (!success) { try { 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; await room.SendStateEventAsync(MappedType!, content.GetDraupnir2StateKey(), content); success = true; } catch (MatrixException e) { if (e is not { ErrorCode: MatrixException.ErrorCodes.M_FORBIDDEN }) throw; Console.WriteLine(e); } catch (Exception e) { //ignored Console.WriteLine(e); } } } }