From a67276252c8bfcd6b6c5344e70debc6d67d917a9 Mon Sep 17 00:00:00 2001 From: TheArcaneBrony Date: Sat, 27 May 2023 00:39:49 +0200 Subject: Been a while since I last committed --- MatrixRoomUtils.Core/AuthenticatedHomeServer.cs | 12 + MatrixRoomUtils.Core/Authentication/MatrixAuth.cs | 3 +- MatrixRoomUtils.Core/Interfaces/IHomeServer.cs | 2 +- .../Responses/CreateRoomRequest.cs | 217 +++++++++++++++ .../Responses/StateEventResponse.cs | 34 +++ MatrixRoomUtils.Core/Room.cs | 34 ++- MatrixRoomUtils.Core/RuntimeCache.cs | 36 +-- MatrixRoomUtils.Core/StateEvent.cs | 71 ++--- MatrixRoomUtils.Web.Server/Pages/Error.cshtml | 2 +- MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs | 9 +- MatrixRoomUtils.Web/FileUploadTest.razor | 19 ++ MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj | 10 +- MatrixRoomUtils.Web/Pages/DataExportPage.razor | 43 ++- MatrixRoomUtils.Web/Pages/DebugTools.razor | 2 +- MatrixRoomUtils.Web/Pages/DevOptions.razor | 3 +- MatrixRoomUtils.Web/Pages/Index.razor | 2 +- .../Pages/KnownHomeserverList.razor | 14 +- MatrixRoomUtils.Web/Pages/LoginPage.razor | 119 ++++++-- .../Pages/PolicyList/PolicyListEditorPage.razor | 122 ++++++--- .../Pages/PolicyList/PolicyListRoomList.razor | 4 +- .../Pages/RoomManager/RoomManager.razor | 44 ++- .../Pages/RoomManager/RoomManagerCreateRoom.razor | 298 +++++++++++++++++++++ .../Pages/RoomManager/RoomManagerSpace.razor | 18 +- .../Pages/RoomState/RoomStateEditorPage.razor | 40 +-- .../Pages/RoomState/RoomStateRoomList.razor | 2 +- .../Pages/RoomState/RoomStateViewerPage.razor | 20 +- MatrixRoomUtils.Web/Pages/UserImportPage.razor | 71 ----- MatrixRoomUtils.Web/Shared/EditablePre.razor | 18 ++ .../Shared/IndexComponents/IndexUserItem.razor | 2 +- MatrixRoomUtils.Web/Shared/MainLayout.razor | 2 +- MatrixRoomUtils.Web/Shared/RoomListItem.razor | 6 +- MatrixRoomUtils.Web/wwwroot/css/app.css | 4 + MatrixRoomUtils.Web/wwwroot/index.html | 51 ++-- 33 files changed, 1004 insertions(+), 330 deletions(-) create mode 100644 MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs create mode 100644 MatrixRoomUtils.Core/Responses/StateEventResponse.cs create mode 100644 MatrixRoomUtils.Web/FileUploadTest.razor create mode 100644 MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor delete mode 100644 MatrixRoomUtils.Web/Pages/UserImportPage.razor create mode 100644 MatrixRoomUtils.Web/Shared/EditablePre.razor diff --git a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs index 7a1f5de..502fe5b 100644 --- a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs +++ b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs @@ -59,6 +59,18 @@ public class AuthenticatedHomeServer : IHomeServer return rooms; } + public async Task UploadFile(string fileName, Stream fileStream, string contentType = "application/octet-stream") + { + var res = await _httpClient.PostAsync($"/_matrix/media/r0/upload?filename={fileName}", new StreamContent(fileStream)); + if (!res.IsSuccessStatusCode) + { + Console.WriteLine($"Failed to upload file: {await res.Content.ReadAsStringAsync()}"); + throw new InvalidDataException($"Failed to upload file: {await res.Content.ReadAsStringAsync()}"); + } + var resJson = await res.Content.ReadFromJsonAsync(); + return resJson.GetProperty("content_uri").GetString()!; + } + diff --git a/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs b/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs index 7bcd75f..b4b8d19 100644 --- a/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs +++ b/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs @@ -1,5 +1,6 @@ using System.Net.Http.Json; using System.Text.Json; +using MatrixRoomUtils.Core.Extensions; using MatrixRoomUtils.Core.Responses; namespace MatrixRoomUtils.Core.Authentication; @@ -33,7 +34,7 @@ public class MatrixAuth await Task.Delay(retryAfter.GetInt32()); return await Login(homeserver, username, password); } - + Console.WriteLine($"Login: {data.ToJson()}"); return data.Deserialize(); //var token = data.GetProperty("access_token").GetString(); //return token; diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs index 8fb8b2c..9f7bfee 100644 --- a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs +++ b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs @@ -108,7 +108,7 @@ public class IHomeServer _profileCache[mxid] = profile; return profile; } - public async Task ResolveMediaUri(string mxc) + public string ResolveMediaUri(string mxc) { return mxc.Replace("mxc://", $"{FullHomeServerDomain}/_matrix/media/r0/download/"); } diff --git a/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs b/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs new file mode 100644 index 0000000..6949b1a --- /dev/null +++ b/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs @@ -0,0 +1,217 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; + +namespace MatrixRoomUtils.Core.Responses; + +public class CreateRoomRequest +{ + [JsonPropertyName("name")] public string Name { get; set; } = null!; + + [JsonPropertyName("room_alias_name")] public string RoomAliasName { get; set; } = null!; + + //we dont want to use this, we want more control + // [JsonPropertyName("preset")] + // public string Preset { get; set; } = null!; + [JsonPropertyName("initial_state")] public List InitialState { get; set; } = null!; + [JsonPropertyName("visibility")] public string Visibility { get; set; } = null!; + + [JsonPropertyName("power_level_content_override")] + public PowerLevelEvent PowerLevelContentOverride { get; set; } = null!; + + [JsonPropertyName("creation_content")] public JsonObject CreationContent { get; set; } = new(); + + /// + /// For use only when you can't use the CreationContent property + /// + + + //extra properties + [JsonIgnore] + public string HistoryVisibility + { + get + { + var stateEvent = InitialState.FirstOrDefault(x => x.Type == "m.room.history_visibility"); + if (stateEvent == null) + { + InitialState.Add(new StateEvent() + { + Type = "m.room.history_visibility", + Content = new JsonObject() + { + ["history_visibility"] = "shared" + } + }); + return "shared"; + } + + return stateEvent.ContentAsJsonNode["history_visibility"].GetValue(); + } + set + { + var stateEvent = InitialState.FirstOrDefault(x => x.Type == "m.room.history_visibility"); + if (stateEvent == null) + { + InitialState.Add(new StateEvent() + { + Type = "m.room.history_visibility", + Content = new JsonObject() + { + ["history_visibility"] = value + } + }); + } + else + { + var v = stateEvent.ContentAsJsonNode; + v["history_visibility"] = value; + stateEvent.ContentAsJsonNode = v; + } + } + } + + [JsonIgnore] + public string RoomIcon + { + get + { + var stateEvent = InitialState.FirstOrDefault(x => x.Type == "m.room.avatar"); + if (stateEvent == null) + { + InitialState.Add(new StateEvent() + { + Type = "m.room.avatar", + Content = new JsonObject() + { + ["url"] = "" + } + }); + return ""; + } + + return stateEvent.ContentAsJsonNode["url"].GetValue(); + } + set + { + var stateEvent = InitialState.FirstOrDefault(x => x.Type == "m.room.avatar"); + if (stateEvent == null) + { + InitialState.Add(new StateEvent() + { + Type = "m.room.avatar", + Content = new JsonObject() + { + ["url"] = value + } + }); + } + else + { + var v = stateEvent.ContentAsJsonNode; + v["url"] = value; + stateEvent.ContentAsJsonNode = v; + } + } + } + + [JsonIgnore] + public string GuestAccess + { + get + { + var stateEvent = InitialState.FirstOrDefault(x => x.Type == "m.room.guest_access"); + if (stateEvent == null) + { + InitialState.Add(new StateEvent() + { + Type = "m.room.guest_access", + Content = new JsonObject() + { + ["guest_access"] = "can_join" + } + }); + return "can_join"; + } + + return stateEvent.ContentAsJsonNode["guest_access"].GetValue(); + } + set + { + var stateEvent = InitialState.FirstOrDefault(x => x.Type == "m.room.guest_access"); + if (stateEvent == null) + { + InitialState.Add(new StateEvent() + { + Type = "m.room.guest_access", + Content = new JsonObject() + { + ["guest_access"] = value + } + }); + } + else + { + var v = stateEvent.ContentAsJsonNode; + v["guest_access"] = value; + stateEvent.ContentAsJsonNode = v; + } + } + } + + + [JsonIgnore] public CreationContentBaseType _creationContentBaseType; + + public CreateRoomRequest() => _creationContentBaseType = new(this); + + + public Dictionary Validate() + { + Dictionary errors = new(); + if (!Regex.IsMatch(RoomAliasName, @"[a-zA-Z0-9_\-]+$")) + errors.Add("room_alias_name", "Room alias name must only contain letters, numbers, underscores, and hyphens."); + + return errors; + } +} + +public class CreationContentBaseType +{ + private readonly CreateRoomRequest createRoomRequest; + + public CreationContentBaseType(CreateRoomRequest createRoomRequest) + { + this.createRoomRequest = createRoomRequest; + } + + [JsonPropertyName("type")] + public string Type + { + get => (string)createRoomRequest.CreationContent["type"]; + set + { + if (value is "null" or "") createRoomRequest.CreationContent.Remove("type"); + else createRoomRequest.CreationContent["type"] = value; + } + } +} + +public class PowerLevelEvent +{ + [JsonPropertyName("ban")] public int Ban { get; set; } // = 50; + [JsonPropertyName("events_default")] public int EventsDefault { get; set; } // = 0; + [JsonPropertyName("events")] public Dictionary Events { get; set; } // = null!; + [JsonPropertyName("invite")] public int Invite { get; set; } // = 50; + [JsonPropertyName("kick")] public int Kick { get; set; } // = 50; + [JsonPropertyName("notifications")] public NotificationsPL NotificationsPl { get; set; } // = null!; + [JsonPropertyName("redact")] public int Redact { get; set; } // = 50; + [JsonPropertyName("state_default")] public int StateDefault { get; set; } // = 50; + [JsonPropertyName("users")] public Dictionary Users { get; set; } // = null!; + [JsonPropertyName("users_default")] public int UsersDefault { get; set; } // = 0; +} + +public class NotificationsPL +{ + [JsonPropertyName("room")] public int Room { get; set; } = 50; +} \ No newline at end of file diff --git a/MatrixRoomUtils.Core/Responses/StateEventResponse.cs b/MatrixRoomUtils.Core/Responses/StateEventResponse.cs new file mode 100644 index 0000000..d86f546 --- /dev/null +++ b/MatrixRoomUtils.Core/Responses/StateEventResponse.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace MatrixRoomUtils.Core; + +public class StateEventResponse +{ + [JsonPropertyName("Content")] + public dynamic Content { get; set; } + [JsonPropertyName("origin_server_ts")] + public long OriginServerTs { get; set; } + [JsonPropertyName("RoomId")] + public string RoomId { get; set; } + [JsonPropertyName("Sender")] + public string Sender { get; set; } + [JsonPropertyName("StateKey")] + public string StateKey { get; set; } + [JsonPropertyName("Type")] + public string Type { get; set; } + [JsonPropertyName("Unsigned")] + public dynamic Unsigned { get; set; } + [JsonPropertyName("EventId")] + public string EventId { get; set; } + [JsonPropertyName("UserId")] + public string UserId { get; set; } + [JsonPropertyName("ReplacesState")] + public string ReplacesState { get; set; } + [JsonPropertyName("PrevContent")] + public dynamic PrevContent { get; set; } +} + +public class StateEventResponse : StateEventResponse where T : class +{ + public T content { get; set; } +} \ No newline at end of file diff --git a/MatrixRoomUtils.Core/Room.cs b/MatrixRoomUtils.Core/Room.cs index 362abf4..b96546e 100644 --- a/MatrixRoomUtils.Core/Room.cs +++ b/MatrixRoomUtils.Core/Room.cs @@ -40,14 +40,6 @@ public class Room } var cache = RuntimeCache.GenericResponseCache[cache_key]; - cache.DefaultExpiry = type switch - { - "m.room.name" => TimeSpan.FromMinutes(30), - "org.matrix.mjolnir.shortcode" => TimeSpan.FromHours(4), - "" => TimeSpan.FromSeconds(0), - _ => TimeSpan.FromMinutes(15) - }; - if (cache.ContainsKey(stateCombo)) { if (cache[stateCombo].ExpiryTime > DateTime.Now) @@ -76,14 +68,28 @@ public class Room } var result = await res.Content.ReadFromJsonAsync(); - - cache[stateCombo] = new GenericResult() + var expiryTime = type switch { - Result = result + "m.room.name" => TimeSpan.FromMinutes(30), + "org.matrix.mjolnir.shortcode" => TimeSpan.FromHours(4), + "" => TimeSpan.FromSeconds(0), + _ => TimeSpan.FromMinutes(15) }; + if(!string.IsNullOrWhiteSpace(type) && !string.IsNullOrWhiteSpace(state_key)) + cache[stateCombo] = new GenericResult() + { + Result = result, + ExpiryTime = DateTime.Now.Add(expiryTime) + }; _semaphore.Release(); return result; } + public async Task GetStateAsync(string type, string state_key = "", bool logOnFailure = false) + { + var res = await GetStateAsync(type, state_key, logOnFailure); + if (res == null) return default; + return res.Value.Deserialize(); + } public async Task GetNameAsync() { @@ -115,8 +121,8 @@ public class Room var members = new List(); foreach (var member in res.Value.EnumerateArray()) { - if(member.GetProperty("type").GetString() != "m.room.member") continue; - var member_id = member.GetProperty("state_key").GetString(); + if(member.GetProperty("Type").GetString() != "m.room.member") continue; + var member_id = member.GetProperty("StateKey").GetString(); members.Add(member_id); } @@ -196,7 +202,7 @@ public class CreateEvent [JsonPropertyName("room_version")] public string RoomVersion { get; set; } [JsonPropertyName("type")] - public string Type { get; set; } + public string? Type { get; set; } [JsonPropertyName("predecessor")] public object? Predecessor { get; set; } diff --git a/MatrixRoomUtils.Core/RuntimeCache.cs b/MatrixRoomUtils.Core/RuntimeCache.cs index 4e756a7..380a150 100644 --- a/MatrixRoomUtils.Core/RuntimeCache.cs +++ b/MatrixRoomUtils.Core/RuntimeCache.cs @@ -23,6 +23,21 @@ public class RuntimeCache { Console.WriteLine($"RuntimeCache.SaveObject({key}, {value}) was called, but no callback was set!"); }; + + static RuntimeCache() + { + Task.Run(async () => + { + while (true) + { + await Task.Delay(1000); + foreach (var (key, value) in RuntimeCache.GenericResponseCache) + { + SaveObject("rory.matrixroomutils.generic_cache:" + key, value); + } + } + }); + } } @@ -41,7 +56,6 @@ public class HomeServerResolutionResult public class ObjectCache where T : class { public Dictionary> Cache { get; set; } = new(); - public TimeSpan DefaultExpiry { get; set; } = new(0, 0, 0); public string Name { get; set; } = null!; public GenericResult this[string key] { @@ -49,19 +63,12 @@ public class ObjectCache where T : class { if (Cache.ContainsKey(key)) { - Console.WriteLine($"cache.get({key}): hit"); + // Console.WriteLine($"cache.get({key}): hit"); // Console.WriteLine($"Found item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); - if(Cache[key].ExpiryTime > DateTime.Now) - return Cache[key]; - Console.WriteLine($"Expired item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); - try - { - Cache.Remove(key); - } - catch (Exception e) - { - Console.WriteLine($"Failed to remove {key} from cache: {e.Message}"); - } + if(Cache[key].ExpiryTime < DateTime.Now) + Console.WriteLine($"WARNING: item {key} in cache {Name} expired at {Cache[key].ExpiryTime}:\n{Cache[key].Result.ToJson(indent: false)}"); + return Cache[key]; + } Console.WriteLine($"cache.get({key}): miss"); return null; @@ -69,7 +76,6 @@ public class ObjectCache where T : class set { Cache[key] = value; - if(Cache[key].ExpiryTime == null) Cache[key].ExpiryTime = DateTime.Now.Add(DefaultExpiry); Console.WriteLine($"set({key}) = {Cache[key].Result.ToJson(indent:false)}"); Console.WriteLine($"new_state: {this.ToJson(indent:false)}"); // Console.WriteLine($"New item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); @@ -90,7 +96,7 @@ public class ObjectCache where T : class // Console.WriteLine($"Removing {x.Key} from cache"); Cache.Remove(x.Key); } - RuntimeCache.SaveObject("rory.matrixroomutils.generic_cache:" + Name, this); + //RuntimeCache.SaveObject("rory.matrixroomutils.generic_cache:" + Name, this); } }); } diff --git a/MatrixRoomUtils.Core/StateEvent.cs b/MatrixRoomUtils.Core/StateEvent.cs index df7267d..2201587 100644 --- a/MatrixRoomUtils.Core/StateEvent.cs +++ b/MatrixRoomUtils.Core/StateEvent.cs @@ -1,53 +1,38 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + namespace MatrixRoomUtils.Core; public class StateEvent { - //example: - /* - { - "content": { - "avatar_url": "mxc://matrix.org/BnmEjNvGAkStmAoUiJtEbycT", - "displayname": "X ⊂ Shekhinah | she/her | you", - "membership": "join" - }, - "origin_server_ts": 1682668449785, - "room_id": "!wDPwzxYCNPTkHGHCFT:the-apothecary.club", - "sender": "@kokern:matrix.org", - "state_key": "@kokern:matrix.org", - "type": "m.room.member", - "unsigned": { - "replaces_state": "$7BWfzN15LN8FFUing1hiUQWFfxnOusrEHYFNiOnNrlM", - "prev_content": { - "avatar_url": "mxc://matrix.org/hEQbGywixsjpxDrWvUYEFNur", - "displayname": "X ⊂ Shekhinah | she/her | you", - "membership": "join" - }, - "prev_sender": "@kokern:matrix.org" - }, - "event_id": "$6AGoMCaxqcOeIIDbez1f0VKwLkOEq3EiVLdlsoxDpNg", - "user_id": "@kokern:matrix.org", - "replaces_state": "$7BWfzN15LN8FFUing1hiUQWFfxnOusrEHYFNiOnNrlM", - "prev_content": { - "avatar_url": "mxc://matrix.org/hEQbGywixsjpxDrWvUYEFNur", - "displayname": "X ⊂ Shekhinah | she/her | you", - "membership": "join" + [JsonPropertyName("content")] + public dynamic Content { get; set; } = new{}; + [JsonPropertyName("state_key")] + public string? StateKey { get; set; } + [JsonPropertyName("type")] + public string Type { get; set; } + [JsonPropertyName("replaces_state")] + public string? ReplacesState { get; set; } + + //extra properties + [JsonIgnore] + public JsonNode ContentAsJsonNode + { + get => JsonSerializer.SerializeToNode(Content); + set => Content = value; } - } - */ - public dynamic content { get; set; } - public long origin_server_ts { get; set; } - public string room_id { get; set; } - public string sender { get; set; } - public string state_key { get; set; } - public string type { get; set; } - public dynamic unsigned { get; set; } - public string event_id { get; set; } - public string user_id { get; set; } - public string replaces_state { get; set; } - public dynamic prev_content { get; set; } } public class StateEvent : StateEvent where T : class { - public T content { get; set; } + public new T content { get; set; } + + + [JsonIgnore] + public new JsonNode ContentAsJsonNode + { + get => JsonSerializer.SerializeToNode(Content); + set => Content = value.Deserialize(); + } } \ No newline at end of file diff --git a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml index 5e41c43..0125c85 100644 --- a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml +++ b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml @@ -14,7 +14,7 @@
-
+

Error.

An error occurred while processing your request.

diff --git a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs index 4a00a8a..bd44f7f 100644 --- a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs +++ b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs @@ -5,6 +5,7 @@ namespace MatrixRoomUtils.Web.Classes; public partial class LocalStorageWrapper { + private static SemaphoreSlim _semaphoreSlim = new(1); public static Settings Settings { get; set; } = new(); //some basic logic @@ -15,6 +16,9 @@ public partial class LocalStorageWrapper } public static async Task LoadFromLocalStorage(ILocalStorageService localStorage) { + await _semaphoreSlim.WaitAsync(); + if (RuntimeCache.WasLoaded) return; + RuntimeCache.WasLoaded = true; Settings = await localStorage.GetItemAsync("rory.matrixroomutils.settings") ?? new(); //RuntimeCache stuff @@ -43,7 +47,8 @@ public partial class LocalStorageWrapper Console.WriteLine($"Loading generic cache entry {s}"); RuntimeCache.GenericResponseCache[s.Replace("rory.matrixroomutils.generic_cache:", "")] = await localStorage.GetItemAsync>(s); } - RuntimeCache.WasLoaded = true; + + _semaphoreSlim.Release(); } public static async Task SaveToLocalStorage(ILocalStorageService localStorage) @@ -70,7 +75,7 @@ public partial class LocalStorageWrapper if (key == "rory.matrixroomutils.user_cache") await localStorage.SetItemAsync(key, RuntimeCache.LoginSessions); if (key == "rory.matrixroomutils.last_used_token") await localStorage.SetItemAsync(key, RuntimeCache.LastUsedToken); if (key == "rory.matrixroomutils.homeserver_resolution_cache") await localStorage.SetItemAsync(key, RuntimeCache.HomeserverResolutionCache); - if (key == "rory.matrixroomutils.generic_cache") await localStorage.SetItemAsync(key, RuntimeCache.GenericResponseCache); + //if (key == "rory.matrixroomutils.generic_cache") await localStorage.SetItemAsync(key, RuntimeCache.GenericResponseCache); } } diff --git a/MatrixRoomUtils.Web/FileUploadTest.razor b/MatrixRoomUtils.Web/FileUploadTest.razor new file mode 100644 index 0000000..2e25b54 --- /dev/null +++ b/MatrixRoomUtils.Web/FileUploadTest.razor @@ -0,0 +1,19 @@ +@page "/FileUploadTest" +

FileUploadTest

+ + + + +@code { + + private async void FilePicked(InputFileChangeEventArgs obj) + { + Console.WriteLine("FilePicked"); + Console.WriteLine(obj.File.Name); + Console.WriteLine(obj.File.Size); + Console.WriteLine(obj.File.ContentType); + var res = await RuntimeCache.CurrentHomeServer.UploadFile(obj.File.Name, obj.File.OpenReadStream(), obj.File.ContentType); + Console.WriteLine(res); + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj index 77a039c..12555c3 100644 --- a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj +++ b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj @@ -15,13 +15,5 @@ - - - <_ContentIncludedByDefault Remove="wwwroot\sample-data\weather.json" /> - - - - - - + diff --git a/MatrixRoomUtils.Web/Pages/DataExportPage.razor b/MatrixRoomUtils.Web/Pages/DataExportPage.razor index 6e1b5ec..58e4111 100644 --- a/MatrixRoomUtils.Web/Pages/DataExportPage.razor +++ b/MatrixRoomUtils.Web/Pages/DataExportPage.razor @@ -15,7 +15,7 @@ { @foreach (var (token, user) in RuntimeCache.LoginSessions) { - + @* *@
 @user.LoginResponse.UserId[1..].Split(":")[0]\auth\access_token=@token
 @user.LoginResponse.UserId[1..].Split(":")[0]\auth\device_id=@user.LoginResponse.DeviceId
@@ -45,32 +45,31 @@ else
         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)
+        }
+        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))
             {
-                if (RuntimeCache.HomeserverResolutionCache.ContainsKey(hs))
-                {
-                    resolvedHomeservers++;
-                    continue;
-                }
-                var resolvedHomeserver = (await new RemoteHomeServer(hs).Configure()).FullHomeServerDomain;
-
-                RuntimeCache.HomeserverResolutionCache.Add(hs, new() { Result = resolvedHomeserver, ResolutionTime = DateTime.Now });
-                await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
-
-                Console.WriteLine("Saved to local storage:");
-                Console.WriteLine(JsonSerializer.Serialize(RuntimeCache.HomeserverResolutionCache, new JsonSerializerOptions()
-                {
-                    WriteIndented = true
-                }));
                 resolvedHomeservers++;
-                StateHasChanged();
+                continue;
             }
+            var resolvedHomeserver = (await new RemoteHomeServer(hs).Configure()).FullHomeServerDomain;
+
+            RuntimeCache.HomeserverResolutionCache.Add(hs, new() { Result = resolvedHomeserver, ResolutionTime = DateTime.Now });
+            await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
+
+            Console.WriteLine("Saved to local storage:");
+            Console.WriteLine(JsonSerializer.Serialize(RuntimeCache.HomeserverResolutionCache, new JsonSerializerOptions()
+            {
+                WriteIndented = true
+            }));
+            resolvedHomeservers++;
             StateHasChanged();
         }
+        StateHasChanged();
         _isLoaded = true;
     }
 
diff --git a/MatrixRoomUtils.Web/Pages/DebugTools.razor b/MatrixRoomUtils.Web/Pages/DebugTools.razor
index ffa2134..c8fabaa 100644
--- a/MatrixRoomUtils.Web/Pages/DebugTools.razor
+++ b/MatrixRoomUtils.Web/Pages/DebugTools.razor
@@ -40,7 +40,7 @@ else
     public List Rooms { get; set; } = new();
     protected override async Task OnInitializedAsync()
     {
-        if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+        await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
         await base.OnInitializedAsync();
         if (RuntimeCache.CurrentHomeServer == null)
         {
diff --git a/MatrixRoomUtils.Web/Pages/DevOptions.razor b/MatrixRoomUtils.Web/Pages/DevOptions.razor
index e1b6ac0..9ade1b8 100644
--- a/MatrixRoomUtils.Web/Pages/DevOptions.razor
+++ b/MatrixRoomUtils.Web/Pages/DevOptions.razor
@@ -23,7 +23,6 @@
         {
             
  • @item.Key: @item.Value.Cache.Count entries
    - Default expiry: @item.Value.DefaultExpiry
    @if (item.Value.Cache.Count > 0) {

    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)

    @@ -45,7 +44,7 @@ { while (true) { - await Task.Delay(100); + await Task.Delay(1000); StateHasChanged(); } }); diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor index 7be4149..8be8570 100644 --- a/MatrixRoomUtils.Web/Pages/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Index.razor @@ -9,7 +9,7 @@ Small collection of tools to do not-so-everyday things.

    -
    Signed in accounts - Add new account or Import from TSV
    +
    Signed in accounts - Add new account

    @foreach (var (token, user) in RuntimeCache.LoginSessions) diff --git a/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor index 882dd1e..13b717d 100644 --- a/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor +++ b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor @@ -84,8 +84,8 @@ else await semaphore.WaitAsync(); progress.ProcessedUsers.Add(room, new()); Console.WriteLine($"Fetching states for room ({rooms.IndexOf(room)}/{rooms.Count}) ({room.RoomId})"); - var states = (await room.GetStateAsync("")).Value.Deserialize>(); - states.RemoveAll(x => x.type != "m.room.member" || x.content.GetProperty("membership").GetString() != "join"); + var states = (await room.GetStateAsync("")).Value.Deserialize>(); + 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) { @@ -119,13 +119,13 @@ else { progress.ProcessedUsers[room].Slowmode = false; } - if (!homeServers.Any(x => x.Server == state.state_key.Split(':')[1])) + if (!homeServers.Any(x => x.Server == state.StateKey.Split(':')[1])) { - homeServers.Add(new HomeServerInfo() { Server = state.state_key.Split(':')[1] }); + homeServers.Add(new HomeServerInfo() { Server = state.StateKey.Split(':')[1] }); } - var hs = homeServers.First(x => x.Server == state.state_key.Split(':')[1]); - if (!hs.KnownUsers.Contains(state.state_key.Split(':')[0])) - hs.KnownUsers.Add(state.state_key.Split(':')[0]); + 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(); diff --git a/MatrixRoomUtils.Web/Pages/LoginPage.razor b/MatrixRoomUtils.Web/Pages/LoginPage.razor index c986d40..9fcedd1 100644 --- a/MatrixRoomUtils.Web/Pages/LoginPage.razor +++ b/MatrixRoomUtils.Web/Pages/LoginPage.razor @@ -1,42 +1,123 @@ @page "/Login" +@using System.Text.Json @using MatrixRoomUtils.Core.Authentication @inject ILocalStorageService LocalStorage +@inject IJSRuntime JsRuntime

    Login

    +
    - - -
    - - + + + @if (inputVisible.username) + { + + } + else + { + @newRecordInput.username + } + + @if (inputVisible.homeserver) + { + + } + else + { + @newRecordInput.homeserver + } + + + + @if (inputVisible.password) + { + + } + else + { + @string.Join("", newRecordInput.password.Select(x => '*')) + } + +
    - - + +
    +

    +

    Parsed records

    +
    + + @foreach (var (homeserver, username, password) in records) + { + + + + + + } +
    @username@homeserver@password.Length chars


    @code { - string homeserver = ""; - string username = ""; - string password = ""; + List<(string homeserver, string username, string password)> records = new(); + (string homeserver, string username, string password) newRecordInput = ("", "", ""); + (bool homeserver, bool username, bool password) inputVisible = (false, false, false); async Task Login() { - var result = await MatrixAuth.Login(homeserver, username, password); - Console.WriteLine($"Obtained access token for {result.UserId}!"); + 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}!"); - RuntimeCache.LastUsedToken = result.AccessToken; + var userinfo = new UserInfo() + { + LoginResponse = result + }; + userinfo.Profile = await (await new AuthenticatedHomeServer(result.UserId, result.AccessToken, result.HomeServer).Configure()).GetProfile(result.UserId); + RuntimeCache.LastUsedToken = result.AccessToken; - var userinfo = new UserInfo() - { - LoginResponse = result, - Profile = await (await new RemoteHomeServer(result.HomeServer).Configure()).GetProfile(result.UserId) - }; - RuntimeCache.LoginSessions.Add(userinfo.AccessToken, userinfo); + RuntimeCache.LoginSessions.Add(result.AccessToken, userinfo); + StateHasChanged(); + } await LocalStorageWrapper.SaveToLocalStorage(LocalStorage); } + private async Task FileChanged(InputFileChangeEventArgs obj) + { + Console.WriteLine(JsonSerializer.Serialize(obj, new JsonSerializerOptions() + { + WriteIndented = true + })); + await using var rs = obj.File.OpenReadStream(); + using var sr = new StreamReader(rs); + string TsvData = await sr.ReadToEndAsync(); + records.Clear(); + foreach (var line in TsvData.Split('\n')) + { + var parts = line.Split('\t'); + if (parts.Length != 3) + continue; + records.Add((parts[0], parts[1], parts[2])); + } + } + + + private ElementReference elementToFocus; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await JsRuntime.InvokeVoidAsync("BlazorFocusElement", elementToFocus); + } + + private void AddRecord() + { + records.Add(newRecordInput); + newRecordInput = ("", "", ""); + } + } \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor index d0f9b87..08cdc2c 100644 --- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor +++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor @@ -8,13 +8,14 @@

    - This policy list contains @PolicyEvents.Count(x => x.type == "m.policy.rule.server") server bans, - @PolicyEvents.Count(x => x.type == "m.policy.rule.room") room bans and - @PolicyEvents.Count(x => x.type == "m.policy.rule.user") user bans. + This policy list contains @PolicyEvents.Count(x => x.Type == "m.policy.rule.server") server bans, + @PolicyEvents.Count(x => x.Type == "m.policy.rule.room") room bans and + @PolicyEvents.Count(x => x.Type == "m.policy.rule.user") user bans.

    + -@if (!PolicyEvents.Any(x => x.type == "m.policy.rule.server")) +@if (!PolicyEvents.Any(x => x.Type == "m.policy.rule.server")) {

    No server policies

    } @@ -22,7 +23,7 @@ else {

    Server policies


    - +
    @@ -32,10 +33,10 @@ else - @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.content.Entity != null)) { - +
    Server
    Entity: @policyEvent.content.Entity
    State: @policyEvent.state_key
    Entity: @policyEvent.content.Entity
    State: @policyEvent.StateKey
    @policyEvent.content.Reason @policyEvent.content.ExpiryDateTime @@ -50,18 +51,18 @@ else
    Invalid events - +
    - + - @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.content.Entity == null)) { - + } @@ -69,7 +70,7 @@ else
    State keySerialised contentsSerialised Contents
    @policyEvent.state_key@policyEvent.StateKey @policyEvent.content.ToJson(indent: false, ignoreNull: true)
    } -@if (!PolicyEvents.Any(x => x.type == "m.policy.rule.room")) +@if (!PolicyEvents.Any(x => x.Type == "m.policy.rule.room")) {

    No room policies

    } @@ -77,7 +78,7 @@ else {

    Room policies


    - +
    @@ -87,10 +88,10 @@ else - @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.content.Entity != null)) { - +
    Room
    Entity: @policyEvent.content.Entity
    State: @policyEvent.state_key
    Entity: @policyEvent.content.Entity
    State: @policyEvent.StateKey
    @policyEvent.content.Reason @policyEvent.content.ExpiryDateTime @@ -104,18 +105,18 @@ else
    Invalid events - +
    - + - @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.content.Entity == null)) { - + } @@ -123,7 +124,7 @@ else
    State keySerialised contentsSerialised Contents
    @policyEvent.state_key@policyEvent.StateKey @policyEvent.content.ToJson(indent: false, ignoreNull: true)
    } -@if (!PolicyEvents.Any(x => x.type == "m.policy.rule.user")) +@if (!PolicyEvents.Any(x => x.Type == "m.policy.rule.user")) {

    No user policies

    } @@ -131,9 +132,13 @@ else {

    User policies


    - +
    + @if (_enableAvatars) + { + + } @@ -141,10 +146,14 @@ else - @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.content.Entity != null)) { - + @if (_enableAvatars) + { + + } +
    User Reason Expires
    Entity: @string.Join("", policyEvent.content.Entity.Take(64))
    State: @string.Join("", policyEvent.state_key.Take(64))
    Entity: @string.Join("", policyEvent.content.Entity.Take(64))
    State: @string.Join("", policyEvent.StateKey.Take(64))
    @policyEvent.content.Reason @policyEvent.content.ExpiryDateTime @@ -158,18 +167,18 @@ else
    Invalid events - +
    - + - @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.content.Entity == null)) { - + } @@ -183,19 +192,24 @@ else @code { //get room list // - sync withroom list filter - // type = support.feline.msc3784 + // Type = support.feline.msc3784 //support.feline.policy.lists.msc.v1 [Parameter] public string? RoomId { get; set; } + + private bool _enableAvatars = false; + + static Dictionary avatars = new Dictionary(); + static Dictionary servers = new Dictionary(); - public List> PolicyEvents { get; set; } = new(); + public static List> PolicyEvents { get; set; } = new(); protected override async Task OnInitializedAsync() { - if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); - // if(RuntimeCache.AccessToken == null || RuntimeCache.CurrentHomeserver == null) + // if(RuntimeCache.AccessToken == null || RuntimeCache.CurrentHomeserver == null) if (RuntimeCache.CurrentHomeServer == null) { NavigationManager.NavigateTo("/Login"); @@ -208,21 +222,49 @@ else 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/r0/rooms/{RoomId}/state"); - // var content = await response.Content.ReadAsStringAsync(); - // Console.WriteLine(JsonSerializer.Deserialize(content).ToJson()); - // var stateEvents = JsonSerializer.Deserialize>(content); + // using var client = new HttpClient(); + // client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", LocalStorageWrapper.AccessToken); + // var response = await client.GetAsync($"{LocalStorageWrapper.CurrentHomeserver}/_matrix/client/r0/rooms/{RoomId}/state"); + // var Content = await response.Content.ReadAsStringAsync(); + // Console.WriteLine(JsonSerializer.Deserialize(Content).ToJson()); + // var stateEvents = JsonSerializer.Deserialize>(Content); var room = await RuntimeCache.CurrentHomeServer.GetRoom(RoomId); var stateEventsQuery = await room.GetStateAsync(""); if (stateEventsQuery == null) { Console.WriteLine("state events query is null!!!"); } - var stateEvents = stateEventsQuery.Value.Deserialize>(); - PolicyEvents = stateEvents.Where(x => x.type.StartsWith("m.policy.rule")) - .Select(x => JsonSerializer.Deserialize>(JsonSerializer.Serialize(x))).ToList(); + var stateEvents = stateEventsQuery.Value.Deserialize>(); + PolicyEvents = stateEvents.Where(x => x.Type.StartsWith("m.policy.rule")) + .Select(x => JsonSerializer.Deserialize>(JsonSerializer.Serialize(x))).ToList(); + StateHasChanged(); + } + + private async Task GetAvatar(string userId) + { + try + { + if (avatars.ContainsKey(userId)) return; + var hs = userId.Split(':')[1]; + RemoteHomeServer server = servers.ContainsKey(hs) ? servers[hs] : await new RemoteHomeServer(userId.Split(':')[1]).Configure(); + if (!servers.ContainsKey(hs)) servers.Add(hs, server); + var profile = await server.GetProfile(userId); + avatars.Add(userId, server.ResolveMediaUri(profile.AvatarUrl)); + servers.Add(userId, server); + StateHasChanged(); + } + catch + { + // ignored + } + } + + 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); + } StateHasChanged(); } diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor index f25fbae..e61598a 100644 --- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor +++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor @@ -35,7 +35,7 @@ else @code { //get room list // - sync withroom list filter - // type = support.feline.msc3784 + // Type = support.feline.msc3784 //support.feline.policy.lists.msc.v1 public List PolicyRoomList { get; set; } = new(); @@ -45,7 +45,7 @@ else protected override async Task OnInitializedAsync() { - if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); if (RuntimeCache.CurrentHomeServer == null) { diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor index 6d27679..35bf501 100644 --- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor @@ -11,21 +11,28 @@ else {

    You are in @Rooms.Count rooms and @Spaces.Count spaces

    +

    + Create room +

    +
    Space List @foreach (var room in Spaces) { - + + + }
    Room List @foreach (var room in Rooms) { - + + + }
    - }
    @@ -34,9 +41,10 @@ else @code { public List Rooms { get; set; } = new(); public List Spaces { get; set; } = new(); + protected override async Task OnInitializedAsync() { - if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); if (RuntimeCache.CurrentHomeServer == null) { @@ -45,40 +53,47 @@ else } Rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); StateHasChanged(); - var semaphore = new SemaphoreSlim(1000); + Console.WriteLine($"Got {Rooms.Count} rooms"); + var semaphore = new SemaphoreSlim(10); var tasks = new List>(); foreach (var room in Rooms) { tasks.Add(CheckIfSpace(room, semaphore)); } await Task.WhenAll(tasks); - + Console.WriteLine("Fetched joined rooms!"); } - + private async Task CheckIfSpace(Room room, SemaphoreSlim semaphore) { await semaphore.WaitAsync(); + // Console.WriteLine($"Checking if {room.RoomId} is a space"); try { - var state = await room.GetStateAsync("m.room.create"); + var state = await room.GetStateAsync("m.room.create"); if (state != null) { - //Console.WriteLine(state.Value.ToJson()); - if(state.Value.TryGetProperty("type", out var type)) + //Console.WriteLine(state.Value.ToJson()); + if (state.Type != null) { - if(type.ToString() == "m.space") + if (state.Type == "m.space") { + Console.WriteLine($"Room {room.RoomId} is a space!"); Spaces.Add(room); Rooms.Remove(room); StateHasChanged(); return room; } + else + { + Console.WriteLine($"Encountered unknown room type {state.Type}"); + } } else { - //this is fine, apprently... - //Console.WriteLine($"Room {room.RoomId} has no content.type in m.room.create!"); + //this is fine, apprently... + // Console.WriteLine($"Room {room.RoomId} has no Content.type in m.room.create!"); } } } @@ -93,4 +108,5 @@ else } return null; } -} \ No newline at end of file + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor new file mode 100644 index 0000000..7b4db37 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor @@ -0,0 +1,298 @@ +@page "/RoomManagerCreateRoom" +@using System.Text.Json +@using MatrixRoomUtils.Core.Extensions +@using MatrixRoomUtils.Core.Responses +@using System.Runtime.Intrinsics.X86 +

    Room Manager - Create Room

    + +@*
    @JsonString
    *@ +
    State keySerialised contentsSerialised Contents
    @policyEvent.state_key@policyEvent.StateKey @policyEvent.content.ToJson(indent: false, ignoreNull: true)
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Preset: + + @foreach (var createRoomRequest in Presets) + { + + } + @* *@ + @* *@ + @* *@ + +
    Room name: + +
    Room alias (localpart): + +
    Room type: + + + + + +
    History visibility: + + + + + + +
    Guest access: + + + + +
    Room icon: + + @* *@ +
    Initial states: +
    + @code{ + + private static string[] ImplementedStates = new[] { "m.room.avatar", "m.room.history_visibility", "m.room.guest_access", }; + + } + @creationEvent.InitialState.Count(x => !ImplementedStates.Contains(x.Type)) custom states + + @foreach (var initialState in creationEvent.InitialState.Where(x => !ImplementedStates.Contains(x.Type))) + { + + + + + + } +
    @(initialState.Type): +
    @JsonSerializer.Serialize(initialState.Content, new JsonSerializerOptions { WriteIndented = true })
    +
    +
    +
    + @creationEvent.InitialState.Count initial states + + @foreach (var initialState in creationEvent.InitialState.Where(x => !new[] { "m.room.avatar", "m.room.history_visibility" }.Contains(x.Type))) + { + + + + + + } +
    @(initialState.Type): +
    @JsonSerializer.Serialize(initialState.Content, new JsonSerializerOptions { WriteIndented = true })
    +
    +
    +
    +
    +
    + Creation JSON +
    +        @creationEvent.ToJson(ignoreNull: true)
    +    
    +
    +
    + Creation JSON (with null values) + +
    + + +@code { + + private string JsonString + { + get => creationEvent.ToJson(); + set + { + creationEvent = JsonSerializer.Deserialize(value); + JsonChanged(); + } + } + + 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(); + } + } + + private Dictionary creationEventValidationErrors { get; set; } = new(); + + private CreateRoomRequest creationEvent { get; set; } + + private Dictionary Presets { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + + creationEvent = Presets["Default room"] = new CreateRoomRequest + { + Name = "My new room", + RoomAliasName = "myroom", + InitialState = new() + { + new() + { + Type = "m.room.history_visibility", + Content = new + { + history_visibility = "world_readable" + } + }, + new() + { + Type = "m.room.guest_access", + Content = new + { + guest_access = "can_join" + } + }, + new() + { + Type = "m.room.join_rules", + Content = new + { + join_rule = "public" + } + }, + new() + { + Type = "m.room.server_acl", + Content = new + { + allow = new[] { "*" }, + deny = new[] + { + "midov.pl", + "qoto.org", + "matrix.kiwifarms.net", + "plan9.rocks", + "thisisjoes.site", + "konqi.work", + "austinhuang.lol", + "arcticfox.ems.host", + "*.thisisjoes.site", + "*.abuser.eu", + "*.austinhuang.lol" + }, + allow_ip_literals = false + } + }, + new() + { + Type = "m.room.avatar", + Content = new + { + url = "mxc://feline.support/UKNhEyrVsrAbYteVvZloZcFj" + } + } + }, + Visibility = "public", + PowerLevelContentOverride = new() + { + UsersDefault = 0, + EventsDefault = 100, + StateDefault = 50, + Invite = 0, + Redact = 50, + Kick = 50, + Ban = 50, + NotificationsPl = new() + { + Room = 50 + }, + Events = new() + { + { "im.vector.modular.widgets", 50 }, + { "io.element.voice_broadcast_info", 50 }, + { "m.reaction", 100 }, + { "m.room.avatar", 50 }, + { "m.room.canonical_alias", 50 }, + { "m.room.encryption", 100 }, + { "m.room.history_visibility", 100 }, + { "m.room.name", 50 }, + { "m.room.pinned_events", 50 }, + { "m.room.power_levels", 100 }, + { "m.room.redaction", 100 }, + { "m.room.server_acl", 100 }, + { "m.room.tombstone", 100 }, + { "m.room.topic", 50 }, + { "m.space.child", 50 }, + { "org.matrix.msc3401.call", 50 }, + { "org.matrix.msc3401.call.member", 50 } + }, + Users = new() + { + { "@alicia:rory.gay", 100 }, + { "@emma:rory.gay", 100 }, + { "@root:rory.gay", 100 }, + { "@rory:rory.gay", 100 } + }, + }, + CreationContent = new() + { + { "type", null } + } + }; + + + await base.OnInitializedAsync(); + } + + private void JsonChanged() + { + Console.WriteLine(JsonString); + } + + + 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 + }; + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor index 4a5bddf..a44b2b4 100644 --- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerSpace.razor @@ -13,9 +13,9 @@
    State list - @foreach (var stateEvent in States.OrderBy(x => x.state_key).ThenBy(x => x.type)) + @foreach (var stateEvent in States.OrderBy(x => x.StateKey).ThenBy(x => x.Type)) { -

    @stateEvent.state_key/@stateEvent.type:

    +

    @stateEvent.StateKey/@stateEvent.Type:

    @stateEvent.content.ToJson()
    }
    @@ -27,7 +27,7 @@ private Room? Room { get; set; } - private StateEvent[] States { get; set; } = Array.Empty>(); + private StateEventResponse[] States { get; set; } = Array.Empty>(); private List Rooms { get; set; } = new(); protected override async Task OnInitializedAsync() @@ -38,14 +38,14 @@ if (state != null) { Console.WriteLine(state.Value.ToJson()); - States = state.Value.Deserialize[]>()!; + States = state.Value.Deserialize[]>()!; foreach (var stateEvent in States) { - if (stateEvent.type == "m.space.child") + if (stateEvent.Type == "m.space.child") { - // if (stateEvent.content.ToJson().Length < 5) return; - var roomId = stateEvent.state_key; + // if (stateEvent.Content.ToJson().Length < 5) return; + var roomId = stateEvent.StateKey; var room = await RuntimeCache.CurrentHomeServer.GetRoom(roomId); if (room != null) { @@ -54,13 +54,13 @@ } } - // if(state.Value.TryGetProperty("type", out var type)) + // if(state.Value.TryGetProperty("Type", out var Type)) // { // } // else // { // //this is fine, apprently... - // //Console.WriteLine($"Room {room.RoomId} has no content.type in m.room.create!"); + // //Console.WriteLine($"Room {room.RoomId} has no Content.Type in m.room.create!"); // } } await base.OnInitializedAsync(); diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor index 638d728..3037dcc 100644 --- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor +++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateEditorPage.razor @@ -12,7 +12,7 @@
    - @foreach (var stateEvent in FilteredEvents.Where(x => x.state_key != "").Select(x => x.state_key).Distinct().OrderBy(x => x)) + @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey != "").Select(x => x.StateKey).Distinct().OrderBy(x => x)) { Console.WriteLine(stateEvent); @@ -21,33 +21,33 @@
    - @foreach (var stateEvent in FilteredEvents.Where(x => x.state_key != shownStateKey).Select(x => x.type).Distinct().OrderBy(x => x)) + @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey != shownStateKey).Select(x => x.Type).Distinct().OrderBy(x => x)) { }
    - + @code { //get room list // - sync withroom list filter - // type = support.feline.msc3784 + // Type = support.feline.msc3784 //support.feline.policy.lists.msc.v1 [Parameter] public string? RoomId { get; set; } - public List FilteredEvents { get; set; } = new(); - public List Events { get; set; } = new(); + public List FilteredEvents { get; set; } = new(); + public List Events { get; set; } = new(); public string status = ""; protected override async Task OnInitializedAsync() { - if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); if (RuntimeCache.CurrentHomeServer != null) { @@ -71,18 +71,18 @@ // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json"); //var _events = await response.Content.ReadFromJsonAsync>(); var _data = await response.Content.ReadAsStreamAsync(); - var __events = JsonSerializer.DeserializeAsyncEnumerable(_data); + var __events = JsonSerializer.DeserializeAsyncEnumerable(_data); await foreach (var _ev in __events) { - var e = new StateEvent() + var e = new StateEventResponse() { - type = _ev.type, - state_key = _ev.state_key, - origin_server_ts = _ev.origin_server_ts, - content = _ev.content + Type = _ev.Type, + StateKey = _ev.StateKey, + OriginServerTs = _ev.OriginServerTs, + Content = _ev.Content }; Events.Add(e); - if (string.IsNullOrEmpty(e.state_key)) + if (string.IsNullOrEmpty(e.StateKey)) { FilteredEvents.Add(e); } @@ -106,7 +106,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(); @@ -114,7 +114,7 @@ FilteredEvents = _FilteredEvents; if(_shownType != null) - shownEventJson = _FilteredEvents.Where(x => x.type == _shownType).First().content.ToJson(indent: true, ignoreNull: true); + shownEventJson = _FilteredEvents.Where(x => x.Type == _shownType).First().Content.ToJson(indent: true, ignoreNull: true); StateHasChanged(); } @@ -126,10 +126,10 @@ 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 event_id { get; set; } - // public string user_id { get; set; } - // public string replaces_state { 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 diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor index ba1b0ec..c654b13 100644 --- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor +++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateRoomList.razor @@ -23,7 +23,7 @@ else public List Rooms { get; set; } = new(); protected override async Task OnInitializedAsync() { - if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); if (RuntimeCache.CurrentHomeServer == null) { diff --git a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor index 0f40cb9..c7f9f3c 100644 --- a/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor +++ b/MatrixRoomUtils.Web/Pages/RoomState/RoomStateViewerPage.razor @@ -11,7 +11,7 @@ Show member events - +
    @@ -23,7 +23,7 @@ { - @@ -35,7 +35,7 @@ {
    @group.Key -
    Type
    @stateEvent.type +
    @stateEvent.content
    +
    @@ -47,7 +47,7 @@ { - @@ -62,7 +62,7 @@ @code { //get room list // - sync withroom list filter - // type = support.feline.msc3784 + // Type = support.feline.msc3784 //support.feline.policy.lists.msc.v1 [Parameter] @@ -74,7 +74,7 @@ protected override async Task OnInitializedAsync() { - if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); await base.OnInitializedAsync(); if (RuntimeCache.CurrentHomeServer == null) { @@ -149,10 +149,10 @@ 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 event_id { get; set; } - // public string user_id { get; set; } - // public string replaces_state { 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 diff --git a/MatrixRoomUtils.Web/Pages/UserImportPage.razor b/MatrixRoomUtils.Web/Pages/UserImportPage.razor deleted file mode 100644 index 6f3045e..0000000 --- a/MatrixRoomUtils.Web/Pages/UserImportPage.razor +++ /dev/null @@ -1,71 +0,0 @@ -@page "/ImportUsers" -@using System.Text.Json -@using MatrixRoomUtils.Core.Authentication -@inject ILocalStorageService LocalStorage -

    Login

    - - -
    - -

    -

    Parsed records

    -
    -
    Type
    @stateEvent.type +
    @stateEvent.content
    - @foreach (var (homeserver, username, password) in records) - { - - - - - - } -
    @username@homeserver@password.Length chars
    -
    -
    - - -@code { - List<(string homeserver, string username, string password)> records = 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 MatrixAuth.GetProfile(result.HomeServer, result.UserId); - RuntimeCache.LastUsedToken = result.AccessToken; - - RuntimeCache.LoginSessions.Add(result.AccessToken, userinfo); - StateHasChanged(); - } - - await LocalStorageWrapper.SaveToLocalStorage(LocalStorage); - } - - private async Task FileChanged(InputFileChangeEventArgs obj) - { - Console.WriteLine(JsonSerializer.Serialize(obj, new JsonSerializerOptions() - { - WriteIndented = true - })); - await using var rs = obj.File.OpenReadStream(); - using var sr = new StreamReader(rs); - string TsvData = await sr.ReadToEndAsync(); - records.Clear(); - foreach (var line in TsvData.Split('\n')) - { - var parts = line.Split('\t'); - if (parts.Length != 3) - continue; - records.Add((parts[0], parts[1], parts[2])); - } - } - -} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Shared/EditablePre.razor b/MatrixRoomUtils.Web/Shared/EditablePre.razor new file mode 100644 index 0000000..01bea0d --- /dev/null +++ b/MatrixRoomUtils.Web/Shared/EditablePre.razor @@ -0,0 +1,18 @@ +@inherits InputBase +
    @CurrentValue
    +@code { + protected override bool TryParseValueFromString(string? value, out string result, out string? validationErrorMessage) + { + result = value; + validationErrorMessage = null; + return true; + } + + public object Id { get; set; } + + private async Task Callback() + { + Console.WriteLine("beep"); + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor b/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor index 87ef831..016b993 100644 --- a/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor +++ b/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor @@ -31,7 +31,7 @@ { var hs = await new AuthenticatedHomeServer(User.LoginResponse.UserId, User.AccessToken, User.LoginResponse.HomeServer).Configure(); if (User.Profile.AvatarUrl != null && User.Profile.AvatarUrl != "") - _avatarUrl = await hs.ResolveMediaUri(User.Profile.AvatarUrl); + _avatarUrl = hs.ResolveMediaUri(User.Profile.AvatarUrl); else _avatarUrl = "https://api.dicebear.com/6.x/identicon/svg?seed=" + User.LoginResponse.UserId; _roomCount = (await hs.GetJoinedRooms()).Count; await base.OnInitializedAsync(); diff --git a/MatrixRoomUtils.Web/Shared/MainLayout.razor b/MatrixRoomUtils.Web/Shared/MainLayout.razor index b1b0b53..cdb1205 100644 --- a/MatrixRoomUtils.Web/Shared/MainLayout.razor +++ b/MatrixRoomUtils.Web/Shared/MainLayout.razor @@ -17,7 +17,7 @@ } -
    +
    @Body
    diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor index 317d25a..b7394c1 100644 --- a/MatrixRoomUtils.Web/Shared/RoomListItem.razor +++ b/MatrixRoomUtils.Web/Shared/RoomListItem.razor @@ -1,7 +1,7 @@ @using MatrixRoomUtils.Core.Authentication @using System.Text.Json @using MatrixRoomUtils.Core.Extensions -
    +
    @if (ShowOwnProfile) { @@ -96,7 +96,7 @@ var url = state.Value.GetProperty("url").GetString(); if (url != null) { - roomIcon = await RuntimeCache.CurrentHomeServer.ResolveMediaUri(url); + roomIcon = RuntimeCache.CurrentHomeServer.ResolveMediaUri(url); } } catch (InvalidOperationException e) @@ -116,7 +116,7 @@ if (_avatar.ValueKind == JsonValueKind.String) { hasCustomProfileAvatar = _avatar.GetString() != profile.AvatarUrl; - profileAvatar = await RuntimeCache.CurrentHomeServer.ResolveMediaUri(_avatar.GetString()); + profileAvatar = RuntimeCache.CurrentHomeServer.ResolveMediaUri(_avatar.GetString()); } else { diff --git a/MatrixRoomUtils.Web/wwwroot/css/app.css b/MatrixRoomUtils.Web/wwwroot/css/app.css index acbbfce..c6d71d1 100644 --- a/MatrixRoomUtils.Web/wwwroot/css/app.css +++ b/MatrixRoomUtils.Web/wwwroot/css/app.css @@ -1,5 +1,9 @@ @import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); +article > h3:first-child { + padding-top: 24px; +} + html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background-color: #222; diff --git a/MatrixRoomUtils.Web/wwwroot/index.html b/MatrixRoomUtils.Web/wwwroot/index.html index 580a88b..028e56b 100644 --- a/MatrixRoomUtils.Web/wwwroot/index.html +++ b/MatrixRoomUtils.Web/wwwroot/index.html @@ -2,31 +2,42 @@ - - + + MatrixRoomUtils.Web - - - - - + + + + + -
    - - - - -
    -
    +
    + + + + +
    +
    -
    - An unhandled error has occurred. - Reload - 🗙 -
    - +
    + An unhandled error has occurred. + Reload + 🗙 +
    + + -- cgit 1.5.1