From 89315fa530e1f21e2e50d94f955693b9413c98fe Mon Sep 17 00:00:00 2001 From: TheArcaneBrony Date: Wed, 25 Oct 2023 14:00:02 +0200 Subject: New things --- ArcaneLibs | 2 +- LibMatrix | 2 +- MatrixRoomUtils.LibDMSpace/DMSpaceConfiguration.cs | 12 + MatrixRoomUtils.LibDMSpace/DMSpaceRoom.cs | 83 +++++++ .../MatrixRoomUtils.LibDMSpace.csproj | 16 ++ .../StateEvents/DMRoomInfo.cs | 14 ++ .../StateEvents/DMSpaceInfo.cs | 14 ++ MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs | 6 +- MatrixRoomUtils.Web/Classes/RoomInfo.cs | 12 +- MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj | 5 + MatrixRoomUtils.Web/Pages/Dev/DevOptions.razor | 55 ++++- MatrixRoomUtils.Web/Pages/Rooms/Index.razor | 2 +- .../Pages/Tools/CopyPowerlevel.razor | 84 +++++++ MatrixRoomUtils.Web/Pages/Tools/MassJoinRoom.razor | 110 ++++++++++ MatrixRoomUtils.Web/Pages/User/DMManager.razor | 56 +++++ MatrixRoomUtils.Web/Pages/User/DMSpace.razor | 86 ++++++++ .../Pages/User/DMSpaceStages/DMSpaceStage0.razor | 11 + .../Pages/User/DMSpaceStages/DMSpaceStage1.razor | 128 +++++++++++ .../Pages/User/DMSpaceStages/DMSpaceStage2.razor | 241 +++++++++++++++++++++ .../Pages/User/DMSpaceStages/DMSpaceStage3.razor | 189 ++++++++++++++++ MatrixRoomUtils.Web/Pages/User/Manage.razor | 11 +- MatrixRoomUtils.Web/Shared/InlineUserItem.razor | 9 +- MatrixRoomUtils.Web/Shared/NavMenu.razor | 10 +- MatrixRoomUtils.Web/Shared/RoomList.razor | 3 +- .../RoomListComponents/RoomListCategory.razor | 3 +- MatrixRoomUtils.Web/Shared/RoomListItem.razor | 52 ++++- .../TimelineComponents/TimelineMemberItem.razor | 3 +- MatrixRoomUtils.Web/Shared/UserListItem.razor | 3 +- MatrixRoomUtils.sln | 6 + 29 files changed, 1187 insertions(+), 41 deletions(-) create mode 100644 MatrixRoomUtils.LibDMSpace/DMSpaceConfiguration.cs create mode 100644 MatrixRoomUtils.LibDMSpace/DMSpaceRoom.cs create mode 100644 MatrixRoomUtils.LibDMSpace/MatrixRoomUtils.LibDMSpace.csproj create mode 100644 MatrixRoomUtils.LibDMSpace/StateEvents/DMRoomInfo.cs create mode 100644 MatrixRoomUtils.LibDMSpace/StateEvents/DMSpaceInfo.cs create mode 100644 MatrixRoomUtils.Web/Pages/Tools/CopyPowerlevel.razor create mode 100644 MatrixRoomUtils.Web/Pages/Tools/MassJoinRoom.razor create mode 100644 MatrixRoomUtils.Web/Pages/User/DMManager.razor create mode 100644 MatrixRoomUtils.Web/Pages/User/DMSpace.razor create mode 100644 MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage0.razor create mode 100644 MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage1.razor create mode 100644 MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor create mode 100644 MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor diff --git a/ArcaneLibs b/ArcaneLibs index e9cf8d3..7c8f845 160000 --- a/ArcaneLibs +++ b/ArcaneLibs @@ -1 +1 @@ -Subproject commit e9cf8d3061cca5319982c1ef15b78f7c7ca36e89 +Subproject commit 7c8f845f2376890aeb9d564f078ee93c3157d578 diff --git a/LibMatrix b/LibMatrix index 0330ff6..478fc1b 160000 --- a/LibMatrix +++ b/LibMatrix @@ -1 +1 @@ -Subproject commit 0330ff6706a968400ca8fe2a3e3ccf6237a15566 +Subproject commit 478fc1b0ef855530e1e93c5212d154280f9d7dd8 diff --git a/MatrixRoomUtils.LibDMSpace/DMSpaceConfiguration.cs b/MatrixRoomUtils.LibDMSpace/DMSpaceConfiguration.cs new file mode 100644 index 0000000..4085367 --- /dev/null +++ b/MatrixRoomUtils.LibDMSpace/DMSpaceConfiguration.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace MatrixRoomUtils.LibDMSpace; + +//gay.rory.dm_space +public class DMSpaceConfiguration { + public const string EventId = "gay.rory.dm_space"; + + [JsonPropertyName("dm_space_id")] + public string? DMSpaceId { get; set; } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.LibDMSpace/DMSpaceRoom.cs b/MatrixRoomUtils.LibDMSpace/DMSpaceRoom.cs new file mode 100644 index 0000000..247ace8 --- /dev/null +++ b/MatrixRoomUtils.LibDMSpace/DMSpaceRoom.cs @@ -0,0 +1,83 @@ +using ArcaneLibs.Extensions; +using LibMatrix; +using LibMatrix.Homeservers; +using LibMatrix.RoomTypes; +using MatrixRoomUtils.LibDMSpace.StateEvents; + +namespace MatrixRoomUtils.LibDMSpace; + +public class DMSpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomId) : SpaceRoom(homeserver, roomId) { + private readonly GenericRoom _room; + + public async Task GetDmSpaceInfo() { + return await GetStateOrNullAsync(DMSpaceInfo.EventId); + } + + public async IAsyncEnumerable GetChildrenAsync(bool includeRemoved = false) { + var rooms = new List(); + var state = GetFullStateAsync(); + await foreach (var stateEvent in state) { + if (stateEvent!.Type != "m.space.child") continue; + if (stateEvent.RawContent!.ToJson() != "{}" || includeRemoved) + yield return homeserver.GetRoom(stateEvent.StateKey); + } + } + + public async Task AddChildAsync(GenericRoom room) { + var members = room.GetMembersAsync(true); + Dictionary memberCountByHs = new(); + await foreach (var member in members) { + var server = member.StateKey.Split(':')[1]; + if (memberCountByHs.ContainsKey(server)) memberCountByHs[server]++; + else memberCountByHs[server] = 1; + } + + var resp = await SendStateEventAsync("m.space.child", room.RoomId, new { + via = memberCountByHs + .OrderByDescending(x => x.Value) + .Select(x => x.Key) + .Take(10) + }); + return resp; + } + + public async Task ImportNativeDMs() { + var dmSpaceInfo = await GetDmSpaceInfo(); + if (dmSpaceInfo is null) throw new NullReferenceException("DM Space is not configured!"); + if (dmSpaceInfo.LayerByUser) + await ImportNativeDMsIntoLayers(); + else await ImportNativeDMsWithoutLayers(); + } + +#region Import Native DMs + + private async Task ImportNativeDMsWithoutLayers() { + var mdirect = await homeserver.GetAccountDataAsync>>("m.direct"); + foreach (var (userId, dmRooms) in mdirect) { + foreach (var roomid in dmRooms) { + var dri = new DMRoomInfo() { + RemoteUsers = new() { + userId + } + }; + // Add all DM room members + var members = homeserver.GetRoom(roomid).GetMembersAsync(); + await foreach (var member in members) + if (member.StateKey != userId) + dri.RemoteUsers.Add(member.StateKey); + // Remove members of DM space + members = GetMembersAsync(); + await foreach (var member in members) + if (dri.RemoteUsers.Contains(member.StateKey)) + dri.RemoteUsers.Remove(member.StateKey); + await SendStateEventAsync(DMRoomInfo.EventId, roomid, dri); + } + } + } + + private async Task ImportNativeDMsIntoLayers() { + var mdirect = await homeserver.GetAccountDataAsync>>("m.direct"); + } + +#endregion +} \ No newline at end of file diff --git a/MatrixRoomUtils.LibDMSpace/MatrixRoomUtils.LibDMSpace.csproj b/MatrixRoomUtils.LibDMSpace/MatrixRoomUtils.LibDMSpace.csproj new file mode 100644 index 0000000..70b4ffc --- /dev/null +++ b/MatrixRoomUtils.LibDMSpace/MatrixRoomUtils.LibDMSpace.csproj @@ -0,0 +1,16 @@ + + + + net7.0 + enable + enable + preview + + + + + + + + + diff --git a/MatrixRoomUtils.LibDMSpace/StateEvents/DMRoomInfo.cs b/MatrixRoomUtils.LibDMSpace/StateEvents/DMRoomInfo.cs new file mode 100644 index 0000000..b88f06a --- /dev/null +++ b/MatrixRoomUtils.LibDMSpace/StateEvents/DMRoomInfo.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; +using LibMatrix.EventTypes; +using LibMatrix.Interfaces; + +namespace MatrixRoomUtils.LibDMSpace.StateEvents; + +[MatrixEvent(EventName = EventId)] +public class DMRoomInfo : EventContent { + public const string EventId = "gay.rory.dm_room_info"; + [JsonPropertyName("remote_users")] + public List RemoteUsers { get; set; } + + +} \ No newline at end of file diff --git a/MatrixRoomUtils.LibDMSpace/StateEvents/DMSpaceInfo.cs b/MatrixRoomUtils.LibDMSpace/StateEvents/DMSpaceInfo.cs new file mode 100644 index 0000000..7824324 --- /dev/null +++ b/MatrixRoomUtils.LibDMSpace/StateEvents/DMSpaceInfo.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; +using LibMatrix.EventTypes; +using LibMatrix.Interfaces; + +namespace MatrixRoomUtils.LibDMSpace.StateEvents; + +[MatrixEvent(EventName = EventId)] +public class DMSpaceInfo : EventContent { + public const string EventId = "gay.rory.dm_space_info"; + + [JsonPropertyName("is_layered")] + public bool LayerByUser { get; set; } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs b/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs index 3223ec6..b6836c8 100644 --- a/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs +++ b/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs @@ -7,8 +7,6 @@ namespace MatrixRoomUtils.Web.Classes; public class MRUStorageWrapper(TieredStorageService storageService, HomeserverProviderService homeserverProviderService, NavigationManager navigationManager) { public async Task?> GetAllTokens() { - if (!await storageService.DataStorageProvider.ObjectExistsAsync("mru.tokens")) { } - return await storageService.DataStorageProvider.LoadObjectAsync>("mru.tokens") ?? new List(); } @@ -48,6 +46,10 @@ public class MRUStorageWrapper(TieredStorageService storageService, HomeserverPr return await homeserverProviderService.GetAuthenticatedWithToken(token.Homeserver, token.AccessToken); } + public async Task GetSession(UserAuth userAuth) { + return await homeserverProviderService.GetAuthenticatedWithToken(userAuth.Homeserver, userAuth.AccessToken); + } + public async Task GetCurrentSessionOrNavigate() { AuthenticatedHomeserverGeneric? session = null; diff --git a/MatrixRoomUtils.Web/Classes/RoomInfo.cs b/MatrixRoomUtils.Web/Classes/RoomInfo.cs index 31943dc..a2fa6f5 100644 --- a/MatrixRoomUtils.Web/Classes/RoomInfo.cs +++ b/MatrixRoomUtils.Web/Classes/RoomInfo.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using System.Text.Json.Nodes; using ArcaneLibs; using LibMatrix; using LibMatrix.EventTypes.Spec.State; @@ -8,7 +9,7 @@ using LibMatrix.RoomTypes; namespace MatrixRoomUtils.Web.Classes; public class RoomInfo : NotifyPropertyChanged { - public GenericRoom Room { get; set; } + public GenericRoom? Room { get; set; } public ObservableCollection StateEvents { get; } = new(); public async Task GetStateEvent(string type, string stateKey = "") { @@ -19,11 +20,12 @@ public class RoomInfo : NotifyPropertyChanged { Type = type, StateKey = stateKey }; + if (Room is null) return null; try { - @event.TypedContent = await Room.GetStateAsync(type, stateKey); + @event.RawContent = await Room.GetStateAsync(type, stateKey); } catch (MatrixException e) { - if (e is { ErrorCode: "M_NOT_FOUND" }) @event.TypedContent = default!; + if (e is { ErrorCode: "M_NOT_FOUND" }) @event.RawContent = default!; else throw; } @@ -37,7 +39,7 @@ public class RoomInfo : NotifyPropertyChanged { } public string? RoomName { - get => _roomName ?? Room.RoomId; + get => _roomName ?? DefaultRoomName ?? Room.RoomId; set => SetField(ref _roomName, value); } @@ -58,6 +60,8 @@ public class RoomInfo : NotifyPropertyChanged { private string? _roomName; private RoomCreateEventContent? _creationEventContent; private string? _roomCreator; + + public string? DefaultRoomName { get; set; } public RoomInfo() { StateEvents.CollectionChanged += (_, args) => { diff --git a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj index 625a303..543f8db 100644 --- a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj +++ b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj @@ -21,9 +21,14 @@ + + + + + diff --git a/MatrixRoomUtils.Web/Pages/Dev/DevOptions.razor b/MatrixRoomUtils.Web/Pages/Dev/DevOptions.razor index 9b0f61c..a1e928f 100644 --- a/MatrixRoomUtils.Web/Pages/Dev/DevOptions.razor +++ b/MatrixRoomUtils.Web/Pages/Dev/DevOptions.razor @@ -1,5 +1,8 @@ @page "/Dev/Options" @using ArcaneLibs.Extensions +@using System.Text.Unicode +@using System.Text +@using System.Text.Json @inject NavigationManager NavigationManager @inject ILocalStorageService LocalStorage @@ -8,23 +11,61 @@

Rory&::MatrixUtils - Developer options


-
-
-
+

+ Import local storage: + +

+

+ Export local storage: + +

+ +@if (userSettings is not null) { + + +
+ + +
+ + +
+}
@code { - MRUStorageWrapper.Settings settings { get; set; } = new(); + private MRUStorageWrapper.Settings? userSettings { get; set; } protected override async Task OnInitializedAsync() { - settings = await TieredStorage.DataStorageProvider.LoadObjectAsync("mru.settings"); + // userSettings = await TieredStorage.DataStorageProvider.LoadObjectAsync("mru.settings"); + await base.OnInitializedAsync(); } private async Task LogStuff() { await Task.Delay(100); - Console.WriteLine($"Settings: {settings.ToJson()}"); - await TieredStorage.DataStorageProvider.SaveObjectAsync("mru.settings", settings); + Console.WriteLine($"Settings: {userSettings.ToJson()}"); + await TieredStorage.DataStorageProvider.SaveObjectAsync("mru.settings", userSettings); + } + + private async Task ExportLocalStorage() { + var keys = await TieredStorage.DataStorageProvider.GetAllKeysAsync(); + var data = new Dictionary(); + foreach (var key in keys) { + data.Add(key, await TieredStorage.DataStorageProvider.LoadObjectAsync(key)); + } + var dataUri = "data:application/json;base64,"; + dataUri += Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(data))); + await JSRuntime.InvokeVoidAsync("window.open", dataUri, "_blank"); + } + + private async Task ImportLocalStorage(InputFileChangeEventArgs obj) { + if (obj.FileCount != 1) return; + var data = await JsonSerializer.DeserializeAsync>(obj.File.OpenReadStream()); + foreach (var (key, value) in data) { + await TieredStorage.DataStorageProvider.SaveObjectAsync(key, value); + } + NavigationManager.NavigateTo(NavigationManager.Uri, true, true); } } diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor index 4d98402..516e9ca 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor @@ -22,7 +22,7 @@ @code { private ObservableCollection Rooms { get; } = new(); - private ProfileResponseEventContent GlobalProfile { get; set; } + private UserProfileResponse GlobalProfile { get; set; } private AuthenticatedHomeserverGeneric? Homeserver { get; set; } diff --git a/MatrixRoomUtils.Web/Pages/Tools/CopyPowerlevel.razor b/MatrixRoomUtils.Web/Pages/Tools/CopyPowerlevel.razor new file mode 100644 index 0000000..aaeb5a3 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/Tools/CopyPowerlevel.razor @@ -0,0 +1,84 @@ +@page "/CopyPowerlevel" +@using System.Diagnostics +@using ArcaneLibs.Extensions +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Homeservers +@using LibMatrix.RoomTypes +

Copy powerlevel

+
+ +

Users:

+@foreach (var hs in hss) { +

@hs.WhoAmI.UserId

+} + +
+Execute +
+@foreach (var line in Enumerable.Reverse(log)) { +

@line

+} + +@code { + private List log { get; set; } = new(); + List hss { get; set; } = new(); + + protected override async Task OnInitializedAsync() { + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + var sessions = await MRUStorage.GetAllTokens(); + foreach (var userAuth in sessions) { + var session = await MRUStorage.GetSession(userAuth); + if (session is not null) { + hss.Add(session); + StateHasChanged(); + } + } + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + foreach (var hs in hss) { + var rooms = await hs.GetJoinedRooms(); + var tasks = rooms.Select(x=>Execute(hs, x)).ToAsyncEnumerable(); + await foreach (var a in tasks) { + if (!string.IsNullOrWhiteSpace(a)) { + log.Add(a); + StateHasChanged(); + } + } + } + } + + private async Task Execute(AuthenticatedHomeserverGeneric hs, GenericRoom room) { + try { + var pls = await room.GetPowerLevelsAsync(); + // if (pls.GetUserPowerLevel(hs.WhoAmI.UserId) == pls.UsersDefault) return "I am default PL in " + room.RoomId; + if (!pls.UserHasPermission(hs.WhoAmI.UserId, RoomPowerLevelEventContent.EventId)) return "I do not have permission to send PL in " + room.RoomId; + foreach (var ahs in hss) { + if (pls.GetUserPowerLevel(hs.WhoAmI.UserId) == pls.GetUserPowerLevel(ahs.WhoAmI.UserId)) { + log.Add("I am same PL in " + room.RoomId); + continue; + } + + pls.SetUserPowerLevel(ahs.WhoAmI.UserId, pls.GetUserPowerLevel(hs.WhoAmI.UserId)); + await room.SendStateEventAsync(RoomPowerLevelEventContent.EventId, pls); + log.Add($"Updated powerlevel of {room.RoomId} to {pls.GetUserPowerLevel(ahs.WhoAmI.UserId)}"); + } + + } + catch (MatrixException e) { + return $"Failed to update PLs in {room.RoomId}: {e.Message}"; + } + catch (Exception e) { + return $"Failed to update PLs in {room.RoomId}: {e.Message}"; + } + StateHasChanged(); + return ""; + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/Tools/MassJoinRoom.razor b/MatrixRoomUtils.Web/Pages/Tools/MassJoinRoom.razor new file mode 100644 index 0000000..bcf8095 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/Tools/MassJoinRoom.razor @@ -0,0 +1,110 @@ +@page "/MassRoomJoin" +@using System.Diagnostics +@using ArcaneLibs.Extensions +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Homeservers +@using LibMatrix.RoomTypes +

Mass join room

+
+

Room:

+ + +

Users:

+@foreach (var hs in hss) { +

@hs.WhoAmI.UserId

+} + +
+Execute +
+@foreach (var line in Enumerable.Reverse(log)) { +

@line

+} + +@code { + private List log { get; set; } = new(); + List hss { get; set; } = new(); + string roomId { get; set; } + + protected override async Task OnInitializedAsync() { + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + var sessions = await MRUStorage.GetAllTokens(); + foreach (var userAuth in sessions) { + var session = await MRUStorage.GetSession(userAuth); + if (session is not null) { + hss.Add(session); + StateHasChanged(); + } + } + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + // foreach (var hs in hss) { + // var rooms = await hs.GetJoinedRooms(); + var tasks = hss.Select(ExecuteInvite).ToAsyncEnumerable(); + await foreach (var a in tasks) { + if (!string.IsNullOrWhiteSpace(a)) { + log.Add(a); + StateHasChanged(); + } + } + tasks = hss.Select(ExecuteJoin).ToAsyncEnumerable(); + await foreach (var a in tasks) { + if (!string.IsNullOrWhiteSpace(a)) { + log.Add(a); + StateHasChanged(); + } + } + // } + } + + private async Task ExecuteInvite(AuthenticatedHomeserverGeneric hs) { + var room = hs.GetRoom(roomId); + try { + try { + var joinRule = await room.GetJoinRuleAsync(); + if (joinRule.JoinRule == "public") return "Room is public, no invite needed"; + } + catch { } + var pls = await room.GetPowerLevelsAsync(); + if (pls.GetUserPowerLevel(hs.WhoAmI.UserId) < pls.Invite) return "I do not have permission to send invite in " + room.RoomId; + await room.InviteUsersAsync(hss.Select(x => x.WhoAmI.UserId).ToList()); + log.Add($"Invited to {room.RoomId} to {pls.GetUserPowerLevel(hs.WhoAmI.UserId)}"); + } + catch (MatrixException e) { + return $"Failed to invite in {room.RoomId}: {e.Message}"; + } + catch (Exception e) { + return $"Failed to invite in {room.RoomId}: {e.Message}"; + } + StateHasChanged(); + return ""; + } + + private async Task ExecuteJoin(AuthenticatedHomeserverGeneric hs) { + var room = hs.GetRoom(roomId); + try { + try { + var mse = await room.GetStateOrNullAsync(RoomMemberEventContent.EventId, hs.WhoAmI.UserId); + if (mse?.Membership == "join") return $"User {hs.WhoAmI.UserId} already in room"; + } + catch { } + await room.JoinAsync(); + } + catch (MatrixException e) { + return $"Failed to join {hs.WhoAmI.UserId} to {room.RoomId}: {e.Message}"; + } + catch (Exception e) { + return $"Failed to join {hs.WhoAmI.UserId} to {room.RoomId}: {e.Message}"; + } + StateHasChanged(); + return ""; + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/DMManager.razor b/MatrixRoomUtils.Web/Pages/User/DMManager.razor new file mode 100644 index 0000000..04ff6e5 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/User/DMManager.razor @@ -0,0 +1,56 @@ +@page "/User/DirectMessages" +@using LibMatrix.Homeservers +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Responses +

Direct Messages

+
+ +@foreach (var (targetUser, rooms) in DMRooms) { +
+ + @foreach (var room in rooms) { + + } +
+} + +@code { + private string? _status; + private AuthenticatedHomeserverGeneric? HomeServer { get; set; } + private Dictionary> DMRooms { get; set; } = new(); + + public string? Status { + get => _status; + set { + _status = value; + StateHasChanged(); + } + } + + protected override async Task OnInitializedAsync() { + HomeServer = await MRUStorage.GetCurrentSessionOrNavigate(); + if (HomeServer is null) return; + Status = "Loading global profile..."; + if (HomeServer.WhoAmI?.UserId is null) return; + + Status = "Loading DM list from account data..."; + var dms = await HomeServer.GetAccountDataAsync>>("m.direct"); + DMRooms.Clear(); + foreach (var (userId, rooms) in dms) { + var roomList = new List(); + DMRooms.Add(await HomeServer.GetProfileAsync(userId), roomList); + foreach (var room in rooms) { + roomList.Add(new RoomInfo() { Room = HomeServer.GetRoom(room) }); + } + StateHasChanged(); + } + + StateHasChanged(); + Status = null; + + await base.OnInitializedAsync(); + } + + + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/DMSpace.razor b/MatrixRoomUtils.Web/Pages/User/DMSpace.razor new file mode 100644 index 0000000..21cc264 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/User/DMSpace.razor @@ -0,0 +1,86 @@ +@page "/User/DMSpace/Setup" +@using LibMatrix.Homeservers +@using LibMatrix +@using MatrixRoomUtils.LibDMSpace +@using MatrixRoomUtils.LibDMSpace.StateEvents +@using MatrixRoomUtils.Web.Pages.User.DMSpaceStages +

DM Space Management

+
+ + @switch (Stage) { + case -1: +

Initialising...

+ break; + case 0: + + break; + case 1: + + break; + case 2: + + break; + case 3: + + break; + default: +

Stage is unknown value: @Stage!

+ break; + } +
+ +@code { + private int _stage = -1; + + [Parameter, SupplyParameterFromQuery(Name = "stage")] + public int Stage { + get => _stage; + set { + _stage = value; + Console.WriteLine($"Stage is now {value}"); + StateHasChanged(); + } + } + + public AuthenticatedHomeserverGeneric? Homeserver { get; set; } + + public DMSpaceConfiguration? DmSpaceConfiguration { get; set; } + + [Parameter] + public DMSpace? DmSpace { get; set; } + + protected override async Task OnInitializedAsync() { + if (NavigationManager.Uri.Contains("?stage=")) { + NavigationManager.NavigateTo("/User/DMSpace", true); + } + DmSpace = this; + Homeserver ??= await MRUStorage.GetCurrentSessionOrNavigate(); + if (Homeserver is null) return; + try { + DmSpaceConfiguration = await Homeserver.GetAccountDataAsync("gay.rory.dm_space"); + var room = Homeserver.GetRoom(DmSpaceConfiguration.DMSpaceId); + await room.GetStateAsync(DMSpaceInfo.EventId); + Stage = 1; + } + catch (MatrixException e) { + if (e.ErrorCode == "M_NOT_FOUND") { + Stage = 0; + DmSpaceConfiguration = new(); + } + else throw; + } + catch (Exception e) { + throw; + } + finally { + StateHasChanged(); + } + await base.OnInitializedAsync(); + } + + protected override async Task OnParametersSetAsync() { + StateHasChanged(); + await base.OnParametersSetAsync(); + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage0.razor b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage0.razor new file mode 100644 index 0000000..49fd5b4 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage0.razor @@ -0,0 +1,11 @@ + + Welcome to the DM Space tool! + +

This wizard will help you set up a DM space.

+

This is useful for eg. sharing DM rooms across multiple accounts.

+
+Get started + +@code { + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage1.razor b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage1.razor new file mode 100644 index 0000000..3642da5 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage1.razor @@ -0,0 +1,128 @@ +@using LibMatrix.Homeservers +@using LibMatrix.RoomTypes +@using LibMatrix +@using LibMatrix.Responses +@using MatrixRoomUtils.LibDMSpace +@using MatrixRoomUtils.LibDMSpace.StateEvents +@using Microsoft.Extensions.Primitives +@using ArcaneLibs.Extensions + + DM Space setup tool - stage 1: Configure space + +

You will need a space to use for DM rooms.

+@if (DmSpace is not null) { +

+ Selected space: + + @foreach (var (id, name) in spaces) { + + } + +

+

+ + Create sub-spaces per user +

+} +else { + Error: DmSpaceConfiguration is null! +} + +
+Next + +@if (!string.IsNullOrWhiteSpace(Status)) { +

@Status

+} + +@code { + + private string? Status { + get => _status; + set { + _status = value; + StateHasChanged(); + } + } + + private Dictionary spaces = new() { { "", "New space" } }; + private string? _status; + + [CascadingParameter] + public DMSpace? DmSpace { get; set; } + + public DMSpaceInfo? DmSpaceInfo { get; set; } = new(); + + protected override async Task OnInitializedAsync() { + await base.OnInitializedAsync(); + } + + SemaphoreSlim _semaphoreSlim = new(1, 1); + protected override async Task OnParametersSetAsync() { + if (DmSpace is null) + return; + await _semaphoreSlim.WaitAsync(); + DmSpace.DmSpaceConfiguration ??= new(); + if (spaces.Count == 1) { + Status = "Looking for spaces..."; + var userRoomsEnum = DmSpace.Homeserver.GetJoinedRoomsByType("m.space"); + List userRooms = new(); + await foreach (var room in userRoomsEnum) { + userRooms.Add(room); + } + var roomChecks = userRooms.Select(GetFeasibleSpaces).ToAsyncEnumerable(); + await foreach(var room in roomChecks) + if(room.HasValue) + spaces.TryAdd(room.Value.id, room.Value.name); + + Status = "Done!"; + } + _semaphoreSlim.Release(); + await base.OnParametersSetAsync(); + } + + private async Task Execute() { + if (string.IsNullOrWhiteSpace(DmSpace.DmSpaceConfiguration.DMSpaceId)) { + var crr = CreateRoomRequest.CreatePrivate(DmSpace.Homeserver, "Direct Messages"); + crr._creationContentBaseType.Type = "m.space"; + DmSpace.DmSpaceConfiguration.DMSpaceId = (await DmSpace.Homeserver.CreateRoom(crr)).RoomId; + } + await DmSpace.Homeserver!.SetAccountDataAsync(DMSpaceConfiguration.EventId, DmSpace.DmSpaceConfiguration); + var space = DmSpace.Homeserver.GetRoom(DmSpace.DmSpaceConfiguration.DMSpaceId); + await space.SendStateEventAsync(DMSpaceInfo.EventId, DmSpaceInfo); + + NavigationManager.NavigateTo("/User/DMSpace/Setup?stage=2"); + } + + public async Task<(string id, string name)?> GetFeasibleSpaces(GenericRoom room) { + try { + var pls = await room.GetPowerLevelsAsync(); + if (!pls.UserHasPermission(DmSpace.Homeserver.WhoAmI.UserId, "m.space.child")) { + Console.WriteLine($"No permission to send m.space.child in {room.RoomId}..."); + return null; + } + var roomName = await room.GetNameAsync(); + Status = $"Found viable space: {roomName}"; + if (string.IsNullOrWhiteSpace(DmSpace.DmSpaceConfiguration.DMSpaceId)) { + try { + var dsi = await DmSpace.Homeserver.GetRoom(room.RoomId).GetStateOrNullAsync(DMSpaceInfo.EventId) ?? new DMSpaceInfo(); + if (await room.GetStateOrNullAsync(DMSpaceInfo.EventId) is not null && dsi is not null) { + DmSpace.DmSpaceConfiguration.DMSpaceId = room.RoomId; + DmSpaceInfo = dsi; + } + } + catch (MatrixException e) { + if (e.ErrorCode == "M_NOT_FOUND") Console.WriteLine($"{room.RoomId} is not a DM space."); + else throw; + } + } + return (room.RoomId, roomName); + } + catch (MatrixException e) { + if (e.ErrorCode == "M_NOT_FOUND") Console.WriteLine($"m.room.power_levels does not exist in {room.RoomId}!!!"); + else throw; + } + return null; + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor new file mode 100644 index 0000000..553f46d --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage2.razor @@ -0,0 +1,241 @@ +@using LibMatrix.Homeservers +@using LibMatrix.RoomTypes +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Responses +@using MatrixRoomUtils.LibDMSpace +@using MatrixRoomUtils.LibDMSpace.StateEvents +@using ArcaneLibs.Extensions +@using System.Text.Json.Serialization + + DM Space setup tool - stage 2: Fix DM room attribution + +

This is just to make sure that your DMs are attributed to the right person!

+ +@if (!string.IsNullOrWhiteSpace(Status)) { +

@Status

+} + +@if (DmSpace is not null) { + @foreach (var (userId, room) in dmRooms.OrderBy(x => x.Key.Id)) { + + @foreach (var roomInfo in room) { + + Reassign + + } + } +} +else { + Error: DmSpaceConfiguration is null! +} + +
+Next + +@{ + var _offset = 0; +} +@foreach (var (room, usersList) in duplicateDmRooms) { + +

Found room assigned to multiple users:

+

Users:

+ @foreach (var userProfileResponse in usersList) { + + Assign to + + +
+ } +
+} + +@if (DmToReassign is not null) { + + + @foreach (var userProfileResponse in roomMembers[DmToReassign]) { + + Assign to + + +
+ } +
+} + +@code { + + private string newMxid { get; set; } = ""; + + private RoomInfo? DmToReassign { + get => _dmToReassign; + set { + _dmToReassign = value; + StateHasChanged(); + } + } + + private string? Status { + get => _status; + set { + _status = value; + StateHasChanged(); + } + } + + private string? _status; + private RoomInfo? _dmToReassign; + + [CascadingParameter] + public DMSpace? DmSpace { get; set; } + + private Dictionary> dmRooms { get; set; } = new(); + private Dictionary> duplicateDmRooms { get; set; } = new(); + private Dictionary> roomMembers { get; set; } = new(); + + protected override async Task OnInitializedAsync() { + await base.OnInitializedAsync(); + } + + SemaphoreSlim _semaphore = new(1, 1); + + protected override async Task OnParametersSetAsync() { + if (DmSpace is null) + return; + await _semaphore.WaitAsync(); + DmToReassign = null; + var hs = DmSpace.Homeserver; + Status = "Loading DM list from account data..."; + var dms = await DmSpace.Homeserver.GetAccountDataAsync>>("m.direct"); + Status = "Optimising DM list from account data..."; + var joinedRooms = (await hs.GetJoinedRooms()).Select(x => x.RoomId).ToList(); + foreach (var (user, rooms) in dms) { + for (var i = rooms.Count - 1; i >= 0; i--) { + var roomId = rooms[i]; + if (!joinedRooms.Contains(roomId)) + rooms.RemoveAt(i); + } + dms[user] = rooms.Distinct().ToList(); + } + dms.RemoveAll((x, y) => y is {Count: 0}); + await DmSpace.Homeserver.SetAccountDataAsync("m.direct", dms); + dmRooms.Clear(); + + Status = "DM list optimised, fetching info..."; + var results = dms.Select(async x => { + var (userId, rooms) = x; + UserProfileWithId userProfile; + try { + var profile = await DmSpace.Homeserver.GetProfileAsync(userId); + userProfile = new() { + AvatarUrl = profile.AvatarUrl, + Id = userId, + DisplayName = profile.DisplayName + }; + } + catch { + userProfile = new() { + AvatarUrl = "mxc://feline.support/uUxBwaboPkMGtbZcAGZaIzpK", + DisplayName = userId, + Id = userId + }; + } + var roomList = new List(); + var tasks = rooms.Select(x => GetRoomInfo(hs.GetRoom(x))).ToAsyncEnumerable(); + await foreach (var result in tasks) + roomList.Add(result); + return (userProfile, roomList); + // StateHasChanged(); + }).ToAsyncEnumerable(); + await foreach (var res in results) { + dmRooms.Add(res.userProfile, res.roomList); + // Status = $"Listed {dmRooms.Count} users"; + } + _semaphore.Release(); + var duplicateDmRoomIds = new Dictionary>(); + foreach (var (user, rooms) in dmRooms) { + foreach (var roomInfo in rooms) { + if (!duplicateDmRoomIds.ContainsKey(roomInfo.Room.RoomId)) + duplicateDmRoomIds.Add(roomInfo.Room.RoomId, new()); + duplicateDmRoomIds[roomInfo.Room.RoomId].Add(user); + } + } + duplicateDmRoomIds.RemoveAll((x, y) => y.Count == 1); + foreach (var (roomId, users) in duplicateDmRoomIds) { + duplicateDmRooms.Add(dmRooms.First(x => x.Value.Any(x => x.Room.RoomId == roomId)).Value.First(x => x.Room.RoomId == roomId), users); + } + + // StateHasChanged(); + Status = null; + await base.OnParametersSetAsync(); + } + + private async Task Execute() { + NavigationManager.NavigateTo("/User/DMSpace/Setup?stage=3"); + } + + private async Task GetRoomInfo(GenericRoom room) { + var roomInfo = new RoomInfo() { + Room = room + }; + roomMembers[roomInfo] = new(); + roomInfo.CreationEventContent = await room.GetCreateEventAsync(); + try { + roomInfo.RoomName = await room.GetNameAsync(); + } + catch { } + + var membersEnum = room.GetMembersAsync(); + await foreach (var member in membersEnum) + if (member.TypedContent is RoomMemberEventContent memberEvent && !string.IsNullOrWhiteSpace(memberEvent.Membership) && memberEvent.Membership == "join") + roomMembers[roomInfo].Add(new() { DisplayName = memberEvent.DisplayName, AvatarUrl = memberEvent.AvatarUrl, Id = member.StateKey }); + + if (string.IsNullOrWhiteSpace(roomInfo.RoomName) || roomInfo.RoomName == room.RoomId) { + List displayNames = new List(); + foreach (var member in roomMembers[roomInfo]) + if (!string.IsNullOrWhiteSpace(member.DisplayName)) + displayNames.Add(member.DisplayName); + roomInfo.RoomName = string.Join(", ", displayNames); + } + try { + string? roomIcon = (await room.GetAvatarUrlAsync())?.Url; + if (room is not null) + roomInfo.RoomIcon = roomIcon; + } + catch { } + return roomInfo; + } + + private async Task> GetRoomInfoForRooms(List rooms) { + var tasks = rooms.Select(GetRoomInfo).ToList(); + await Task.WhenAll(tasks); + return tasks.Select(x => x.Result).ToList(); + } + + private async Task SetRoomAssignment(string roomId, string userId) { + var hs = DmSpace.Homeserver; + Status = "Loading DM list from account data..."; + var dms = await DmSpace.Homeserver.GetAccountDataAsync>>("m.direct"); + Status = "Updating DM list from account data..."; + + foreach (var (user, rooms) in dms) { + rooms.RemoveAll(x => x == roomId); + dms[user] = rooms.Distinct().ToList(); + } + if(!dms.ContainsKey(userId)) + dms.Add(userId, new()); + dms[userId].Add(roomId); + dms.RemoveAll((x, y) => y is {Count: 0}); + await DmSpace.Homeserver.SetAccountDataAsync("m.direct", dms); + + duplicateDmRooms.RemoveAll((x, y) => x.Room.RoomId == roomId); + StateHasChanged(); + if (duplicateDmRooms.Count == 0) await OnParametersSetAsync(); + } + + private class UserProfileWithId : UserProfileResponse { + [JsonIgnore] + public string Id { get; set; } + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor new file mode 100644 index 0000000..854b09c --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/User/DMSpaceStages/DMSpaceStage3.razor @@ -0,0 +1,189 @@ +@using LibMatrix.Homeservers +@using LibMatrix.RoomTypes +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Responses +@using MatrixRoomUtils.LibDMSpace +@using MatrixRoomUtils.LibDMSpace.StateEvents +@using ArcaneLibs.Extensions +@using System.Text.Json.Serialization + + DM Space setup tool - stage 3: Preview space layout + +

This gives you a preview of how your settings would impact layout!

+ +@if (!string.IsNullOrWhiteSpace(Status)) { +

@Status

+} + +@if (DmSpace is not null) { + @if (dmSpaceInfo is not null && dmSpaceRoomInfo is not null) { +

+ + Create sub-spaces per user +

+ @if (!dmSpaceInfo.LayerByUser) { + + @foreach (var (userId, room) in dmRooms.OrderBy(x => x.Key.RoomName)) { + @foreach (var roomInfo in room) { +
+ +
+ } + } + } + else { + + @foreach (var (userId, room) in dmRooms.OrderBy(x => x.Key.RoomName)) { +
+ +
+ @foreach (var roomInfo in room) { +
+ +
+ } + } + } + } + else { + Error: dmSpaceInfo is null! + } +} +else { + Error: DmSpaceConfiguration is null! +} + +
+Next + +@code { + + private string? Status { + get => _status; + set { + _status = value; + StateHasChanged(); + } + } + + private string? _status; + + [CascadingParameter] + public DMSpace? DmSpace { get; set; } + + private Dictionary> dmRooms { get; set; } = new(); + private DMSpaceInfo? dmSpaceInfo { get; set; } + private RoomInfo? dmSpaceRoomInfo { get; set; } + + protected override async Task OnInitializedAsync() { + await base.OnInitializedAsync(); + } + + SemaphoreSlim _semaphore = new(1, 1); + + protected override async Task OnParametersSetAsync() { + if (DmSpace is null) + return; + await _semaphore.WaitAsync(); + var hs = DmSpace.Homeserver; + var dmSpaceRoom = new DMSpaceRoom(hs, DmSpace.DmSpaceConfiguration.DMSpaceId); + dmSpaceRoomInfo = new() { + RoomName = await dmSpaceRoom.GetNameAsync(), + CreationEventContent = await dmSpaceRoom.GetCreateEventAsync(), + RoomIcon = "mxc://feline.support/uUxBwaboPkMGtbZcAGZaIzpK", + Room = dmSpaceRoom + }; + dmSpaceInfo = await dmSpaceRoom.GetDmSpaceInfo(); + Status = "Loading DM list from account data..."; + var dms = await DmSpace.Homeserver.GetAccountDataAsync>>("m.direct"); + dmRooms.Clear(); + + Status = "DM list optimised, fetching info..."; + var results = dms.Select(async x => { + var (userId, rooms) = x; + UserProfileWithId userProfile; + try { + var profile = await DmSpace.Homeserver.GetProfileAsync(userId); + userProfile = new() { + AvatarUrl = profile.AvatarUrl, + Id = userId, + DisplayName = profile.DisplayName + }; + } + catch { + userProfile = new() { + AvatarUrl = "mxc://feline.support/uUxBwaboPkMGtbZcAGZaIzpK", + DisplayName = userId, + Id = userId + }; + } + var roomList = new List(); + var tasks = rooms.Select(x => GetRoomInfo(hs.GetRoom(x))).ToAsyncEnumerable(); + await foreach (var result in tasks) + roomList.Add(result); + return (userProfile, roomList); + }).ToAsyncEnumerable(); + await foreach (var res in results) { + dmRooms.Add(new RoomInfo() { + Room = dmSpaceRoom, + RoomIcon = res.userProfile.AvatarUrl, + RoomName = res.userProfile.DisplayName, + CreationEventContent = await dmSpaceRoom.GetCreateEventAsync() + }, res.roomList); + } + _semaphore.Release(); + Status = null; + await base.OnParametersSetAsync(); + } + + private async Task Execute() { + var hs = DmSpace.Homeserver; + var dmSpaceRoom = new DMSpaceRoom(hs, DmSpace.DmSpaceConfiguration.DMSpaceId); + NavigationManager.NavigateTo("/User/DMSpace/Setup?stage=3"); + } + + private async Task GetRoomInfo(GenericRoom room) { + var roomInfo = new RoomInfo() { + Room = room + }; + var roomMembers = new List(); + roomInfo.CreationEventContent = await room.GetCreateEventAsync(); + try { + roomInfo.RoomName = await room.GetNameAsync(); + } + catch { } + + var membersEnum = room.GetMembersAsync(); + await foreach (var member in membersEnum) + if (member.TypedContent is RoomMemberEventContent memberEvent && !string.IsNullOrWhiteSpace(memberEvent.Membership) && memberEvent.Membership == "join") + roomMembers.Add(new() { DisplayName = memberEvent.DisplayName, AvatarUrl = memberEvent.AvatarUrl, Id = member.StateKey }); + + if (string.IsNullOrWhiteSpace(roomInfo.RoomName) || roomInfo.RoomName == room.RoomId) { + List displayNames = new List(); + foreach (var member in roomMembers) + if (!string.IsNullOrWhiteSpace(member.DisplayName)) + displayNames.Add(member.DisplayName); + roomInfo.RoomName = string.Join(", ", displayNames); + } + try { + string? roomIcon = (await room.GetAvatarUrlAsync())?.Url; + if (room is not null) + roomInfo.RoomIcon = roomIcon; + } + catch { } + return roomInfo; + } + + private async Task> GetRoomInfoForRooms(List rooms) { + var tasks = rooms.Select(GetRoomInfo).ToList(); + await Task.WhenAll(tasks); + return tasks.Select(x => x.Result).ToList(); + } + + private class UserProfileWithId : UserProfileResponse { + [JsonIgnore] + public string Id { get; set; } + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/User/Manage.razor b/MatrixRoomUtils.Web/Pages/User/Manage.razor index 25debf7..eac47e8 100644 --- a/MatrixRoomUtils.Web/Pages/User/Manage.razor +++ b/MatrixRoomUtils.Web/Pages/User/Manage.razor @@ -1,8 +1,9 @@ -@page "/User/Manage" +@page "/User/Profile" @using LibMatrix.Homeservers @using LibMatrix.EventTypes.Spec.State @using ArcaneLibs.Extensions -

Manage user - @HomeServer?.WhoAmI?.UserId

+@using LibMatrix.Responses +

Manage Profile - @HomeServer?.WhoAmI?.UserId


@if (Profile is not null) { @@ -48,8 +49,8 @@ private string? _status = null; private AuthenticatedHomeserverGeneric? HomeServer { get; set; } - private ProfileResponseEventContent? Profile { get; set; } - private ProfileResponseEventContent? OldProfile { get; set; } + private UserProfileResponse? Profile { get; set; } + private UserProfileResponse? OldProfile { get; set; } private string? Status { get => _status; @@ -77,7 +78,7 @@ var roomNameTasks = RoomProfiles.Keys.Select(x => HomeServer.GetRoom(x)).Select(async x => { var name = await x.GetNameAsync(); - return new KeyValuePair(x.RoomId, name); + return new KeyValuePair(x.RoomId, name); }).ToAsyncEnumerable(); await foreach (var (roomId, roomName) in roomNameTasks) { // Status = $"Got room name for {roomId}: {roomName}"; diff --git a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor index 3aea0e0..7bc88e5 100644 --- a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor +++ b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor @@ -2,6 +2,7 @@ @using LibMatrix.EventTypes.Spec.State @using LibMatrix.Helpers @using LibMatrix.Homeservers +@using LibMatrix.Responses
@ProfileName @@ -20,10 +21,10 @@ public RenderFragment? ChildContent { get; set; } [Parameter] - public ProfileResponseEventContent User { get; set; } + public UserProfileResponse? User { get; set; } [Parameter] - public ProfileResponseEventContent MemberEvent { get; set; } + public RoomMemberEventContent? MemberEvent { get; set; } [Parameter] public string? UserId { get; set; } @@ -50,7 +51,7 @@ throw new ArgumentNullException(nameof(UserId)); if (MemberEvent != null) { - User = new ProfileResponseEventContent { + User = new UserProfileResponse { AvatarUrl = MemberEvent.AvatarUrl, DisplayName = MemberEvent.DisplayName }; @@ -61,7 +62,7 @@ } - ProfileAvatar ??= await hsResolver.ResolveMediaUri(HomeServer.ServerName, User.AvatarUrl); + ProfileAvatar ??= HomeServer.ResolveMediaUri(User.AvatarUrl); ProfileName ??= User.DisplayName; _semaphoreSlim.Release(); diff --git a/MatrixRoomUtils.Web/Shared/NavMenu.razor b/MatrixRoomUtils.Web/Shared/NavMenu.razor index 68b491d..daa4a52 100644 --- a/MatrixRoomUtils.Web/Shared/NavMenu.razor +++ b/MatrixRoomUtils.Web/Shared/NavMenu.razor @@ -35,8 +35,14 @@
+ + diff --git a/MatrixRoomUtils.Web/Shared/RoomList.razor b/MatrixRoomUtils.Web/Shared/RoomList.razor index 705f68c..f78c7f7 100644 --- a/MatrixRoomUtils.Web/Shared/RoomList.razor +++ b/MatrixRoomUtils.Web/Shared/RoomList.razor @@ -4,6 +4,7 @@ @using ArcaneLibs.Extensions @using LibMatrix.EventTypes.Spec.State @using System.Collections.ObjectModel +@using LibMatrix.Responses @using _Imports = MatrixRoomUtils.Web._Imports @if (!StillFetching) {

Fetching room details... @RoomsWithTypes.Sum(x => x.Value.Count) out of @Rooms.Count done!

@@ -23,7 +24,7 @@ else { public ObservableCollection Rooms { get; set; } [Parameter] - public ProfileResponseEventContent? GlobalProfile { get; set; } + public UserProfileResponse? GlobalProfile { get; set; } [Parameter] public bool StillFetching { get; set; } = true; diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor index 27084cc..e2c1285 100644 --- a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor +++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor @@ -2,6 +2,7 @@ @using LibMatrix @using LibMatrix.EventTypes.Spec.State @using LibMatrix.Homeservers +@using LibMatrix.Responses
@roomType (@rooms.Count) @foreach (var room in rooms) { @@ -29,7 +30,7 @@ public KeyValuePair> Category { get; set; } [Parameter] - public ProfileResponseEventContent? GlobalProfile { get; set; } + public UserProfileResponse? GlobalProfile { get; set; } [CascadingParameter] public AuthenticatedHomeserverGeneric Homeserver { get; set; } = null!; diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor index 79c7f4e..a24ccad 100644 --- a/MatrixRoomUtils.Web/Shared/RoomListItem.razor +++ b/MatrixRoomUtils.Web/Shared/RoomListItem.razor @@ -3,24 +3,25 @@ @using LibMatrix.EventTypes.Spec.State @using LibMatrix.Helpers @using LibMatrix.Homeservers +@using LibMatrix.Responses @using LibMatrix.RoomTypes @using MatrixRoomUtils.Web.Classes.Constants @if (RoomInfo is not null) {
@if (OwnMemberState != null) { - @(OwnMemberState?.DisplayName ?? GlobalProfile?.DisplayName ?? "Loading...") -> } - @* style="@(ChildContent is not null ? "vertical-align: baseline;" : "")"*@ +
@RoomInfo.RoomName - @* @if (ChildContent is not null) { *@ - @* @ChildContent *@ - @* } *@ + @if (ChildContent is not null) { + @ChildContent + }
@@ -31,8 +32,8 @@ else { @code { - // [Parameter] - // public RenderFragment? ChildContent { get; set; } + [Parameter] + public RenderFragment? ChildContent { get; set; } [Parameter] public RoomInfo? RoomInfo { get; set; } @@ -44,7 +45,10 @@ else { public RoomMemberEventContent? OwnMemberState { get; set; } [CascadingParameter] - public ProfileResponseEventContent? GlobalProfile { get; set; } + public UserProfileResponse? GlobalProfile { get; set; } + + [Parameter] + public bool LoadData { get; set; } = false; private bool HasOldRoomVersion { get; set; } = false; private bool HasDangerousRoomVersion { get; set; } = false; @@ -57,6 +61,33 @@ else { 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" } + }); + RoomInfo.StateEvents.Add(new() { + Type = "m.room.name", + TypedContent = new RoomNameEventContent() { + Name = "M_FORBIDDEN: Are you a member of this room? " + RoomInfo.Room.RoomId + } + }); + } + } + } + await base.OnParametersSetAsync(); } @@ -69,7 +100,7 @@ else { if (hs is null) return; try { - await CheckRoomVersion(); + await CheckRoomVersion(); // await GetRoomInfo(); // await LoadOwnProfile(); } @@ -139,4 +170,5 @@ else { // } // } -} \ No newline at end of file +} + diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor index a454103..075e402 100644 --- a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor +++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor @@ -1,5 +1,6 @@ @using ArcaneLibs.Extensions @using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Responses @inherits BaseTimelineItem @if (roomMemberData is not null) { @@ -14,7 +15,7 @@ @Event.StateKey changed their display name to @(roomMemberData.DisplayName ?? Event.Sender) break; case "join": - joined + joined break; case "leave": @Event.StateKey left diff --git a/MatrixRoomUtils.Web/Shared/UserListItem.razor b/MatrixRoomUtils.Web/Shared/UserListItem.razor index 96e8e64..167809e 100644 --- a/MatrixRoomUtils.Web/Shared/UserListItem.razor +++ b/MatrixRoomUtils.Web/Shared/UserListItem.razor @@ -1,6 +1,7 @@ @using LibMatrix.Helpers @using LibMatrix.EventTypes.Spec.State @using LibMatrix.Homeservers +@using LibMatrix.Responses
@User?.DisplayName @@ -19,7 +20,7 @@ public RenderFragment? ChildContent { get; set; } [Parameter] - public ProfileResponseEventContent? User { get; set; } + public UserProfileResponse? User { get; set; } [Parameter] public string UserId { get; set; } diff --git a/MatrixRoomUtils.sln b/MatrixRoomUtils.sln index 79650cf..3ea06bf 100755 --- a/MatrixRoomUtils.sln +++ b/MatrixRoomUtils.sln @@ -44,6 +44,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibMatrix.Tests", "LibMatri EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestDataGenerator", "LibMatrix\Tests\TestDataGenerator\TestDataGenerator.csproj", "{F3312DE9-4335-4E85-A4CF-2616427A651E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.LibDMSpace", "MatrixRoomUtils.LibDMSpace\MatrixRoomUtils.LibDMSpace.csproj", "{EDD2FBAB-2DEC-4527-AE9C-20E21D0D6B14}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -114,6 +116,10 @@ Global {F3312DE9-4335-4E85-A4CF-2616427A651E}.Debug|Any CPU.Build.0 = Debug|Any CPU {F3312DE9-4335-4E85-A4CF-2616427A651E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F3312DE9-4335-4E85-A4CF-2616427A651E}.Release|Any CPU.Build.0 = Release|Any CPU + {EDD2FBAB-2DEC-4527-AE9C-20E21D0D6B14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDD2FBAB-2DEC-4527-AE9C-20E21D0D6B14}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDD2FBAB-2DEC-4527-AE9C-20E21D0D6B14}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDD2FBAB-2DEC-4527-AE9C-20E21D0D6B14}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {F4E241C3-0300-4B87-8707-BCBDEF1F0185} = {8F4F6BEC-0C66-486B-A21A-1C35B2EDAD33} -- cgit 1.4.1