diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
deleted file mode 100644
index e477f4c..0000000
--- a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
+++ /dev/null
@@ -1,338 +0,0 @@
-@page "/Rooms/Create"
-@using System.Text.Json
-@using System.Reflection
-@using ArcaneLibs.Extensions
-@using LibMatrix
-@using LibMatrix.EventTypes.Spec.State
-@using LibMatrix.EventTypes.Spec.State.RoomInfo
-@using LibMatrix.Homeservers
-@using LibMatrix.Responses
-@using MatrixRoomUtils.Web.Classes.RoomCreationTemplates
-@* @* ReSharper disable once RedundantUsingDirective - Must not remove this, Rider marks this as "unused" when it's not */ *@
-
-<h3>Room Manager - Create Room</h3>
-
-@* <pre Contenteditable="true" @onkeypress="@JsonChanged" content="JsonString">@JsonString</pre> *@
-<style>
- table.table-top-first-tr tr td:first-child {
- vertical-align: top;
- }
- </style>
-<table class="table-top-first-tr">
- <tr style="padding-bottom: 16px;">
- <td>Preset:</td>
- <td>
- @if (Presets is null) {
- <p style="color: red;">Presets is null!</p>
- }
- else {
- <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>
- @if (creationEvent.Name is null) {
- <p style="color: red;">creationEvent.Name is null!</p>
- }
- else {
- <FancyTextBox @bind-Value="@creationEvent.Name"></FancyTextBox>
- <p>(#<FancyTextBox @bind-Value="@creationEvent.RoomAliasName"></FancyTextBox>:@Homeserver.WhoAmI.UserId.Split(':').Last())</p>
- }
- </td>
- </tr>
- <tr>
- <td>Room type:</td>
- <td>
- @if (creationEvent.CreationContentBaseType is null) {
- <p style="color: red;">creationEvent._creationContentBaseType is null!</p>
- }
- else {
- <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="@historyVisibility.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 @bind-Value="guestAccessEvent.IsGuestAccessEnabled">
- @(guestAccessEvent.IsGuestAccessEnabled ? "Guests can join" : "Guests cannot join") (@guestAccessEvent.GuestAccess)
- </ToggleSlider>
- <InputSelect @bind-Value="@guestAccessEvent.GuestAccess">
- <option value="can_join">Can join</option>
- <option value="forbidden">Forbidden</option>
- </InputSelect>
- </td>
- </tr>
-
- <tr>
- <td>Room icon:</td>
- <td>
- <img src="@Homeserver.ResolveMediaUri(roomAvatarEvent.Url)" style="width: 128px; height: 128px; border-radius: 50%;"/>
- <div style="display: inline-block; vertical-align: middle;">
- <FancyTextBox @bind-Value="@roomAvatarEvent.Url"></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>
- @if (serverAcl?.Allow is null) {
- <p>No allow rules exist!</p>
- <button @onclick="@(() => { serverAcl.Allow = new List<string> { "*" }; })">Create sane defaults</button>
- }
- else {
- <details>
- <summary>@((creationEvent["m.room.server_acls"].TypedContent as RoomServerACLEventContent).Allow.Count) allow rules</summary>
- @* <StringListEditor @bind-Items="@serverAcl.Allow"></StringListEditor> *@
- </details>
- }
- @if (serverAcl?.Deny is null) {
- <p>No deny rules exist!</p>
- <button @onclick="@(() => { serverAcl.Allow = new List<string>(); })">Create sane defaults</button>
- }
- else {
- <details>
- <summary>@((creationEvent["m.room.server_acls"].TypedContent as RoomServerACLEventContent).Deny.Count) deny rules</summary>
- @* <StringListEditor @bind-Items="@serverAcl.Allow"></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 != Homeserver.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.RawContent, 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.RawContent, new JsonSerializerOptions { WriteIndented = true })</pre>
- </td>
- </tr>
- }
- </table>
- </details>
- </td>
- </tr>
- }
-</table>
-<button @onclick="CreateRoom">Create room</button>
-<br/>
-<ModalWindow Title="Creation JSON">
- <pre>
- @creationEvent.ToJson(ignoreNull: true)
- </pre>
-</ModalWindow>
-<ModalWindow Title="Creation JSON (with null values)">
- <pre>
- @creationEvent.ToJson()
- </pre>
-</ModalWindow>
-
-@if (_matrixException is not null) {
- <ModalWindow Title="@("Matrix exception: " + _matrixException.ErrorCode)">
- <pre>
- @_matrixException.Message
- </pre>
- </ModalWindow>
-}
-
-@code {
-
- private string RoomPreset {
- get => Presets.ContainsValue(creationEvent) ? Presets.First(x => x.Value == creationEvent).Key : "Not a preset";
- set {
- creationEvent = Presets[value];
- JsonChanged();
- StateHasChanged();
- }
- }
-
- private CreateRoomRequest? creationEvent { get; set; }
-
- private Dictionary<string, CreateRoomRequest>? Presets { get; set; } = new();
- private AuthenticatedHomeserverGeneric? Homeserver { get; set; }
-
- private MatrixException? _matrixException { get; set; }
-
- private RoomHistoryVisibilityEventContent? historyVisibility => creationEvent?["m.room.history_visibility"].TypedContent as RoomHistoryVisibilityEventContent;
- private RoomGuestAccessEventContent? guestAccessEvent => creationEvent?["m.room.guest_access"].TypedContent as RoomGuestAccessEventContent;
- private RoomServerACLEventContent? serverAcl => creationEvent?["m.room.server_acls"].TypedContent as RoomServerACLEventContent;
- private RoomAvatarEventContent? roomAvatarEvent => creationEvent?["m.room.avatar"].TypedContent as RoomAvatarEventContent;
-
- protected override async Task OnInitializedAsync() {
- Homeserver = await MRUStorage.GetCurrentSessionOrNavigate();
- if (Homeserver is null) return;
-
- 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());
-
- private async Task RoomIconFilePicked(InputFileChangeEventArgs obj) {
- var res = await Homeserver.UploadFile(obj.File.Name, obj.File.OpenReadStream(), obj.File.ContentType);
- Console.WriteLine(res);
- (creationEvent["m.room.avatar"].TypedContent as RoomAvatarEventContent).Url = 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)");
- try {
- var id = await Homeserver.CreateRoom(creationEvent);
- }
- catch (MatrixException e) {
- _matrixException = e;
- }
- }
-
- private void InviteMember(string mxid) {
- if (!creationEvent.InitialState.Any(x => x.Type == "m.room.member" && x.StateKey == mxid) && Homeserver.UserId != mxid)
- creationEvent.InitialState.Add(new StateEvent {
- Type = "m.room.member",
- StateKey = mxid,
- TypedContent = new RoomMemberEventContent {
- 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/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
deleted file mode 100644
index 6cabe82..0000000
--- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
+++ /dev/null
@@ -1,250 +0,0 @@
-@page "/Rooms"
-@using LibMatrix.Filters
-@using LibMatrix.Helpers
-@using LibMatrix.Extensions
-@using LibMatrix.Responses
-@using System.Collections.ObjectModel
-@using System.Diagnostics
-@using ArcaneLibs.Extensions
-@using MatrixRoomUtils.Abstractions
-@inject ILogger<Index> logger
-<h3>Room list</h3>
-
-<p>@Status</p>
-<p>@Status2</p>
-
-<LinkButton href="/Rooms/Create">Create new room</LinkButton>
-
-<RoomList Rooms="Rooms" GlobalProfile="@GlobalProfile" @bind-StillFetching="RenderContents"></RoomList>
-
-@code {
- private ObservableCollection<RoomInfo> Rooms { get; } = new();
- private UserProfileResponse GlobalProfile { get; set; }
-
- private AuthenticatedHomeserverGeneric? Homeserver { get; set; }
-
- private static SyncFilter filter = new() {
- AccountData = new SyncFilter.EventFilter {
- NotTypes = new List<string> { "*" },
- Limit = 1
- },
- Presence = new SyncFilter.EventFilter {
- NotTypes = new List<string> { "*" },
- Limit = 1
- },
- Room = new SyncFilter.RoomFilter {
- AccountData = new SyncFilter.RoomFilter.StateFilter {
- NotTypes = new List<string> { "*" },
- Limit = 1
- },
- Ephemeral = new SyncFilter.RoomFilter.StateFilter {
- NotTypes = new List<string> { "*" },
- Limit = 1
- },
- State = new SyncFilter.RoomFilter.StateFilter {
- Types = new List<string> {
- "m.room.create",
- "m.room.name",
- "m.room.avatar",
- "org.matrix.mjolnir.shortcode",
- "m.room.power_levels",
- }
- },
- Timeline = new SyncFilter.RoomFilter.StateFilter {
- NotTypes = new List<string> { "*" },
- Limit = 1
- }
- }
- };
-
- // private static SyncFilter profileUpdateFilter = new() {
- // AccountData = new SyncFilter.EventFilter {
- // NotTypes = new List<string> { "*" },
- // Limit = 1
- // },
- // Presence = new SyncFilter.EventFilter {
- // NotTypes = new List<string> { "*" },
- // Limit = 1
- // },
- // Room = new SyncFilter.RoomFilter {
- // AccountData = new SyncFilter.RoomFilter.StateFilter {
- // NotTypes = new List<string> { "*" },
- // Limit = 1
- // },
- // Ephemeral = new SyncFilter.RoomFilter.StateFilter {
- // NotTypes = new List<string> { "*" },
- // Limit = 1
- // },
- // State = new SyncFilter.RoomFilter.StateFilter {
- // Types = new List<string> {
- // "m.room.member"
- // },
- // Senders = new()
- // },
- // Timeline = new SyncFilter.RoomFilter.StateFilter {
- // NotTypes = new List<string> { "*" },
- // Limit = 1
- // }
- // }
- // };
-
- private SyncHelper syncHelper;
-
- // SyncHelper profileSyncHelper;
-
- protected override async Task OnInitializedAsync() {
- Homeserver = await MRUStorage.GetCurrentSessionOrNavigate();
- if (Homeserver is null) return;
- var rooms = await Homeserver.GetJoinedRooms();
- // SemaphoreSlim _semaphore = new(160, 160);
-
- var roomTasks = rooms.Select(async room => {
- RoomInfo ri;
- // await _semaphore.WaitAsync();
- ri = new() { Room = room };
- await Task.WhenAll((filter.Room?.State?.Types ?? []).Select(x => ri.GetStateEvent(x)));
- return ri;
- }).ToAsyncEnumerable();
-
- await foreach (var room in roomTasks) {
- Rooms.Add(room);
- StateHasChanged();
- // await Task.Delay(50);
- // _semaphore.Release();
- }
-
- if (rooms.Count >= 150) RenderContents = true;
-
- GlobalProfile = await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId);
- syncHelper = new SyncHelper(Homeserver, logger) {
- Timeout = 30000,
- Filter = filter,
- MinimumDelay = TimeSpan.FromMilliseconds(5000)
- };
- // profileSyncHelper = new SyncHelper(Homeserver, logger) {
- // Timeout = 10000,
- // Filter = profileUpdateFilter,
- // MinimumDelay = TimeSpan.FromMilliseconds(5000)
- // };
- // profileUpdateFilter.Room.State.Senders.Add(Homeserver.WhoAmI.UserId);
-
- RunSyncLoop(syncHelper);
- // RunSyncLoop(profileSyncHelper);
- RunQueueProcessor();
-
- await base.OnInitializedAsync();
- }
-
- private async Task RunQueueProcessor() {
- var renderTimeSw = Stopwatch.StartNew();
- var isInitialSync = true;
- while (true) {
- try {
- while (queue.Count == 0) {
- Console.WriteLine("Queue is empty, waiting...");
- await Task.Delay(isInitialSync ? 100 : 2500);
- }
-
- Console.WriteLine($"Queue no longer empty after {renderTimeSw.Elapsed}!");
-
- int maxUpdates = 10;
- isInitialSync = false;
- while (maxUpdates-- > 0 && queue.TryDequeue(out var queueEntry)) {
- var (roomId, roomData) = queueEntry;
- Console.WriteLine($"Dequeued room {roomId}");
- RoomInfo room;
-
- if (Rooms.Any(x => x.Room.RoomId == roomId)) {
- room = Rooms.First(x => x.Room.RoomId == roomId);
- Console.WriteLine($"QueueWorker: {roomId} already known with {room.StateEvents?.Count ?? 0} state events");
- }
- else {
- Console.WriteLine($"QueueWorker: encountered new room {roomId}!");
- room = new RoomInfo() {
- Room = Homeserver.GetRoom(roomId)
- };
- Rooms.Add(room);
- }
-
- if (room.StateEvents is null) {
- Console.WriteLine($"QueueWorker: {roomId} does not have state events on record?");
- throw new InvalidDataException("Somehow this is null???");
- }
-
- if (roomData.State?.Events is { Count: > 0 })
- room.StateEvents.MergeStateEventLists(roomData.State.Events);
- else {
- Console.WriteLine($"QueueWorker: could not merge state for {room.Room.RoomId} as new data contains no state events!");
- }
- }
- Console.WriteLine($"QueueWorker: {queue.Count} entries left in queue, {maxUpdates} maxUpdates left, RenderContents: {RenderContents}");
- Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue...";
-
- RenderContents |= queue.Count == 0;
- await Task.Delay(Rooms.Count);
- }
- catch (Exception e) {
- Console.WriteLine("QueueWorker exception: " + e);
- }
- }
- }
-
- private bool RenderContents { get; set; } = false;
-
- private string _status;
-
- public string Status {
- get => _status;
- set {
- _status = value;
- StateHasChanged();
- }
- }
-
- private string _status2;
-
- public string Status2 {
- get => _status2;
- set {
- _status2 = value;
- StateHasChanged();
- }
- }
-
- private Queue<KeyValuePair<string, SyncResponse.RoomsDataStructure.JoinedRoomDataStructure>> queue = new();
-
- private async Task RunSyncLoop(SyncHelper syncHelper) {
- Status = "Initial syncing...";
- Console.WriteLine("starting sync");
-
- var syncs = syncHelper.EnumerateSyncAsync();
- await foreach (var sync in syncs) {
- Console.WriteLine("trying sync");
- if (sync is null) continue;
-
- Status = $"Got sync with {sync.Rooms?.Join?.Count ?? 0} room updates, next batch: {sync.NextBatch}!";
- if (sync?.Rooms?.Join != null)
- foreach (var joinedRoom in sync.Rooms.Join)
- if ( /*joinedRoom.Value.AccountData?.Events?.Count > 0 ||*/ joinedRoom.Value.State?.Events?.Count > 0) {
- joinedRoom.Value.State.Events.RemoveAll(x => x.Type == "m.room.member" && x.StateKey != Homeserver.WhoAmI?.UserId);
- // We can't trust servers to give us what we ask for, and this ruins performance
- // Thanks, Conduit.
- joinedRoom.Value.State.Events.RemoveAll(x => filter.Room?.State?.Types?.Contains(x.Type) == false);
- if (filter.Room?.State?.NotSenders?.Any() ?? false)
- joinedRoom.Value.State.Events.RemoveAll(x => filter.Room?.State?.NotSenders?.Contains(x.Sender) ?? false);
-
- queue.Enqueue(joinedRoom);
- }
- if (sync.Rooms.Leave is {Count: > 0})
- foreach (var leftRoom in sync.Rooms.Leave)
- if (Rooms.Any(x => x.Room.RoomId == leftRoom.Key))
- Rooms.Remove(Rooms.First(x => x.Room.RoomId == leftRoom.Key));
-
- Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue... " +
- $"{sync?.Rooms?.Join?.Count ?? 0} new updates!";
-
- Status2 = $"Next batch: {sync.NextBatch}";
- }
- }
-
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor
deleted file mode 100644
index b89d59c..0000000
--- a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor
+++ /dev/null
@@ -1,267 +0,0 @@
-@page "/Rooms/{RoomId}/Policies"
-@using LibMatrix
-@using ArcaneLibs.Extensions
-@using LibMatrix.EventTypes.Spec.State
-@using LibMatrix.EventTypes.Spec.State.Policy
-@using System.Diagnostics
-@using LibMatrix.RoomTypes
-@using System.Collections.Frozen
-@using System.Reflection
-@using ArcaneLibs.Attributes
-@using LibMatrix.EventTypes
-
-@using MatrixRoomUtils.Web.Shared.PolicyEditorComponents
-
-<h3>Policy list editor - Editing @RoomId</h3>
-<hr/>
-@* <InputCheckbox @bind-Value="EnableAvatars"></InputCheckbox><label>Enable avatars (WILL EXPOSE YOUR IP TO TARGET HOMESERVERS!)</label> *@
-<LinkButton OnClick="@(() => { CurrentlyEditingEvent = new() { Type = "", RawContent = new() }; return Task.CompletedTask; })">Create new policy</LinkButton>
-
-@if (Loading) {
- <p>Loading...</p>
-}
-else if (PolicyEventsByType is not { Count: > 0 }) {
- <p>No policies yet</p>
-}
-else {
- @foreach (var (type, value) in PolicyEventsByType) {
- <p>
- @(GetValidPolicyEventsByType(type).Count) active,
- @(GetInvalidPolicyEventsByType(type).Count) invalid
- (@value.Count total)
- @(GetPolicyTypeName(type).ToLower())
- </p>
- }
-
- @foreach (var type in KnownPolicyTypes.OrderByDescending(t => GetPolicyEventsByType(t).Count)) {
- <details>
- <summary>
- <span>
- @($"{GetPolicyTypeName(type)}: {GetPolicyEventsByType(type).Count} policies")
- </span>
- <hr style="margin: revert;"/>
- </summary>
- <table class="table table-striped table-hover" style="width: fit-content; border-width: 1px; vertical-align: middle;">
- @{
- var policies = GetValidPolicyEventsByType(type);
- var invalidPolicies = GetInvalidPolicyEventsByType(type);
- // enumerate all properties with friendly name
- var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
- .Where(x => (x.GetFriendlyNameOrNull() ?? x.GetJsonPropertyNameOrNull()) is not null)
- .Where(x => x.GetCustomAttribute<TableHideAttribute>() is null)
- .ToFrozenSet();
- var propNames = props.Select(x => x.GetFriendlyNameOrNull() ?? x.GetJsonPropertyName()!).ToFrozenSet();
- }
- <thead>
- <tr>
- @foreach (var name in propNames) {
- <th style="border-width: 1px">@name</th>
- }
- <th style="border-width: 1px">Actions</th>
- </tr>
- </thead>
- <tbody style="border-width: 1px;">
- @foreach (var policy in policies.OrderBy(x => x.RawContent?["entity"]?.GetValue<string>())) {
- <tr>
- @{
- var typedContent = policy.TypedContent!;
- var proxySafeProps = typedContent.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
- .Where(x => props.Any(y => y.Name == x.Name))
- .ToFrozenSet();
- Console.WriteLine($"{proxySafeProps?.Count} proxy safe props found in {policies.FirstOrDefault()?.TypedContent?.GetType()}");
- }
- @foreach (var prop in proxySafeProps ?? Enumerable.Empty<PropertyInfo>()) {
- <td>@prop.GetGetMethod()?.Invoke(typedContent, null)</td>
- }
- <td>
- <div style="display: ruby;">
- @if (PowerLevels.UserHasStatePermission(Homeserver.WhoAmI.UserId, policy.Type)) {
- <LinkButton OnClick="@(() => { CurrentlyEditingEvent = policy; return Task.CompletedTask; })">Edit</LinkButton>
- <LinkButton OnClick="@(() => RemovePolicyAsync(policy))">Remove</LinkButton>
- @if (policy.IsLegacyType) {
- <LinkButton OnClick="@(() => RemovePolicyAsync(policy))">Update policy type</LinkButton>
- }
- }
- </div>
- </td>
- </tr>
- }
- </tbody>
- </table>
- <details>
- <summary>
- <u>
- @("Invalid " + GetPolicyTypeName(type).ToLower())
- </u>
- </summary>
- <table class="table table-striped table-hover" style="width: fit-content; border-width: 1px; vertical-align: middle;">
- <thead>
- <tr>
- <th style="border-width: 1px">State key</th>
- <th style="border-width: 1px">Json contents</th>
- </tr>
- </thead>
- <tbody>
- @foreach (var policy in invalidPolicies) {
- <tr>
- <td>@policy.StateKey</td>
- <td>
- <pre>@policy.RawContent.ToJson(true, false)</pre>
- </td>
- </tr>
- }
- </tbody>
- </table>
- </details>
- </details>
- }
-}
-
-@if (CurrentlyEditingEvent is not null) {
- <PolicyEditorModal PolicyEvent="@CurrentlyEditingEvent" OnClose="@(() => CurrentlyEditingEvent = null)" OnSave="@(e => UpdatePolicyAsync(e))"></PolicyEditorModal>
-}
-
-@code {
-
-#if DEBUG
- private const bool Debug = true;
-#else
- private const bool Debug = false;
-#endif
-
- private bool Loading { get; set; } = true;
- //get room list
- // - sync withroom list filter
- // Type = support.feline.msc3784
- //support.feline.policy.lists.msc.v1
-
- [Parameter]
- public string RoomId { get; set; } = null!;
-
- private bool _enableAvatars;
- private StateEventResponse? _currentlyEditingEvent;
-
- // static readonly Dictionary<string, string?> Avatars = new();
- // static readonly Dictionary<string, RemoteHomeserver> Servers = new();
-
- // private static List<StateEventResponse> PolicyEvents { get; set; } = new();
- private Dictionary<Type, List<StateEventResponse>> PolicyEventsByType { get; set; } = new();
-
- private StateEventResponse? CurrentlyEditingEvent {
- get => _currentlyEditingEvent;
- set {
- _currentlyEditingEvent = value;
- StateHasChanged();
- }
- }
-
- // public bool EnableAvatars {
- // get => _enableAvatars;
- // set {
- // _enableAvatars = value;
- // if (value) GetAllAvatars();
- // }
- // }
-
- private AuthenticatedHomeserverGeneric Homeserver { get; set; }
- private GenericRoom Room { get; set; }
- private RoomPowerLevelEventContent PowerLevels { get; set; }
-
- protected override async Task OnInitializedAsync() {
- var sw = Stopwatch.StartNew();
- await base.OnInitializedAsync();
- Homeserver = (await MRUStorage.GetCurrentSessionOrNavigate())!;
- if (Homeserver is null) return;
- Room = Homeserver.GetRoom(RoomId!);
- PowerLevels = (await Room.GetPowerLevelsAsync())!;
- await LoadStatesAsync();
- Console.WriteLine($"Policy list editor initialized in {sw.Elapsed}!");
- }
-
- private async Task LoadStatesAsync() {
- Loading = true;
- var states = Room.GetFullStateAsync();
- PolicyEventsByType.Clear();
- await foreach (var state in states) {
- if (state is null) continue;
- if (!state.MappedType.IsAssignableTo(typeof(PolicyRuleEventContent))) continue;
- if (!PolicyEventsByType.ContainsKey(state.MappedType)) PolicyEventsByType.Add(state.MappedType, new());
- PolicyEventsByType[state.MappedType].Add(state);
- }
-
- Loading = false;
- StateHasChanged();
- }
-
- // private async Task GetAllAvatars() {
- // // if (!_enableAvatars) return;
- // Console.WriteLine("Getting avatars...");
- // var users = GetValidPolicyEventsByType(typeof(UserPolicyRuleEventContent)).Select(x => x.RawContent!["entity"]!.GetValue<string>()).Where(x => x.Contains(':') && !x.Contains("*")).ToList();
- // Console.WriteLine($"Got {users.Count} users!");
- // var usersByHomeServer = users.GroupBy(x => x!.Split(':')[1]).ToDictionary(x => x.Key!, x => x.ToList());
- // Console.WriteLine($"Got {usersByHomeServer.Count} homeservers!");
- // var homeserverTasks = usersByHomeServer.Keys.Select(x => RemoteHomeserver.TryCreate(x)).ToAsyncEnumerable();
- // await foreach (var server in homeserverTasks) {
- // if (server is null) continue;
- // var profileTasks = usersByHomeServer[server.BaseUrl].Select(x => TryGetProfile(server, x)).ToList();
- // await Task.WhenAll(profileTasks);
- // profileTasks.RemoveAll(x => x.Result is not { Value: { AvatarUrl: not null } });
- // foreach (var profile in profileTasks.Select(x => x.Result!.Value)) {
- // // if (profile is null) continue;
- // if (!string.IsNullOrWhiteSpace(profile.Value.AvatarUrl)) {
- // var url = await hsResolver.ResolveMediaUri(server.BaseUrl, profile.Value.AvatarUrl);
- // Avatars.TryAdd(profile.Key, url);
- // }
- // else Avatars.TryAdd(profile.Key, null);
- // }
- //
- // StateHasChanged();
- // }
- // }
- //
- // private async Task<KeyValuePair<string, UserProfileResponse>?> TryGetProfile(RemoteHomeserver server, string mxid) {
- // try {
- // return new KeyValuePair<string, UserProfileResponse>(mxid, await server.GetProfileAsync(mxid));
- // }
- // catch {
- // return null;
- // }
- // }
-
- private List<StateEventResponse> GetPolicyEventsByType(Type type) => PolicyEventsByType.ContainsKey(type) ? PolicyEventsByType[type] : [];
-
- private List<StateEventResponse> GetValidPolicyEventsByType(Type type) => GetPolicyEventsByType(type)
- .Where(x => !string.IsNullOrWhiteSpace(x.RawContent?["entity"]?.GetValue<string>())).ToList();
-
- private List<StateEventResponse> GetInvalidPolicyEventsByType(Type type) => GetPolicyEventsByType(type)
- .Where(x => string.IsNullOrWhiteSpace(x.RawContent?["entity"]?.GetValue<string>())).ToList();
-
- private string? GetPolicyTypeNameOrNull(Type type) => type.GetFriendlyNamePluralOrNull()
- ?? type.GetCustomAttributes<MatrixEventAttribute>()
- .FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.EventName))?.EventName;
-
- private string GetPolicyTypeName(Type type) => GetPolicyTypeNameOrNull(type) ?? type.Name;
-
- private async Task RemovePolicyAsync(StateEventResponse policyEvent) {
- await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey, new { });
- PolicyEventsByType[policyEvent.MappedType].Remove(policyEvent);
- await LoadStatesAsync();
- }
-
- private async Task UpdatePolicyAsync(StateEventResponse policyEvent) {
- await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey, policyEvent.RawContent);
- await LoadStatesAsync();
- }
-
- private async Task UpgradePolicyAsync(StateEventResponse policyEvent) {
- policyEvent.RawContent["upgraded_from_type"] = policyEvent.Type;
- await LoadStatesAsync();
- }
-
- private static FrozenSet<Type> KnownPolicyTypes = StateEvent.KnownStateEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent))).ToFrozenSet();
-
- // event types, unnamed
- private static Dictionary<string, Type> PolicyTypes = KnownPolicyTypes
- .ToDictionary(x => x.GetCustomAttributes<MatrixEventAttribute>().First(y => !string.IsNullOrWhiteSpace(y.EventName)).EventName, x => x);
-
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Space.razor b/MatrixRoomUtils.Web/Pages/Rooms/Space.razor
deleted file mode 100644
index ce94d01..0000000
--- a/MatrixRoomUtils.Web/Pages/Rooms/Space.razor
+++ /dev/null
@@ -1,100 +0,0 @@
-@page "/Rooms/{RoomId}/Space"
-@using LibMatrix.RoomTypes
-@using ArcaneLibs.Extensions
-@using LibMatrix
-<h3>Room manager - Viewing Space</h3>
-
-<button onclick="@JoinAllRooms">Join all rooms</button>
-@foreach (var room in Rooms) {
- <RoomListItem Room="room" ShowOwnProfile="true"></RoomListItem>
-}
-
-
-<br/>
-<details style="background: #0002;">
- <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.RawContent.ToJson()</pre>
- }
-</details>
-
-@code {
-
- [Parameter]
- public string RoomId { get; set; } = "invalid!!!!!!";
-
- private GenericRoom? Room { get; set; }
-
- 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() {
- var hs = await MRUStorage.GetCurrentSessionOrNavigate();
- if (hs is null) return;
-
- Room = hs.GetRoom(RoomId.Replace('~', '.'));
-
- var state = Room.GetFullStateAsync();
- await foreach (var stateEvent in state) {
- switch (stateEvent.Type) {
- case "m.space.child": {
- var roomId = stateEvent.StateKey;
- var room = hs.GetRoom(roomId);
- if (room is not null) {
- Rooms.Add(room);
- }
- break;
- }
- case "m.room.member": {
- var serverName = stateEvent.StateKey.Split(':').Last();
- if (!ServersInSpace.Contains(serverName)) {
- ServersInSpace.Add(serverName);
- }
- break;
- }
- }
- }
- 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 = 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))
- // {
- // }
- // else
- // {
- // //this is fine, apprently...
- // //Console.WriteLine($"Room {room.RoomId} has no Content.Type in m.room.create!");
- // }
-
- // await base.OnInitializedAsync();
- }
-
- private async Task JoinAllRooms() {
- List<Task<RoomIdResponse>> tasks = Rooms.Select(room => room.JoinAsync(ServersInSpace.ToArray())).ToList();
- await Task.WhenAll(tasks);
- }
-
-}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor
deleted file mode 100644
index 0e9d4f6..0000000
--- a/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor
+++ /dev/null
@@ -1,144 +0,0 @@
-@page "/Rooms/{RoomId}/State/Edit"
-@using ArcaneLibs.Extensions
-@using LibMatrix
-@inject ILocalStorageService LocalStorage
-@inject NavigationManager NavigationManager
-<h3>Room state editor - Editing @RoomId</h3>
-<hr/>
-
-<p>@status</p>
-
-<input type="checkbox" id="showAll" @bind="ShowMembershipEvents"/> Show member events
-<br/>
-<InputSelect @bind-Value="shownStateKey">
- <option value="">-- State key --</option>
- @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey != "").Select(x => x.StateKey).Distinct().OrderBy(x => x)) {
- <option value="@stateEvent">@stateEvent</option>
- Console.WriteLine(stateEvent);
- }
-</InputSelect>
-<br/>
-<InputSelect @bind-Value="shownType">
- <option value="">-- Type --</option>
- @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey != shownStateKey).Select(x => x.Type).Distinct().OrderBy(x => x)) {
- <option value="@stateEvent">@stateEvent</option>
- }
-</InputSelect>
-<br/>
-
-<textarea @bind="shownEventJson" style="width: 100%; height: fit-Content;"></textarea>
-
-<LogView></LogView>
-
-@code {
- //get room list
- // - sync withroom list filter
- // Type = support.feline.msc3784
- //support.feline.policy.lists.msc.v1
-
- [Parameter]
- public string? RoomId { get; set; }
-
- public List<StateEventResponse> FilteredEvents { get; set; } = new();
- public List<StateEventResponse> Events { get; set; } = new();
- public string status = "";
-
- protected override async Task OnInitializedAsync() {
- await base.OnInitializedAsync();
- var hs = await MRUStorage.GetCurrentSessionOrNavigate();
- if (hs is null) return;
- RoomId = RoomId.Replace('~', '.');
- await LoadStatesAsync();
- Console.WriteLine("Policy list editor initialized!");
- }
-
- private DateTime _lastUpdate = DateTime.Now;
-
- private async Task LoadStatesAsync() {
- var hs = await MRUStorage.GetCurrentSessionOrNavigate();
-
- var StateLoaded = 0;
- var response = (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)) continue;
- _lastUpdate = DateTime.Now;
- status = $"Loaded {StateLoaded} state events";
- StateHasChanged();
- await Task.Delay(0);
- }
-
- StateHasChanged();
- }
-
- private async Task RebuildFilteredData() {
- status = "Rebuilding filtered data...";
- StateHasChanged();
- await Task.Delay(1);
- var _FilteredEvents = Events;
- if (!ShowMembershipEvents)
- _FilteredEvents = _FilteredEvents.Where(x => x.Type != "m.room.member").ToList();
-
- status = "Done, rerendering!";
- StateHasChanged();
- await Task.Delay(1);
- FilteredEvents = _FilteredEvents;
-
- if (_shownType is not null)
- shownEventJson = _FilteredEvents.First(x => x.Type == _shownType).RawContent.ToJson(indent: true, ignoreNull: true);
-
- 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 {
- _showMembershipEvents = value;
- RebuildFilteredData();
- }
- }
-
- private bool _showMembershipEvents;
- private string _shownStateKey;
- private string _shownType;
-
- private string shownStateKey {
- get => _shownStateKey;
- set {
- _shownStateKey = value;
- RebuildFilteredData();
- }
- }
-
- private string shownType {
- get => _shownType;
- set {
- _shownType = value;
- RebuildFilteredData();
- }
- }
-
- private string shownEventJson { get; set; }
-}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor
deleted file mode 100644
index 2d0e0b0..0000000
--- a/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor
+++ /dev/null
@@ -1,127 +0,0 @@
-@page "/Rooms/{RoomId}/State/View"
-@using ArcaneLibs.Extensions
-@using LibMatrix
-@inject ILocalStorageService LocalStorage
-@inject NavigationManager NavigationManager
-<h3>Room state viewer - Viewing @RoomId</h3>
-<hr/>
-
-<p>@status</p>
-
-<input type="checkbox" id="showAll" @bind="ShowMembershipEvents"/> Show member events
-
-<table class="table table-striped table-hover" style="width: fit-Content;">
- <thead>
- <tr>
- <th scope="col">Type</th>
- <th scope="col">Content</th>
- </tr>
- </thead>
- <tbody>
- @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey == "").OrderBy(x => x.OriginServerTs)) {
- <tr>
- <td>@stateEvent.Type</td>
- <td style="max-width: fit-Content;">
- <pre>@stateEvent.RawContent.ToJson()</pre>
- </td>
- </tr>
- }
- </tbody>
-</table>
-
-@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;">
- <thead>
- <tr>
- <th scope="col">Type</th>
- <th scope="col">Content</th>
- </tr>
- </thead>
- <tbody>
- @foreach (var stateEvent in group.OrderBy(x => x.OriginServerTs)) {
- <tr>
- <td>@stateEvent.Type</td>
- <td style="max-width: fit-Content;">
- <pre>@stateEvent.RawContent.ToJson()</pre>
- </td>
- </tr>
- }
- </tbody>
- </table>
- </details>
-}
-
-<LogView></LogView>
-
-@code {
- //get room list
- // - sync withroom list filter
- // Type = support.feline.msc3784
- //support.feline.policy.lists.msc.v1
-
- [Parameter]
- public string? RoomId { get; set; }
-
- public List<StateEventResponse> FilteredEvents { get; set; } = new();
- public List<StateEventResponse> Events { get; set; } = new();
- public string status = "";
-
- protected override async Task OnInitializedAsync() {
- await base.OnInitializedAsync();
- var hs = await MRUStorage.GetCurrentSessionOrNavigate();
- if (hs is null) return;
- await LoadStatesAsync();
- Console.WriteLine("Policy list editor initialized!");
- }
-
- private DateTime _lastUpdate = DateTime.Now;
-
- private async Task LoadStatesAsync() {
- var StateLoaded = 0;
- var hs = await MRUStorage.GetCurrentSessionOrNavigate();
- if (hs is null) return;
- var response = (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)) continue;
- _lastUpdate = DateTime.Now;
- status = $"Loaded {StateLoaded} state events";
- StateHasChanged();
- await Task.Delay(0);
- }
-
- StateHasChanged();
- }
-
- private async Task RebuildFilteredData() {
- status = "Rebuilding filtered data...";
- StateHasChanged();
- await Task.Delay(1);
- var _FilteredEvents = Events;
- if (!ShowMembershipEvents)
- _FilteredEvents = _FilteredEvents.Where(x => x.Type != "m.room.member").ToList();
-
- status = "Done, rerendering!";
- StateHasChanged();
- await Task.Delay(1);
- FilteredEvents = _FilteredEvents;
- StateHasChanged();
- }
-
- public bool ShowMembershipEvents {
- get => _showMembershipEvents;
- set {
- _showMembershipEvents = value;
- RebuildFilteredData();
- }
- }
-
- private bool _showMembershipEvents;
-}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor b/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
deleted file mode 100644
index 01bf555..0000000
--- a/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
+++ /dev/null
@@ -1,60 +0,0 @@
-@page "/Rooms/{RoomId}/Timeline"
-@using MatrixRoomUtils.Web.Shared.TimelineComponents
-@using LibMatrix
-@using LibMatrix.EventTypes.Spec
-@using LibMatrix.EventTypes.Spec.State
-@using LibMatrix.Homeservers
-<h3>RoomManagerTimeline</h3>
-<hr/>
-<p>Loaded @Events.Count events...</p>
-
-@foreach (var evt in Events) {
- <div type="@evt.Type" key="@evt.StateKey" itemid="@evt.EventId">
- <DynamicComponent Type="@ComponentType(evt)"
- Parameters="@(new Dictionary<string, object> { { "Event", evt }, { "Events", Events }, { "Homeserver", Homeserver!} })">
- </DynamicComponent>
- </div>
-}
-
-@code {
-
- [Parameter]
- public string RoomId { get; set; }
-
- private List<MessagesResponse> Messages { get; } = new();
- private List<StateEventResponse> Events { get; } = new();
-
- private AuthenticatedHomeserverGeneric? Homeserver { get; set; }
-
- protected override async Task OnInitializedAsync() {
- Console.WriteLine("RoomId: " + RoomId);
- Homeserver = await MRUStorage.GetCurrentSessionOrNavigate();
- if (Homeserver is null) return;
- var room = Homeserver.GetRoom(RoomId);
- MessagesResponse? msgs = null;
- do {
- msgs = await room.GetMessagesAsync(limit: 1000, from: msgs?.End, dir: "b");
- Messages.Add(msgs);
- Console.WriteLine($"Got {msgs.Chunk.Count} messages");
- msgs.Chunk.Reverse();
- Events.InsertRange(0, msgs.Chunk);
- } while (msgs.End is not null);
-
-
- await base.OnInitializedAsync();
- }
-
- private StateEventResponse GetProfileEventBefore(StateEventResponse Event) => Events.TakeWhile(x => x != Event).Last(e => e.Type == "m.room.member" && e.StateKey == Event.Sender);
-
- private Type ComponentType(StateEvent Event) => Event.TypedContent switch {
- RoomCanonicalAliasEventContent => typeof(TimelineCanonicalAliasItem),
- RoomHistoryVisibilityEventContent => typeof(TimelineHistoryVisibilityItem),
- RoomTopicEventContent => typeof(TimelineRoomTopicItem),
- RoomMemberEventContent => typeof(TimelineMemberItem),
- RoomMessageEventContent => typeof(TimelineMessageItem),
- RoomCreateEventContent => typeof(TimelineRoomCreateItem),
- RoomNameEventContent => typeof(TimelineRoomNameItem),
- _ => typeof(TimelineUnknownItem)
- };
-
-}
|