From 83e6d98d2d7586fb518ed1b2097c59ea9b8af223 Mon Sep 17 00:00:00 2001 From: Rory& Date: Wed, 31 Jan 2024 12:10:03 +0100 Subject: New tools, fix room list items --- LibMatrix | 2 +- MatrixUtils.Abstractions/RoomInfo.cs | 111 ++++++++---- .../Moderation/DraupnirProtectedRoomsEditor.razor | 97 ++++++++++ .../Pages/Moderation/UserRoomHistory.razor | 115 ++++++++++++ .../ModerationUtilities/UserRoomHistory.razor | 115 ------------ MatrixUtils.Web/Pages/Rooms/Index.razor | 80 +++------ MatrixUtils.Web/Pages/Rooms/PolicyList.razor | 1 + MatrixUtils.Web/Pages/Rooms/Space.razor | 7 +- .../Pages/Tools/RoomIntersections.razor | 199 +++++++++++++++++++++ MatrixUtils.Web/Pages/Tools/SessionCount.razor | 155 ++++++++++++++++ MatrixUtils.Web/Pages/Tools/SpaceDebug.razor | 22 +-- MatrixUtils.Web/Pages/Tools/UserTrace.razor | 139 ++++++++++++++ MatrixUtils.Web/Pages/Tools/ViewAccountData.razor | 30 ++++ MatrixUtils.Web/Pages/User/Profile.razor | 56 +++++- .../PolicyEditorComponents/PolicyEditorModal.razor | 120 ++++++++----- .../RoomListComponents/RoomListCategory.razor | 2 +- MatrixUtils.Web/Shared/RoomListItem.razor | 125 +++++++------ 17 files changed, 1042 insertions(+), 334 deletions(-) create mode 100644 MatrixUtils.Web/Pages/Moderation/DraupnirProtectedRoomsEditor.razor create mode 100644 MatrixUtils.Web/Pages/Moderation/UserRoomHistory.razor delete mode 100644 MatrixUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor create mode 100644 MatrixUtils.Web/Pages/Tools/RoomIntersections.razor create mode 100644 MatrixUtils.Web/Pages/Tools/SessionCount.razor create mode 100644 MatrixUtils.Web/Pages/Tools/UserTrace.razor create mode 100644 MatrixUtils.Web/Pages/Tools/ViewAccountData.razor diff --git a/LibMatrix b/LibMatrix index b7dbc01..9f8d0c8 160000 --- a/LibMatrix +++ b/LibMatrix @@ -1 +1 @@ -Subproject commit b7dbc011e0eee55c011623d2747e517436d04106 +Subproject commit 9f8d0c85c54b4715974994aea52562072d6f1751 diff --git a/MatrixUtils.Abstractions/RoomInfo.cs b/MatrixUtils.Abstractions/RoomInfo.cs index 0cd4dc1..877246b 100644 --- a/MatrixUtils.Abstractions/RoomInfo.cs +++ b/MatrixUtils.Abstractions/RoomInfo.cs @@ -1,9 +1,11 @@ +using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.Text.Json.Nodes; using ArcaneLibs; using LibMatrix; using LibMatrix.EventTypes.Spec.State; using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Homeservers; using LibMatrix.RoomTypes; namespace MatrixUtils.Abstractions; @@ -12,51 +14,22 @@ public class RoomInfo : NotifyPropertyChanged { public required GenericRoom Room { get; set; } public ObservableCollection StateEvents { get; } = new(); + private static ConcurrentBag homeserversWithoutEventFormatSupport = new(); + public async Task GetStateEvent(string type, string stateKey = "") { + if (homeserversWithoutEventFormatSupport.Contains(Room.Homeserver)) return await GetStateEventForged(type, stateKey); var @event = StateEvents.FirstOrDefault(x => x?.Type == type && x.StateKey == stateKey); if (@event is not null) return @event; - // @event = new StateEventResponse { - // RoomId = Room.RoomId, - // Type = type, - // StateKey = stateKey, - // Sender = null, //TODO implement - // EventId = null - // }; - // // if (Room is null) return null; - // try { - // @event.RawContent = await Room.GetStateAsync(type, stateKey); - // } - // catch (MatrixException e) { - // if (e is { ErrorCode: "M_NOT_FOUND" }) { - // if (type == "m.room.name") - // @event = new() { - // Type = type, - // StateKey = stateKey, - // TypedContent = new RoomNameEventContent() { - // Name = await Room.GetNameOrFallbackAsync() - // }, - // //TODO implement - // RoomId = null, - // Sender = null, - // EventId = null - // }; - // else - // @event.RawContent = default!; - // } - // else { - // throw; - // } - // } - // catch (Exception e) { - // await Task.Delay(1000); - // return await GetStateEvent(type, stateKey); - // } - + try { @event = await Room.GetStateEventOrNullAsync(type, stateKey); StateEvents.Add(@event); } catch (Exception e) { + if (e is InvalidDataException) { + homeserversWithoutEventFormatSupport.Add(Room.Homeserver); + return await GetStateEventForged(type, stateKey); + } Console.Error.WriteLine(e); await Task.Delay(1000); return await GetStateEvent(type, stateKey); @@ -65,6 +38,46 @@ public class RoomInfo : NotifyPropertyChanged { return @event; } + private async Task GetStateEventForged(string type, string stateKey = "") { + var @event = new StateEventResponse { + RoomId = Room.RoomId, + Type = type, + StateKey = stateKey, + Sender = null, //TODO implement + EventId = null + }; + try { + @event.RawContent = await Room.GetStateAsync(type, stateKey); + } + catch (MatrixException e) { + if (e is { ErrorCode: "M_NOT_FOUND" }) { + if (type == "m.room.name") + @event = new() { + Type = type, + StateKey = stateKey, + TypedContent = new RoomNameEventContent() { + Name = await Room.GetNameOrFallbackAsync() + }, + //TODO implement + RoomId = null, + Sender = null, + EventId = null + }; + else + @event.RawContent = default!; + } + else { + throw; + } + } + catch (Exception e) { + await Task.Delay(1000); + return await GetStateEvent(type, stateKey); + } + + return @event; + } + public string? RoomIcon { get => _roomIcon ?? "https://api.dicebear.com/6.x/identicon/svg?seed=" + Room.RoomId; set => SetField(ref _roomIcon, value); @@ -92,11 +105,31 @@ public class RoomInfo : NotifyPropertyChanged { private string? _roomName; private RoomCreateEventContent? _creationEventContent; private string? _roomCreator; + private string? _overrideRoomType; + private string? _defaultRoomName; + private RoomMemberEventContent? _ownMembership; + + public string? DefaultRoomName { + get => _defaultRoomName; + set { + if (SetField(ref _defaultRoomName, value)) OnPropertyChanged(nameof(RoomName)); + } + } + + public string? OverrideRoomType { + get => _overrideRoomType; + set { + if (SetField(ref _overrideRoomType, value)) OnPropertyChanged(nameof(RoomType)); + } + } - public string? DefaultRoomName { get; set; } - public string? OverrideRoomType { get; set; } public string? RoomType => OverrideRoomType ?? CreationEventContent?.Type; + public RoomMemberEventContent? OwnMembership { + get => _ownMembership; + set => SetField(ref _ownMembership, value); + } + public RoomInfo() { StateEvents.CollectionChanged += (_, args) => { if (args.NewItems is { Count: > 0 }) diff --git a/MatrixUtils.Web/Pages/Moderation/DraupnirProtectedRoomsEditor.razor b/MatrixUtils.Web/Pages/Moderation/DraupnirProtectedRoomsEditor.razor new file mode 100644 index 0000000..fb4f9bf --- /dev/null +++ b/MatrixUtils.Web/Pages/Moderation/DraupnirProtectedRoomsEditor.razor @@ -0,0 +1,97 @@ +@page "/Moderation/DraupnirProtectedRoomsEditor" +@using System.Text.Json.Serialization +@using MatrixUtils.Abstractions +@using System.Collections.Frozen +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.RoomTypes +

Edit Draupnir protected rooms

+
+ +@if (data is not null) { +
+
+

Current rooms

+
    + @foreach (var room in data.Rooms) { +
  • @room
  • + } +
+
+

Tickyboxes

+ + + + @* Checkbox column *@ + @* PL > kick *@ + @* PL > ban *@ + @* PL > m.room.server_acls event *@ + + + + + + @foreach (var room in Rooms.OrderBy(x => x.RoomName)) { + + + + + + + + + } + +
Kick?Ban?ACL?Room IDRoom name
+ + @(room.PowerLevels.Kick <= room.PowerLevels.GetUserPowerLevel(hs.UserId) ? "X" : "")@(room.PowerLevels.Ban <= room.PowerLevels.GetUserPowerLevel(hs.UserId) ? "X" : "")@(room.PowerLevels.UserHasStatePermission(hs.UserId, RoomServerACLEventContent.EventId) ? "X" : "")@room.Room.RoomId@room.RoomName
+
+
+} +
+Apply + + +@code { + private DraupnirProtectedRoomsData data { get; set; } = new(); + private List Rooms { get; set; } = new(); + private AuthenticatedHomeserverGeneric hs { get; set; } + + protected override async Task OnInitializedAsync() { + hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + data = await hs.GetAccountDataAsync("org.matrix.mjolnir.protected_rooms"); + StateHasChanged(); + foreach (var room in await hs.GetJoinedRooms()) { + var plTask = room.GetPowerLevelsAsync(); + var roomNameTask = room.GetNameOrFallbackAsync(); + var EditorRoomInfo = new EditorRoomInfo { + Room = room, + IsProtected = data.Rooms.Contains(room.RoomId), + RoomName = await roomNameTask, + PowerLevels = await plTask + }; + + Rooms.Add(EditorRoomInfo); + StateHasChanged(); + } + } + + private class DraupnirProtectedRoomsData { + [JsonPropertyName("rooms")] + public List Rooms { get; set; } = new(); + } + + private class EditorRoomInfo { + public GenericRoom Room { get; set; } + public bool IsProtected { get; set; } + public string RoomName { get; set; } + public RoomPowerLevelEventContent PowerLevels { get; set; } + } + + private async Task Apply() { + Console.WriteLine(string.Join('\n', Rooms.Where(x=>x.IsProtected).Select(x=>x.Room.RoomId))); + data.Rooms = Rooms.Where(x => x.IsProtected).Select(x => x.Room.RoomId).ToList(); + await hs.SetAccountDataAsync("org.matrix.mjolnir.protected_rooms", data); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Moderation/UserRoomHistory.razor b/MatrixUtils.Web/Pages/Moderation/UserRoomHistory.razor new file mode 100644 index 0000000..e4eea83 --- /dev/null +++ b/MatrixUtils.Web/Pages/Moderation/UserRoomHistory.razor @@ -0,0 +1,115 @@ +@page "/Moderation/UserRoomHistory/{UserId}" +@using LibMatrix.Homeservers +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.RoomTypes +@using ArcaneLibs.Extensions +@using MatrixUtils.Abstractions +

UserRoomHistory

+ +Enter mxid: + + +@if (string.IsNullOrWhiteSpace(UserId)) { +

UserId is null!

+} +else { +

Checked @checkedRooms.Count so far...

+ @if (currentHs is not null) { +

Checking rooms from @currentHs.UserId's perspective

+ } + else if (checkedRooms.Count > 1) { +

Done!

+ } + @foreach (var (state, rooms) in matchingStates) { + @state +
+ @foreach (var roomInfo in rooms) { + + } + } +} + +@code { + private string? _userId; + + [Parameter] + public string? UserId { + get => _userId; + set { + _userId = value; + FindMember(value); + } + } + + private List hss = new(); + private AuthenticatedHomeserverGeneric? currentHs { get; set; } + + protected override async Task OnInitializedAsync() { + var hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + var sessions = await RMUStorage.GetAllTokens(); + foreach (var userAuth in sessions) { + var session = await RMUStorage.GetSession(userAuth); + if (session is not null) { + hss.Add(session); + StateHasChanged(); + } + } + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + if (!string.IsNullOrWhiteSpace(UserId)) FindMember(UserId); + } + + public Dictionary> matchingStates = new(); + public List checkedRooms = new(); + private SemaphoreSlim _semaphoreSlim = new(1, 1); + + public async Task FindMember(string mxid) { + await _semaphoreSlim.WaitAsync(); + if (mxid != UserId) { + _semaphoreSlim.Release(); + return; //abort if changed + } + matchingStates.Clear(); + foreach (var homeserver in hss) { + currentHs = homeserver; + var rooms = await homeserver.GetJoinedRooms(); + rooms.RemoveAll(x => checkedRooms.Contains(x.RoomId)); + checkedRooms.AddRange(rooms.Select(x => x.RoomId)); + var tasks = rooms.Select(x => GetMembershipAsync(x, mxid)).ToAsyncEnumerable(); + await foreach (var (room, state) in tasks) { + if (state is null) continue; + if (!matchingStates.ContainsKey(state.Membership)) + matchingStates.Add(state.Membership, new()); + var roomInfo = new RoomInfo() { + Room = room + }; + matchingStates[state.Membership].Add(roomInfo); + roomInfo.StateEvents.Add(new() { + Type = RoomNameEventContent.EventId, + TypedContent = new RoomNameEventContent() { + Name = await room.GetNameOrFallbackAsync(4) + }, + RoomId = null, Sender = null, EventId = null //TODO implement + }); + StateHasChanged(); + if (mxid != UserId) { + _semaphoreSlim.Release(); + return; //abort if changed + } + } + StateHasChanged(); + } + currentHs = null; + StateHasChanged(); + _semaphoreSlim.Release(); + } + + public async Task<(GenericRoom roomId, RoomMemberEventContent? content)> GetMembershipAsync(GenericRoom room, string mxid) { + return (room, await room.GetStateOrNullAsync(RoomMemberEventContent.EventId, mxid)); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor b/MatrixUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor deleted file mode 100644 index 5ba83e4..0000000 --- a/MatrixUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor +++ /dev/null @@ -1,115 +0,0 @@ -@page "/UserRoomHistory/{UserId}" -@using LibMatrix.Homeservers -@using LibMatrix -@using LibMatrix.EventTypes.Spec.State -@using LibMatrix.RoomTypes -@using ArcaneLibs.Extensions -@using MatrixUtils.Abstractions -

UserRoomHistory

- -Enter mxid: - - -@if (string.IsNullOrWhiteSpace(UserId)) { -

UserId is null!

-} -else { -

Checked @checkedRooms.Count so far...

- @if (currentHs is not null) { -

Checking rooms from @currentHs.UserId's perspective

- } - else if (checkedRooms.Count > 1) { -

Done!

- } - @foreach (var (state, rooms) in matchingStates) { - @state -
- @foreach (var roomInfo in rooms) { - - } - } -} - -@code { - private string? _userId; - - [Parameter] - public string? UserId { - get => _userId; - set { - _userId = value; - FindMember(value); - } - } - - private List hss = new(); - private AuthenticatedHomeserverGeneric? currentHs { get; set; } - - protected override async Task OnInitializedAsync() { - var hs = await RMUStorage.GetCurrentSessionOrNavigate(); - if (hs is null) return; - var sessions = await RMUStorage.GetAllTokens(); - foreach (var userAuth in sessions) { - var session = await RMUStorage.GetSession(userAuth); - if (session is not null) { - hss.Add(session); - StateHasChanged(); - } - } - - StateHasChanged(); - Console.WriteLine("Rerendered!"); - await base.OnInitializedAsync(); - if (!string.IsNullOrWhiteSpace(UserId)) FindMember(UserId); - } - - public Dictionary> matchingStates = new(); - public List checkedRooms = new(); - private SemaphoreSlim _semaphoreSlim = new(1, 1); - - public async Task FindMember(string mxid) { - await _semaphoreSlim.WaitAsync(); - if (mxid != UserId) { - _semaphoreSlim.Release(); - return; //abort if changed - } - matchingStates.Clear(); - foreach (var homeserver in hss) { - currentHs = homeserver; - var rooms = await homeserver.GetJoinedRooms(); - rooms.RemoveAll(x => checkedRooms.Contains(x.RoomId)); - checkedRooms.AddRange(rooms.Select(x => x.RoomId)); - var tasks = rooms.Select(x => GetMembershipAsync(x, mxid)).ToAsyncEnumerable(); - await foreach (var (room, state) in tasks) { - if (state is null) continue; - if (!matchingStates.ContainsKey(state.Membership)) - matchingStates.Add(state.Membership, new()); - var roomInfo = new RoomInfo() { - Room = room - }; - matchingStates[state.Membership].Add(roomInfo); - roomInfo.StateEvents.Add(new() { - Type = RoomNameEventContent.EventId, - TypedContent = new RoomNameEventContent() { - Name = await room.GetNameOrFallbackAsync(4) - }, - RoomId = null, Sender = null, EventId = null //TODO implement - }); - StateHasChanged(); - if (mxid != UserId) { - _semaphoreSlim.Release(); - return; //abort if changed - } - } - StateHasChanged(); - } - currentHs = null; - StateHasChanged(); - _semaphoreSlim.Release(); - } - - public async Task<(GenericRoom roomId, RoomMemberEventContent? content)> GetMembershipAsync(GenericRoom room, string mxid) { - return (room, await room.GetStateOrNullAsync(RoomMemberEventContent.EventId, mxid)); - } - -} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Rooms/Index.razor b/MatrixUtils.Web/Pages/Rooms/Index.razor index 170f489..c3deb40 100644 --- a/MatrixUtils.Web/Pages/Rooms/Index.razor +++ b/MatrixUtils.Web/Pages/Rooms/Index.razor @@ -6,6 +6,7 @@ @using System.Collections.ObjectModel @using System.Diagnostics @using ArcaneLibs.Extensions +@using LibMatrix.Utilities @using MatrixUtils.Abstractions @inject ILogger logger

Room list

@@ -18,8 +19,9 @@ @code { - + private ObservableCollection _rooms = new(); + private ObservableCollection Rooms { get => _rooms; set => _rooms = value; @@ -29,39 +31,7 @@ private AuthenticatedHomeserverGeneric? Homeserver { get; set; } - private static SyncFilter filter = new() { - AccountData = new SyncFilter.EventFilter { - NotTypes = new List { "*" }, - Limit = 1 - }, - Presence = new SyncFilter.EventFilter { - NotTypes = new List { "*" }, - Limit = 1 - }, - Room = new SyncFilter.RoomFilter { - AccountData = new SyncFilter.RoomFilter.StateFilter { - NotTypes = new List { "*" }, - Limit = 1 - }, - Ephemeral = new SyncFilter.RoomFilter.StateFilter { - NotTypes = new List { "*" }, - Limit = 1 - }, - State = new SyncFilter.RoomFilter.StateFilter { - Types = new List { - "m.room.create", - "m.room.name", - "m.room.avatar", - "org.matrix.mjolnir.shortcode", - "m.room.power_levels", - } - }, - Timeline = new SyncFilter.RoomFilter.StateFilter { - NotTypes = new List { "*" }, - Limit = 1 - } - } - }; + // private static SyncFilter filter = // private static SyncFilter profileUpdateFilter = new() { // AccountData = new SyncFilter.EventFilter { @@ -105,22 +75,23 @@ // SemaphoreSlim _semaphore = new(160, 160); GlobalProfile = await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId); - Rooms = new ObservableCollection(rooms.Select(x => new RoomInfo() { Room = x })); - foreach (var stateType in filter.Room?.State?.Types ?? []) { - var tasks = Rooms.Select(async room => { - try { - - await room.GetStateEvent(stateType); - } - catch (Exception e) { - Console.WriteLine($"Failed to get state event {stateType} for room {room.Room.RoomId}: {e}"); - } - }); - await Task.WhenAll(tasks); - Status = $"Fetched all {stateType} events..."; - // StateHasChanged(); - } + var filter = await Homeserver.GetOrUploadNamedFilterIdAsync(CommonSyncFilters.GetBasicRoomInfo); + var filterData = await Homeserver.GetFilterAsync(filter); + Rooms = new ObservableCollection(rooms.Select(x => new RoomInfo() { Room = x })); + // foreach (var stateType in filterData.Room?.State?.Types ?? []) { + // var tasks = Rooms.Select(async room => { + // try { + // await room.GetStateEvent(stateType); + // } + // catch (Exception e) { + // Console.WriteLine($"Failed to get state event {stateType} for room {room.Room.RoomId}: {e}"); + // } + // }); + // await Task.WhenAll(tasks); + // Status = $"Fetched all {stateType} events..."; + // // StateHasChanged(); + // } RenderContents = true; Status = "Initial fetch done! Starting initial sync..."; @@ -128,7 +99,7 @@ await Task.Delay(1000); syncHelper = new SyncHelper(Homeserver, logger) { Timeout = 30000, - Filter = filter, + FilterId = filter, MinimumDelay = TimeSpan.FromMilliseconds(5000) }; // profileSyncHelper = new SyncHelper(Homeserver, logger) { @@ -189,8 +160,9 @@ await Task.Delay(100); } + Console.WriteLine($"QueueWorker: {queue.Count} entries left in queue, {maxUpdates} maxUpdates left, RenderContents: {RenderContents}"); - Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue..."; + Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue..."; RenderContents |= queue.Count == 0; await Task.Delay(Rooms.Count); @@ -224,7 +196,6 @@ } private Queue> queue = new(); - private async Task RunSyncLoop(SyncHelper syncHelper) { // Status = "Initial syncing..."; @@ -235,6 +206,8 @@ Console.WriteLine("trying sync"); if (sync is null) continue; + var filter = await Homeserver.GetFilterAsync(syncHelper.FilterId); + Status = $"Got sync with {sync.Rooms?.Join?.Count ?? 0} room updates, next batch: {sync.NextBatch}!"; if (sync?.Rooms?.Join != null) foreach (var joinedRoom in sync.Rooms.Join) @@ -248,7 +221,8 @@ queue.Enqueue(joinedRoom); } - if (sync.Rooms.Leave is {Count: > 0}) + + if (sync.Rooms.Leave is { Count: > 0 }) foreach (var leftRoom in sync.Rooms.Leave) if (Rooms.Any(x => x.Room.RoomId == leftRoom.Key)) Rooms.Remove(Rooms.First(x => x.Room.RoomId == leftRoom.Key)); diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor index bfc0375..b7ebae2 100644 --- a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor +++ b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor @@ -250,6 +250,7 @@ else { private async Task UpdatePolicyAsync(StateEventResponse policyEvent) { await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey, policyEvent.RawContent); + CurrentlyEditingEvent = null; await LoadStatesAsync(); } diff --git a/MatrixUtils.Web/Pages/Rooms/Space.razor b/MatrixUtils.Web/Pages/Rooms/Space.razor index 2dd84a1..01ab1c4 100644 --- a/MatrixUtils.Web/Pages/Rooms/Space.razor +++ b/MatrixUtils.Web/Pages/Rooms/Space.razor @@ -93,8 +93,11 @@ } private async Task JoinAllRooms() { - List> tasks = Rooms.Select(room => room.JoinAsync(ServersInSpace.ToArray())).ToList(); - await Task.WhenAll(tasks); + // List> tasks = Rooms.Select(room => room.JoinAsync(ServersInSpace.ToArray())).ToList(); + // await Task.WhenAll(tasks); + foreach (var room in Rooms) { + await room.JoinAsync(ServersInSpace.ToArray()); + } } } diff --git a/MatrixUtils.Web/Pages/Tools/RoomIntersections.razor b/MatrixUtils.Web/Pages/Tools/RoomIntersections.razor new file mode 100644 index 0000000..395f84c --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/RoomIntersections.razor @@ -0,0 +1,199 @@ +@page "/Tools/RoomIntersections" +@using ArcaneLibs.Extensions +@using LibMatrix.RoomTypes +@using System.Collections.ObjectModel +@using LibMatrix +@using System.Collections.Frozen +@using LibMatrix.EventTypes.Spec.State +

Room intersections

+
+ +

Set A:

+ +Append Set A + +

Set B:

+ +Append Set B +
+Execute +
+ +
+ Results +
+        @{
+            var userColWidth = matches.Count == 0 ? 0 : matches.Keys.Max(x => x.Length);
+        }
+        
+            @foreach (var (userId, sets) in matches) {
+                
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                    
+                
+                @for (int i = 1; i < Math.Max(sets.Item1.Count, sets.Item2.Count); i++) {
+                    
+                        
+                            
+                            
+                            
+                        }
+                        else {
+                            
+                            
+                            
+                             
+                        }
+                        else {
+                            
+                }
+            }
+            
+        
@userId.PadRight(userColWidth + 5)@sets.Item1[0].Room.RoomId@((sets.Item1[0].Member.TypedContent as RoomMemberEventContent).Membership)@(roomNames.ContainsKey(sets.Item1[0].Room) ? roomNames[sets.Item1[0].Room] : "")@(roomAliasses.ContainsKey(sets.Item1[0].Room) ? roomAliasses[sets.Item1[0].Room] : "")@sets.Item2[0].Room.RoomId@((sets.Item2[0].Member.TypedContent as RoomMemberEventContent).Membership)@(roomNames.ContainsKey(sets.Item2[0].Room) ? roomNames[sets.Item2[0].Room] : "")@(roomAliasses.ContainsKey(sets.Item2[0].Room) ? roomAliasses[sets.Item2[0].Room] : "")
+ @if (sets.Item1.Count > i) { + @sets.Item1[i].Room.RoomId@((sets.Item1[i].Member.TypedContent as RoomMemberEventContent).Membership)@(roomNames.ContainsKey(sets.Item1[i].Room) ? roomNames[sets.Item1[i].Room] : "")@(roomAliasses.ContainsKey(sets.Item1[i].Room) ? roomAliasses[sets.Item1[i].Room] : "") + + + + } + @if (sets.Item2.Count > i) { + @sets.Item2[0].Room.RoomId@((sets.Item2[i].Member.TypedContent as RoomMemberEventContent).Membership)@(roomNames.ContainsKey(sets.Item2[i].Room) ? roomNames[sets.Item2[i].Room] : "")@(roomAliasses.ContainsKey(sets.Item2[i].Room) ? roomAliasses[sets.Item2[i].Room] : "") + + + + } +
+
+
+
+ +
+@foreach (var line in Log.Reverse()) { +
@line
+} + +@code { + private ObservableCollection Log { get; set; } = new(); + List RoomsA { get; set; } = new(); + List RoomsB { get; set; } = new(); + + [Parameter, SupplyParameterFromQuery(Name = "a")] + public string ImportSetASpaceId { get; set; } = ""; + + [Parameter, SupplyParameterFromQuery(Name = "b")] + public string ImportSetBSpaceId { get; set; } = ""; + + Dictionary> roomMembers { get; set; } = new(); + + Dictionary, List)> matches { get; set; } = new(); + + AuthenticatedHomeserverGeneric hs { get; set; } + + // private string RoomListAString { + // get => string.Join("\n", RoomIdsA); + // set => RoomIdsA = value.Split("\n").Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); + // } + // + // private string RoomListBString { + // get => string.Join("\n", RoomIdsB); + // set => RoomIdsB = value.Split("\n").Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); + // } + + // private List RoomIdsA { get; set; } = new(); + // private List RoomIdsB { get; set; } = new(); + + // room info + Dictionary roomNames { get; set; } = new(); + Dictionary roomAliasses { get; set; } = new(); + + protected override async Task OnInitializedAsync() { + Log.CollectionChanged += (sender, args) => StateHasChanged(); + hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + // get all users which are in any room of both sets of rooms, and which rooms + var setAusers = new Dictionary>(); + var setBusers = new Dictionary>(); + + await Task.WhenAll(GetMembers(RoomsA, setAusers), GetMembers(RoomsB, setBusers)); + + Log.Add($"Got {setAusers.Count} users in set A"); + Log.Add($"Got {setBusers.Count} users in set B"); + Log.Add("Calculating intersections..."); + + // get all users which are in both sets of rooms + // var users = setAusers.Keys.Intersect(setBusers.Keys).ToList(); + // var groups = setAusers.IntersectBy(setBusers, (x,y) => x.Key).ToList(); + matches = setAusers.Keys.Intersect(setBusers.Keys).Select(x => (x, setAusers[x], setBusers[x])).ToDictionary(x => x.x, x => (x.Item2, x.Item3)); + + Log.Add($"Found {matches.Count} users in both sets of rooms"); + StateHasChanged(); + } + + public async Task GetMembers(List rooms, Dictionary> users) { + foreach (var room in rooms) { + Log.Add($"Getting members for {room.RoomId}"); + var members = await room.GetMembersListAsync(false); + foreach (var member in members) { + if (member.RawContent?["membership"]?.ToString() == "ban") continue; + if (member.RawContent?["membership"]?.ToString() == "invite") continue; + if (!users.ContainsKey(member.StateKey)) users[member.StateKey] = new(); + users[member.StateKey].Add(new() { + Room = room, + Member = member + }); + } + } + } + + public async Task AppendSet(string spaceId, List rooms) { + var space = hs.GetRoom(spaceId).AsSpace; + Log.Add($"Found space {spaceId}"); + var roomIdsEnum = space.GetChildrenAsync(true); + List tasks = new(); + await foreach (var room in roomIdsEnum) { + tasks.Add(loadRoomData(room, rooms)); + } + + await Task.WhenAll(tasks); + + async Task loadRoomData(GenericRoom room, List rooms) { + Log.Add($"Found room {room.RoomId}"); + try { + await room.GetPowerLevelsAsync(); + rooms.Add(room); + try { + roomAliasses[room] = (await room.GetCanonicalAliasAsync()).Alias; + } + catch { } + + try { + roomNames[room] = await room.GetNameOrFallbackAsync(); + } + catch { } + } + catch (MatrixException e) { + Log.Add($"Failed to get power levels for {room.RoomId}: {e.Message}"); + } + } + } + + public class Match { + public GenericRoom Room { get; set; } + public StateEventResponse Member { get; set; } + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/SessionCount.razor b/MatrixUtils.Web/Pages/Tools/SessionCount.razor new file mode 100644 index 0000000..3b68bfa --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/SessionCount.razor @@ -0,0 +1,155 @@ +@page "/Tools/SessionCount" +@using ArcaneLibs.Extensions +@using LibMatrix.RoomTypes +@using System.Collections.ObjectModel +@using LibMatrix +@using System.Collections.Frozen +@using LibMatrix.EventTypes.Spec.State +

User Trace

+
+ +

Users:

+ +
+Import from room (ID) + +
+ Rooms to be searched (@rooms.Count) + @foreach (var room in rooms) { + @room.RoomId +
+ } +
+
+Execute +
+ +
+ Results + @foreach (var (userId, events) in matches) { +

@userId

+
    + @foreach (var eventResponse in events) { +
  • @eventResponse.Room.RoomId
  • + } +
+ } +
+
+ Results text + @{ + var col1Width = matches.Keys.Max(x => x.Length); + } +
+        @foreach (var (userId, events) in matches) {
+            

+ @userId.PadRight(col1Width) + @foreach (var @event in events) { + +} +

+ } +
+
+ +
+@foreach (var line in log.Reverse()) { +
@line
+} + +@code { + private ObservableCollection log { get; set; } = new(); + List hss { get; set; } = new(); + ObservableCollection rooms { get; set; } = new(); + Dictionary> roomMembers { get; set; } = new(); + 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(); + + protected override async Task OnInitializedAsync() { + log.CollectionChanged += (sender, args) => StateHasChanged(); + var hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + rooms.CollectionChanged += (sender, args) => StateHasChanged(); + var sessions = await RMUStorage.GetAllTokens(); + foreach (var userAuth in sessions) { + var session = await RMUStorage.GetSession(userAuth); + if (session is not null) { + var sessionRooms = await session.GetJoinedRooms(); + foreach (var room in sessionRooms) { + rooms.Add(room); + } + + StateHasChanged(); + log.Add($"Got {sessionRooms.Count} rooms for {userAuth.UserId}"); + } + } + + log.Add("Done fetching rooms!"); + + var distinctRooms = rooms.DistinctBy(x => x.RoomId).ToArray(); + Random.Shared.Shuffle(distinctRooms); + rooms = new ObservableCollection(distinctRooms); + rooms.CollectionChanged += (sender, args) => StateHasChanged(); + + var stateTasks = rooms.Select(async x => (x, await x.GetMembersListAsync(false))).ToAsyncEnumerable(); + + await foreach (var (room, state) in stateTasks) { + roomMembers.Add(room, state); + log.Add($"Got {state.Count} members for {room.RoomId}..."); + } + + log.Add($"Done fetching members!"); + + UserIDs.RemoveAll(x => sessions.Any(y => y.UserId == x)); + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + foreach (var userId in UserIDs) { + matches.Add(userId, new List()); + foreach (var (room, events) in roomMembers) { + if (events.Any(x => x.Type == RoomMemberEventContent.EventId && x.StateKey == userId)) { + matches[userId].Add(new() { + Event = events.First(x => x.StateKey == userId && x.Type == RoomMemberEventContent.EventId), + Room = room, + }); + } + } + } + + 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 Matches { + public GenericRoom Room; + + public StateEventResponse Event; + // public + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/SpaceDebug.razor b/MatrixUtils.Web/Pages/Tools/SpaceDebug.razor index 5d9b8eb..09e5b12 100644 --- a/MatrixUtils.Web/Pages/Tools/SpaceDebug.razor +++ b/MatrixUtils.Web/Pages/Tools/SpaceDebug.razor @@ -1,6 +1,7 @@ @page "/Tools/SpaceDebug" @using LibMatrix.Filters @using LibMatrix.Helpers +@using LibMatrix.Utilities

SpaceDebug


@@ -49,16 +50,17 @@ if (hs is null) return; var syncHelper = new SyncHelper(hs) { - Filter = new SyncFilter() { - Presence = new(0), - Room = new() { - AccountData = new(limit: 0), - Ephemeral = new(limit: 0), - State = new(limit: 1000, types: new() { "m.space.child", "m.space.parent" }), - Timeline = new(limit: 0) - }, - AccountData = new(limit: 0) - } + // Filter = new SyncFilter() { + // Presence = new(0), + // Room = new() { + // AccountData = new(limit: 0), + // Ephemeral = new(limit: 0), + // State = new(limit: 1000, types: new() { "m.space.child", "m.space.parent" }), + // Timeline = new(limit: 0) + // }, + // AccountData = new(limit: 0) + // } + NamedFilterName = CommonSyncFilters.GetSpaceRelations }; Status = "Syncing..."; diff --git a/MatrixUtils.Web/Pages/Tools/UserTrace.razor b/MatrixUtils.Web/Pages/Tools/UserTrace.razor new file mode 100644 index 0000000..b3a7487 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/UserTrace.razor @@ -0,0 +1,139 @@ +@page "/Tools/UserTrace" +@using ArcaneLibs.Extensions +@using LibMatrix.RoomTypes +@using System.Collections.ObjectModel +@using LibMatrix +@using System.Collections.Frozen +@using LibMatrix.EventTypes.Spec.State +

User Trace

+
+ +

Users:

+ +
+Import from room (ID) + +
+ Rooms to be searched (@rooms.Count) + @foreach (var room in rooms) { + @room.RoomId +
+ } +
+
+Execute +
+ +
+ Results + @foreach (var (userId, events) in matches) { +

@userId

+
    + @foreach (var eventResponse in events) { +
  • @eventResponse.Room.RoomId
  • + } +
+ } +
+ +
+@foreach (var line in log.Reverse()) { +
@line
+} + +@code { + private ObservableCollection log { get; set; } = new(); + List hss { get; set; } = new(); + ObservableCollection rooms { get; set; } = new(); + Dictionary> roomMembers { get; set; } = new(); + 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(); + + protected override async Task OnInitializedAsync() { + log.CollectionChanged += (sender, args) => StateHasChanged(); + var hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + rooms.CollectionChanged += (sender, args) => StateHasChanged(); + var sessions = await RMUStorage.GetAllTokens(); + foreach (var userAuth in sessions) { + var session = await RMUStorage.GetSession(userAuth); + if (session is not null) { + var sessionRooms = await session.GetJoinedRooms(); + foreach (var room in sessionRooms) { + rooms.Add(room); + } + + StateHasChanged(); + log.Add($"Got {sessionRooms.Count} rooms for {userAuth.UserId}"); + } + } + + log.Add("Done fetching rooms!"); + + var distinctRooms = rooms.DistinctBy(x => x.RoomId).ToArray(); + Random.Shared.Shuffle(distinctRooms); + rooms = new ObservableCollection(distinctRooms); + rooms.CollectionChanged += (sender, args) => StateHasChanged(); + + var stateTasks = rooms.Select(async x => (x, await x.GetMembersListAsync(false))).ToAsyncEnumerable(); + + await foreach (var (room, state) in stateTasks) { + roomMembers.Add(room, state); + log.Add($"Got {state.Count} members for {room.RoomId}..."); + } + + log.Add($"Done fetching members!"); + + UserIDs.RemoveAll(x=>sessions.Any(y=>y.UserId == x)); + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + foreach (var userId in UserIDs) { + matches.Add(userId, new List()); + foreach (var (room, events) in roomMembers) { + if (events.Any(x => x.Type == RoomMemberEventContent.EventId && x.StateKey == userId)) { + matches[userId].Add(new() { + Event = events.First(x => x.StateKey == userId && x.Type == RoomMemberEventContent.EventId), + Room = room, + + }); + } + } + } + + 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 Matches { + public GenericRoom Room; + public StateEventResponse Event; + // public + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/ViewAccountData.razor b/MatrixUtils.Web/Pages/Tools/ViewAccountData.razor new file mode 100644 index 0000000..398c7ce --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/ViewAccountData.razor @@ -0,0 +1,30 @@ +@page "/Tools/ViewAccountData" +@using ArcaneLibs.Extensions +@using LibMatrix +@using LibMatrix.Filters +@using LibMatrix.Helpers +@using LibMatrix.Utilities +

View account data

+
+
@globalAccountData?.Events.ToJson(ignoreNull: true)
+
+ +@foreach (var (key, value) in perRoomAccountData) { + @key

+
@value?.Events.ToJson(ignoreNull: true)
+} + +@code { + EventList? globalAccountData; + Dictionary perRoomAccountData = new(); + + protected override async Task OnInitializedAsync() { + var hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + perRoomAccountData = await hs.EnumerateAccountDataPerRoom(); + globalAccountData = await hs.EnumerateAccountData(); + + StateHasChanged(); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/User/Profile.razor b/MatrixUtils.Web/Pages/User/Profile.razor index 8cffaab..deebdaf 100644 --- a/MatrixUtils.Web/Pages/User/Profile.razor +++ b/MatrixUtils.Web/Pages/User/Profile.razor @@ -2,7 +2,9 @@ @using LibMatrix.Homeservers @using LibMatrix.EventTypes.Spec.State @using ArcaneLibs.Extensions +@using LibMatrix @using LibMatrix.Responses +@using MatrixUtils.Abstractions

Manage Profile - @Homeserver?.WhoAmI?.UserId


@@ -28,6 +30,35 @@ @*
*@

Room profiles

+ @foreach (var room in Rooms) { +
+ +
+ + + +
+
+ @if (room.OwnMembership is not null) { + +
+ Display name:
+ Avatar URL: +
+ Update profile +
+
+ @if (!string.IsNullOrWhiteSpace(Status)) { +

@Status

+ } + } + else { +

Something went wrong, own membership is missing...

+ } +
+
+ } + @foreach (var (roomId, roomProfile) in RoomProfiles.OrderBy(x => RoomNames.TryGetValue(x.Key, out var _name) ? _name : x.Key)) {
@(RoomNames.TryGetValue(roomId, out var name) ? name : roomId) @@ -63,6 +94,7 @@ } } + private List Rooms { get; set; } = new(); private Dictionary RoomProfiles { get; set; } = new(); private Dictionary RoomNames { get; set; } = new(); @@ -76,6 +108,28 @@ Status = "Loading room profiles..."; var roomProfiles = Homeserver.GetRoomProfilesAsync(); await foreach (var (roomId, roomProfile) in roomProfiles) { + var room = Homeserver.GetRoom(roomId); + var roomNameTask = room.GetNameOrFallbackAsync(); + var roomIconTask = room.GetAvatarUrlAsync(); + var roomInfo = new RoomInfo() { + Room = room, + OwnMembership = roomProfile + }; + try { + roomInfo.RoomIcon = (await roomIconTask).Url; + } + catch (MatrixException e) { + if (e is not { ErrorCode: "M_NOT_FOUND" }) throw; + } + + try { + roomInfo.RoomName = await roomNameTask; + } + catch (MatrixException e) { + if (e is not { ErrorCode: "M_NOT_FOUND" }) throw; + } + + Rooms.Add(roomInfo); // Status = $"Got profile for {roomId}..."; RoomProfiles[roomId] = roomProfile; //.DeepClone(); } @@ -87,7 +141,7 @@ var name = await x.GetNameOrFallbackAsync(); return new KeyValuePair(x.RoomId, name); }).ToAsyncEnumerable(); - + await foreach (var (roomId, roomName) in roomNameTasks) { // Status = $"Got room name for {roomId}: {roomName}"; RoomNames[roomId] = roomName; diff --git a/MatrixUtils.Web/Shared/PolicyEditorComponents/PolicyEditorModal.razor b/MatrixUtils.Web/Shared/PolicyEditorComponents/PolicyEditorModal.razor index 4fd151d..1bd00d1 100644 --- a/MatrixUtils.Web/Shared/PolicyEditorComponents/PolicyEditorModal.razor +++ b/MatrixUtils.Web/Shared/PolicyEditorComponents/PolicyEditorModal.razor @@ -7,12 +7,9 @@ @using LibMatrix.EventTypes - @{ - var policyData = (PolicyEvent.TypedContent as PolicyRuleEventContent)!; - } @if (string.IsNullOrWhiteSpace(PolicyEvent.EventId)) { Policy type: - @foreach (var (type, mappedType) in PolicyTypes) { @@ -20,7 +17,6 @@ } - @{ // enumerate all properties with friendly name var props = PolicyEvent.MappedType.GetProperties(BindingFlags.Public | BindingFlags.Instance) @@ -29,64 +25,94 @@ .ToFrozenSet(); var propNames = props.Select(x => x.GetFriendlyNameOrNull() ?? x.GetJsonPropertyName()!).ToFrozenSet(); } - - - - - - - - - @foreach (var prop in props) { + @if (PolicyData is not null) { +
PropertyValue
+ - - @{ - var getter = prop.GetGetMethod(); - var setter = prop.GetSetMethod(); - } - @switch (Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType) { - case Type t when t == typeof(string): - {e}"); setter?.Invoke(policyData, [e]); StateHasChanged(); })"> - break; - default: -

Unsupported type: @prop.PropertyType

- break; - } + + - } - -
- @prop.GetFriendlyName() - @if (Nullable.GetUnderlyingType(prop.PropertyType) is not null) { - * - } - PropertyValue
-
-
-        @PolicyEvent.ToJson(true, false)
-    
- Cancel - Save - @* Target entity: *@ - @*
*@ - @* Reason: *@ - @* *@ + + + @foreach (var prop in props) { + + + @prop.GetFriendlyName() + @if (Nullable.GetUnderlyingType(prop.PropertyType) is not null) { + * + } + + @{ + var getter = prop.GetGetMethod(); + var setter = prop.GetSetMethod(); + } + @switch (Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType) { + case Type t when t == typeof(string): + {e}"); setter?.Invoke(PolicyData, [e]); PolicyEvent.TypedContent = PolicyData; StateHasChanged(); })"> + break; + default: +

Unsupported type: @prop.PropertyType

+ break; + } + + } + + +
+
+            @PolicyEvent.ToJson(true, false)
+        
+ Cancel + Save + @* Target entity: *@ + @*
*@ + @* Reason: *@ + @* *@ + } + else { +

Policy data is null

+ }
@code { [Parameter] - public StateEventResponse? PolicyEvent { get; set; } + public StateEventResponse? PolicyEvent { + get => _policyEvent; + set { + if (value is not null && value != _policyEvent) + PolicyData = (value.TypedContent as PolicyRuleEventContent)!; + _policyEvent = value; + if (string.IsNullOrWhiteSpace(value.StateKey)) + value.StateKey = Guid.NewGuid().ToString(); + } + } [Parameter] public required Action OnClose { get; set; } - + [Parameter] public required Action OnSave { get; set; } + public PolicyRuleEventContent? PolicyData { get; set; } + private static FrozenSet KnownPolicyTypes = StateEvent.KnownStateEventTypes.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 StateEventResponse? _policyEvent; + + private string? MappedType { + get => _policyEvent?.Type; + set { + if (value is not null && PolicyTypes.ContainsKey(value)) { + PolicyEvent.Type = value; + PolicyEvent.TypedContent ??= Activator.CreateInstance(PolicyTypes[value]) as PolicyRuleEventContent; + PolicyData = PolicyEvent.TypedContent as PolicyRuleEventContent; + } + } + } + + } \ No newline at end of file diff --git a/MatrixUtils.Web/Shared/RoomListComponents/RoomListCategory.razor b/MatrixUtils.Web/Shared/RoomListComponents/RoomListCategory.razor index 4b24c18..7670ec5 100644 --- a/MatrixUtils.Web/Shared/RoomListComponents/RoomListCategory.razor +++ b/MatrixUtils.Web/Shared/RoomListComponents/RoomListCategory.razor @@ -4,7 +4,7 @@ @using LibMatrix.Homeservers @using LibMatrix.Responses @using MatrixUtils.Abstractions -
+
@RoomType (@Rooms.Count) @foreach (var room in Rooms) {
diff --git a/MatrixUtils.Web/Shared/RoomListItem.razor b/MatrixUtils.Web/Shared/RoomListItem.razor index 2e7a372..623a03a 100644 --- a/MatrixUtils.Web/Shared/RoomListItem.razor +++ b/MatrixUtils.Web/Shared/RoomListItem.razor @@ -10,14 +10,14 @@ @if (RoomInfo is not null) {
@if (OwnMemberState != null) { - + @* Class="@("avatar32" + (OwnMemberState?.AvatarUrl != GlobalProfile?.AvatarUrl ? " highlightChange" : "") + (ChildContent is not null ? " vcenter" : ""))" *@ + @(OwnMemberState?.DisplayName ?? GlobalProfile?.DisplayName ?? "Loading...") -> } - +
@RoomInfo.RoomName @if (ChildContent is not null) { @@ -40,11 +40,14 @@ else { public RoomInfo? RoomInfo { get => _roomInfo; set { + if (RoomInfo != value) + RoomInfoChanged(); _roomInfo = value; - OnParametersSetAsync(); } } + + [Parameter] public bool ShowOwnProfile { get; set; } = false; @@ -72,72 +75,66 @@ else { private static AuthenticatedHomeserverGeneric? hs { get; set; } private bool _hooked; - protected override async Task OnParametersSetAsync() { - if (RoomInfo != null) { - if (!_hooked) { - _hooked = true; - RoomInfo.PropertyChanged += (_, a) => { - Console.WriteLine(a.PropertyName); - StateHasChanged(); - }; - } - - if (LoadData) { - try { - await RoomInfo.GetStateEvent("m.room.create"); - if (ShowOwnProfile) - OwnMemberState ??= (await RoomInfo.GetStateEvent("m.room.member", hs.WhoAmI.UserId)).TypedContent as RoomMemberEventContent; - - await RoomInfo.GetStateEvent("m.room.name"); - await RoomInfo.GetStateEvent("m.room.avatar"); - } - catch (MatrixException e) { - if (e.ErrorCode == "M_FORBIDDEN") { - LoadData = false; - RoomInfo.StateEvents.Add(new() { - Type = "m.room.create", - TypedContent = new RoomCreateEventContent() { RoomVersion = "0" }, - RoomId = null, Sender = null, EventId = null //TODO: implement - }); - RoomInfo.StateEvents.Add(new() { - Type = "m.room.name", - TypedContent = new RoomNameEventContent() { - Name = "M_FORBIDDEN: Are you a member of this room? " + RoomInfo.Room.RoomId - }, - RoomId = null, Sender = null, EventId = null //TODO: implement - }); - } - } + + private async Task RoomInfoChanged() { + RoomInfo.PropertyChanged += async (_, a) => { + if (a.PropertyName == nameof(RoomInfo.CreationEventContent)) { + await CheckRoomVersion(); } - } - - await base.OnParametersSetAsync(); + + StateHasChanged(); + }; } + + // protected override async Task OnParametersSetAsync() { + // if (RoomInfo != null) { + // if (!_hooked) { + // _hooked = true; + // RoomInfo.PropertyChanged += (_, a) => { + // Console.WriteLine(a.PropertyName); + // StateHasChanged(); + // }; + // } + // + // if (LoadData) { + // try { + // await RoomInfo.GetStateEvent("m.room.create"); + // if (ShowOwnProfile) + // OwnMemberState ??= (await RoomInfo.GetStateEvent("m.room.member", hs.WhoAmI.UserId)).TypedContent as RoomMemberEventContent; + // + // await RoomInfo.GetStateEvent("m.room.name"); + // await RoomInfo.GetStateEvent("m.room.avatar"); + // } + // catch (MatrixException e) { + // if (e.ErrorCode == "M_FORBIDDEN") { + // LoadData = false; + // RoomInfo.StateEvents.Add(new() { + // Type = "m.room.create", + // TypedContent = new RoomCreateEventContent() { RoomVersion = "0" }, + // RoomId = null, Sender = null, EventId = null //TODO: implement + // }); + // RoomInfo.StateEvents.Add(new() { + // Type = "m.room.name", + // TypedContent = new RoomNameEventContent() { + // Name = "M_FORBIDDEN: Are you a member of this room? " + RoomInfo.Room.RoomId + // }, + // RoomId = null, Sender = null, EventId = null //TODO: implement + // }); + // } + // } + // } + // } + // + // await base.OnParametersSetAsync(); + // } protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - await _semaphoreSlim.WaitAsync(); - hs ??= await RMUStorage.GetCurrentSessionOrNavigate(); if (hs is null) return; - try { - await CheckRoomVersion(); - // await GetRoomInfo(); - // await LoadOwnProfile(); - } - catch (MatrixException e) { - if (e is not { ErrorCode: "M_FORBIDDEN" }) { - throw; - } - // RoomName = "Error: " + e.Message; - // RoomIcon = "/blobfox_outage.gif"; - } - catch (Exception e) { - Console.WriteLine($"Failed to load room info for {RoomInfo.Room.RoomId}: {e.Message}"); - } - _semaphoreSlim.Release(); + await CheckRoomVersion(); } private async Task LoadOwnProfile() { @@ -158,10 +155,8 @@ else { } private async Task CheckRoomVersion() { - while (RoomInfo?.CreationEventContent is null) { - Console.WriteLine($"Room creation event content for {RoomInfo.Room.RoomId} is null..."); - await Task.Delay(Random.Shared.Next(1000, 2500)); - } + if (RoomInfo?.CreationEventContent is null) return; + var ce = RoomInfo.CreationEventContent; if (int.TryParse(ce.RoomVersion, out var rv)) { if (rv < 10) -- cgit 1.4.1