about summary refs log tree commit diff
path: root/MatrixRoomUtils.Web
diff options
context:
space:
mode:
Diffstat (limited to 'MatrixRoomUtils.Web')
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor2
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor32
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor3
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/Index.razor5
-rw-r--r--MatrixRoomUtils.Web/Shared/NavMenu.razor15
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomList.razor40
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor6
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor12
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor7
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListItem.razor131
10 files changed, 136 insertions, 117 deletions
diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor
index b2d28f6..8b2ff0c 100644
--- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor
+++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor
@@ -1,4 +1,4 @@
-@page "/RoomStateViewer/{RoomId}/Edit"
+@page "/Rooms/{RoomId}/State/Edit"
 @using System.Net.Http.Headers
 @using System.Text.Json
 @using MatrixRoomUtils.Core.Responses
diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor
deleted file mode 100644
index 55c44d9..0000000
--- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor
+++ /dev/null
@@ -1,32 +0,0 @@
-@page "/RoomStateViewer"
-@inject ILocalStorageService LocalStorage
-@inject NavigationManager NavigationManager
-<h3>Room state viewer - Room list</h3>
-<hr/>
-@if (Rooms.Count == 0) {
-    <p>You are not in any rooms!</p>
-    @* <p>Loading progress: @checkedRoomCount/@totalRoomCount</p> *@
-}
-else {
-    @foreach (var room in Rooms) {
-        <a style="color: unset; text-decoration: unset;" href="/RoomStateViewer/@room.Replace('.', '~')">
-            <RoomListItem RoomId="@room"></RoomListItem>
-        </a>
-    }
-    <div style="margin-bottom: 4em;"></div>
-}
-
-<LogView></LogView>
-
-@code {
-    public List<string> Rooms { get; set; } = new();
-
-    protected override async Task OnInitializedAsync() {
-        await base.OnInitializedAsync();
-        var hs = await MRUStorage.GetCurrentSessionOrNavigate();
-        if (hs is null) return;
-        Rooms = (await hs.GetJoinedRooms()).Select(x => x.RoomId).ToList();
-        Console.WriteLine("Fetched joined rooms!");
-    }
-
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor
index a0072ab..09b38f0 100644
--- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor
+++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor
@@ -1,4 +1,4 @@
-@page "/RoomStateViewer/{RoomId}"
+@page "/Rooms/{RoomId}/State/View"
 @using System.Net.Http.Headers
 @using System.Text.Json
 @using MatrixRoomUtils.Core.Responses
@@ -73,7 +73,6 @@
         await base.OnInitializedAsync();
         var hs = await MRUStorage.GetCurrentSessionOrNavigate();
         if (hs is null) return;
-        RoomId = RoomId.Replace('~', '.');
         await LoadStatesAsync();
         Console.WriteLine("Policy list editor initialized!");
     }
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
index 20ddd0d..932748d 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
@@ -1,18 +1,21 @@
 @page "/Rooms"
+@using MatrixRoomUtils.Core.StateEventTypes
 <h3>Room list</h3>
 
 @if (Rooms is not null) {
-    <RoomList Rooms="Rooms"></RoomList>
+    <RoomList Rooms="Rooms" GlobalProfile="@GlobalProfile"></RoomList>
 }
 
 
 @code {
 
     private List<GenericRoom> Rooms { get; set; }
+    private ProfileResponse GlobalProfile { get; set; }
     
     protected override async Task OnInitializedAsync() {
         var hs = await MRUStorage.GetCurrentSessionOrNavigate();
         if (hs is null) return;
+        GlobalProfile = await hs.GetProfile(hs.WhoAmI.UserId);
         Rooms = await hs.GetJoinedRooms();
 
         await base.OnInitializedAsync();
diff --git a/MatrixRoomUtils.Web/Shared/NavMenu.razor b/MatrixRoomUtils.Web/Shared/NavMenu.razor
index 5f9ad8a..48d3196 100644
--- a/MatrixRoomUtils.Web/Shared/NavMenu.razor
+++ b/MatrixRoomUtils.Web/Shared/NavMenu.razor
@@ -23,19 +23,10 @@
             <h5 style="margin-left: 1em;">Main tools</h5>
             <hr style="margin-bottom: 0em;"/>
         </div>
+       
         <div class="nav-item px-3">
-            <NavLink class="nav-link" href="RoomManager">
-                <span class="oi oi-plus" aria-hidden="true"></span> Manage Rooms
-            </NavLink>
-        </div>
-        <div class="nav-item px-3">
-            <NavLink class="nav-link" href="PolicyListEditor">
-                <span class="oi oi-plus" aria-hidden="true"></span> Policy list editor
-            </NavLink>
-        </div>
-        <div class="nav-item px-3">
-            <NavLink class="nav-link" href="RoomStateViewer">
-                <span class="oi oi-plus" aria-hidden="true"></span> Room state viewer
+            <NavLink class="nav-link" href="Rooms">
+                <span class="oi oi-plus" aria-hidden="true"></span> Room list
             </NavLink>
         </div>
         @* <div class="nav-item px-3"> *@
diff --git a/MatrixRoomUtils.Web/Shared/RoomList.razor b/MatrixRoomUtils.Web/Shared/RoomList.razor
index ac2cbb3..7e002ed 100644
--- a/MatrixRoomUtils.Web/Shared/RoomList.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomList.razor
@@ -1,18 +1,29 @@
 @using MatrixRoomUtils.Web.Shared.RoomListComponents;
 @using MatrixRoomUtils.Core.StateEventTypes
 <p>@Rooms.Count rooms total, @RoomsWithTypes.Sum(x=>x.Value.Count) fetched so far...</p>
-@foreach (var category in RoomsWithTypes.OrderBy(x => x.Value.Count)) {
-    <RoomListCategory Category="@category"></RoomListCategory>
+@if(Rooms.Count != RoomsWithTypes.Sum(x=>x.Value.Count)) {
+    <p>Fetching more rooms...</p>
+    @foreach (var category in RoomsWithTypes.OrderBy(x => x.Value.Count)) {
+        <p>@category.Key (@category.Value.Count)</p>
+    }
+}
+else {
+    @foreach (var category in RoomsWithTypes.OrderBy(x => x.Value.Count)) {
+        <RoomListCategory Category="@category" GlobalProfile="@GlobalProfile"></RoomListCategory>
+    }
 }
 
 @code {
 
     [Parameter]
     public List<GenericRoom> Rooms { get; set; }
+    [Parameter]
+    public ProfileResponse? GlobalProfile { get; set; }
 
     Dictionary<string, List<GenericRoom>> RoomsWithTypes = new();
-
+    
     protected override async Task OnInitializedAsync() {
+        GlobalProfile ??= await (await MRUStorage.GetCurrentSession()!).GetProfile((await MRUStorage.GetCurrentSession()!).WhoAmI.UserId);
         if (RoomsWithTypes.Any()) return;
 
         var tasks = Rooms.Select(AddRoom);
@@ -29,27 +40,32 @@
         };
 
     
-    private static SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(8, 8);
+    private static SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(4, 4);
     private async Task AddRoom(GenericRoom room) {
         await _semaphoreSlim.WaitAsync();
-        var roomType = GetRoomTypeName((await room.GetCreateEventAsync()).Type);
+        string roomType;
+        try {
+            var createEvent = await room.GetCreateEventAsync();
+            roomType = GetRoomTypeName(createEvent.Type);
 
-        if (roomType == "Room") {
-            var shortcodeState = await room.GetStateAsync<MjolnirShortcodeEventData>("org.matrix.mjolnir.shortcode");
-            if (shortcodeState is not null) roomType = "Legacy policy room";
+            if (roomType == "Room") {
+                var shortcodeState = await room.GetStateAsync<MjolnirShortcodeEventData>("org.matrix.mjolnir.shortcode");
+                if (shortcodeState is not null) roomType = "Legacy policy room";
+            }
+        }
+        catch (MatrixException e) {
+            roomType = $"Error: {e.ErrorCode}";
         }
         
         if (!RoomsWithTypes.ContainsKey(roomType)) {
             RoomsWithTypes.Add(roomType, new List<GenericRoom>());
         }
         RoomsWithTypes[roomType].Add(room);
-
+        
     // if (RoomsWithTypes.Count % 10 == 0)
         StateHasChanged();
-        await Task.Delay(100);
+        // await Task.Delay(100);
         _semaphoreSlim.Release();
     }
 
-    private bool _isSpaceChildrenOpen = false;
-
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
index a7e9399..e860321 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
@@ -1,9 +1,12 @@
+@using MatrixRoomUtils.Core.StateEventTypes
 <details>
     <summary>@roomType (@rooms.Count)</summary>
     @foreach (var room in rooms) {
         <div class="room-list-item">
             <RoomListItem Room="@room" ShowOwnProfile="@(roomType == "Room")"></RoomListItem>
             <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.RoomId}/Timeline")">View timeline</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
+            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.RoomId}/State/View")">View state</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
+            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.RoomId}/State/Edit")">Edit state</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
             
             @if (roomType == "Space") {
                 <RoomListSpace Space="@room"></RoomListSpace>
@@ -17,6 +20,9 @@
 
     [Parameter]
     public KeyValuePair<string, List<GenericRoom>> Category { get; set; }
+    
+    [Parameter]
+    public ProfileResponse? GlobalProfile { get; set; }
 
     private string roomType => Category.Key;
     private List<GenericRoom> rooms => Category.Value;
diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor
new file mode 100644
index 0000000..f05ac7b
--- /dev/null
+++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor
@@ -0,0 +1,12 @@
+<LinkButton href="@($"/Rooms/{Room.RoomId}/Policies")">Manage policies</LinkButton>
+
+@code {
+
+    [Parameter]
+    public GenericRoom Room { get; set; }
+
+    protected override async Task OnInitializedAsync() {
+        await base.OnInitializedAsync();
+    }
+
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
index 5d106c3..73dc334 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
@@ -26,7 +26,12 @@
 
     protected override async Task OnInitializedAsync() {
         if (Breadcrumbs == null) throw new ArgumentNullException(nameof(Breadcrumbs));
-        Children = (await Space.AsSpace.GetRoomsAsync()).Where(x => !Breadcrumbs.Contains(x.RoomId)).ToList();
+        await Task.Delay(Random.Shared.Next(1000, 10000));
+        var rooms = Space.AsSpace.GetRoomsAsync();
+        await foreach (var room in rooms) {
+            if(Breadcrumbs.Contains(room.RoomId)) continue;
+            Children.Add(room);
+        }
         await base.OnInitializedAsync();
     }
 
diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
index 53219d6..13cc02d 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListItem.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
@@ -2,15 +2,20 @@
 @using System.Text.Json
 @using MatrixRoomUtils.Core.Helpers
 @using MatrixRoomUtils.Core.StateEventTypes
-<div class="roomListItem" style="background-color: #ffffff11; border-radius: 25px; margin: 8px; width: fit-Content; @(hasDangerousRoomVersion ? "border: red 4px solid;" : hasOldRoomVersion ? "border: #FF0 1px solid;" : "")">
-    @if (ShowOwnProfile) {
-        <img class="imageUnloaded @(string.IsNullOrWhiteSpace(profileAvatar) ? "" : "imageLoaded")" style="@(ChildContent is not null ? "vertical-align: baseline;" : "") width: 32px; height: 32px; border-radius: 50%; @(hasCustomProfileAvatar ? "border-color: red; border-width: 3px; border-style: dashed;" : "")" src="@(profileAvatar ?? "/icon-192.png")"/>
-        <span style="vertical-align: middle; margin-right: 8px; border-radius: 75px; @(hasCustomProfileName ? "background-color: red;" : "")">@(profileName ?? "Loading...")</span>
+<div class="roomListItem" id="@RoomId" style="background-color: #ffffff11; border-radius: 25px; margin: 8px; width: fit-Content; @(hasDangerousRoomVersion ? "border: red 4px solid;" : hasOldRoomVersion ? "border: #FF0 1px solid;" : "")">
+    @if (OwnMemberState != null) {
+        <img class="imageUnloaded @(string.IsNullOrWhiteSpace(OwnMemberState?.AvatarUrl ?? GlobalProfile?.AvatarUrl) ? "" : "imageLoaded")"
+             style="@(ChildContent is not null ? "vertical-align: baseline;" : "") width: 32px; height: 32px; border-radius: 50%; @(OwnMemberState?.AvatarUrl != GlobalProfile?.AvatarUrl ? "border-color: red; border-width: 3px; border-style: dashed;" : "")"
+             src="@MediaResolver.ResolveMediaUri(hs.FullHomeServerDomain, OwnMemberState.AvatarUrl ?? GlobalProfile.AvatarUrl ?? "/icon-192.png")"/>
+        <span style="vertical-align: middle; margin-right: 8px; border-radius: 75px; @(OwnMemberState?.AvatarUrl != GlobalProfile?.AvatarUrl ? "background-color: red;" : "")">
+            @(OwnMemberState?.Displayname ?? GlobalProfile?.DisplayName ?? "Loading...")
+        </span>
         <span style="vertical-align: middle; padding-right: 8px; padding-left: 0px;">-></span>
     }
-    <img style="@(ChildContent is not null ? "vertical-align: baseline;" : "") width: 32px; height:  32px; border-radius: 50%;" src="@roomIcon"/>
+    <img style="@(ChildContent is not null ? "vertical-align: baseline;" : "") width: 32px; height:  32px; border-radius: 50%;"
+         src="@roomIcon"/>
     <div style="display: inline-block;">
-        <span style="vertical-align: middle; padding-right: 8px;">@RoomName</span>
+        <span style="vertical-align: middle; padding-right: 8px;">@roomName</span>
         @if (ChildContent is not null) {
             @ChildContent
         }
@@ -24,91 +29,105 @@
     public RenderFragment? ChildContent { get; set; }
 
     [Parameter]
-    public GenericRoom Room { get; set; }
+    public GenericRoom? Room { get; set; }
 
     [Parameter]
-    public string RoomId { get; set; }
+    public string? RoomId { get; set; }
 
     [Parameter]
     public bool ShowOwnProfile { get; set; } = false;
 
     [Parameter]
-    public string? RoomName { get; set; }
+    public RoomMemberEventData? OwnMemberState { get; set; }
 
-    private string? roomIcon { get; set; } = "/icon-192.png";
+    [Parameter]
+    public ProfileResponse? GlobalProfile { get; set; }
 
-    private string? profileAvatar { get; set; }
-    private string? profileName { get; set; }
-    private bool hasCustomProfileAvatar { get; set; } = false;
-    private bool hasCustomProfileName { get; set; } = false;
+    private string? roomName { get; set; }
+
+    private string? roomIcon { get; set; } = "/icon-192.png";
 
     private bool hasOldRoomVersion { get; set; } = false;
     private bool hasDangerousRoomVersion { get; set; } = false;
 
-    private static SemaphoreSlim _semaphoreSlim = new(128);
+    private static SemaphoreSlim _semaphoreSlim = new(8);
+    private static AuthenticatedHomeServer? hs { get; set; }
+    private static readonly string[] DangerousRoomVersions = { "1", "8" };
 
     protected override async Task OnInitializedAsync() {
         await base.OnInitializedAsync();
 
         await _semaphoreSlim.WaitAsync();
 
-        var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+        hs ??= await MRUStorage.GetCurrentSessionOrNavigate();
         if (hs is null) return;
 
-        if (Room == null) {
-            if (RoomId == null) {
-                throw new ArgumentNullException(nameof(RoomId));
-            }
-            Room = await hs.GetRoom(RoomId);
-        }
-        else {
-            RoomId = Room.RoomId;
+        if (Room is null && RoomId is null) {
+            throw new ArgumentNullException(nameof(RoomId));
         }
+        Room ??= await hs.GetRoom(RoomId);
+        RoomId = Room.RoomId;
 
-        RoomName ??= await Room.GetNameAsync() ?? "Unnamed room: " + RoomId;
+        await CheckRoomVersion();
+        await GetRoomInfo();
+        await LoadOwnProfile();
+        _semaphoreSlim.Release();
+    }
 
-        var ce = await Room.GetCreateEventAsync();
-        if (ce is not null) {
-            if (int.TryParse(ce.RoomVersion, out var rv) && rv < 10) {
-                hasOldRoomVersion = true;
+    private async Task LoadOwnProfile() {
+        if (!ShowOwnProfile) return;
+        try {
+            OwnMemberState ??= await Room.GetStateAsync<RoomMemberEventData>("m.room.member", hs.UserId);
+            GlobalProfile ??= await hs.GetProfile(hs.UserId, true);
+        }
+        catch (MatrixException e) {
+            if (e is { ErrorCode: "M_FORBIDDEN" }) {
+                Console.WriteLine($"Failed to get profile for {hs.UserId}: {e.Message}");
+                ShowOwnProfile = false;
             }
-            if (new[] { "1", "8" }.Contains(ce.RoomVersion)) {
-                hasDangerousRoomVersion = true;
-                RoomName = "Dangerous room: " + RoomName;
+            else {
+                throw;
             }
         }
+    }
 
-        var state = await Room.GetStateAsync<RoomAvatarEventData>("m.room.avatar");
-        if (state is not null) {
-            try {
-                var url = state.Url;
-                if (url is not null) {
-                    roomIcon = MediaResolver.ResolveMediaUri(hs.FullHomeServerDomain, url);
-                    Console.WriteLine($"Got avatar for room {RoomId}: {roomIcon} ({url})");
-                }
+    private async Task CheckRoomVersion() {
+        try {
+            var ce = await Room.GetCreateEventAsync();
+            if (int.TryParse(ce.RoomVersion, out var rv)) {
+                if (rv < 10)
+                    hasOldRoomVersion = true;
             }
-            catch (InvalidOperationException e) {
-                Console.WriteLine($"Failed to get avatar for room {RoomId}: {e.Message}\n{state.ToJson()}");
+            else // treat unstable room versions as dangerous
+                hasDangerousRoomVersion = true;
+
+            if (DangerousRoomVersions.Contains(ce.RoomVersion)) {
+                hasDangerousRoomVersion = true;
+                roomName = "Dangerous room: " + roomName;
             }
-            catch (Exception e) {
-                Console.WriteLine(e);
+        }
+        catch (MatrixException e) {
+            if (e is not { ErrorCode: "M_FORBIDDEN" }) {
+                throw;
             }
         }
+    }
+
+    private async Task GetRoomInfo() {
+        try {
+            roomName ??= await Room.GetNameAsync();
 
-        if (ShowOwnProfile) {
-            var profile = await hs.GetProfile(hs.UserId, true);
-
-            var memberState = await Room.GetStateAsync<RoomMemberEventData>("m.room.member", hs.UserId);
-            if (memberState is not null) {
-                
-                hasCustomProfileAvatar = memberState.AvatarUrl != profile.AvatarUrl;
-                profileAvatar = MediaResolver.ResolveMediaUri(hs.FullHomeServerDomain, memberState.AvatarUrl ?? profile.AvatarUrl ?? "/icon-192.png");
-                
-                hasCustomProfileName = memberState.Displayname != profile.DisplayName;
-                profileName = memberState.Displayname;
+            var state = await Room.GetStateAsync<RoomAvatarEventData>("m.room.avatar");
+            if (state?.Url is { } url) {
+                roomIcon = MediaResolver.ResolveMediaUri(hs.FullHomeServerDomain, url);
+                Console.WriteLine($"Got avatar for room {RoomId}: {roomIcon} ({url})");
+            }
+        }
+        catch (MatrixException e) {
+            if (e is not { ErrorCode: "M_FORBIDDEN" }) {
+                throw;
             }
         }
-        _semaphoreSlim.Release();
     }
 
 }
\ No newline at end of file