about summary refs log tree commit diff
path: root/MatrixRoomUtils.Web/Pages
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-28 11:30:53 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-28 11:30:53 +0200
commita357bec1831611758a19bf23ff0fa5a5fe99ca52 (patch)
tree2aa839591e39fdfd9e94a4f1c75fe93b94b246d5 /MatrixRoomUtils.Web/Pages
parentRemove a bunch of caching, make room listings more reliable (diff)
downloadMatrixUtils-a357bec1831611758a19bf23ff0fa5a5fe99ca52.tar.xz
Add changes
Diffstat (limited to 'MatrixRoomUtils.Web/Pages')
-rw-r--r--MatrixRoomUtils.Web/Pages/LoginPage.razor41
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor494
2 files changed, 290 insertions, 245 deletions
diff --git a/MatrixRoomUtils.Web/Pages/LoginPage.razor b/MatrixRoomUtils.Web/Pages/LoginPage.razor

index 9fcedd1..c46dc9a 100644 --- a/MatrixRoomUtils.Web/Pages/LoginPage.razor +++ b/MatrixRoomUtils.Web/Pages/LoginPage.razor
@@ -1,41 +1,21 @@ @page "/Login" @using System.Text.Json @using MatrixRoomUtils.Core.Authentication +@using MatrixRoomUtils.Web.Shared.SimpleComponents @inject ILocalStorageService LocalStorage @inject IJSRuntime JsRuntime <h3>Login</h3> <hr/> <span> - <label>@@</label> - @if (inputVisible.username) - { - <input autofocus @bind="newRecordInput.username" @onfocusout="() => inputVisible.username = false" @ref="elementToFocus"/> - } - else - { - <span tabindex="0" style="border-bottom: #ccc solid 1px; min-width: 50px; display: inline-block; height: 1.4em;" @onfocusin="() => inputVisible.username = true">@newRecordInput.username</span> - } - <label>:</label> - @if (inputVisible.homeserver) - { - <input autofocus @bind="newRecordInput.homeserver" @onfocusout="() => inputVisible.homeserver = false" @ref="elementToFocus"/> - } - else - { - <span tabindex="0" style="border-bottom: #ccc solid 1px; min-width: 50px; display: inline-block; margin-left: 2px; height: 1.4em;" @onfocusin="() => inputVisible.homeserver = true">@newRecordInput.homeserver</span> - } + <span>@@</span><!-- + --><FancyTextBox @bind-Value="@newRecordInput.username"></FancyTextBox><!-- + --><span>:</span><!-- + --><FancyTextBox @bind-Value="@newRecordInput.homeserver"></FancyTextBox> </span> <span style="display: block;"> <label>Password:</label> - @if (inputVisible.password) - { - <input autofocus="true" @bind="newRecordInput.password" @onfocusout="() => inputVisible.password = false" @ref="elementToFocus" type="password"/> - } - else - { - <span tabindex="0" style="border-bottom: #ccc solid 1px; min-width: 50px; display: inline-block; height: 1.4em;" @onfocusin="() => inputVisible.password = true">@string.Join("", newRecordInput.password.Select(x => '*'))</span> - } + <FancyTextBox @bind-Value="@newRecordInput.password" IsPassword="true"></FancyTextBox> </span> <button @onclick="AddRecord">Add account to queue</button> <br/> @@ -63,7 +43,6 @@ @code { 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() { @@ -106,14 +85,6 @@ } } - - private ElementReference elementToFocus; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await JsRuntime.InvokeVoidAsync("BlazorFocusElement", elementToFocus); - } - private void AddRecord() { records.Add(newRecordInput); diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor
index 8cbbca6..c43e276 100644 --- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor +++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerCreateRoom.razor
@@ -2,12 +2,21 @@ @using System.Text.Json @using MatrixRoomUtils.Core.Extensions @using MatrixRoomUtils.Core.Responses +@using MatrixRoomUtils.Web.Shared.SimpleComponents +@using System.Reflection @using System.Runtime.Intrinsics.X86 +@using System.Text.Json.Serialization +@using MatrixRoomUtils.Web.Classes.RoomCreationTemplates <h3>Room Manager - Create Room</h3> @* <pre Contenteditable="true" @onkeypress="@JsonChanged" ="JsonString">@JsonString</pre> *@ -<table> - <tr > +<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"> @@ -15,105 +24,184 @@ { <option value="@createRoomRequest.Key">@createRoomRequest.Key</option> } - @* <option value="private_chat">Private chat</option> *@ - @* <option value="trusted_private_chat">Trusted private chat</option> *@ - @* <option value="public_chat">Public chat</option> *@ - </InputSelect> - </td> - </tr> - <tr> - <td>Room name:</td> - <td> - <InputText @bind-Value="@creationEvent.Name"></InputText> - </td> - </tr> - <tr> - <td>Room alias (localpart):</td> - <td> - <InputText @bind-Value="@creationEvent.RoomAliasName"></InputText> - </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> - <InputText @bind-Value="@creationEvent._creationContentBaseType.Type"></InputText> - </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> - <InputSelect @bind-Value="@creationEvent.GuestAccess"> - <option value="can_join">Can join</option> - <option value="forbidden">Forbidden</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> +@code +{ + bool test { get; set; } = true; + GuestAccessContent a => creationEvent["m.room.guest_access"].As<GuestAccessContent>().Content; +} +<ToggleSlider @bind-Value="a.IsGuestAccessEnabled">@(a.IsGuestAccessEnabled ? "Guests can join" : "Guests cannot join")</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="max-width: 100px; max-height: 100px; border-radius: 50%;"/> - @* <InputText @bind-Value="@creationEvent.RoomIcon"></InputText> *@ - </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> - <tr> - <td style="vertical-align: top;">Initial states:</td> - <td> + </td> + </tr> + <tr> + <td>Permissions:</td> <details> - @code{ - - private static readonly string[] ImplementedStates = { "m.room.avatar", "m.room.history_visibility", "m.room.guest_access", }; - + <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> } - <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):</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.Where(x => !new[] { "m.room.avatar", "m.room.history_visibility" }.Contains(x.Type))) + </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)) { - <tr> - <td style="vertical-align: top;">@(initialState.Type):</td> + <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" }; - <td> - <pre>@JsonSerializer.Serialize(initialState.Content, new JsonSerializerOptions { WriteIndented = true })</pre> - </td> - </tr> } - </table> - </details> - </td> - </tr> + + <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> @@ -123,22 +211,14 @@ </details> <details open> <summary>Creation JSON (with null values)</summary> - <EditablePre @bind-Value="@JsonString" oninput="@JsonChanged"></EditablePre> + <pre> + @creationEvent.ToJson() + </pre> </details> @code { - private string JsonString - { - get => creationEvent.ToJson(); - set - { - creationEvent = JsonSerializer.Deserialize<CreateRoomRequest>(value); - JsonChanged(); - } - } - private string RoomPreset { get @@ -153,6 +233,8 @@ { 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); } } @@ -166,123 +248,87 @@ { await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); - creationEvent = Presets["Default room"] = new CreateRoomRequest + //creationEvent = Presets["Default room"] = + foreach (var x in Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsClass && !x.IsAbstract && x.GetInterfaces().Contains(typeof(IRoomCreationTemplate))).ToList()) { - 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 } - } - }; + 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(JsonString); + 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() + { + 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() + { + Type = "m.room.member", + StateKey = mxid, + Content = new + { + membership = "invite", + reason = "Automatically invited at room creation time." + } + }); } @@ -295,4 +341,32 @@ _ => key }; -} \ No newline at end of file + 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 + }; + public class GuestAccessContent + { + [JsonPropertyName("guest_access")] + public string GuestAccess { get; set; } + + public bool IsGuestAccessEnabled + { + get => GuestAccess == "can_join"; + set => GuestAccess = value ? "can_join" : "forbidden"; + } + } + + } + +