diff options
Diffstat (limited to 'MatrixRoomUtils.Web/Shared')
6 files changed, 130 insertions, 81 deletions
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 |