@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 match in events) {
-
- @match.RoomName (@match.Room.RoomId)
- Membership: @(match.Event.RawContent.ToJson(indent: false)) (sent by @match.Event.Sender)
}
}
@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;
}
}