about summary refs log tree commit diff
path: root/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor
diff options
context:
space:
mode:
Diffstat (limited to 'MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor')
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor194
1 files changed, 194 insertions, 0 deletions
diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor b/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor
new file mode 100644
index 0000000..915f8dc
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor
@@ -0,0 +1,194 @@
+@page "/Tools/Moderation/UserTrace"
+@using ArcaneLibs.Extensions
+@using LibMatrix.RoomTypes
+@using System.Collections.ObjectModel
+@using LibMatrix
+<h3>User Trace</h3>
+<hr/>
+
+<p>Users: </p>
+<InputTextArea @bind-Value="@UserIdString"></InputTextArea>
+<br/>
+<InputText @bind-Value="@ImportFromRoomId"></InputText><LinkButton OnClick="@DoImportFromRoomId">Import from room (ID)</LinkButton>
+
+<details>
+    <summary>Rooms to be searched (@rooms.Count)</summary>
+    @foreach (var room in rooms) {
+        <span>@room.RoomId</span>
+        <br/>
+    }
+</details>
+<br/>
+<LinkButton OnClick="Execute">Execute</LinkButton>
+<br/>
+
+<details>
+    <summary>Results</summary>
+    @foreach (var (userId, events) in matches) {
+        <h4>@userId</h4>
+        <ul>
+            @foreach (var match in events) {
+                <li>
+                    <ul>
+                        <li>@match.RoomName (<span>@match.Room.RoomId</span>)</li>
+                        <li>Membership: @(match.Event.RawContent.ToJson(indent: false))</li>
+                    </ul>
+                </li>
+            }
+        </ul>
+    }
+</details>
+
+<br/>
+@foreach (var line in log.Reverse()) {
+    <pre>@line</pre>
+}
+
+@code {
+
+    private ObservableCollection<string> log { get; set; } = new();
+
+    // List<RoomInfo> rooms { get; set; } = new();
+    List<GenericRoom> rooms { get; set; } = [];
+    Dictionary<string, List<Match>> 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<string> UserIDs { get; set; } = new();
+
+    protected override async Task OnInitializedAsync() {
+        log.CollectionChanged += (sender, args) => StateHasChanged();
+        var hs = await RMUStorage.GetCurrentSessionOrNavigate();
+        if (hs is null) return;
+        // var sessions = await RMUStorage.GetAllTokens();
+        // var baseRooms = new List<GenericRoom>();
+        // foreach (var userAuth in sessions) {
+        //     var session = await RMUStorage.GetSession(userAuth);
+        //     if (session is not null) {
+        //         baseRooms.AddRange(await session.GetJoinedRooms());
+        //         var sessionRooms = (await session.GetJoinedRooms()).Where(x => !rooms.Any(y => y.Room.RoomId == x.RoomId)).ToList();
+        //         StateHasChanged();
+        //         log.Add($"Got {sessionRooms.Count} rooms for {userAuth.UserId}");
+        //     }
+        // }
+        //
+        // log.Add("Done fetching rooms!");
+        //
+        // baseRooms = baseRooms.DistinctBy(x => x.RoomId).ToList();
+        //
+        // // rooms.CollectionChanged += (sender, args) => StateHasChanged();
+        // var tasks = baseRooms.Select(async newRoom => {
+        //     bool success = false;
+        //     while (!success)
+        //         try {
+        //             var state = await newRoom.GetFullStateAsListAsync();
+        //             var newRoomInfo = new RoomInfo(newRoom, state);
+        //             rooms.Add(newRoomInfo);
+        //             log.Add($"Got {newRoomInfo.StateEvents.Count} events for {newRoomInfo.RoomName}");
+        //             success = true;
+        //         }
+        //         catch (MatrixException e) {
+        //             log.Add($"Failed to fetch room {newRoom.RoomId}! {e}");
+        //             throw;
+        //         }
+        //         catch (HttpRequestException e) {
+        //             log.Add($"Failed to fetch room {newRoom.RoomId}! {e}");
+        //         }
+        // });
+        // await Task.WhenAll(tasks);
+        //
+        // log.Add($"Done fetching members!");
+        //
+        // UserIDs.RemoveAll(x => sessions.Any(y => y.UserId == x));
+
+        foreach (var session in await RMUStorage.GetAllTokens()) {
+            var _hs = await RMUStorage.GetSession(session);
+            if (_hs is not null) {
+                rooms.AddRange(await _hs.GetJoinedRooms());
+                log.Add($"Got {rooms.Count} rooms after adding {_hs.UserId}");
+            }
+        }
+
+        //get distinct rooms evenly distributed per session, accounting for count per session
+        rooms = rooms.OrderBy(x => rooms.Count(y => y.Homeserver == x.Homeserver)).DistinctBy(x => x.RoomId).ToList();
+        log.Add($"Got {rooms.Count} rooms");
+
+        StateHasChanged();
+        Console.WriteLine("Rerendered!");
+        await base.OnInitializedAsync();
+    }
+
+    private async Task<string> Execute() {
+        foreach (var userId in UserIDs) {
+            matches.Add(userId, new List<Match>());
+
+            // foreach (var room in rooms) {
+            //     var state = room.StateEvents.Where(x => x!.Type == RoomMemberEventContent.EventId).ToList();
+            //     if (state!.Any(x => x.StateKey == userId)) {
+            //         matches[userId].Add(new() {
+            //             Event = state.First(x => x.StateKey == userId),
+            //             Room = room.Room,
+            //             RoomName = room.RoomName ?? "No name"
+            //         });
+            //     }
+            // }
+
+            log.Add($"Searching for {userId}...");
+            await foreach (var match in GetMatches(userId)) {
+                matches[userId].Add(match);
+            }
+        }
+
+        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<Match> 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;
+            }
+        }
+    }
+
+}
\ No newline at end of file