From 4601c2f1fcdaf551705a9da3c5e6ddfc3eff9138 Mon Sep 17 00:00:00 2001 From: Rory& Date: Fri, 22 Nov 2024 06:42:27 +0100 Subject: Some fixes all over, policy list work --- .../Pages/Tools/Moderation/FindUsersByRegex.razor | 193 +++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor (limited to 'MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor') diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor b/MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor new file mode 100644 index 0000000..2d78f4e --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor @@ -0,0 +1,193 @@ +@page "/Tools/Moderation/FindUsersByRegex" +@using System.Collections.Frozen +@using ArcaneLibs.Extensions +@using LibMatrix.RoomTypes +@using System.Collections.ObjectModel +@using System.Text.RegularExpressions +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Filters +@using LibMatrix.Helpers +@using LibMatrix.Utilities +

Find users by regex

+
+ +

Users (regex):

+ + +Execute +
+Remove kicks +Remove bans +
+ + +
+ Results + @foreach (var (userId, events) in matches) { +

@userId

+ + } +
+ +
+@foreach (var line in log.Reverse()) { +
@line
+} + +@code { + + private ObservableCollection log { get; set; } = new(); + + // List rooms { get; set; } = new(); + List rooms { get; set; } = []; + Dictionary> matches = new(); + + private string UserIdString { + get => string.Join("\n", UserIDs); + set => UserIDs = value.Split("\n").Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); + } + + private List UserIDs { get; set; } = new(); + + private AuthenticatedHomeserverGeneric hs { get; set; } + + protected override async Task OnInitializedAsync() { + log.CollectionChanged += (sender, args) => StateHasChanged(); + log.Add("Authenticating"); + hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + log.Add("Constructing sync helper..."); + var sh = new SyncHelper(hs) { + Filter = new SyncFilter() { + AccountData = new(types: []), + Presence = new(types: []), + Room = new() { + AccountData = new(types: []), + Ephemeral = new(types: []), + State = new(types: [RoomMemberEventContent.EventId]), + Timeline = new(types: []), + IncludeLeave = false + }, + } + }; + + log.Add("Starting sync..."); + var res = await sh.SyncAsync(); + + log.Add("Got sync response, parsing..."); + + var roomNames = (await Task.WhenAll((await hs.GetJoinedRooms()).Select(async room => { return (room.RoomId, await room.GetNameOrFallbackAsync()); }).ToList())).ToFrozenDictionary(x => x.Item1, x => x.Item2); + + foreach (var userIdRegex in UserIDs) { + var regex = new Regex(userIdRegex, RegexOptions.Compiled); + log.Add($"Searching for {regex}:"); + foreach (var (roomId, joinedRoom) in res.Rooms.Join) { + log.Add($"- Checking room {roomId}..."); + foreach (var evt in joinedRoom.State.Events) { + if (evt.StateKey is null) continue; + if (evt.Type is not RoomMemberEventContent.EventId) continue; + + if (regex.IsMatch(evt.StateKey)) { + log.Add($" - Found match in {roomId} for {evt.StateKey}"); + if (!matches.ContainsKey(evt.StateKey)) { + matches[evt.StateKey] = new(); + } + + var room = hs.GetRoom(roomId); + matches[evt.StateKey].Add(new Match { + Room = room, + Event = evt, + RoomName = roomNames[roomId] + }); + } + } + } + } + + log.Add("Done!"); + + StateHasChanged(); + + return ""; + } + + public string? ImportFromRoomId { get; set; } + + private async Task DoImportFromRoomId() { + try { + if (ImportFromRoomId is null) return; + var room = rooms.FirstOrDefault(x => x.RoomId == ImportFromRoomId); + UserIdString = string.Join("\n", (await room.GetMembersListAsync()).Select(x => x.StateKey)); + } + catch (Exception e) { + Console.WriteLine(e); + log.Add("Could not fetch members list!\n" + e.ToString()); + } + + StateHasChanged(); + } + + private class Match { + public GenericRoom Room; + public StateEventResponse Event; + public string RoomName { get; set; } + } + + private async IAsyncEnumerable GetMatches(string userId) { + var results = rooms.Select(async room => { + var state = await room.GetStateEventOrNullAsync(room.RoomId, userId); + if (state is not null) { + return new Match { + Room = room, + Event = state, + RoomName = await room.GetNameOrFallbackAsync() + }; + } + + return null; + }).ToAsyncEnumerable(); + await foreach (var result in results) { + if (result is not null) { + yield return result; + } + } + } + + private Task RemoveKicks() { + foreach (var (userId, matches) in matches) { + matches.RemoveAll(x => x.Event.ContentAs()!.Membership == "leave" && x.Event.Sender != x.Event.StateKey); + } + + matches.RemoveAll((x, y) => y.Count == 0); + StateHasChanged(); + return Task.CompletedTask; + } + + private Task RemoveBans() { + foreach (var (userId, matches) in matches) { + matches.RemoveAll(x => x.Event.ContentAs()!.Membership == "ban" && x.Event.Sender != x.Event.StateKey); + } + + matches.RemoveAll((x, y) => y.Count == 0); + StateHasChanged(); + return Task.CompletedTask; + } + +} \ No newline at end of file -- cgit 1.5.1