From d105d1a7ec709ddb6240a286bbd7be292a9acd1c Mon Sep 17 00:00:00 2001 From: Rory& Date: Sun, 21 Sep 2025 16:03:44 +0200 Subject: Various fixes --- MatrixUtils.Web/Pages/Tools/Index.razor | 1 + .../Pages/Tools/Room/SpacePermissions.razor | 204 +++++++++++++++++++++ .../Pages/Tools/User/StickerManager.razor | 80 ++++++++ 3 files changed, 285 insertions(+) create mode 100644 MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor create mode 100644 MatrixUtils.Web/Pages/Tools/User/StickerManager.razor (limited to 'MatrixUtils.Web/Pages/Tools') diff --git a/MatrixUtils.Web/Pages/Tools/Index.razor b/MatrixUtils.Web/Pages/Tools/Index.razor index 4a44753..a0abcd4 100644 --- a/MatrixUtils.Web/Pages/Tools/Index.razor +++ b/MatrixUtils.Web/Pages/Tools/Index.razor @@ -12,6 +12,7 @@ Join room across all session
Copy highest powerlevel across all session
View account data
+Manage custom stickers and emojis

Room tools


diff --git a/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor b/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor new file mode 100644 index 0000000..a47d7f5 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor @@ -0,0 +1,204 @@ +@page "/Tools/Room/SpacePermissions" +@using ArcaneLibs.Extensions +@using LibMatrix.EventTypes.Spec.State.RoomInfo +@using LibMatrix.RoomTypes +@using MatrixUtils.Web.Pages.Rooms +

Space Permissions

+
+Space ID: + +Execute +
+ + Auto-recurse into child spaces +
+ +@if (RoomPowerLevels.Count == 0) { +

No data loaded.

+} +else { + Loaded @LoadedSpaceRooms.Count spaces. +
+ @if (SpaceRooms.Count > 0) { +

Load more spaces:

+ @foreach (var room in SpaceRooms) { + @room.Value + } + } + +

By event type:

+ + + + @foreach (var key in OrderedEventTypes) { + + } + + + @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Events!.Values.Average())) { + + + @foreach (var eventType in OrderedEventTypes) { + if (!powerLevels.Events!.ContainsKey(eventType.Key)) { + + continue; + } + + + } + + } + +
Room@key.Key +
+ ~ @Math.Round(key.Value, 2) +
@roomName-@(powerLevels.Events![eventType.Key])
+
+

By user:

+ + + + @foreach (var key in OrderedUsers) { + + } + + + @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Users!.Values.Average())) { + + + @foreach (var eventType in OrderedUsers) { + if (!powerLevels.Users!.ContainsKey(eventType.Key)) { + + continue; + } + + + } + + } + +
Room@key.Key +
+ ~ @Math.Round(key.Value, 2) +
@roomName-@(powerLevels.Users![eventType.Key])
+} + +@code { + + [Parameter, SupplyParameterFromQuery] + public string? SpaceId { get; set; } + + [Parameter, SupplyParameterFromQuery] + public bool AutoRecurseSpaces { get; set; } + + private AuthenticatedHomeserverGeneric? Homeserver { get; set; } + private List AllHomeservers { get; set; } = []; + private Dictionary> JoinedHomeserversByRoom { get; set; } = []; + + private Dictionary RoomPowerLevels { get; set; } = []; + private Dictionary SpaceRooms { get; set; } = []; + private List LoadedSpaceRooms { get; set; } = []; + + private Dictionary OrderedEventTypes { get; set; } = new(); + private Dictionary OrderedUsers { get; set; } = new(); + + protected override async Task OnInitializedAsync() { + if (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true) is not AuthenticatedHomeserverGeneric hs) return; + Homeserver = hs; + await foreach (var server in sessionStore.TryGetAllHomeservers()) { + AllHomeservers.Add(server); + var joinedRooms = await server.GetJoinedRooms(); + foreach (var room in joinedRooms) { + if (!JoinedHomeserversByRoom.ContainsKey(room.RoomId)) { + JoinedHomeserversByRoom[room.RoomId] = []; + } + + JoinedHomeserversByRoom[room.RoomId].Add(room); + } + } + + if (!string.IsNullOrWhiteSpace(SpaceId)) { + await Execute(); + } + } + + private async Task Execute() { + RoomPowerLevels = []; + SpaceRooms = []; + await LoadSpaceAsync(SpaceId); + } + + private async Task GetJoinedRoomAsync(string roomId) { + var room = Homeserver.GetRoom(roomId); + if (await room.IsJoinedAsync()) return room; + + if (JoinedHomeserversByRoom.TryGetValue(roomId, out var rooms)) { + foreach (var r in rooms) { + if (await r.IsJoinedAsync()) return r; + } + } + + foreach (var hs in AllHomeservers) { + if (hs == Homeserver) continue; + room = hs.GetRoom(roomId); + if (await room.IsJoinedAsync()) return room; + } + + Console.WriteLine($"Not joined to room {roomId} on any known homeserver."); + return room; // not null, in case we can preview the room + } + + private async Task LoadSpaceAsync(string spaceId) { + LoadedSpaceRooms.Add(spaceId); + SpaceRooms.Remove(spaceId); + + var space = (await GetJoinedRoomAsync(spaceId)).AsSpace(); + RoomPowerLevels[await space.GetNameOrFallbackAsync()] = AddFakeEvents(await space.GetPowerLevelsAsync()); + var children = space.GetChildrenAsync(); + await foreach (var childRoom in children) { + var child = await GetJoinedRoomAsync(childRoom.RoomId); + try { + var powerlevels = await child.GetPowerLevelsAsync(); + RoomPowerLevels[await child.GetNameOrFallbackAsync()] = AddFakeEvents(powerlevels!); + if (await child.GetRoomType() == SpaceRoom.TypeName) { + if (AutoRecurseSpaces) + await LoadSpaceAsync(child.RoomId); + else + SpaceRooms.Add(child.RoomId, await child.GetNameOrFallbackAsync()); + } + + OrderedEventTypes = RoomPowerLevels + .SelectMany(x => x.Value.Events!) + .GroupBy(x => x.Key) + .ToDictionary(x => x.Key, x => x.Average(y => y.Value)) + .OrderByDescending(x => x.Value) + .ToDictionary(x => x.Key, x => x.Value); + + OrderedUsers = RoomPowerLevels + .SelectMany(x => x.Value.Users!) + .GroupBy(x => x.Key) + .ToDictionary(x => x.Key, x => x.Average(y => y.Value)) + .OrderByDescending(x => x.Value) + .ToDictionary(x => x.Key, x => x.Value); + StateHasChanged(); + } + catch (Exception ex) { + Console.WriteLine($"Failed to get power levels for room {child.RoomId}: {ex}"); + } + } + } + + private RoomPowerLevelEventContent AddFakeEvents(RoomPowerLevelEventContent powerlevels) { + powerlevels.Events ??= []; + powerlevels.Events["[user_default]"] = powerlevels.UsersDefault ?? 0; + powerlevels.Events["[event_default]"] = powerlevels.EventsDefault ?? 0; + powerlevels.Events["[state_default]"] = powerlevels.StateDefault ?? 100; + powerlevels.Events["[ban]"] = powerlevels.Ban ?? 100; + powerlevels.Events["[invite]"] = powerlevels.Invite ?? 100; + powerlevels.Events["[kick]"] = powerlevels.Kick ?? 100; + powerlevels.Events["[ping_room]"] = powerlevels.NotificationsPl?.Room ?? 100; + powerlevels.Events["[redact]"] = powerlevels.Redact ?? 100; + return powerlevels; + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/User/StickerManager.razor b/MatrixUtils.Web/Pages/Tools/User/StickerManager.razor new file mode 100644 index 0000000..984130f --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/User/StickerManager.razor @@ -0,0 +1,80 @@ +@page "/Tools/User/StickerManager" +@using System.Diagnostics +@using ArcaneLibs.Extensions +@using LibMatrix.EventTypes.Common +@using LibMatrix.EventTypes.Spec +@inject ILogger Logger +

Sticker/emoji manager

+ +@if (TotalStepsProgress is not null) { + +
+} +@if (_observableProgressState is not null) { + +
+} + +@code { + + private AuthenticatedHomeserverGeneric Homeserver { get; set; } = null!; + private Msc2545EmoteRoomsAccountDataEventContent? EnabledEmoteRooms { get; set; } + private Dictionary StickerRooms { get; set; } = []; + + private SimpleProgressIndicator.ObservableProgressState? _observableProgressState; + + private SimpleProgressIndicator.ObservableProgressState? TotalStepsProgress { get; set; } = new() { + Label = "Authenticating with Matrix...", + Max = 2, + Value = 0 + }; + + protected override async Task OnInitializedAsync() { + if (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true) is not { } hs) + return; + Homeserver = hs; + TotalStepsProgress?.Next("Fetching enabled emote packs..."); + _ = hs.GetAccountDataOrNullAsync(Msc2545EmoteRoomsAccountDataEventContent.EventId) + .ContinueWith(r => { + EnabledEmoteRooms = r.Result; + StateHasChanged(); + }); + + TotalStepsProgress?.Next("Getting joined rooms..."); + _observableProgressState = new() { + Label = "Loading rooms...", + Max = 1, + Value = 0 + }; + var rooms = await hs.GetJoinedRooms(); + _observableProgressState.Max.Value = rooms.Count; + StateHasChanged(); + + var ss = new SemaphoreSlim(32, 32); + var ss1 = new SemaphoreSlim(1, 1); + var roomScanTasks = rooms.Select(async room => { + // await Task.Delay(Random.Shared.Next(100, 1000 + (rooms.Count * 100))); + // await ss.WaitAsync(); + var state = await room.GetFullStateAsListAsync(); + StickerRoom sr = new(); + foreach (var evt in state) { + if (evt.Type == RoomEmotesEventContent.EventId) { } + } + + // ss.Release(); + // await ss1.WaitAsync(); + Console.WriteLine("Got state for room " + room.RoomId); + // _observableProgressState.Next($"Got state for room {room.RoomId}"); + // await Task.Delay(1); + // ss1.Release(); + return room.RoomId; + }) + .ToList(); + await foreach (var roomScanResult in roomScanTasks.ToAsyncEnumerable()) { + _observableProgressState.Label.Value = roomScanResult; + } + } + + private class StickerRoom { } + +} \ No newline at end of file -- cgit 1.5.1