diff options
Diffstat (limited to 'MatrixRoomUtils.Web/Pages')
19 files changed, 686 insertions, 749 deletions
diff --git a/MatrixRoomUtils.Web/Pages/DataExportPage.razor b/MatrixRoomUtils.Web/Pages/DataExportPage.razor deleted file mode 100644 index 732cd74..0000000 --- a/MatrixRoomUtils.Web/Pages/DataExportPage.razor +++ /dev/null @@ -1,67 +0,0 @@ -@page "/Export" -@using System.Text.Json -@inject NavigationManager NavigationManager -@inject ILocalStorageService LocalStorage - -<PageTitle>Export</PageTitle> - -<h3>Data export</h3> - -<br/><br/> -<h5>Signed in accounts - <a href="/Login">Add new account</a> or <a href="/ImportUsers">Import from TSV</a></h5> -<hr/> -@if (_isLoaded) { - @foreach (var (token, user) in RuntimeCache.LoginSessions) { - @* <IndexUserItem User="@user"/> *@ - <pre> -@user.LoginResponse.UserId[1..].Split(":")[0]\auth\access_token=@token -@user.LoginResponse.UserId[1..].Split(":")[0]\auth\device_id=@user.LoginResponse.DeviceId -@user.LoginResponse.UserId[1..].Split(":")[0]\auth\home_server=@(RuntimeCache.HomeserverResolutionCache.ContainsKey(user.LoginResponse.HomeServer) ? RuntimeCache.HomeserverResolutionCache[user.LoginResponse.HomeServer].Result : "loading...") -@user.LoginResponse.UserId[1..].Split(":")[0]\auth\user_id=@@@user.LoginResponse.UserId -@user.LoginResponse.UserId[1..].Split(":")[0]\user\automatically_share_keys_with_trusted_users=true -@user.LoginResponse.UserId[1..].Split(":")[0]\user\muted_tags=global -@user.LoginResponse.UserId[1..].Split(":")[0]\user\online_key_backup=true -@user.LoginResponse.UserId[1..].Split(":")[0]\user\only_share_keys_with_verified_users=false - </pre> - } -} -else { - <p>Loading...</p> - <p>@resolvedHomeservers/@totalHomeservers homeservers resolved...</p> -} - -@code { - private bool _isLoaded; - private int resolvedHomeservers; - private int totalHomeservers; - - protected override async Task OnInitializedAsync() { - await base.OnInitializedAsync(); - if (!RuntimeCache.WasLoaded) { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - } - var homeservers = RuntimeCache.LoginSessions.Values.Select(x => x.LoginResponse.HomeServer).Distinct(); - totalHomeservers = homeservers.Count(); - StateHasChanged(); - foreach (var hs in homeservers) { - if (RuntimeCache.HomeserverResolutionCache.ContainsKey(hs)) { - resolvedHomeservers++; - continue; - } - var resolvedHomeserver = (await new RemoteHomeServer(hs).Configure()).FullHomeServerDomain; - - RuntimeCache.HomeserverResolutionCache.Add(hs, new HomeServerResolutionResult { Result = resolvedHomeserver, ResolutionTime = DateTime.Now }); - await LocalStorageWrapper.SaveCacheToLocalStorage(LocalStorage); - - Console.WriteLine("Saved to local storage:"); - Console.WriteLine(JsonSerializer.Serialize(RuntimeCache.HomeserverResolutionCache, new JsonSerializerOptions { - WriteIndented = true - })); - resolvedHomeservers++; - StateHasChanged(); - } - StateHasChanged(); - _isLoaded = true; - } - -} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/DebugTools.razor b/MatrixRoomUtils.Web/Pages/DebugTools.razor index 4e4cec8..5116754 100644 --- a/MatrixRoomUtils.Web/Pages/DebugTools.razor +++ b/MatrixRoomUtils.Web/Pages/DebugTools.razor @@ -37,13 +37,10 @@ else { public List<string> Rooms { get; set; } = new(); protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - if (RuntimeCache.CurrentHomeServer == null) { - NavigationManager.NavigateTo("/Login"); - return; - } - Rooms = (await RuntimeCache.CurrentHomeServer.GetJoinedRooms()).Select(x => x.RoomId).ToList(); + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs == null) return; + Rooms = (await hs.GetJoinedRooms()).Select(x => x.RoomId).ToList(); Console.WriteLine("Fetched joined rooms!"); } @@ -53,7 +50,9 @@ else { private async Task SendGetRequest() { var field = typeof(IHomeServer).GetRuntimeFields().First(x => x.ToString().Contains("<_httpClient>k__BackingField")); - var httpClient = field.GetValue(RuntimeCache.CurrentHomeServer) as HttpClient; + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs == null) return; + var httpClient = field.GetValue(hs) as MatrixHttpClient; try { var res = await httpClient.GetAsync(get_request_url); if (res.IsSuccessStatusCode) { diff --git a/MatrixRoomUtils.Web/Pages/DevOptions.razor b/MatrixRoomUtils.Web/Pages/DevOptions.razor index cdb5693..70dac31 100644 --- a/MatrixRoomUtils.Web/Pages/DevOptions.razor +++ b/MatrixRoomUtils.Web/Pages/DevOptions.razor @@ -7,69 +7,23 @@ <h3>Rory&::MatrixUtils - Developer options</h3> <hr/> -<InputCheckbox @bind-Value="@LocalStorageWrapper.Settings.DeveloperSettings.EnableLogViewers" @oninput="@LogStuff"></InputCheckbox><label> Enable log views</label><br/> -<InputCheckbox @bind-Value="@LocalStorageWrapper.Settings.DeveloperSettings.EnableConsoleLogging" @oninput="@LogStuff"></InputCheckbox><label> Enable console logging</label><br/> -<InputCheckbox @bind-Value="@LocalStorageWrapper.Settings.DeveloperSettings.EnablePortableDevtools" @oninput="@LogStuff"></InputCheckbox><label> Enable portable devtools</label><br/> -<button @onclick="@DropCaches">Drop caches</button> -<button @onclick="@RandomiseCacheTimers">Randomise cache timers</button> +<InputCheckbox @bind-Value="@settings.DeveloperSettings.EnableLogViewers" @oninput="@LogStuff"></InputCheckbox><label> Enable log views</label><br/> +<InputCheckbox @bind-Value="@settings.DeveloperSettings.EnableConsoleLogging" @oninput="@LogStuff"></InputCheckbox><label> Enable console logging</label><br/> +<InputCheckbox @bind-Value="@settings.DeveloperSettings.EnablePortableDevtools" @oninput="@LogStuff"></InputCheckbox><label> Enable portable devtools</label><br/> <br/> -<details open> - <summary>View caches</summary> - <p>Generic cache:</p> - <ul> - @foreach (var item in RuntimeCache.GenericResponseCache) { - <li> - @item.Key: @item.Value.Cache.Count entries<br/> - @if (item.Value.Cache.Count > 0) { - <p>Earliest expiry: @(item.Value.Cache.Min(x => x.Value.ExpiryTime)) (@string.Format("{0:g}", item.Value.Cache.Min(x => x.Value.ExpiryTime).Value.Subtract(DateTime.Now)) from now)</p> - @* <p>Average expiry: @(item.Value.Cache.Average(x => x.Value.ExpiryTime.Value))(@item.Value.Cache.Average(x => x.Value.ExpiryTime).Value.Subtract(DateTime.Now) from now)</p> *@ - <p>Last expiry: @(item.Value.Cache.Max(x => x.Value.ExpiryTime)) (@string.Format("{0:g}", item.Value.Cache.Max(x => x.Value.ExpiryTime).Value.Subtract(DateTime.Now)) from now)</p> - } - </li> - } - </ul> -</details> - @code { + MRUStorageWrapper.Settings settings { get; set; } = new(); protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + settings = await TieredStorage.DataStorageProvider.LoadObjectAsync<MRUStorageWrapper.Settings>("mru.settings"); await base.OnInitializedAsync(); - Task.Run(async () => { - while (true) { - await Task.Delay(1000); - StateHasChanged(); - } - }); } - protected async Task LogStuff() { + private async Task LogStuff() { await Task.Delay(100); - Console.WriteLine($"Settings: {LocalStorageWrapper.Settings.ToJson()}"); - - await LocalStorageWrapper.SaveToLocalStorage(LocalStorage); - } - - protected async Task DropCaches() { - foreach (var (key, value) in RuntimeCache.GenericResponseCache) { - value.Cache.Clear(); - } - - //RuntimeCache.GenericResponseCache.Clear(); - RuntimeCache.HomeserverResolutionCache.Clear(); - await LocalStorageWrapper.SaveCacheToLocalStorage(LocalStorage); - } - - protected async Task RandomiseCacheTimers() { - foreach (var keyValuePair in RuntimeCache.GenericResponseCache) { - Console.WriteLine($"Randomising cache timer for {keyValuePair.Key}"); - foreach (var cacheItem in keyValuePair.Value.Cache) { - cacheItem.Value.ExpiryTime = DateTime.Now.AddSeconds(Random.Shared.Next(15, 120)); - } - - await LocalStorageWrapper.SaveCacheToLocalStorage(LocalStorage); - } + Console.WriteLine($"Settings: {settings.ToJson()}"); + await TieredStorage.DataStorageProvider.SaveObjectAsync("mru.settings", settings); } } \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor b/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor index 858fad9..e3ebc72 100644 --- a/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor +++ b/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor @@ -165,7 +165,9 @@ private async Task Search() { Results.Clear(); - var searchRooms = RuntimeCache.CurrentHomeServer.Admin.SearchRoomsAsync(orderBy: OrderBy!, dir: Ascending ? "f" : "b", searchTerm: SearchTerm, localFilter: Filter).GetAsyncEnumerator(); + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + var searchRooms = hs.Admin.SearchRoomsAsync(orderBy: OrderBy!, dir: Ascending ? "f" : "b", searchTerm: SearchTerm, localFilter: Filter).GetAsyncEnumerator(); while (await searchRooms.MoveNextAsync()) { var room = searchRooms.Current; Console.WriteLine("Hit: " + room.ToJson(false)); diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor index 33cca61..16a6cee 100644 --- a/MatrixRoomUtils.Web/Pages/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Index.razor @@ -1,7 +1,7 @@ @page "/" -@using MatrixRoomUtils.Web.Shared.IndexComponents -@inject NavigationManager NavigationManager -@inject ILocalStorageService LocalStorage +@using MatrixRoomUtils.Core.Helpers +@using MatrixRoomUtils.Core.Responses +@using MatrixRoomUtils.Web.Shared.SimpleComponents <PageTitle>Index</PageTitle> @@ -12,18 +12,67 @@ Small collection of tools to do not-so-everyday things. <h5>Signed in accounts - <a href="/Login">Add new account</a></h5> <hr/> <form> - @foreach (var (token, user) in RuntimeCache.LoginSessions) { - <IndexUserItem User="@user"/> + @foreach (var (auth, user) in _users.OrderByDescending(x=>x.Value.RoomCount)) { + var _auth = auth; + var _user = user; + <div style="margin-bottom: 1em;"> + <img style="border-radius: 50%; height: 3em; width: 3em;" src="@_user.AvatarUrl"/> + <p style="margin-left: 1em; margin-top: -0.5em; display: inline-block;"> + <input type="radio" name="csa" checked="@(_currentSession.AccessToken == _auth.AccessToken)" @onclick="@(()=>SwitchSession(_auth))" style="text-decoration-line: unset;"/> + <b>@_user.DisplayName</b> on <b>@_auth.Homeserver</b> + <a role="button" @onclick="@(() => RemoveUser(_auth))">Remove</a> + + </p> + <p style="margin-top: -1.5em; margin-left: 4em;">Member of @_user.RoomCount rooms</p> + + </div> } </form> @code { + private Dictionary<LoginResponse, UserInfo> _users = new(); + protected override async Task OnInitializedAsync() { - if (!RuntimeCache.WasLoaded) { - Console.WriteLine("[INDEX] !!! LOCALSTORAGE WAS NOT LOADED !!!"); - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - } + _currentSession = await MRUStorage.GetCurrentToken(); + _users.Clear(); + var tokens = await MRUStorage.GetAllTokens(); + var profileTasks = tokens.Select(async token => { + UserInfo userInfo = new(); + var hs = await HomeserverProvider.GetAuthenticatedWithToken(token.Homeserver, token.AccessToken); + var roomCountTask = hs.GetJoinedRooms(); + var profile = await hs.GetProfile(hs.WhoAmI.UserId); + userInfo.DisplayName = profile.DisplayName ?? hs.WhoAmI.UserId; + userInfo.AvatarUrl = MediaResolver.ResolveMediaUri(hs.FullHomeServerDomain, + profile.AvatarUrl + ?? "https://api.dicebear.com/6.x/identicon/svg?seed=" + hs.WhoAmI.UserId + ); + userInfo.RoomCount = (await roomCountTask).Count; + _users.Add(token, userInfo); + // StateHasChanged(); + }); + await Task.WhenAll(profileTasks); await base.OnInitializedAsync(); } + + private class UserInfo { + internal string AvatarUrl { get; set; } + internal string DisplayName { get; set; } + internal int RoomCount { get; set; } = 0; + } + + private async Task RemoveUser(LoginResponse auth) { + await MRUStorage.RemoveToken(auth); + if ((await MRUStorage.GetCurrentToken()).AccessToken == auth.AccessToken) + MRUStorage.SetCurrentToken((await MRUStorage.GetAllTokens()).FirstOrDefault()); + await OnInitializedAsync(); + } + + private LoginResponse _currentSession; + + private async Task SwitchSession(LoginResponse auth) { + Console.WriteLine($"Switching to {auth.Homeserver} {auth.AccessToken} {auth.UserId}"); + await MRUStorage.SetCurrentToken(auth); + await OnInitializedAsync(); + } } \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor index 80dbfd1..5ccecab 100644 --- a/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor +++ b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor @@ -2,6 +2,7 @@ @using System.Text.Json @using System.Diagnostics @using MatrixRoomUtils.Core.Responses +@using MatrixRoomUtils.Core.StateEventTypes <h3>Known Homeserver List</h3> <hr/> @@ -33,10 +34,10 @@ else { List<HomeServerInfo> HomeServers = new(); bool IsFinished { get; set; } HomeServerInfoQueryProgress QueryProgress { get; set; } = new(); - + AuthenticatedHomeServer hs { get; set; } protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - + hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; var sw = Stopwatch.StartNew(); HomeServers = await GetHomeservers(progressCallback: async progress => { if (sw.ElapsedMilliseconds > 1000) { @@ -61,7 +62,8 @@ else { private async Task<List<HomeServerInfo>> GetHomeservers(int memberLimit = 1000, Func<HomeServerInfoQueryProgress, Task<bool>>? progressCallback = null) { HomeServerInfoQueryProgress progress = new(); List<HomeServerInfo> homeServers = new(); - var rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); + + var rooms = await hs.GetJoinedRooms(); progress.TotalRooms = rooms.Count; var semaphore = new SemaphoreSlim(4); @@ -70,53 +72,69 @@ else { await semaphore.WaitAsync(); progress.ProcessedUsers.Add(room, new HomeServerInfoQueryProgress.State()); Console.WriteLine($"Fetching states for room ({rooms.IndexOf(room)}/{rooms.Count}) ({room.RoomId})"); - var states = (await room.GetStateAsync("")).Value.Deserialize<List<StateEventResponse>>(); - states.RemoveAll(x => x.Type != "m.room.member" || x.Content.GetProperty("membership").GetString() != "join"); - Console.WriteLine($"Room {room.RoomId} has {states.Count} members"); - if (states.Count > memberLimit) { - Console.WriteLine("Skipping!"); - semaphore.Release(); - progress.ProcessedUsers.Remove(room); - progress.TotalRooms--; - return; - } - progress.ProcessedUsers[room].Total = states.Count; - var updateInterval = progress.ProcessedUsers[room].Total >= 1000 ? 1000 : 100; - while (progress.ProcessedUsers.Any(x => x.Value.Total == 0) && progress.ProcessedUsers[room].Total >= 1000) { - progress.ProcessedUsers[room].Blocked = true; - await Task.Delay(1000); - // if(progressCallback != null) - // await progressCallback.Invoke(progress); - } - progress.ProcessedUsers[room].Blocked = false; - var processedStates = 0; - foreach (var state in states) { - await semLock.WaitAsync(); - semLock.Release(); - if (progress.ProcessedUsers.Count(x => x.Value.Total == 0) > 5 && progress.ProcessedUsers[room].Total >= 200) { - progress.ProcessedUsers[room].Slowmode = true; - await Task.Delay(progress.ProcessedUsers[room].Total >= 500 ? 1000 : 100); - } - else { - progress.ProcessedUsers[room].Slowmode = false; - } + var states = room.GetFullStateAsync(); + await foreach (var state in states) { + if (state.Type is not "m.room.member") continue; + progress.ProcessedUsers[room].Total++; if (!homeServers.Any(x => x.Server == state.StateKey.Split(':')[1])) { homeServers.Add(new HomeServerInfo { Server = state.StateKey.Split(':')[1] }); - } - var hs = homeServers.First(x => x.Server == state.StateKey.Split(':')[1]); - if (!hs.KnownUsers.Contains(state.StateKey.Split(':')[0])) - hs.KnownUsers.Add(state.StateKey.Split(':')[0]); - if (++progress.ProcessedUsers[room].Processed % updateInterval == 0 && progressCallback != null) { - await semLock.WaitAsync(); - var _ = await progressCallback.Invoke(progress); - semLock.Release(); + Console.WriteLine($"Added new homeserver {state.StateKey.Split(':')[1]}"); } } - Console.WriteLine("Collected states!"); - progress.ProcessedRooms++; - progress.ProcessedUsers[room].IsFinished = true; - progressCallback?.Invoke(progress); semaphore.Release(); + progress.ProcessedUsers[room].IsFinished = true; + progress.ProcessedRooms++; + if (progressCallback is not null) + await progressCallback.Invoke(progress); + + + + // states.RemoveAll(x => x.Type != "m.room.member" || (x.TypedContent as RoomMemberEventData).Membership != "join"); + // Console.WriteLine($"Room {room.RoomId} has {states.Count} members"); + // if (states.Count > memberLimit) { + // Console.WriteLine("Skipping!"); + // semaphore.Release(); + // progress.ProcessedUsers.Remove(room); + // progress.TotalRooms--; + // return; + // } + // progress.ProcessedUsers[room].Total = states.Count; + // var updateInterval = progress.ProcessedUsers[room].Total >= 1000 ? 1000 : 100; + // while (progress.ProcessedUsers.Any(x => x.Value.Total == 0) && progress.ProcessedUsers[room].Total >= 1000) { + // progress.ProcessedUsers[room].Blocked = true; + // await Task.Delay(1000); + // // if(progressCallback is not null) + // // await progressCallback.Invoke(progress); + // } + // progress.ProcessedUsers[room].Blocked = false; + // var processedStates = 0; + // foreach (var state in states) { + // await semLock.WaitAsync(); + // semLock.Release(); + // if (progress.ProcessedUsers.Count(x => x.Value.Total == 0) > 5 && progress.ProcessedUsers[room].Total >= 200) { + // progress.ProcessedUsers[room].Slowmode = true; + // await Task.Delay(progress.ProcessedUsers[room].Total >= 500 ? 1000 : 100); + // } + // else { + // progress.ProcessedUsers[room].Slowmode = false; + // } + // if (!homeServers.Any(x => x.Server == state.StateKey.Split(':')[1])) { + // homeServers.Add(new HomeServerInfo { Server = state.StateKey.Split(':')[1] }); + // } + // var hs = homeServers.First(x => x.Server == state.StateKey.Split(':')[1]); + // if (!hs.KnownUsers.Contains(state.StateKey.Split(':')[0])) + // hs.KnownUsers.Add(state.StateKey.Split(':')[0]); + // if (++progress.ProcessedUsers[room].Processed % updateInterval == 0 && progressCallback is not null) { + // await semLock.WaitAsync(); + // var _ = await progressCallback.Invoke(progress); + // semLock.Release(); + // } + // } + // Console.WriteLine("Collected states!"); + // progress.ProcessedRooms++; + // progress.ProcessedUsers[room].IsFinished = true; + // progressCallback?.Invoke(progress); + // semaphore.Release(); }); await Task.WhenAll(tasks); @@ -136,7 +154,7 @@ else { class HomeServerInfoQueryProgress { public int ProcessedRooms { get; set; } public int TotalRooms { get; set; } - public Dictionary<Room, State> ProcessedUsers { get; } = new(); + public Dictionary<GenericRoom, State> ProcessedUsers { get; } = new(); public List<HomeServerInfo> CurrentState { get; set; } = new(); public class State { diff --git a/MatrixRoomUtils.Web/Pages/LoginPage.razor b/MatrixRoomUtils.Web/Pages/LoginPage.razor index 9df7fa6..e19dd04 100644 --- a/MatrixRoomUtils.Web/Pages/LoginPage.razor +++ b/MatrixRoomUtils.Web/Pages/LoginPage.razor @@ -1,6 +1,6 @@ @page "/Login" -@using MatrixRoomUtils.Core.Authentication @using System.Text.Json +@using MatrixRoomUtils.Core.Responses @using MatrixRoomUtils.Web.Shared.SimpleComponents @inject ILocalStorageService LocalStorage @inject IJSRuntime JsRuntime @@ -22,20 +22,25 @@ <InputFile OnChange="@FileChanged" accept=".tsv"></InputFile> <br/> -<button @onclick="Login">Login</button> <br/><br/> <h4>Parsed records</h4> <hr/> <table border="1"> + <thead> + <td>Username</td> + <td>Homeserver</td> + </thead> @foreach (var (homeserver, username, password) in records) { - <tr style="background-color: @(RuntimeCache.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}") ? "green" : "unset")"> + var record = (homeserver, username, password); + <tr style="background-color: @(LoggedInSessions.Any(x => x.UserId == $"@{username}:{homeserver}") ? "green" : "unset")"> <td style="border-width: 1px;">@username</td> <td style="border-width: 1px;">@homeserver</td> - <td style="border-width: 1px;">@password.Length chars</td> + <td><a role="button" @onclick="() => records.Remove(record)">Remove</a></td> </tr> } </table> <br/> +<button @onclick="Login">Login</button> <br/> <LogView></LogView> @@ -43,26 +48,34 @@ readonly List<(string homeserver, string username, string password)> records = new(); (string homeserver, string username, string password) newRecordInput = ("", "", ""); + List<LoginResponse> LoggedInSessions { get; set; } = new(); + async Task Login() { - foreach (var (homeserver, username, password) in records) { - if (RuntimeCache.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}")) continue; - var result = await MatrixAuth.Login(homeserver, username, password); - Console.WriteLine($"Obtained access token for {result.UserId}!"); - - var userinfo = new UserInfo { - LoginResponse = result - }; - userinfo.Profile = await RuntimeCache.CurrentHomeServer.GetProfile(result.UserId); - RuntimeCache.LastUsedToken = result.AccessToken; + var loginTasks = records.Select(async record => { + var (homeserver, username, password) = record; + if (LoggedInSessions.Any(x => x.UserId == $"@{username}:{homeserver}")) return; + try { + var result = await HomeserverProvider.Login(homeserver, username, password); + if (result == null) { + Console.WriteLine($"Failed to login to {homeserver} as {username}!"); + return; + } + Console.WriteLine($"Obtained access token for {result.UserId}!"); - RuntimeCache.LoginSessions.Add(result.AccessToken, userinfo); + await MRUStorage.AddToken(result); + LoggedInSessions = await MRUStorage.GetAllTokens(); + } + catch (Exception e) { + Console.WriteLine($"Failed to login to {homeserver} as {username}!"); + Console.WriteLine(e); + } StateHasChanged(); - } - - await LocalStorageWrapper.SaveToLocalStorage(LocalStorage); + }); + await Task.WhenAll(loginTasks); } private async Task FileChanged(InputFileChangeEventArgs obj) { + LoggedInSessions = await MRUStorage.GetAllTokens(); Console.WriteLine(JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true })); @@ -78,7 +91,8 @@ } } - private void AddRecord() { + private async Task AddRecord() { + LoggedInSessions = await MRUStorage.GetAllTokens(); records.Add(newRecordInput); newRecordInput = ("", "", ""); } diff --git a/MatrixRoomUtils.Web/Pages/MediaLocator.razor b/MatrixRoomUtils.Web/Pages/MediaLocator.razor index 38d1514..6221041 100644 --- a/MatrixRoomUtils.Web/Pages/MediaLocator.razor +++ b/MatrixRoomUtils.Web/Pages/MediaLocator.razor @@ -82,7 +82,6 @@ } async Task addMoreHomeservers() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); var res = await Http.GetAsync("/homeservers.txt"); var content = await res.Content.ReadAsStringAsync(); homeservers.Clear(); @@ -93,10 +92,8 @@ lines.ToList().ForEach(async line => { await sem.WaitAsync(); try { - homeservers.Add(await rhs.ResolveHomeserverFromWellKnown(line)); + homeservers.Add(await HomeserverResolver.ResolveHomeserverFromWellKnown(line)); StateHasChanged(); - if (Random.Shared.Next(0, 101) == 50) - await LocalStorageWrapper.SaveCacheToLocalStorage(LocalStorage); } catch (Exception e) { Console.WriteLine(e); diff --git a/MatrixRoomUtils.Web/Pages/ModalTest.razor b/MatrixRoomUtils.Web/Pages/ModalTest.razor index d031dc2..f32c672 100644 --- a/MatrixRoomUtils.Web/Pages/ModalTest.razor +++ b/MatrixRoomUtils.Web/Pages/ModalTest.razor @@ -31,20 +31,6 @@ double _y = 0; double multiplier = 1; - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - //var rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); - - //rooms.ForEach(async room => { - // var name = await room.GetNameAsync(); - // _windowInfos.Add(_windowInfos.Count, new WindowInfo() { X = _x, Y = _y, Title = name}); - // _x += 20; - // _y += 20; - // var dimension = await JsRuntime.InvokeAsync<WindowDimension>("getWindowDimensions"); - // if (_x > dimension.Width - 100) _x %= dimension.Width - 100; - // if (_y > dimension.Height - 50) _y %= dimension.Height - 50; - // StateHasChanged(); - //}); - for (int i = 0; i < 200; i++) { var i1 = i; _windowInfos.Add(_windowInfos.Count, new WindowInfo() { diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor index 0840ebf..8e2609f 100644 --- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor +++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor @@ -1,9 +1,8 @@ @page "/PolicyListEditor/{RoomId}" @using MatrixRoomUtils.Core.StateEventTypes @using System.Text.Json +@using MatrixRoomUtils.Core.Helpers @using MatrixRoomUtils.Core.Responses -@inject ILocalStorageService LocalStorage -@inject NavigationManager NavigationManager <h3>Policy list editor - Editing @RoomId</h3> <hr/> @@ -31,12 +30,13 @@ else { </tr> </thead> <tbody> - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.server" && x.Content.Entity != null)) { + @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.server" && (x.TypedContent as PolicyRuleStateEventData).Entity is not null)) { + var policyData = policyEvent.TypedContent as PolicyRuleStateEventData; <tr> - <td>Entity: @policyEvent.Content.Entity<br/>State: @policyEvent.StateKey</td> - <td>@policyEvent.Content.Reason</td> + <td>Entity: @policyData.Entity<br/>State: @policyEvent.StateKey</td> + <td>@policyData.Reason</td> <td> - @policyEvent.Content.ExpiryDateTime + @policyData.ExpiryDateTime </td> <td> <button class="btn" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Edit</button> @@ -47,7 +47,7 @@ else { </tbody> </table> <details> - <summary>Invalid events</summary> + <summary>Redacted events</summary> <table class="table table-striped table-hover" style="width: fit-Content;"> <thead> <tr> @@ -56,10 +56,11 @@ else { </tr> </thead> <tbody> - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.server" && x.Content.Entity == null)) { + @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.server" && (x.TypedContent as PolicyRuleStateEventData).Entity == null)) { + var policyData = policyEvent.TypedContent as PolicyRuleStateEventData; <tr> <td>@policyEvent.StateKey</td> - <td>@policyEvent.Content.ToJson(false, true)</td> + <td>@policyEvent.RawContent.ToJson(false, true)</td> </tr> } </tbody> @@ -82,12 +83,13 @@ else { </tr> </thead> <tbody> - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.room" && x.Content.Entity != null)) { + @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.room" && (x.TypedContent as PolicyRuleStateEventData).Entity is not null)) { + var policyData = policyEvent.TypedContent as PolicyRuleStateEventData; <tr> - <td>Entity: @policyEvent.Content.Entity<br/>State: @policyEvent.StateKey</td> - <td>@policyEvent.Content.Reason</td> + <td>Entity: @policyData.Entity<br/>State: @policyEvent.StateKey</td> + <td>@policyData.Reason</td> <td> - @policyEvent.Content.ExpiryDateTime + @policyData.ExpiryDateTime </td> <td> <button class="btn btn-danger" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Remove</button> @@ -97,7 +99,7 @@ else { </tbody> </table> <details> - <summary>Invalid events</summary> + <summary>Redacted events</summary> <table class="table table-striped table-hover" style="width: fit-Content;"> <thead> <tr> @@ -106,10 +108,10 @@ else { </tr> </thead> <tbody> - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.room" && x.Content.Entity == null)) { + @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.room" && (x.TypedContent as PolicyRuleStateEventData).Entity == null)) { <tr> <td>@policyEvent.StateKey</td> - <td>@policyEvent.Content.ToJson(false, true)</td> + <td>@policyEvent.RawContent.ToJson(false, true)</td> </tr> } </tbody> @@ -135,17 +137,18 @@ else { </tr> </thead> <tbody> - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && x.Content.Entity != null)) { + @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && (x.TypedContent as PolicyRuleStateEventData).Entity is not null)) { + var policyData = policyEvent.TypedContent as PolicyRuleStateEventData; <tr> @if (_enableAvatars) { <td scope="col"> - <img style="width: 48px; height: 48px; aspect-ratio: unset; border-radius: 50%;" src="@(avatars.ContainsKey(policyEvent.Content.Entity) ? avatars[policyEvent.Content.Entity] : "")"/> + <img style="width: 48px; height: 48px; aspect-ratio: unset; border-radius: 50%;" src="@(avatars.ContainsKey(policyData.Entity) ? avatars[policyData.Entity] : "")"/> </td> } - <td style="word-wrap: anywhere;">Entity: @string.Join("", policyEvent.Content.Entity.Take(64))<br/>State: @string.Join("", policyEvent.StateKey.Take(64))</td> - <td>@policyEvent.Content.Reason</td> + <td style="word-wrap: anywhere;">Entity: @string.Join("", policyData.Entity.Take(64))<br/>State: @string.Join("", policyEvent.StateKey.Take(64))</td> + <td>@policyData.Reason</td> <td> - @policyEvent.Content.ExpiryDateTime + @policyData.ExpiryDateTime </td> <td> <button class="btn btn-danger" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Remove</button> @@ -155,7 +158,7 @@ else { </tbody> </table> <details> - <summary>Invalid events</summary> + <summary>Redacted events</summary> <table class="table table-striped table-hover" style="width: fit-Content;"> <thead> <tr> @@ -164,10 +167,10 @@ else { </tr> </thead> <tbody> - @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && x.Content.Entity == null)) { + @foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && (x.TypedContent as PolicyRuleStateEventData).Entity == null)) { <tr> <td>@policyEvent.StateKey</td> - <td>@policyEvent.Content.ToJson(false, true)</td> + <td>@policyEvent.RawContent.ToJson(false, true)</td> </tr> } </tbody> @@ -191,36 +194,32 @@ else { static readonly Dictionary<string, string?> avatars = new(); static readonly Dictionary<string, RemoteHomeServer> servers = new(); - public static List<StateEventResponse<PolicyRuleStateEventData>> PolicyEvents { get; set; } = new(); + public static List<StateEventResponse> PolicyEvents { get; set; } = new(); protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - // if(RuntimeCache.AccessToken == null || RuntimeCache.CurrentHomeserver == null) - if (RuntimeCache.CurrentHomeServer == null) { - NavigationManager.NavigateTo("/Login"); - return; - } + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; RoomId = RoomId.Replace('~', '.'); await LoadStatesAsync(); Console.WriteLine("Policy list editor initialized!"); } private async Task LoadStatesAsync() { - // using var client = new HttpClient(); - // client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", LocalStorageWrapper.AccessToken); - // var response = await client.GetAsync($"{LocalStorageWrapper.CurrentHomeserver}/_matrix/client/v3/rooms/{RoomId}/state"); - // var Content = await response.Content.ReadAsStringAsync(); - // Console.WriteLine(JsonSerializer.Deserialize<object>(Content).ToJson()); - // var stateEvents = JsonSerializer.Deserialize<List<StateEventResponse>>(Content); - var room = await RuntimeCache.CurrentHomeServer.GetRoom(RoomId); - var stateEventsQuery = await room.GetStateAsync(""); - if (stateEventsQuery == null) { - Console.WriteLine("state events query is null!!!"); + var hs = await MRUStorage.GetCurrentSession(); + var room = await hs.GetRoom(RoomId); + + var states = room.GetFullStateAsync(); + await foreach (var state in states) { + if (!state.Type.StartsWith("m.policy.rule")) continue; + PolicyEvents.Add(state); } - var stateEvents = stateEventsQuery.Value.Deserialize<List<StateEventResponse>>(); - PolicyEvents = stateEvents.Where(x => x.Type.StartsWith("m.policy.rule")) - .Select(x => JsonSerializer.Deserialize<StateEventResponse<PolicyRuleStateEventData>>(JsonSerializer.Serialize(x))).ToList(); + + + // var stateEventsQuery = await room.GetStateAsync(""); + // var stateEvents = stateEventsQuery.Value.Deserialize<List<StateEventResponse>>(); + // PolicyEvents = stateEvents.Where(x => x.Type.StartsWith("m.policy.rule")) + // .Select(x => JsonSerializer.Deserialize<StateEventResponse>(JsonSerializer.Serialize(x))).ToList(); StateHasChanged(); } @@ -228,10 +227,10 @@ else { try { if (avatars.ContainsKey(userId)) return; var hs = userId.Split(':')[1]; - var server = servers.ContainsKey(hs) ? servers[hs] : await new RemoteHomeServer(userId.Split(':')[1]).Configure(); + var server = servers.ContainsKey(hs) ? servers[hs] : new RemoteHomeServer(userId.Split(':')[1]); if (!servers.ContainsKey(hs)) servers.Add(hs, server); var profile = await server.GetProfile(userId); - avatars.Add(userId, server.ResolveMediaUri(profile.AvatarUrl)); + avatars.Add(userId, MediaResolver.ResolveMediaUri(server.FullHomeServerDomain, profile.AvatarUrl)); servers.Add(userId, server); StateHasChanged(); } @@ -241,8 +240,8 @@ else { } private async Task GetAllAvatars() { - foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && x.Content.Entity != null)) { - await GetAvatar(policyEvent.Content.Entity); + foreach (var policyEvent in PolicyEvents.Where(x => x.Type == "m.policy.rule.user" && (x.TypedContent as PolicyRuleStateEventData).Entity is not null)) { + await GetAvatar((policyEvent.TypedContent as PolicyRuleStateEventData).Entity); } StateHasChanged(); } diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor index 8f711b5..4db2b5a 100644 --- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor +++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor @@ -1,4 +1,7 @@ @page "/PolicyListEditor" +@using System.Text.Json.Serialization +@using MatrixRoomUtils.Core.Interfaces +@using MatrixRoomUtils.Core.StateEventTypes @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Policy list editor - Room list</h3> @@ -39,28 +42,26 @@ else { private int totalRoomCount { get; set; } protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - if (RuntimeCache.CurrentHomeServer == null) { - NavigationManager.NavigateTo("/Login"); - return; - } + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; await EnumeratePolicyRooms(); Console.WriteLine("Policy list editor initialized!"); } private async Task EnumeratePolicyRooms() { - var xxxrooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); - totalRoomCount = xxxrooms.Count; + var hs = await MRUStorage.GetCurrentSession(); + var rooms = await hs.GetJoinedRooms(); + totalRoomCount = rooms.Count; StateHasChanged(); - var xxxsemaphore = new SemaphoreSlim(1000); - var xxxtasks = new List<Task<PolicyRoomInfo?>>(); - foreach (var room in xxxrooms) { - xxxtasks.Add(GetPolicyRoomInfo(room.RoomId, xxxsemaphore)); + var semaphore = new SemaphoreSlim(8); + var tasks = new List<Task<PolicyRoomInfo?>>(); + foreach (var room in rooms) { + tasks.Add(GetPolicyRoomInfo(room.RoomId, semaphore)); } - var xxxresults = await Task.WhenAll(xxxtasks); - PolicyRoomList.AddRange(xxxresults.Where(x => x != null).Select(x => x.Value)); + var results = await Task.WhenAll(tasks); + PolicyRoomList.AddRange(results.Where(x => x is not null).Select(x => x.Value)); Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}"); } @@ -68,15 +69,15 @@ else { private async Task<PolicyRoomInfo?> GetPolicyRoomInfo(string room, SemaphoreSlim semaphore) { try { await semaphore.WaitAsync(); + var hs = await MRUStorage.GetCurrentSession(); PolicyRoomInfo roomInfo = new() { RoomId = room }; - var r = await RuntimeCache.CurrentHomeServer.GetRoom(room); - var shortcodeState = await r.GetStateAsync("org.matrix.mjolnir.shortcode"); - if (!shortcodeState.HasValue) return null; - roomInfo.Shortcode = shortcodeState.Value.TryGetProperty("shortcode", out var shortcode) ? shortcode.GetString() : null; + var r = await hs.GetRoom(room); + var shortcodeState = await r.GetStateAsync<MjolnirShortcodeEventData>("org.matrix.mjolnir.shortcode"); + roomInfo.Shortcode = shortcodeState.Shortcode; - if (roomInfo.Shortcode != null) { + if (roomInfo.Shortcode is not null) { roomInfo.Name = await r.GetNameAsync(); return roomInfo; } @@ -90,6 +91,8 @@ else { } } + + public struct PolicyRoomInfo { public string RoomId { get; set; } diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor index 9b0bb88..087adf8 100644 --- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor @@ -34,25 +34,22 @@ else { <LogView></LogView> @code { - public List<Room> Rooms { get; set; } = new(); - public List<Room> Spaces { get; set; } = new(); + public List<GenericRoom> Rooms { get; set; } = new(); + public List<GenericRoom> Spaces { get; set; } = new(); protected override async Task OnInitializedAsync() { Console.WriteLine("Initializing room manager"); - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); Console.WriteLine("Loaded from local storage"); await base.OnInitializedAsync(); Console.WriteLine("Initialized base"); - if (RuntimeCache.CurrentHomeServer == null) { - NavigationManager.NavigateTo("/Login"); - return; - } + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; Console.WriteLine("Fetching joined rooms"); - var _rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); + var _rooms = await hs.GetJoinedRooms(); StateHasChanged(); Console.WriteLine($"Got {_rooms.Count} rooms"); var semaphore = new SemaphoreSlim(10); - var tasks = new List<Task<Room?>>(); + var tasks = new List<Task<GenericRoom?>>(); foreach (var room in _rooms) { tasks.Add(CheckIfSpace(room, semaphore)); } @@ -61,14 +58,14 @@ else { Console.WriteLine("Fetched joined rooms!"); } - private async Task<Room?> CheckIfSpace(Room room, SemaphoreSlim semaphore) { + private async Task<GenericRoom?> CheckIfSpace(GenericRoom room, SemaphoreSlim semaphore) { await semaphore.WaitAsync(); // Console.WriteLine($"Checking if {room.RoomId} is a space"); try { var state = await room.GetStateAsync<CreateEvent>("m.room.create"); - if (state != null) { + if (state is not null) { //Console.WriteLine(state.Value.ToJson()); - if (state.Type != null) { + if (state.Type is not null) { if (state.Type == "m.space") { Console.WriteLine($"Room {room.RoomId} is a space!"); Spaces.Add(room); diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor index 80d852a..8368aa5 100644 --- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor @@ -1,339 +1,339 @@ -@page "/RoomManagerCreateRoom" -@using MatrixRoomUtils.Core.Responses -@using System.Text.Json -@using System.Reflection -@using MatrixRoomUtils.Core.StateEventTypes -@using MatrixRoomUtils.Web.Classes.RoomCreationTemplates -@* ReSharper disable once RedundantUsingDirective - Must not remove this, Rider marks this as "unused" when it's not *@ -@using MatrixRoomUtils.Web.Shared.SimpleComponents - -<h3>Room Manager - Create Room</h3> - -@* <pre Contenteditable="true" @onkeypress="@JsonChanged" ="JsonString">@JsonString</pre> *@ -<style> - table.table-top-first-tr tr td:first-child { - vertical-align: top; - } -</style> -<table class="table-top-first-tr"> - <tr> - <td style="padding-bottom: 16px;">Preset:</td> - <td style="padding-bottom: 16px;"> - <InputSelect @bind-Value="@RoomPreset"> - @foreach (var createRoomRequest in Presets) { - <option value="@createRoomRequest.Key">@createRoomRequest.Key</option> - } - </InputSelect> - </td> - </tr> - @if (creationEvent != null) { - <tr> - <td>Room name:</td> - <td> - <FancyTextBox @bind-Value="@creationEvent.Name"></FancyTextBox> - </td> - </tr> - <tr> - <td>Room alias (localpart):</td> - <td> - <FancyTextBox @bind-Value="@creationEvent.RoomAliasName"></FancyTextBox> - </td> - </tr> - <tr> - <td>Room type:</td> - <td> - <InputSelect @bind-Value="@creationEvent._creationContentBaseType.Type"> - <option value="">Room</option> - <option value="m.space">Space</option> - </InputSelect> - <FancyTextBox @bind-Value="@creationEvent._creationContentBaseType.Type"></FancyTextBox> - </td> - </tr> - <tr> - <td style="padding-top: 16px;">History visibility:</td> - <td style="padding-top: 16px;"> - @* <InputSelect @bind-Value="@creationEvent.HistoryVisibility"> *@ - @* <option value="invited">Invited</option> *@ - @* <option value="joined">Joined</option> *@ - @* <option value="shared">Shared</option> *@ - @* <option value="world_readable">World readable</option> *@ - @* </InputSelect> *@ - </td> - </tr> - <tr> - <td>Guest access:</td> - <td> - <ToggleSlider Value="guestAccessEvent.IsGuestAccessEnabled" ValueChanged="@(v => { guestAccessEvent.IsGuestAccessEnabled = v; creationEvent["m.room.guest_access"].Content = guestAccessEvent; })">@(guestAccessEvent.IsGuestAccessEnabled ? "Guests can join" : "Guests cannot join") (@guestAccessEvent.GuestAccess)</ToggleSlider> - @* <InputSelect @bind-Value="@creationEvent.GuestAccess"> *@ - @* <option value="can_join">Can join</option> *@ - @* <option value="forbidden">Forbidden</option> *@ - @* </InputSelect> *@ - </td> - </tr> - - <tr> - <td>Room icon:</td> - <td> - <img src="@RuntimeCache.CurrentHomeServer?.ResolveMediaUri(creationEvent.RoomIcon ?? "")" style="width: 128px; height: 128px; border-radius: 50%;"/> - <div style=" display: inline-block; - vertical-align: middle;"> - <FancyTextBox @bind-Value="@creationEvent.RoomIcon"></FancyTextBox><br/> - <InputFile OnChange="RoomIconFilePicked"></InputFile> - </div> - - </td> - </tr> - <tr> - <td>Permissions:</td> - <details> - <summary>@creationEvent.PowerLevelContentOverride.Users.Count members</summary> - @foreach (var user in creationEvent.PowerLevelContentOverride.Events.Keys) { - var _event = user; - <tr> - <td><FancyTextBox Formatter="@GetPermissionFriendlyName" Value="@_event" ValueChanged="val => { creationEvent.PowerLevelContentOverride.Events.ChangeKey(_event, val); }"></FancyTextBox>:</td> - <td> - <input type="number" value="@creationEvent.PowerLevelContentOverride.Events[_event]" @oninput="val => { creationEvent.PowerLevelContentOverride.Events[_event] = int.Parse(val.Value.ToString()); }" @onfocusout="() => { creationEvent.PowerLevelContentOverride.Events = creationEvent.PowerLevelContentOverride.Events.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"/> - </td> - </tr> - } - @foreach (var user in creationEvent.PowerLevelContentOverride.Users.Keys) { - var _user = user; - <tr> - <td><FancyTextBox Value="@_user" ValueChanged="val => { creationEvent.PowerLevelContentOverride.Users.ChangeKey(_user, val); creationEvent.PowerLevelContentOverride.Users = creationEvent.PowerLevelContentOverride.Users.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"></FancyTextBox>:</td> - <td> - <input type="number" value="@creationEvent.PowerLevelContentOverride.Users[_user]" @oninput="val => { creationEvent.PowerLevelContentOverride.Users[_user] = int.Parse(val.Value.ToString()); }"/> - </td> - </tr> - } - </details> - </tr> - <tr> - <td>Server ACLs:</td> - <td> - <details> - <summary>@(creationEvent.ServerACLs.Allow.Count) allow rules</summary> - <StringListEditor ItemsChanged="OverwriteWrappedProperties" Items="@ServerACLAllowRules"></StringListEditor> - </details> - <details> - <summary>@creationEvent.ServerACLs.Deny.Count deny rules</summary> - <StringListEditor ItemsChanged="OverwriteWrappedProperties" Items="@ServerACLDenyRules"></StringListEditor> - </details> - </td> - </tr> - - <tr> - <td>Invited members:</td> - <td> - <details> - <summary>@creationEvent.InitialState.Count(x => x.Type == "m.room.member") members</summary> - <button @onclick="() => { RuntimeCache.LoginSessions.Select(x => x.Value.LoginResponse.UserId).ToList().ForEach(InviteMember); }">Invite all logged in accounts</button> - @foreach (var member in creationEvent.InitialState.Where(x => x.Type == "m.room.member" && x.StateKey != RuntimeCache.CurrentHomeServer.UserId)) { - <UserListItem UserId="@member.StateKey"></UserListItem> - } - </details> - </td> - </tr> - - @* Initial states, should remain at bottom? *@ - - <tr> - <td style="vertical-align: top;">Initial states:</td> - <td> - <details> - - @code{ - - private static readonly string[] ImplementedStates = { "m.room.avatar", "m.room.history_visibility", "m.room.guest_access", "m.room.server_acl" }; - - } - - <summary>@creationEvent.InitialState.Count(x => !ImplementedStates.Contains(x.Type)) custom states</summary> - <table> - @foreach (var initialState in creationEvent.InitialState.Where(x => !ImplementedStates.Contains(x.Type))) { - <tr> - <td style="vertical-align: top;"> - @(initialState.Type): - @if (!string.IsNullOrEmpty(initialState.StateKey)) { - <br/> - <span>(@initialState.StateKey)</span> - } - </td> - - <td> - <pre>@JsonSerializer.Serialize(initialState.Content, new JsonSerializerOptions { WriteIndented = true })</pre> - </td> - </tr> - } - </table> - </details> - <details> - <summary>@creationEvent.InitialState.Count initial states</summary> - <table> - @foreach (var initialState in creationEvent.InitialState) { - var _state = initialState; - <tr> - <td style="vertical-align: top;"> - <span>@(_state.Type):</span><br/> - <button @onclick="() => { creationEvent.InitialState.Remove(_state); StateHasChanged(); }">Remove</button> - </td> - - <td> - <pre>@JsonSerializer.Serialize(_state.Content, new JsonSerializerOptions { WriteIndented = true })</pre> - </td> - </tr> - } - </table> - </details> - </td> - </tr> - } -</table> -<button @onclick="CreateRoom">Create room</button> -<br/> -<details> - <summary>Creation JSON</summary> - <pre> - @creationEvent.ToJson(ignoreNull: true) - </pre> -</details> -<details open> - <summary>Creation JSON (with null values)</summary> - <pre> - @creationEvent.ToJson() - </pre> -</details> - - -@code { - - private string RoomPreset { - get { - if (Presets.ContainsValue(creationEvent)) { - return Presets.First(x => x.Value == creationEvent).Key; - } - return "Not a preset"; - } - set { - creationEvent = Presets[value]; - JsonChanged(); - OverwriteWrappedPropertiesFromEvent(); - creationEvent.PowerLevelContentOverride.Events = creationEvent.PowerLevelContentOverride.Events.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); - creationEvent.PowerLevelContentOverride.Users = creationEvent.PowerLevelContentOverride.Users.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); - guestAccessEvent = creationEvent["m.room.guest_access"].As<GuestAccessData>().Content; - - Console.WriteLine($"Creation event uncasted: {creationEvent["m.room.guest_access"].ToJson()}"); - Console.WriteLine($"Creation event casted: {creationEvent["m.room.guest_access"].As<GuestAccessData>().ToJson()}"); - creationEvent["m.room.guest_access"].As<GuestAccessData>().Content.IsGuestAccessEnabled = true; - Console.WriteLine("-- Created new guest access content --"); - Console.WriteLine($"Creation event uncasted: {creationEvent["m.room.guest_access"].ToJson()}"); - Console.WriteLine($"Creation event casted: {creationEvent["m.room.guest_access"].As<GuestAccessData>().ToJson()}"); - Console.WriteLine($"Creation event casted back: {creationEvent["m.room.guest_access"].As<GuestAccessData>().ToJson()}"); - StateHasChanged(); - } - } - - private Dictionary<string, string> creationEventValidationErrors { get; set; } = new(); - - private CreateRoomRequest creationEvent { get; set; } - GuestAccessData guestAccessEvent { get; set; } - - private Dictionary<string, CreateRoomRequest> Presets { get; set; } = new(); - - protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - - //creationEvent = Presets["Default room"] = - foreach (var x in Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsClass && !x.IsAbstract && x.GetInterfaces().Contains(typeof(IRoomCreationTemplate))).ToList()) { - Console.WriteLine($"Found room creation template in class: {x.FullName}"); - var instance = (IRoomCreationTemplate)Activator.CreateInstance(x); - Presets[instance.Name] = instance.CreateRoomRequest; - } - Presets = Presets.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); - - if (!Presets.ContainsKey("Default")) { - Console.WriteLine($"No default room found in {Presets.Count} presets: {string.Join(", ", Presets.Keys)}"); - } - else RoomPreset = "Default"; - - await base.OnInitializedAsync(); - } - - private void JsonChanged() => Console.WriteLine(creationEvent.ToJson()); - - //wrappers - private List<string> ServerACLAllowRules { get; set; } = new(); - private List<string> ServerACLDenyRules { get; set; } = new(); - - private void OverwriteWrappedPropertiesFromEvent() { - Console.WriteLine("Overwriting wrapped properties from event"); - ServerACLAllowRules = creationEvent.ServerACLs.Allow; - ServerACLDenyRules = creationEvent.ServerACLs.Deny; - } - - private async Task OverwriteWrappedProperties() { - Console.WriteLine("Overwriting wrapped properties"); - Console.WriteLine($"Allow: {ServerACLAllowRules.Count}: {string.Join(", ", ServerACLAllowRules)}"); - Console.WriteLine($"Deny: {ServerACLDenyRules.Count}: {string.Join(", ", ServerACLDenyRules)}"); - creationEvent.ServerACLs = new ServerACLData { - Allow = ServerACLAllowRules, - Deny = ServerACLDenyRules, - AllowIpLiterals = creationEvent.ServerACLs.AllowIpLiterals - }; - - StateHasChanged(); - } - - private async Task RoomIconFilePicked(InputFileChangeEventArgs obj) { - var res = await RuntimeCache.CurrentHomeServer.UploadFile(obj.File.Name, obj.File.OpenReadStream(), obj.File.ContentType); - Console.WriteLine(res); - creationEvent.RoomIcon = res; - StateHasChanged(); - } - - private async Task CreateRoom() { - Console.WriteLine("Create room"); - Console.WriteLine(creationEvent.ToJson()); - creationEvent.CreationContent.Add("rory.gay.created_using", "Rory&::MatrixRoomUtils (https://mru.rory.gay)"); - //creationEvent.CreationContent.Add(); - var id = await RuntimeCache.CurrentHomeServer.CreateRoom(creationEvent); - // NavigationManager.NavigateTo($"/RoomManager/{id.RoomId.Replace('.','~')}"); - } - - private void InviteMember(string mxid) { - if (!creationEvent.InitialState.Any(x => x.Type == "m.room.member" && x.StateKey == mxid) && RuntimeCache.CurrentHomeServer.UserId != mxid) - creationEvent.InitialState.Add(new StateEvent { - Type = "m.room.member", - StateKey = mxid, - Content = new { - membership = "invite", - reason = "Automatically invited at room creation time." - } - }); - } - - private string GetStateFriendlyName(string key) => key switch { - "m.room.history_visibility" => "History visibility", - "m.room.guest_access" => "Guest access", - "m.room.join_rules" => "Join rules", - "m.room.server_acl" => "Server ACL", - "m.room.avatar" => "Avatar", - _ => key - }; - - private string GetPermissionFriendlyName(string key) => key switch { - "m.reaction" => "Send reaction", - "m.room.avatar" => "Change room icon", - "m.room.canonical_alias" => "Change room alias", - "m.room.encryption" => "Enable encryption", - "m.room.history_visibility" => "Change history visibility", - "m.room.name" => "Change room name", - "m.room.power_levels" => "Change power levels", - "m.room.tombstone" => "Upgrade room", - "m.room.topic" => "Change room topic", - "m.room.pinned_events" => "Pin events", - "m.room.server_acl" => "Change server ACLs", - _ => key - }; - - } - +@* @page "/RoomManagerCreateRoom" *@ +@* @using MatrixRoomUtils.Core.Responses *@ +@* @using System.Text.Json *@ +@* @using System.Reflection *@ +@* @using MatrixRoomUtils.Core.Helpers *@ +@* @using MatrixRoomUtils.Core.StateEventTypes *@ +@* @using MatrixRoomUtils.Web.Classes.RoomCreationTemplates *@ +@* $1$ ReSharper disable once RedundantUsingDirective - Must not remove this, Rider marks this as "unused" when it's not #1# *@ +@* @using MatrixRoomUtils.Web.Shared.SimpleComponents *@ +@* *@ +@* <h3>Room Manager - Create Room</h3> *@ +@* *@ +@* $1$ <pre Contenteditable="true" @onkeypress="@JsonChanged" ="JsonString">@JsonString</pre> #1# *@ +@* <style> *@ +@* table.table-top-first-tr tr td:first-child { *@ +@* vertical-align: top; *@ +@* } *@ +@* </style> *@ +@* <table class="table-top-first-tr"> *@ +@* <tr> *@ +@* <td style="padding-bottom: 16px;">Preset:</td> *@ +@* <td style="padding-bottom: 16px;"> *@ +@* <InputSelect @bind-Value="@RoomPreset"> *@ +@* @foreach (var createRoomRequest in Presets) { *@ +@* <option value="@createRoomRequest.Key">@createRoomRequest.Key</option> *@ +@* } *@ +@* </InputSelect> *@ +@* </td> *@ +@* </tr> *@ +@* @if (creationEvent is not null) { *@ +@* <tr> *@ +@* <td>Room name:</td> *@ +@* <td> *@ +@* <FancyTextBox @bind-Value="@creationEvent.Name"></FancyTextBox> *@ +@* </td> *@ +@* </tr> *@ +@* <tr> *@ +@* <td>Room alias (localpart):</td> *@ +@* <td> *@ +@* <FancyTextBox @bind-Value="@creationEvent.RoomAliasName"></FancyTextBox> *@ +@* </td> *@ +@* </tr> *@ +@* <tr> *@ +@* <td>Room type:</td> *@ +@* <td> *@ +@* <InputSelect @bind-Value="@creationEvent._creationContentBaseType.Type"> *@ +@* <option value="">Room</option> *@ +@* <option value="m.space">Space</option> *@ +@* </InputSelect> *@ +@* <FancyTextBox @bind-Value="@creationEvent._creationContentBaseType.Type"></FancyTextBox> *@ +@* </td> *@ +@* </tr> *@ +@* <tr> *@ +@* <td style="padding-top: 16px;">History visibility:</td> *@ +@* <td style="padding-top: 16px;"> *@ +@* $1$ <InputSelect @bind-Value="@creationEvent.HistoryVisibility"> #1# *@ +@* $1$ <option value="invited">Invited</option> #1# *@ +@* $1$ <option value="joined">Joined</option> #1# *@ +@* $1$ <option value="shared">Shared</option> #1# *@ +@* $1$ <option value="world_readable">World readable</option> #1# *@ +@* $1$ </InputSelect> #1# *@ +@* </td> *@ +@* </tr> *@ +@* <tr> *@ +@* <td>Guest access:</td> *@ +@* <td> *@ +@* <ToggleSlider Value="guestAccessEvent.IsGuestAccessEnabled" ValueChanged="@(v => { guestAccessEvent.IsGuestAccessEnabled = v; creationEvent["m.room.guest_access"].Content = guestAccessEvent; })">@(guestAccessEvent.IsGuestAccessEnabled ? "Guests can join" : "Guests cannot join") (@guestAccessEvent.GuestAccess)</ToggleSlider> *@ +@* $1$ <InputSelect @bind-Value="@creationEvent.GuestAccess"> #1# *@ +@* $1$ <option value="can_join">Can join</option> #1# *@ +@* $1$ <option value="forbidden">Forbidden</option> #1# *@ +@* $1$ </InputSelect> #1# *@ +@* </td> *@ +@* </tr> *@ +@* *@ +@* <tr> *@ +@* <td>Room icon:</td> *@ +@* <td> *@ +@* <img src="@MediaResolver.ResolveMediaUri(creationEvent.RoomIcon ?? "")" style="width: 128px; height: 128px; border-radius: 50%;"/> *@ +@* <div style=" display: inline-block; *@ +@* vertical-align: middle;"> *@ +@* <FancyTextBox @bind-Value="@creationEvent.RoomIcon"></FancyTextBox><br/> *@ +@* <InputFile OnChange="RoomIconFilePicked"></InputFile> *@ +@* </div> *@ +@* *@ +@* </td> *@ +@* </tr> *@ +@* <tr> *@ +@* <td>Permissions:</td> *@ +@* <details> *@ +@* <summary>@creationEvent.PowerLevelContentOverride.Users.Count members</summary> *@ +@* @foreach (var user in creationEvent.PowerLevelContentOverride.Events.Keys) { *@ +@* var _event = user; *@ +@* <tr> *@ +@* <td><FancyTextBox Formatter="@GetPermissionFriendlyName" Value="@_event" ValueChanged="val => { creationEvent.PowerLevelContentOverride.Events.ChangeKey(_event, val); }"></FancyTextBox>:</td> *@ +@* <td> *@ +@* <input type="number" value="@creationEvent.PowerLevelContentOverride.Events[_event]" @oninput="val => { creationEvent.PowerLevelContentOverride.Events[_event] = int.Parse(val.Value.ToString()); }" @onfocusout="() => { creationEvent.PowerLevelContentOverride.Events = creationEvent.PowerLevelContentOverride.Events.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"/> *@ +@* </td> *@ +@* </tr> *@ +@* } *@ +@* @foreach (var user in creationEvent.PowerLevelContentOverride.Users.Keys) { *@ +@* var _user = user; *@ +@* <tr> *@ +@* <td><FancyTextBox Value="@_user" ValueChanged="val => { creationEvent.PowerLevelContentOverride.Users.ChangeKey(_user, val); creationEvent.PowerLevelContentOverride.Users = creationEvent.PowerLevelContentOverride.Users.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"></FancyTextBox>:</td> *@ +@* <td> *@ +@* <input type="number" value="@creationEvent.PowerLevelContentOverride.Users[_user]" @oninput="val => { creationEvent.PowerLevelContentOverride.Users[_user] = int.Parse(val.Value.ToString()); }"/> *@ +@* </td> *@ +@* </tr> *@ +@* } *@ +@* </details> *@ +@* </tr> *@ +@* <tr> *@ +@* <td>Server ACLs:</td> *@ +@* <td> *@ +@* <details> *@ +@* <summary>@(creationEvent["server"].ServerACLs.Allow.Count) allow rules</summary> *@ +@* <StringListEditor ItemsChanged="OverwriteWrappedProperties" Items="@ServerACLAllowRules"></StringListEditor> *@ +@* </details> *@ +@* <details> *@ +@* <summary>@creationEvent.ServerACLs.Deny.Count deny rules</summary> *@ +@* <StringListEditor ItemsChanged="OverwriteWrappedProperties" Items="@ServerACLDenyRules"></StringListEditor> *@ +@* </details> *@ +@* </td> *@ +@* </tr> *@ +@* *@ +@* <tr> *@ +@* <td>Invited members:</td> *@ +@* <td> *@ +@* <details> *@ +@* <summary>@creationEvent.InitialState.Count(x => x.Type == "m.room.member") members</summary> *@ +@* <button @onclick="() => { RuntimeCache.LoginSessions.Select(x => x.Value.LoginResponse.UserId).ToList().ForEach(InviteMember); }">Invite all logged in accounts</button> *@ +@* @foreach (var member in creationEvent.InitialState.Where(x => x.Type == "m.room.member" && x.StateKey != RuntimeCache.CurrentHomeServer.UserId)) { *@ +@* <UserListItem UserId="@member.StateKey"></UserListItem> *@ +@* } *@ +@* </details> *@ +@* </td> *@ +@* </tr> *@ +@* *@ +@* $1$ Initial states, should remain at bottom? #1# *@ +@* *@ +@* <tr> *@ +@* <td style="vertical-align: top;">Initial states:</td> *@ +@* <td> *@ +@* <details> *@ +@* *@ +@* @code{ *@ +@* *@ +@* private static readonly string[] ImplementedStates = { "m.room.avatar", "m.room.history_visibility", "m.room.guest_access", "m.room.server_acl" }; *@ +@* *@ +@* } *@ +@* *@ +@* <summary>@creationEvent.InitialState.Count(x => !ImplementedStates.Contains(x.Type)) custom states</summary> *@ +@* <table> *@ +@* @foreach (var initialState in creationEvent.InitialState.Where(x => !ImplementedStates.Contains(x.Type))) { *@ +@* <tr> *@ +@* <td style="vertical-align: top;"> *@ +@* @(initialState.Type): *@ +@* @if (!string.IsNullOrEmpty(initialState.StateKey)) { *@ +@* <br/> *@ +@* <span>(@initialState.StateKey)</span> *@ +@* } *@ +@* </td> *@ +@* *@ +@* <td> *@ +@* <pre>@JsonSerializer.Serialize(initialState.Content, new JsonSerializerOptions { WriteIndented = true })</pre> *@ +@* </td> *@ +@* </tr> *@ +@* } *@ +@* </table> *@ +@* </details> *@ +@* <details> *@ +@* <summary>@creationEvent.InitialState.Count initial states</summary> *@ +@* <table> *@ +@* @foreach (var initialState in creationEvent.InitialState) { *@ +@* var _state = initialState; *@ +@* <tr> *@ +@* <td style="vertical-align: top;"> *@ +@* <span>@(_state.Type):</span><br/> *@ +@* <button @onclick="() => { creationEvent.InitialState.Remove(_state); StateHasChanged(); }">Remove</button> *@ +@* </td> *@ +@* *@ +@* <td> *@ +@* <pre>@JsonSerializer.Serialize(_state.Content, new JsonSerializerOptions { WriteIndented = true })</pre> *@ +@* </td> *@ +@* </tr> *@ +@* } *@ +@* </table> *@ +@* </details> *@ +@* </td> *@ +@* </tr> *@ +@* } *@ +@* </table> *@ +@* <button @onclick="CreateRoom">Create room</button> *@ +@* <br/> *@ +@* <details> *@ +@* <summary>Creation JSON</summary> *@ +@* <pre> *@ +@* @creationEvent.ToJson(ignoreNull: true) *@ +@* </pre> *@ +@* </details> *@ +@* <details open> *@ +@* <summary>Creation JSON (with null values)</summary> *@ +@* <pre> *@ +@* @creationEvent.ToJson() *@ +@* </pre> *@ +@* </details> *@ +@* *@ +@* *@ +@* @code { *@ +@* *@ +@* private string RoomPreset { *@ +@* get { *@ +@* if (Presets.ContainsValue(creationEvent)) { *@ +@* return Presets.First(x => x.Value == creationEvent).Key; *@ +@* } *@ +@* return "Not a preset"; *@ +@* } *@ +@* set { *@ +@* creationEvent = Presets[value]; *@ +@* JsonChanged(); *@ +@* OverwriteWrappedPropertiesFromEvent(); *@ +@* creationEvent.PowerLevelContentOverride.Events = creationEvent.PowerLevelContentOverride.Events.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); *@ +@* creationEvent.PowerLevelContentOverride.Users = creationEvent.PowerLevelContentOverride.Users.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); *@ +@* guestAccessEvent = creationEvent["m.room.guest_access"].As<GuestAccessData>().Content; *@ +@* *@ +@* Console.WriteLine($"Creation event uncasted: {creationEvent["m.room.guest_access"].ToJson()}"); *@ +@* Console.WriteLine($"Creation event casted: {creationEvent["m.room.guest_access"].As<GuestAccessData>().ToJson()}"); *@ +@* creationEvent["m.room.guest_access"].As<GuestAccessData>().Content.IsGuestAccessEnabled = true; *@ +@* Console.WriteLine("-- Created new guest access content --"); *@ +@* Console.WriteLine($"Creation event uncasted: {creationEvent["m.room.guest_access"].ToJson()}"); *@ +@* Console.WriteLine($"Creation event casted: {creationEvent["m.room.guest_access"].As<GuestAccessData>().ToJson()}"); *@ +@* Console.WriteLine($"Creation event casted back: {creationEvent["m.room.guest_access"].As<GuestAccessData>().ToJson()}"); *@ +@* StateHasChanged(); *@ +@* } *@ +@* } *@ +@* *@ +@* private Dictionary<string, string> creationEventValidationErrors { get; set; } = new(); *@ +@* *@ +@* private CreateRoomRequest creationEvent { get; set; } *@ +@* GuestAccessData guestAccessEvent { get; set; } *@ +@* *@ +@* private Dictionary<string, CreateRoomRequest> Presets { get; set; } = new(); *@ +@* *@ +@* protected override async Task OnInitializedAsync() { *@ +@* *@ +@* //creationEvent = Presets["Default room"] = *@ +@* foreach (var x in Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsClass && !x.IsAbstract && x.GetInterfaces().Contains(typeof(IRoomCreationTemplate))).ToList()) { *@ +@* Console.WriteLine($"Found room creation template in class: {x.FullName}"); *@ +@* var instance = (IRoomCreationTemplate)Activator.CreateInstance(x); *@ +@* Presets[instance.Name] = instance.CreateRoomRequest; *@ +@* } *@ +@* Presets = Presets.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); *@ +@* *@ +@* if (!Presets.ContainsKey("Default")) { *@ +@* Console.WriteLine($"No default room found in {Presets.Count} presets: {string.Join(", ", Presets.Keys)}"); *@ +@* } *@ +@* else RoomPreset = "Default"; *@ +@* *@ +@* await base.OnInitializedAsync(); *@ +@* } *@ +@* *@ +@* private void JsonChanged() => Console.WriteLine(creationEvent.ToJson()); *@ +@* *@ +@* //wrappers *@ +@* private List<string> ServerACLAllowRules { get; set; } = new(); *@ +@* private List<string> ServerACLDenyRules { get; set; } = new(); *@ +@* *@ +@* private void OverwriteWrappedPropertiesFromEvent() { *@ +@* Console.WriteLine("Overwriting wrapped properties from event"); *@ +@* ServerACLAllowRules = creationEvent.ServerACLs.Allow; *@ +@* ServerACLDenyRules = creationEvent.ServerACLs.Deny; *@ +@* } *@ +@* *@ +@* private async Task OverwriteWrappedProperties() { *@ +@* Console.WriteLine("Overwriting wrapped properties"); *@ +@* Console.WriteLine($"Allow: {ServerACLAllowRules.Count}: {string.Join(", ", ServerACLAllowRules)}"); *@ +@* Console.WriteLine($"Deny: {ServerACLDenyRules.Count}: {string.Join(", ", ServerACLDenyRules)}"); *@ +@* creationEvent.ServerACLs = new ServerACLData { *@ +@* Allow = ServerACLAllowRules, *@ +@* Deny = ServerACLDenyRules, *@ +@* AllowIpLiterals = creationEvent.ServerACLs.AllowIpLiterals *@ +@* }; *@ +@* *@ +@* StateHasChanged(); *@ +@* } *@ +@* *@ +@* private async Task RoomIconFilePicked(InputFileChangeEventArgs obj) { *@ +@* var res = await RuntimeCache.CurrentHomeServer.UploadFile(obj.File.Name, obj.File.OpenReadStream(), obj.File.ContentType); *@ +@* Console.WriteLine(res); *@ +@* creationEvent.RoomIcon = res; *@ +@* StateHasChanged(); *@ +@* } *@ +@* *@ +@* private async Task CreateRoom() { *@ +@* Console.WriteLine("Create room"); *@ +@* Console.WriteLine(creationEvent.ToJson()); *@ +@* creationEvent.CreationContent.Add("rory.gay.created_using", "Rory&::MatrixRoomUtils (https://mru.rory.gay)"); *@ +@* //creationEvent.CreationContent.Add(); *@ +@* var id = await RuntimeCache.CurrentHomeServer.CreateRoom(creationEvent); *@ +@* // NavigationManager.NavigateTo($"/RoomManager/{id.RoomId.Replace('.','~')}"); *@ +@* } *@ +@* *@ +@* private void InviteMember(string mxid) { *@ +@* if (!creationEvent.InitialState.Any(x => x.Type == "m.room.member" && x.StateKey == mxid) && RuntimeCache.CurrentHomeServer.UserId != mxid) *@ +@* creationEvent.InitialState.Add(new StateEvent { *@ +@* Type = "m.room.member", *@ +@* StateKey = mxid, *@ +@* Content = new { *@ +@* membership = "invite", *@ +@* reason = "Automatically invited at room creation time." *@ +@* } *@ +@* }); *@ +@* } *@ +@* *@ +@* private string GetStateFriendlyName(string key) => key switch { *@ +@* "m.room.history_visibility" => "History visibility", *@ +@* "m.room.guest_access" => "Guest access", *@ +@* "m.room.join_rules" => "Join rules", *@ +@* "m.room.server_acl" => "Server ACL", *@ +@* "m.room.avatar" => "Avatar", *@ +@* _ => key *@ +@* }; *@ +@* *@ +@* private string GetPermissionFriendlyName(string key) => key switch { *@ +@* "m.reaction" => "Send reaction", *@ +@* "m.room.avatar" => "Change room icon", *@ +@* "m.room.canonical_alias" => "Change room alias", *@ +@* "m.room.encryption" => "Enable encryption", *@ +@* "m.room.history_visibility" => "Change history visibility", *@ +@* "m.room.name" => "Change room name", *@ +@* "m.room.power_levels" => "Change power levels", *@ +@* "m.room.tombstone" => "Upgrade room", *@ +@* "m.room.topic" => "Change room topic", *@ +@* "m.room.pinned_events" => "Pin events", *@ +@* "m.room.server_acl" => "Change server ACLs", *@ +@* _ => key *@ +@* }; *@ +@* *@ +@* } *@ +@* *@ diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor index a9c71c4..afa39b9 100644 --- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor @@ -14,7 +14,7 @@ <summary style="background: #fff1;">State list</summary> @foreach (var stateEvent in States.OrderBy(x => x.StateKey).ThenBy(x => x.Type)) { <p>@stateEvent.StateKey/@stateEvent.Type:</p> - <pre>@stateEvent.Content.ToJson()</pre> + <pre>@stateEvent.RawContent.ToJson()</pre> } </details> @@ -23,36 +23,57 @@ [Parameter] public string RoomId { get; set; } = "invalid!!!!!!"; - private Room? Room { get; set; } + private GenericRoom? Room { get; set; } - private StateEventResponse<object>[] States { get; set; } = Array.Empty<StateEventResponse<object>>(); - private List<Room> Rooms { get; } = new(); + private StateEventResponse[] States { get; set; } = Array.Empty<StateEventResponse>(); + private List<GenericRoom> Rooms { get; } = new(); private List<string> ServersInSpace { get; } = new(); protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - Room = await RuntimeCache.CurrentHomeServer.GetRoom(RoomId.Replace('~', '.')); - var state = await Room.GetStateAsync(""); - if (state != null) { - // Console.WriteLine(state.Value.ToJson()); - States = state.Value.Deserialize<StateEventResponse<object>[]>()!; + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; - foreach (var stateEvent in States) { - if (stateEvent.Type == "m.space.child") { - // if (stateEvent.Content.ToJson().Length < 5) return; - var roomId = stateEvent.StateKey; - var room = await RuntimeCache.CurrentHomeServer.GetRoom(roomId); - if (room != null) { - Rooms.Add(room); - } + Room = await hs.GetRoom(RoomId.Replace('~', '.')); + + var state = Room.GetFullStateAsync(); + await foreach (var stateEvent in state) { + if (stateEvent.Type == "m.space.child") { + var roomId = stateEvent.StateKey; + var room = await hs.GetRoom(roomId); + if (room is not null) { + Rooms.Add(room); } - else if (stateEvent.Type == "m.room.member") { - var serverName = stateEvent.StateKey.Split(':').Last(); - if (!ServersInSpace.Contains(serverName)) { - ServersInSpace.Add(serverName); - } + } + else if (stateEvent.Type == "m.room.member") { + var serverName = stateEvent.StateKey.Split(':').Last(); + if (!ServersInSpace.Contains(serverName)) { + ServersInSpace.Add(serverName); } } + } + await base.OnInitializedAsync(); + + // var state = await Room.GetStateAsync(""); + // if (state is not null) { + // // Console.WriteLine(state.Value.ToJson()); + // States = state.Value.Deserialize<StateEventResponse[]>()!; + // + // foreach (var stateEvent in States) { + // if (stateEvent.Type == "m.space.child") { + // // if (stateEvent.Content.ToJson().Length < 5) return; + // var roomId = stateEvent.StateKey; + // var room = await hs.GetRoom(roomId); + // if (room is not null) { + // Rooms.Add(room); + // } + // } + // else if (stateEvent.Type == "m.room.member") { + // var serverName = stateEvent.StateKey.Split(':').Last(); + // if (!ServersInSpace.Contains(serverName)) { + // ServersInSpace.Add(serverName); + // } + // } + // } // if(state.Value.TryGetProperty("Type", out var Type)) // { @@ -62,8 +83,8 @@ // //this is fine, apprently... // //Console.WriteLine($"Room {room.RoomId} has no Content.Type in m.room.create!"); // } - } - await base.OnInitializedAsync(); + + // await base.OnInitializedAsync(); } private async Task JoinAllRooms() { diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor index 9513a8a..e32b5cb 100644 --- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor @@ -20,10 +20,11 @@ private List<StateEventResponse> Events { get; } = new(); protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); RoomId = RoomId.Replace('~', '.'); Console.WriteLine("RoomId: " + RoomId); - var room = await RuntimeCache.CurrentHomeServer.GetRoom(RoomId); + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + var room = await hs.GetRoom(RoomId); MessagesResponse? msgs = null; do { msgs = await room.GetMessagesAsync(limit: 250, from: msgs?.End, dir: "b"); @@ -32,7 +33,7 @@ msgs.Chunk.Reverse(); Events.InsertRange(0, msgs.Chunk); StateHasChanged(); - } while (msgs.End != null); + } while (msgs.End is not null); await base.OnInitializedAsync(); } diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor index 296514c..b2d28f6 100644 --- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor +++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor @@ -45,12 +45,9 @@ public string status = ""; protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - if (RuntimeCache.CurrentHomeServer != null) { - NavigationManager.NavigateTo("/Login"); - return; - } + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; RoomId = RoomId.Replace('~', '.'); await LoadStatesAsync(); Console.WriteLine("Policy list editor initialized!"); @@ -59,25 +56,20 @@ private DateTime _lastUpdate = DateTime.Now; private async Task LoadStatesAsync() { + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + var StateLoaded = 0; - using var client = new HttpClient(); - //TODO: can this be improved? - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.CurrentHomeServer.AccessToken); - var response = await client.GetAsync($"{RuntimeCache.CurrentHomeServer.FullHomeServerDomain}/_matrix/client/v3/rooms/{RoomId}/state"); - // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json"); - //var _events = await response.Content.ReadFromJsonAsync<Queue<StateEventStruct>>(); - var _data = await response.Content.ReadAsStreamAsync(); - var __events = JsonSerializer.DeserializeAsyncEnumerable<StateEventResponse>(_data); - await foreach (var _ev in __events) { - var e = new StateEventResponse { - Type = _ev.Type, - StateKey = _ev.StateKey, - OriginServerTs = _ev.OriginServerTs, - Content = _ev.Content - }; - Events.Add(e); - if (string.IsNullOrEmpty(e.StateKey)) { - FilteredEvents.Add(e); + var response = (await hs.GetRoom(RoomId)).GetFullStateAsync(); + await foreach (var _ev in response) { + // var e = new StateEventResponse { + // Type = _ev.Type, + // StateKey = _ev.StateKey, + // OriginServerTs = _ev.OriginServerTs, + // Content = _ev.Content + // }; + Events.Add(_ev); + if (string.IsNullOrEmpty(_ev.StateKey)) { + FilteredEvents.Add(_ev); } StateLoaded++; if ((DateTime.Now - _lastUpdate).TotalMilliseconds > 100) { @@ -104,8 +96,8 @@ await Task.Delay(1); FilteredEvents = _FilteredEvents; - if (_shownType != null) - shownEventJson = _FilteredEvents.Where(x => x.Type == _shownType).First().Content.ToJson(indent: true, ignoreNull: true); + if (_shownType is not null) + shownEventJson = _FilteredEvents.Where(x => x.Type == _shownType).First().RawContent.ToJson(indent: true, ignoreNull: true); StateHasChanged(); } diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor index 82b5d75..55c44d9 100644 --- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor +++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor @@ -22,13 +22,10 @@ else { public List<string> Rooms { get; set; } = new(); protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - if (RuntimeCache.CurrentHomeServer == null) { - NavigationManager.NavigateTo("/Login"); - return; - } - Rooms = (await RuntimeCache.CurrentHomeServer.GetJoinedRooms()).Select(x => x.RoomId).ToList(); + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + Rooms = (await hs.GetJoinedRooms()).Select(x => x.RoomId).ToList(); Console.WriteLine("Fetched joined rooms!"); } diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor index ff1d9ac..a0072ab 100644 --- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor +++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor @@ -1,6 +1,7 @@ @page "/RoomStateViewer/{RoomId}" @using System.Net.Http.Headers @using System.Text.Json +@using MatrixRoomUtils.Core.Responses @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Room state viewer - Viewing @RoomId</h3> @@ -18,18 +19,18 @@ </tr> </thead> <tbody> - @foreach (var stateEvent in FilteredEvents.Where(x => x.state_key == "").OrderBy(x => x.origin_server_ts)) { + @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey == "").OrderBy(x => x.OriginServerTs)) { <tr> - <td>@stateEvent.type</td> + <td>@stateEvent.Type</td> <td style="max-width: fit-Content;"> - <pre>@stateEvent.content</pre> + <pre>@stateEvent.RawContent.ToJson()</pre> </td> </tr> } </tbody> </table> -@foreach (var group in FilteredEvents.GroupBy(x => x.state_key).OrderBy(x => x.Key).Where(x => x.Key != "")) { +@foreach (var group in FilteredEvents.GroupBy(x => x.StateKey).OrderBy(x => x.Key).Where(x => x.Key != "")) { <details> <summary>@group.Key</summary> <table class="table table-striped table-hover" style="width: fit-Content;"> @@ -40,11 +41,11 @@ </tr> </thead> <tbody> - @foreach (var stateEvent in group.OrderBy(x => x.origin_server_ts)) { + @foreach (var stateEvent in group.OrderBy(x => x.OriginServerTs)) { <tr> - <td>@stateEvent.type</td> + <td>@stateEvent.Type</td> <td style="max-width: fit-Content;"> - <pre>@stateEvent.content</pre> + <pre>@stateEvent.RawContent.ToJson()</pre> </td> </tr> } @@ -64,17 +65,14 @@ [Parameter] public string? RoomId { get; set; } - public List<PreRenderedStateEvent> FilteredEvents { get; set; } = new(); - public List<PreRenderedStateEvent> Events { get; set; } = new(); + public List<StateEventResponse> FilteredEvents { get; set; } = new(); + public List<StateEventResponse> Events { get; set; } = new(); public string status = ""; protected override async Task OnInitializedAsync() { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - if (RuntimeCache.CurrentHomeServer == null) { - NavigationManager.NavigateTo("/Login"); - return; - } + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; RoomId = RoomId.Replace('~', '.'); await LoadStatesAsync(); Console.WriteLine("Policy list editor initialized!"); @@ -84,24 +82,13 @@ private async Task LoadStatesAsync() { var StateLoaded = 0; - //TODO: can we improve this? - using var client = new HttpClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.CurrentHomeServer.AccessToken); - var response = await client.GetAsync($"{RuntimeCache.CurrentHomeServer.FullHomeServerDomain}/_matrix/client/v3/rooms/{RoomId}/state"); - // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json"); - //var _events = await response.Content.ReadFromJsonAsync<Queue<StateEventStruct>>(); - var _data = await response.Content.ReadAsStreamAsync(); - var __events = JsonSerializer.DeserializeAsyncEnumerable<StateEventStruct>(_data); - await foreach (var _ev in __events) { - var e = new PreRenderedStateEvent { - type = _ev.type, - state_key = _ev.state_key, - origin_server_ts = _ev.origin_server_ts, - content = _ev.content.ToJson(true, true) - }; - Events.Add(e); - if (string.IsNullOrEmpty(e.state_key)) { - FilteredEvents.Add(e); + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + var response = (await hs.GetRoom(RoomId)).GetFullStateAsync(); + await foreach (var _ev in response) { + Events.Add(_ev); + if (string.IsNullOrEmpty(_ev.StateKey)) { + FilteredEvents.Add(_ev); } StateLoaded++; if ((DateTime.Now - _lastUpdate).TotalMilliseconds > 100) { @@ -121,7 +108,7 @@ await Task.Delay(1); var _FilteredEvents = Events; if (!ShowMembershipEvents) - _FilteredEvents = _FilteredEvents.Where(x => x.type != "m.room.member").ToList(); + _FilteredEvents = _FilteredEvents.Where(x => x.Type != "m.room.member").ToList(); status = "Done, rerendering!"; StateHasChanged(); @@ -130,17 +117,6 @@ StateHasChanged(); } - public struct PreRenderedStateEvent { - public string content { get; set; } - public long origin_server_ts { get; set; } - public string state_key { get; set; } - public string type { get; set; } - // public string Sender { get; set; } - // public string EventId { get; set; } - // public string UserId { get; set; } - // public string ReplacesState { get; set; } - } - public bool ShowMembershipEvents { get => _showMembershipEvents; set { diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor index 17551c9..20ddd0d 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor @@ -1,20 +1,19 @@ @page "/Rooms" <h3>Room list</h3> -@if (Rooms != null) { +@if (Rooms is not null) { <RoomList Rooms="Rooms"></RoomList> } @code { - private List<Room> Rooms { get; set; } + private List<GenericRoom> Rooms { get; set; } - protected override async Task OnInitializedAsync() - { - await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - - Rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); + protected override async Task OnInitializedAsync() { + var hs = await MRUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + Rooms = await hs.GetJoinedRooms(); await base.OnInitializedAsync(); } |