about summary refs log tree commit diff
path: root/MatrixUtils.Web
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2024-10-23 16:14:45 +0200
committerRory& <root@rory.gay>2024-10-23 16:14:45 +0200
commit7aba1a4570cc4d7275fa290e6eba487845fc8e43 (patch)
treef47f75daa85a667cd036f58c87a5f3c4dbe4d7fd /MatrixUtils.Web
parentSmall fixes, fix policy list editor (diff)
downloadMatrixUtils-dev/media-streaming.tar.xz
Diffstat (limited to 'MatrixUtils.Web')
-rw-r--r--MatrixUtils.Web/Pages/About.razor2
-rw-r--r--MatrixUtils.Web/Pages/Rooms/PolicyLists.razor177
-rw-r--r--MatrixUtils.Web/Pages/Rooms/PolicyLists.razor.css6
-rw-r--r--MatrixUtils.Web/Pages/Rooms/Space.razor11
-rw-r--r--MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor2
-rw-r--r--MatrixUtils.Web/Shared/NavMenu.razor6
6 files changed, 201 insertions, 3 deletions
diff --git a/MatrixUtils.Web/Pages/About.razor b/MatrixUtils.Web/Pages/About.razor
index 330d1c2..9f83991 100644
--- a/MatrixUtils.Web/Pages/About.razor
+++ b/MatrixUtils.Web/Pages/About.razor
@@ -8,5 +8,5 @@
 <p>These range from joining rooms on dead homeservers, to managing your accounts and rooms, and creating rooms based on templates.</p>
 
 <br/>
-<p>You can find the source code on <a href="https://cgit.rory.gay/matrix/MatrixRoomUtils.git/">cgit.rory.gay</a>.<br/></p>
+<p>You can find the source code on <a href="https://cgit.rory.gay/matrix/tools/MatrixUtils.git/about/">cgit.rory.gay</a>.<br/></p>
 <p>You can also join the <a href="https://matrix.to/#/%23mru%3Arory.gay?via=rory.gay&via=matrix.org&via=feline.support">Matrix room</a> for this project.</p>
diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyLists.razor b/MatrixUtils.Web/Pages/Rooms/PolicyLists.razor
new file mode 100644
index 0000000..63dc206
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/PolicyLists.razor
@@ -0,0 +1,177 @@
+@page "/PolicyLists"
+@using System.Collections.ObjectModel
+@using ArcaneLibs.Extensions
+@using LibMatrix
+@using LibMatrix.EventTypes
+@using LibMatrix.EventTypes.Common
+@using LibMatrix.EventTypes.Spec.State.Policy
+@using LibMatrix.RoomTypes
+@inject ILogger<Index> logger
+<h3>Policy lists </h3> @* <LinkButton href="/Rooms/Create">Create new policy list</LinkButton> *@
+
+@if (!string.IsNullOrWhiteSpace(Status)) {
+    <p>@Status</p>
+}
+@if (!string.IsNullOrWhiteSpace(Status2)) {
+    <p>@Status2</p>
+}
+<hr/>
+
+<table>
+    <thead>
+        <tr>
+            <th/>
+            <th>Room name</th>
+            <th>Policies</th>
+        </tr>
+    </thead>
+    <tbody>
+        @foreach (var room in Rooms.OrderByDescending(x => x.PolicyCounts.Sum(y => y.Value))) {
+            <tr>
+                <td>
+                    <LinkButton href="@($"/Rooms/{room.Room.RoomId}/Policies")">
+                        <span class="oi oi-pencil" aria-hidden="true"></span>
+                    </LinkButton>
+                </td>
+                <td style="padding-right: 24px;">
+                    <span>@room.RoomName</span>
+                    @if (room.IsLegacy) {
+                        <span style="color: red;"> (legacy)</span>
+                    }
+                    <br/>
+                    @if (!string.IsNullOrWhiteSpace(room.Shortcode)) {
+                        <span style="font-size: 0.8em;">@room.Shortcode</span>
+                    }
+                    else {
+                        <span style="color: red;">(no shortcode)</span>
+                    }
+                </td>
+                <td>
+                    <span>@(room.PolicyCounts.GetValueOrDefault(RoomInfo.PolicyType.User) ?? 0) user policies</span><br/>
+                    <span>@(room.PolicyCounts.GetValueOrDefault(RoomInfo.PolicyType.Server) ?? 0) server policies</span><br/>
+                    <span>@(room.PolicyCounts.GetValueOrDefault(RoomInfo.PolicyType.Room) ?? 0) room policies</span><br/>
+                </td>
+            </tr>
+        }
+    </tbody>
+</table>
+
+@code {
+
+    private List<RoomInfo> Rooms { get; } = [];
+
+    private AuthenticatedHomeserverGeneric? Homeserver { get; set; }
+
+    protected override async Task OnInitializedAsync() {
+        Homeserver = await RMUStorage.GetCurrentSessionOrNavigate();
+        if (Homeserver is null) return;
+
+        Status = "Fetching rooms...";
+
+        var userEventTypes = EventContent.GetMatchingEventTypes<UserPolicyRuleEventContent>();
+        var serverEventTypes = EventContent.GetMatchingEventTypes<ServerPolicyRuleEventContent>();
+        var roomEventTypes = EventContent.GetMatchingEventTypes<RoomPolicyRuleEventContent>();
+        var knownPolicyTypes = (List<string>) [..userEventTypes, ..serverEventTypes, ..roomEventTypes];
+
+        List<GenericRoom> roomsByType = [];
+        await foreach (var room in Homeserver.GetJoinedRoomsByType("support.feline.policy.lists.msc.v1")) {
+            roomsByType.Add(room);
+            Status2 = $"Found {room.RoomId} (MSC3784)...";
+        }
+
+        List<Task<RoomInfo>> tasks = roomsByType.Select(async room => {
+            Status2 = $"Fetching room {room.RoomId}...";
+            return await RoomInfo.FromRoom(room);
+        }).ToList();
+
+        var results = tasks.ToAsyncEnumerable();
+        await foreach (var result in results) {
+            Rooms.Add(result);
+            StateHasChanged();
+        }
+
+        Status = "Searching for legacy lists...";
+
+        var rooms = (await Homeserver.GetJoinedRooms())
+            .Where(x => !Rooms.Any(y => y.Room.RoomId == x.RoomId))
+            .Select(async room => {
+                var state = await room.GetFullStateAsListAsync();
+                var policies = state
+                    .Where(x => knownPolicyTypes.Contains(x.Type))
+                    .ToList();
+                if (policies.Count == 0) return null;
+                Status2 = $"Found legacy list {room.RoomId}...";
+                return await RoomInfo.FromRoom(room, state, true);
+            })
+            .ToAsyncEnumerable();
+
+        await foreach (var room in rooms) {
+            if (room is not null) {
+                Rooms.Add(room);
+                StateHasChanged();
+            }
+        }
+
+        Status = "";
+        Status2 = "";
+        await base.OnInitializedAsync();
+    }
+
+    private string _status;
+
+    public string Status {
+        get => _status;
+        set {
+            _status = value;
+            StateHasChanged();
+        }
+    }
+
+    private string _status2;
+
+    public string Status2 {
+        get => _status2;
+        set {
+            _status2 = value;
+            StateHasChanged();
+        }
+    }
+
+    private class RoomInfo {
+        public GenericRoom Room { get; set; }
+        public string RoomName { get; set; }
+        public string? Shortcode { get; set; }
+        public Dictionary<PolicyType, int?> PolicyCounts { get; set; }
+        public bool IsLegacy { get; set; }
+
+        public enum PolicyType {
+            User,
+            Room,
+            Server
+        }
+
+        private static readonly List<string> userEventTypes = EventContent.GetMatchingEventTypes<UserPolicyRuleEventContent>();
+        private static readonly List<string> serverEventTypes = EventContent.GetMatchingEventTypes<ServerPolicyRuleEventContent>();
+        private static readonly List<string> roomEventTypes = EventContent.GetMatchingEventTypes<RoomPolicyRuleEventContent>();
+        private static readonly List<string> allKnownPolicyTypes = [..userEventTypes, ..serverEventTypes, ..roomEventTypes];
+
+        public static async Task<RoomInfo> FromRoom(GenericRoom room, List<StateEventResponse>? state = null, bool legacy = false) {
+            state ??= await room.GetFullStateAsListAsync();
+            return new RoomInfo() {
+                Room = room,
+                IsLegacy = legacy,
+                RoomName = await room.GetNameAsync()
+                           ?? (await room.GetCanonicalAliasAsync())?.Alias
+                           ?? (await room.GetStateOrNullAsync<MjolnirShortcodeEventContent>(MjolnirShortcodeEventContent.EventId))?.Shortcode
+                           ?? room.RoomId,
+                Shortcode = (await room.GetStateOrNullAsync<MjolnirShortcodeEventContent>(MjolnirShortcodeEventContent.EventId))?.Shortcode,
+                PolicyCounts = new() {
+                    { PolicyType.User, state.Count(x => userEventTypes.Contains(x.Type)) },
+                    { PolicyType.Server, state.Count(x => serverEventTypes.Contains(x.Type)) },
+                    { PolicyType.Room, state.Count(x => roomEventTypes.Contains(x.Type)) }
+                }
+            };
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyLists.razor.css b/MatrixUtils.Web/Pages/Rooms/PolicyLists.razor.css
new file mode 100644
index 0000000..f9b5b3f
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/PolicyLists.razor.css
@@ -0,0 +1,6 @@
+table, th, td {
+    border-width: 1px;
+}
+td {
+    padding: 8px;
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Rooms/Space.razor b/MatrixUtils.Web/Pages/Rooms/Space.razor
index 8153224..088fdcd 100644
--- a/MatrixUtils.Web/Pages/Rooms/Space.razor
+++ b/MatrixUtils.Web/Pages/Rooms/Space.razor
@@ -6,6 +6,9 @@
 @using MatrixUtils.Abstractions
 <h3>Room manager - Viewing Space</h3>
 
+<span>Add new room to space: </span>
+<FancyTextBox @bind-Value="@NewRoomId"></FancyTextBox>
+<button onclick="@AddNewRoom">Add</button>
 <button onclick="@JoinAllRooms">Join all rooms</button>
 @foreach (var room in Rooms) {
     <RoomListItem RoomInfo="room" ShowOwnProfile="true"></RoomListItem>
@@ -31,6 +34,7 @@
     private StateEventResponse[] States { get; set; } = Array.Empty<StateEventResponse>();
     private List<RoomInfo> Rooms { get; } = new();
     private List<string> ServersInSpace { get; } = new();
+    private string? NewRoomId { get; set; }
 
     protected override async Task OnInitializedAsync() {
         var hs = await RMUStorage.GetCurrentSessionOrNavigate();
@@ -123,7 +127,7 @@
                 var ce = await room.GetCreateEventAsync();
                 if(ce is null) continue;
                 if (ce.Type == "m.space") {
-                     var children = room.AsSpace.GetChildrenAsync(true);
+                     var children = room.AsSpace.GetChildrenAsync(false);
                      await foreach (var child in children) {
                          JoinRecursive(child.RoomId);
                      }
@@ -137,4 +141,9 @@
 
     }
 
+    private async Task AddNewRoom() {
+        if (string.IsNullOrWhiteSpace(NewRoomId)) return;
+        await Room.AsSpace.AddChildByIdAsync(NewRoomId);
+    }
+
 }
diff --git a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
index f2af9b5..e093db2 100644
--- a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
+++ b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
@@ -140,7 +140,7 @@ else
 
                     var rgb = RoomData[roomName][date.Year][date];
                     if (message.RawContent?.Count == 0) rgb.R++;
-                    else if (string.IsNullOrWhiteSpace(message.Unsigned?.ReplacesState)) rgb.G++;
+                    else if (message.Unsigned?.ContainsKey("replaces_state") ?? false) rgb.G++;
                     else rgb.B++;
                     RoomData[roomName][date.Year][date] = rgb;
                 }
diff --git a/MatrixUtils.Web/Shared/NavMenu.razor b/MatrixUtils.Web/Shared/NavMenu.razor
index 770a246..7371e66 100644
--- a/MatrixUtils.Web/Shared/NavMenu.razor
+++ b/MatrixUtils.Web/Shared/NavMenu.razor
@@ -37,6 +37,12 @@
         </div>
 
         <div class="nav-item px-3">
+            <NavLink class="nav-link" href="PolicyLists">
+                <span class="oi oi-ban" aria-hidden="true"></span> Manage policy lists
+            </NavLink>
+        </div>
+
+        <div class="nav-item px-3">
             <NavLink class="nav-link" href="User/Profile">
                 <span class="oi oi-person" aria-hidden="true"></span> Manage profile
             </NavLink>