about summary refs log tree commit diff
path: root/MatrixUtils.Web/Pages/Tools
diff options
context:
space:
mode:
Diffstat (limited to 'MatrixUtils.Web/Pages/Tools')
-rw-r--r--MatrixUtils.Web/Pages/Tools/Debug/JoinRoom.razor70
-rw-r--r--MatrixUtils.Web/Pages/Tools/Debug/LeaveRoom.razor4
-rw-r--r--MatrixUtils.Web/Pages/Tools/Debug/MigrateRoom.razor6
-rw-r--r--MatrixUtils.Web/Pages/Tools/Index.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor12
-rw-r--r--MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor13
-rw-r--r--MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor15
-rw-r--r--MatrixUtils.Web/Pages/Tools/InviteCounter.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/MassCMEBan.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor10
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/InviteCounter.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/MassCMEBan.razor2
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/MembershipHistory.razor195
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor18
-rw-r--r--MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor17
-rw-r--r--MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor51
-rw-r--r--MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor204
-rw-r--r--MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor4
-rw-r--r--MatrixUtils.Web/Pages/Tools/User/CopyPowerlevel.razor8
-rw-r--r--MatrixUtils.Web/Pages/Tools/User/MassJoinRoom.razor17
-rw-r--r--MatrixUtils.Web/Pages/Tools/User/StickerManager.razor80
24 files changed, 596 insertions, 144 deletions
diff --git a/MatrixUtils.Web/Pages/Tools/Debug/JoinRoom.razor b/MatrixUtils.Web/Pages/Tools/Debug/JoinRoom.razor
new file mode 100644

index 0000000..cb56a40 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Debug/JoinRoom.razor
@@ -0,0 +1,70 @@ +@page "/Tools/Debug/JoinRoom" +@using System.Collections.ObjectModel +<h3>Join room</h3> +<hr/> +<span>Room ID: </span> +<InputText @bind-Value="@RoomId"></InputText> +<br/> +<span>Via server(s), comma separated: </span> +<InputText @bind-Value="@Servers"></InputText> +<br/> +<span>Unblock room (Synapse): </span> +<InputCheckbox @bind-Value="@Unblock"></InputCheckbox> +<br/> +<LinkButton OnClickAsync="@Join">Join</LinkButton> +<br/><br/> +@foreach (var line in Log) { + <pre>@line</pre> + <br/> +} + +@code { + AuthenticatedHomeserverGeneric? hs { get; set; } + ObservableCollection<string> Log { get; set; } = new ObservableCollection<string>(); + + [Parameter, SupplyParameterFromQuery(Name = "roomId")] + public string? RoomId { get; set; } + + [Parameter, SupplyParameterFromQuery(Name = "via")] + public string? Servers { get; set; } + + [Parameter, SupplyParameterFromQuery(Name = "unblock")] + public bool Unblock { get; set; } = false; + + protected override async Task OnInitializedAsync() { + hs = await sessionStore.GetCurrentHomeserver(navigateOnFailure: true); + if (hs is null) return; + Log.CollectionChanged += (sender, args) => StateHasChanged(); + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Join() { + if (string.IsNullOrWhiteSpace(RoomId)) return; + var room = hs.GetRoom(RoomId); + Log.Add("Got room object..."); + + if (Unblock && hs is AuthenticatedHomeserverSynapse synapse) { + try { + await synapse.Admin.BlockRoom(RoomId, false); + Log.Add($"Synapse: unblocked room"); + } + catch (Exception e) { + Log.Add($"Synapse: failed to unblock room: {e}"); + } + } + + try { + await room.JoinAsync(Servers?.Split(','), checkIfAlreadyMember: false); + Log.Add("Joined room!"); + } + catch (Exception e) { + Log.Add(e.ToString()); + } + + Log.Add("Done!"); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Debug/LeaveRoom.razor b/MatrixUtils.Web/Pages/Tools/Debug/LeaveRoom.razor
index 9a56fc0..c40fa0b 100644 --- a/MatrixUtils.Web/Pages/Tools/Debug/LeaveRoom.razor +++ b/MatrixUtils.Web/Pages/Tools/Debug/LeaveRoom.razor
@@ -1,11 +1,11 @@ -@page "/Tools/LeaveRoom" +@page "/Tools/Debug/LeaveRoom" @using System.Collections.ObjectModel <h3>Leave room</h3> <hr/> <span>Room ID: </span> <InputText @bind-Value="@RoomId"></InputText> <br/> -<LinkButton OnClick="@Leave">Leave</LinkButton> +<LinkButton OnClickAsync="@Leave">Leave</LinkButton> <br/><br/> @foreach (var line in Log) { <p>@line</p> diff --git a/MatrixUtils.Web/Pages/Tools/Debug/MigrateRoom.razor b/MatrixUtils.Web/Pages/Tools/Debug/MigrateRoom.razor
index 0943216..067036e 100644 --- a/MatrixUtils.Web/Pages/Tools/Debug/MigrateRoom.razor +++ b/MatrixUtils.Web/Pages/Tools/Debug/MigrateRoom.razor
@@ -17,7 +17,7 @@ </details> <br/> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> @foreach (var line in Enumerable.Reverse(log)) { <p>@line</p> @@ -53,8 +53,8 @@ var oldRoom = hs.GetRoom(roomId); var newRoom = hs.GetRoom(newRoomId); var members = await oldRoom.GetMembersListAsync(); - var tasks = members.Select(x => ExecuteInvite(hs, newRoom, x.StateKey)).ToAsyncEnumerable(); - // var tasks = hss.Select(ExecuteInvite).ToAsyncEnumerable(); + var tasks = members.Select(x => ExecuteInvite(hs, newRoom, x.StateKey)).ToAsyncResultEnumerable(); + // var tasks = hss.Select(ExecuteInvite).ToAsyncResultEnumerable(); await foreach (var a in tasks) { if (!string.IsNullOrWhiteSpace(a)) { log.Add(a); diff --git a/MatrixUtils.Web/Pages/Tools/Index.razor b/MatrixUtils.Web/Pages/Tools/Index.razor
index f99e932..a0abcd4 100644 --- a/MatrixUtils.Web/Pages/Tools/Index.razor +++ b/MatrixUtils.Web/Pages/Tools/Index.razor
@@ -12,6 +12,7 @@ <a href="/Tools/User/MassRoomJoin">Join room across all session</a><br/> <a href="/Tools/User/CopyPowerlevel">Copy highest powerlevel across all session</a><br/> <a href="/Tools/User/ViewAccountData">View account data</a><br/> +<a href="/Tools/User/StickerManager">Manage custom stickers and emojis</a><br/> <h4 class="tool-category">Room tools</h4> <hr/> @@ -30,6 +31,7 @@ <h4 class="tool-category">Debugging tools</h4> <hr/> <a href="/Tools/Debug/SpaceDebug">Debug space relationships</a><br/> +<a href="/Tools/Debug/JoinRoom">Join room by ID</a><br/> <a href="/Tools/Debug/LeaveRoom">Leave room by ID</a><br/> <a href="/Tools/Debug/MediaLocator">Locate lost media</a><br/> <a href="/Tools/Debug/MigrateRoom">Migrate users from a split room to a new room</a><br/> diff --git a/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor b/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor
index acad827..8ba160a 100644 --- a/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor +++ b/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor
@@ -41,13 +41,13 @@ var ss = new SemaphoreSlim(32, 32); var rooms = await hs.GetJoinedRooms(); RoomCount = rooms.Count; - var fetchTasks = rooms.Select(roomId => workerService.TaskPool.Invoke(() => InternalGetMembersByHomeserver(hs.WellKnownUris.Client, hs.AccessToken, roomId.RoomId))).ToList().ToAsyncEnumerable(); + var fetchTasks = rooms.Select(roomId => workerService.TaskPool.Invoke(() => InternalGetMembersByHomeserver(hs.WellKnownUris.Client, hs.AccessToken, roomId.RoomId))).ToList().ToAsyncResultEnumerable(); // var fetchTasks = rooms.Select(async x => { - // await ss.WaitAsync(); - // var res = await x.GetMembersByHomeserverAsync(); - // ss.Release(); - // return res; - // }).ToAsyncEnumerable(); + // await ss.WaitAsync(); + // var res = await x.GetMembersByHomeserverAsync(); + // ss.Release(); + // return res; + // }).ToAsyncResultEnumerable(); await foreach (var result in fetchTasks) { foreach (var (resHomeserver, resMembers) in result) { if (!homeservers.TryAdd(resHomeserver, resMembers)) { diff --git a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
index f8d1d31..ba8036c 100644 --- a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor +++ b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
@@ -74,7 +74,7 @@ else } //use timeline - var types = StateEventResponse.KnownStateEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent))); + var types = MatrixEvent.KnownEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent))); var filter = new SyncFilter.EventFilter(types: types.SelectMany(x => x.GetCustomAttributes<MatrixEventAttribute>().Select(y => y.EventName)).ToList()); var timeline = room.GetManyMessagesAsync(limit: int.MaxValue, chunkSize: 2500, filter: filter.ToJson(indent: false, ignoreNull: true)); await foreach (var response in timeline) { @@ -83,7 +83,7 @@ else foreach (var message in response.Chunk) { if (!message.MappedType.IsAssignableTo(typeof(PolicyRuleEventContent))) continue; //OriginServerTs to datetime - var dt = DateTimeOffset.FromUnixTimeMilliseconds((long)message.OriginServerTs!.Value).DateTime; + var dt = DateTimeOffset.FromUnixTimeMilliseconds(message.OriginServerTs!.Value).DateTime; var date = new DateOnly(dt.Year, dt.Month, dt.Day); if (!RoomData[roomName].ContainsKey(date.Year)) { RoomData[roomName][date.Year] = new(); @@ -100,9 +100,8 @@ else else rgb.B++; RoomData[roomName][date.Year][date] = rgb; } - - } + var max = RoomData.SelectMany(x => x.Value.Values).Aggregate(new ActivityGraph.RGB(), (current, next) => new() { R = Math.Max(current.R, next.Average(x => x.Value.R)), G = Math.Max(current.G, next.Average(x => x.Value.G)), @@ -120,10 +119,10 @@ else private readonly struct StateEventEntry { public required DateTime Timestamp { get; init; } public required StateEventTransition State { get; init; } - public required StateEventResponse Event { get; init; } - public required StateEventResponse? Previous { get; init; } + public required MatrixEventResponse Event { get; init; } + public required MatrixEventResponse? Previous { get; init; } - public void Deconstruct(out StateEventTransition transition, out StateEventResponse evt, out StateEventResponse? prev) { + public void Deconstruct(out StateEventTransition transition, out MatrixEventResponse evt, out MatrixEventResponse? prev) { transition = State; evt = Event; prev = Previous; diff --git a/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor b/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor
index ce3513b..76ff629 100644 --- a/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor +++ b/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor
@@ -11,7 +11,8 @@ <p>Users: </p> <InputTextArea @bind-Value="@UserIdString"></InputTextArea> <br/> -<InputText @bind-Value="@ImportFromRoomId"></InputText><LinkButton OnClick="@DoImportFromRoomId">Import from room (ID)</LinkButton> +<InputText @bind-Value="@ImportFromRoomId"></InputText> +<LinkButton OnClickAsync="@DoImportFromRoomId">Import from room (ID)</LinkButton> <details> <summary>Rooms to be searched (@rooms.Count)</summary> @@ -21,7 +22,7 @@ } </details> <br/> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> <details> @@ -44,9 +45,7 @@ @foreach (var (userId, events) in matches) { <p> <span>@userId.PadRight(col1Width)</span> - @foreach (var @event in events) { - -} + @foreach (var @event in events) { } </p> } </pre> @@ -61,7 +60,7 @@ private ObservableCollection<string> log { get; set; } = new(); List<AuthenticatedHomeserverGeneric> hss { get; set; } = new(); ObservableCollection<GenericRoom> rooms { get; set; } = new(); - Dictionary<GenericRoom, FrozenSet<StateEventResponse>> roomMembers { get; set; } = new(); + Dictionary<GenericRoom, FrozenSet<MatrixEventResponse>> roomMembers { get; set; } = new(); Dictionary<string, List<Matches>> matches = new(); private string UserIdString { @@ -97,7 +96,7 @@ rooms = new ObservableCollection<GenericRoom>(distinctRooms); rooms.CollectionChanged += (sender, args) => StateHasChanged(); - var stateTasks = rooms.Select(async x => (x, await x.GetMembersListAsync(false))).ToAsyncEnumerable(); + var stateTasks = rooms.Select(async x => (x, await x.GetMembersListAsync())).ToAsyncResultEnumerable(); await foreach (var (room, state) in stateTasks) { roomMembers.Add(room, state); @@ -148,7 +147,7 @@ private class Matches { public GenericRoom Room; - public StateEventResponse Event; + public MatrixEventResponse Event; // public } diff --git a/MatrixUtils.Web/Pages/Tools/InviteCounter.razor b/MatrixUtils.Web/Pages/Tools/InviteCounter.razor
index 2313884..16a3853 100644 --- a/MatrixUtils.Web/Pages/Tools/InviteCounter.razor +++ b/MatrixUtils.Web/Pages/Tools/InviteCounter.razor
@@ -9,7 +9,7 @@ <br/> <span>Room ID: </span> <InputText @bind-Value="@roomId"></InputText> -<LinkButton OnClick="@Execute">Execute</LinkButton> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> <br/> diff --git a/MatrixUtils.Web/Pages/Tools/MassCMEBan.razor b/MatrixUtils.Web/Pages/Tools/MassCMEBan.razor
index a252e6b..5b0f510 100644 --- a/MatrixUtils.Web/Pages/Tools/MassCMEBan.razor +++ b/MatrixUtils.Web/Pages/Tools/MassCMEBan.razor
@@ -7,7 +7,7 @@ <br/> <span>Users:</span> <InputTextArea @bind-Value="@roomId"></InputTextArea> -<LinkButton OnClick="@Execute">Execute</LinkButton> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> <br/> diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor
index b0d5a65..1ff97c8 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor
@@ -53,7 +53,7 @@ </div> } <br/> -<LinkButton OnClick="@Apply">Apply</LinkButton> +<LinkButton OnClickAsync="@Apply">Apply</LinkButton> @code { diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor
index ea39c9a..9b0266c 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor
@@ -49,7 +49,7 @@ </div> } <br/> -<LinkButton OnClick="@Apply">Apply</LinkButton> +<LinkButton OnClickAsync="@Apply">Apply</LinkButton> @code { diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor
index 9e70687..69a9048 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor
@@ -49,7 +49,7 @@ </div> } <br/> -<LinkButton OnClick="@Apply">Apply</LinkButton> +<LinkButton OnClickAsync="@Apply">Apply</LinkButton> @code { diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor b/MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor
index b62cf57..9139561 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/FindUsersByRegex.razor
@@ -14,10 +14,10 @@ <p>Users (regex): </p> <InputTextArea @bind-Value="@UserIdString"></InputTextArea> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> -<LinkButton OnClick="RemoveKicks">Remove kicks</LinkButton> -<LinkButton OnClick="RemoveBans">Remove bans</LinkButton> +<LinkButton OnClickAsync="RemoveKicks">Remove kicks</LinkButton> +<LinkButton OnClickAsync="RemoveBans">Remove bans</LinkButton> <br/> @@ -145,7 +145,7 @@ private class Match { public GenericRoom Room; - public StateEventResponse Event; + public MatrixEventResponse Event; public string RoomName { get; set; } } @@ -161,7 +161,7 @@ } return null; - }).ToAsyncEnumerable(); + }).ToAsyncResultEnumerable(); await foreach (var result in results) { if (result is not null) { yield return result; diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/InviteCounter.razor b/MatrixUtils.Web/Pages/Tools/Moderation/InviteCounter.razor
index 5c5946f..ac68e3d 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/InviteCounter.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/InviteCounter.razor
@@ -9,7 +9,7 @@ <br/> <span>Room ID: </span> <InputText @bind-Value="@roomId"></InputText> -<LinkButton OnClick="@Execute">Execute</LinkButton> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> <br/> diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/MassCMEBan.razor b/MatrixUtils.Web/Pages/Tools/Moderation/MassCMEBan.razor
index 8fdad84..605890d 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/MassCMEBan.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/MassCMEBan.razor
@@ -8,7 +8,7 @@ <br/> <span>Users:</span> <InputTextArea @bind-Value="@roomId"></InputTextArea> -<LinkButton OnClick="@Execute">Execute</LinkButton> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> <br/> diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/MembershipHistory.razor b/MatrixUtils.Web/Pages/Tools/Moderation/MembershipHistory.razor
index 1ec3cd0..ec1d190 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/MembershipHistory.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/MembershipHistory.razor
@@ -16,7 +16,7 @@ <br/> <span>Room ID: </span> <InputText @bind-Value="@RoomId"></InputText> -<LinkButton OnClick="@Execute">Execute</LinkButton> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> <p> <span><InputCheckbox @bind-Value="ChronologicalOrder"/>Chronological order</span> <span><InputCheckbox @bind-Value="DoDisambiguate"/>Enable extended filters</span> @@ -30,24 +30,24 @@ <span><InputCheckbox @bind-Value="ShowBans"/> bans</span> </p> <p> - <LinkButton OnClick="@(async () => { - ShowJoins = ShowLeaves = ShowKnocks = ShowInvites = ShowBans = false; - StateHasChanged(); - })">Hide all + <LinkButton OnClickAsync="@(async () => { + ShowJoins = ShowLeaves = ShowKnocks = ShowInvites = ShowBans = false; + StateHasChanged(); + })">Hide all </LinkButton> - <LinkButton OnClick="@(async () => { - ShowJoins = ShowLeaves = ShowKnocks = ShowInvites = ShowBans = true; - StateHasChanged(); - })">Show all + <LinkButton OnClickAsync="@(async () => { + ShowJoins = ShowLeaves = ShowKnocks = ShowInvites = ShowBans = true; + StateHasChanged(); + })">Show all </LinkButton> - <LinkButton OnClick="@(async () => { - ShowJoins ^= true; - ShowLeaves ^= true; - ShowKnocks ^= true; - ShowInvites ^= true; - ShowBans ^= true; - StateHasChanged(); - })">Toggle all + <LinkButton OnClickAsync="@(async () => { + ShowJoins ^= true; + ShowLeaves ^= true; + ShowKnocks ^= true; + ShowInvites ^= true; + ShowBans ^= true; + StateHasChanged(); + })">Toggle all </LinkButton> </p> <p> @@ -56,25 +56,25 @@ <span><InputCheckbox @bind-Value="DisambiguateKicks"/> kicks</span> <span><InputCheckbox @bind-Value="DisambiguateUnbans"/> unbans</span> <span><InputCheckbox @bind-Value="DisambiguateProfileUpdates"/> profile updates</span> - <details style="display: inline-block; vertical-align: top;"> - <summary> - <InputCheckbox @bind-Value="DisambiguateInviteActions"/> - invite actions - </summary> - <span><InputCheckbox @bind-Value="DisambiguateInviteAccepted"/> accepted</span> - <span><InputCheckbox @bind-Value="DisambiguateInviteRejected"/> rejected</span> - <span><InputCheckbox @bind-Value="DisambiguateInviteRetracted"/> retracted</span> - </details> - <details style="display: inline-block; vertical-align: top;"> - <summary> - <InputCheckbox @bind-Value="DisambiguateKnockActions"/> - knock actions - </summary> - <span><InputCheckbox @bind-Value="DisambiguateKnockAccepted"/> accepted</span> - <span><InputCheckbox @bind-Value="DisambiguateKnockRejected"/> rejected</span> - <span><InputCheckbox @bind-Value="DisambiguateKnockRetracted"/> retracted</span> - </details> - } + <details style="display: inline-block; vertical-align: top;"> + <summary> + <InputCheckbox @bind-Value="DisambiguateInviteActions"/> + invite actions + </summary> + <span><InputCheckbox @bind-Value="DisambiguateInviteAccepted"/> accepted</span> + <span><InputCheckbox @bind-Value="DisambiguateInviteRejected"/> rejected</span> + <span><InputCheckbox @bind-Value="DisambiguateInviteRetracted"/> retracted</span> + </details> + <details style="display: inline-block; vertical-align: top;"> + <summary> + <InputCheckbox @bind-Value="DisambiguateKnockActions"/> + knock actions + </summary> + <span><InputCheckbox @bind-Value="DisambiguateKnockAccepted"/> accepted</span> + <span><InputCheckbox @bind-Value="DisambiguateKnockRejected"/> rejected</span> + <span><InputCheckbox @bind-Value="DisambiguateKnockRetracted"/> retracted</span> + </details> +} </p> @if (DoDisambiguate) { <p> @@ -129,30 +129,30 @@ </p> <p> - <LinkButton OnClick="@(async () => { - DoDisambiguate = DisambiguateProfileUpdates = DisambiguateKicks = DisambiguateUnbans = DisambiguateInviteAccepted = DisambiguateInviteRejected = DisambiguateInviteRetracted = DisambiguateKnockAccepted = DisambiguateKnockRejected = DisambiguateKnockRetracted = DisambiguateKnockActions = DisambiguateInviteActions = false; - StateHasChanged(); - })">Un-disambiguate all + <LinkButton OnClickAsync="@(async () => { + DoDisambiguate = DisambiguateProfileUpdates = DisambiguateKicks = DisambiguateUnbans = DisambiguateInviteAccepted = DisambiguateInviteRejected = DisambiguateInviteRetracted = DisambiguateKnockAccepted = DisambiguateKnockRejected = DisambiguateKnockRetracted = DisambiguateKnockActions = DisambiguateInviteActions = false; + StateHasChanged(); + })">Un-disambiguate all </LinkButton> - <LinkButton OnClick="@(async () => { - DoDisambiguate = DisambiguateProfileUpdates = DisambiguateKicks = DisambiguateUnbans = DisambiguateInviteAccepted = DisambiguateInviteRejected = DisambiguateInviteRetracted = DisambiguateKnockAccepted = DisambiguateKnockRejected = DisambiguateKnockRetracted = DisambiguateKnockActions = DisambiguateInviteActions = true; - StateHasChanged(); - })">Disambiguate all + <LinkButton OnClickAsync="@(async () => { + DoDisambiguate = DisambiguateProfileUpdates = DisambiguateKicks = DisambiguateUnbans = DisambiguateInviteAccepted = DisambiguateInviteRejected = DisambiguateInviteRetracted = DisambiguateKnockAccepted = DisambiguateKnockRejected = DisambiguateKnockRetracted = DisambiguateKnockActions = DisambiguateInviteActions = true; + StateHasChanged(); + })">Disambiguate all </LinkButton> - <LinkButton OnClick="@(async () => { - DisambiguateProfileUpdates ^= true; - DisambiguateKicks ^= true; - DisambiguateUnbans ^= true; - DisambiguateInviteAccepted ^= true; - DisambiguateInviteRejected ^= true; - DisambiguateInviteRetracted ^= true; - DisambiguateKnockAccepted ^= true; - DisambiguateKnockRejected ^= true; - DisambiguateKnockRetracted ^= true; - DisambiguateKnockActions ^= true; - DisambiguateInviteActions ^= true; - StateHasChanged(); - })">Toggle all + <LinkButton OnClickAsync="@(async () => { + DisambiguateProfileUpdates ^= true; + DisambiguateKicks ^= true; + DisambiguateUnbans ^= true; + DisambiguateInviteAccepted ^= true; + DisambiguateInviteRejected ^= true; + DisambiguateInviteRetracted ^= true; + DisambiguateKnockAccepted ^= true; + DisambiguateKnockRejected ^= true; + DisambiguateKnockRetracted ^= true; + DisambiguateKnockActions ^= true; + DisambiguateInviteActions ^= true; + StateHasChanged(); + })">Toggle all </LinkButton> </p> } @@ -306,18 +306,61 @@ private bool ShowBans { get; set; } = true; private bool DoDisambiguate { get; set; } = true; - private bool DisambiguateProfileUpdates { get => field && DoDisambiguate; set; } = true; - private bool DisambiguateKicks { get => field && DoDisambiguate; set; } = true; - private bool DisambiguateUnbans { get => field && DoDisambiguate; set; } = true; - private bool DisambiguateInviteAccepted { get => field && DoDisambiguate && DisambiguateInviteActions; set; } = true; - private bool DisambiguateInviteRejected { get => field && DoDisambiguate && DisambiguateInviteActions; set; } = true; - private bool DisambiguateInviteRetracted { get => field && DoDisambiguate && DisambiguateInviteActions; set; } = true; - private bool DisambiguateKnockAccepted { get => field && DoDisambiguate && DisambiguateKnockActions; set; } = true; - private bool DisambiguateKnockRejected { get => field && DoDisambiguate && DisambiguateKnockActions; set; } = true; - private bool DisambiguateKnockRetracted { get => field && DoDisambiguate && DisambiguateKnockActions; set; } = true; - - private bool DisambiguateKnockActions { get => field && DoDisambiguate; set; } = true; - private bool DisambiguateInviteActions { get => field && DoDisambiguate; set; } = true; + + private bool DisambiguateProfileUpdates { + get => field && DoDisambiguate; + set; + } = true; + + private bool DisambiguateKicks { + get => field && DoDisambiguate; + set; + } = true; + + private bool DisambiguateUnbans { + get => field && DoDisambiguate; + set; + } = true; + + private bool DisambiguateInviteAccepted { + get => field && DoDisambiguate && DisambiguateInviteActions; + set; + } = true; + + private bool DisambiguateInviteRejected { + get => field && DoDisambiguate && DisambiguateInviteActions; + set; + } = true; + + private bool DisambiguateInviteRetracted { + get => field && DoDisambiguate && DisambiguateInviteActions; + set; + } = true; + + private bool DisambiguateKnockAccepted { + get => field && DoDisambiguate && DisambiguateKnockActions; + set; + } = true; + + private bool DisambiguateKnockRejected { + get => field && DoDisambiguate && DisambiguateKnockActions; + set; + } = true; + + private bool DisambiguateKnockRetracted { + get => field && DoDisambiguate && DisambiguateKnockActions; + set; + } = true; + + private bool DisambiguateKnockActions { + get => field && DoDisambiguate; + set; + } = true; + + private bool DisambiguateInviteActions { + get => field && DoDisambiguate; + set; + } = true; private bool ShowProfileUpdates { get => field && DisambiguateProfileUpdates; @@ -399,7 +442,7 @@ #endregion private ObservableCollection<string> Log { get; set; } = new(); - private List<StateEventResponse> Memberships { get; set; } = []; + private List<MatrixEventResponse> Memberships { get; set; } = []; private AuthenticatedHomeserverGeneric Homeserver { get; set; } [Parameter, SupplyParameterFromQuery(Name = "room")] @@ -444,10 +487,10 @@ private readonly struct MembershipEntry { public required MembershipTransition State { get; init; } - public required StateEventResponse Event { get; init; } - public required StateEventResponse? Previous { get; init; } + public required MatrixEventResponse Event { get; init; } + public required MatrixEventResponse? Previous { get; init; } - public void Deconstruct(out MembershipTransition transition, out StateEventResponse evt, out StateEventResponse? prev) { + public void Deconstruct(out MembershipTransition transition, out MatrixEventResponse evt, out MatrixEventResponse? prev) { transition = State; evt = Event; prev = Previous; @@ -474,7 +517,7 @@ KnockRetracted } - private static IEnumerable<MembershipEntry> GetTransitions(List<StateEventResponse> evts) { + private static IEnumerable<MembershipEntry> GetTransitions(List<MatrixEventResponse> evts) { Dictionary<string, MembershipEntry> transitions = new(); foreach (var evt in evts.OrderBy(x => x.OriginServerTs)) { var content = evt.TypedContent as RoomMemberEventContent ?? throw new InvalidOperationException("Event is not a RoomMemberEventContent!"); @@ -528,7 +571,7 @@ { MembershipTransition.KnockRejected, MembershipTransition.Leave }, { MembershipTransition.KnockRetracted, MembershipTransition.Leave } }.ToFrozenDictionary(); - + foreach (var entry in entries) { if (!DoDisambiguate) { yield return entry; diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor b/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor
index 736e59a..a8ae603 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/RoomIntersections.razor
@@ -8,13 +8,13 @@ <p>Set A: </p> <InputText @bind-Value="@ImportSetASpaceId"></InputText> -<LinkButton OnClick="@(() => AppendSet(ImportSetASpaceId, RoomsA))">Append Set A</LinkButton> +<LinkButton OnClickAsync="@(() => AppendSet(ImportSetASpaceId, RoomsA))">Append Set A</LinkButton> <p>Set B: </p> <InputText @bind-Value="@ImportSetBSpaceId"></InputText> -<LinkButton OnClick="@(() => AppendSet(ImportSetBSpaceId, RoomsB))">Append Set B</LinkButton> +<LinkButton OnClickAsync="@(() => AppendSet(ImportSetBSpaceId, RoomsB))">Append Set B</LinkButton> <br/> -<LinkButton OnClick="@Execute">Execute</LinkButton> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> <br/> <details> @@ -55,7 +55,7 @@ <td>@sets.Item2[0].Room.RoomId</td> <td>@((sets.Item2[i].Member.TypedContent as RoomMemberEventContent).Membership)</td> <td>@(roomNames.ContainsKey(sets.Item2[i].Room) ? roomNames[sets.Item2[i].Room] : "")</td> - <td>@(roomAliasses.ContainsKey(sets.Item2[i].Room) ? roomAliasses[sets.Item2[i].Room] : "")</td> + <td>@(roomAliasses.ContainsKey(sets.Item2[i].Room) ? roomAliasses[sets.Item2[i].Room] : "")</td> } else { <td/> @@ -88,7 +88,7 @@ [Parameter, SupplyParameterFromQuery(Name = "b")] public string ImportSetBSpaceId { get; set; } = ""; - Dictionary<string, Dictionary<GenericRoom, StateEventResponse>> roomMembers { get; set; } = new(); + Dictionary<string, Dictionary<GenericRoom, MatrixEventResponse>> roomMembers { get; set; } = new(); Dictionary<string, (List<Match>, List<Match>)> matches { get; set; } = new(); @@ -127,7 +127,7 @@ var setBusers = new Dictionary<string, List<Match>>(); await Task.WhenAll(GetMembers(RoomsA, setAusers), GetMembers(RoomsB, setBusers)); - + Log.Add($"Got {setAusers.Count} users in set A"); Log.Add($"Got {setBusers.Count} users in set B"); Log.Add("Calculating intersections..."); @@ -144,7 +144,7 @@ public async Task GetMembers(List<GenericRoom> rooms, Dictionary<string, List<Match>> users) { foreach (var room in rooms) { Log.Add($"Getting members for {room.RoomId}"); - var members = await room.GetMembersListAsync(false); + var members = await room.GetMembersListAsync(); foreach (var member in members) { if (member.RawContent?["membership"]?.ToString() == "ban") continue; if (member.RawContent?["membership"]?.ToString() == "invite") continue; @@ -158,7 +158,7 @@ } public async Task AppendSet(string spaceId, List<GenericRoom> rooms) { - var space = hs.GetRoom(spaceId).AsSpace; + var space = hs.GetRoom(spaceId).AsSpace(); Log.Add($"Found space {spaceId}"); var roomIdsEnum = space.GetChildrenAsync(true); List<Task> tasks = new(); @@ -191,7 +191,7 @@ public class Match { public GenericRoom Room { get; set; } - public StateEventResponse Member { get; set; } + public MatrixEventResponse Member { get; set; } } } \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor b/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor
index c3cc09c..d160922 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/UserTrace.razor
@@ -11,7 +11,7 @@ <InputTextArea @bind-Value="@UserIdString"></InputTextArea> <br/> <InputText @bind-Value="@ImportFromRoomId"></InputText> -<LinkButton OnClick="@DoImportFromRoomId">Import from room (ID)</LinkButton> +<LinkButton OnClickAsync="@DoImportFromRoomId">Import from room (ID)</LinkButton> <details> <summary>Rooms to be searched (@rooms.Count)</summary> @@ -21,15 +21,15 @@ } </details> <br/> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> <details> <summary>Results</summary> - @foreach (var (userId, events) in matches.OrderBy(x=>x.Key)) { + @foreach (var (userId, events) in matches.OrderBy(x => x.Key)) { <h4>@userId</h4> <table> - @foreach (var match in events.OrderBy(x=>x.RoomName)) { + @foreach (var match in events.OrderBy(x => x.RoomName)) { <tr> <td>@match.RoomName (<span>@match.Room.RoomId</span>)</td> <td> @@ -139,7 +139,7 @@ private class Match { public GenericRoom Room; - public StateEventResponse Event; + public MatrixEventResponse Event; public string RoomName { get; set; } } @@ -161,7 +161,7 @@ } return null; - }).ToAsyncEnumerable(); + }).ToAsyncResultEnumerable(); await foreach (var result in results) { if (result is not null) { yield return result; @@ -169,7 +169,7 @@ } } - public string SummarizeMembership(StateEventResponse state) { + public string SummarizeMembership(MatrixEventResponse state) { var membership = state.ContentAs<RoomMemberEventContent>(); var time = DateTimeOffset.FromUnixTimeMilliseconds(state.OriginServerTs!.Value); return membership switch { @@ -186,10 +186,9 @@ _ => $"Unknown membership {membership.Membership}, sent at {time} by {state.Sender} for {membership.Reason}" }; } - + private async Task ExportJson() { var json = matches.ToJson(); - } } \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor b/MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor new file mode 100644
index 0000000..208cd19 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Room/DropPowerlevel.razor
@@ -0,0 +1,51 @@ +@page "/Tools/Room/DropPowerlevel" +@using ArcaneLibs.Extensions +@using LibMatrix.EventTypes.Spec.State.RoomInfo +<h3>DropPowerlevel</h3> +<hr/> + +<span>User ID: </span><FancyTextBox @bind-Value="@UserId"/><br/> +<span>Room ID: </span><FancyTextBox @bind-Value="@RoomId"/><br/> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> + +<pre>@Result</pre> + +@code { + private AuthenticatedHomeserverGeneric? Homeserver { get; set; } = null!; + + [Parameter, SupplyParameterFromQuery(Name = "RoomId")] + public string RoomId { get; set; } = ""; + + [Parameter, SupplyParameterFromQuery(Name = "UserId")] + public string UserId { get; set; } = ""; + + private string Result { get; set; } = ""; + + protected override async Task OnInitializedAsync() { + Homeserver = await sessionStore.GetCurrentHomeserver(); + Result = "I am: " + Homeserver.WhoAmI.ToJson() + "\n"; + StateHasChanged(); + } + + private async Task Execute() { + try { + if (Homeserver is not AuthenticatedHomeserverGeneric hs) { + Result = "Not authenticated"; + return; + } + + var room = hs.GetRoom(RoomId); + + var powerlevels = await room.GetPowerLevelsAsync(); + powerlevels.Users.Remove(UserId); + Result = (await room.SendStateEventAsync(RoomPowerLevelEventContent.EventId, powerlevels)).ToJson(); + } + catch (Exception e) { + Result = e.Message; + } + finally { + StateHasChanged(); + } + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor b/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor new file mode 100644
index 0000000..a47d7f5 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Room/SpacePermissions.razor
@@ -0,0 +1,204 @@ +@page "/Tools/Room/SpacePermissions" +@using ArcaneLibs.Extensions +@using LibMatrix.EventTypes.Spec.State.RoomInfo +@using LibMatrix.RoomTypes +@using MatrixUtils.Web.Pages.Rooms +<h3>Space Permissions</h3> +<hr/> +<span>Space ID: </span> +<FancyTextBox @bind-Value="@SpaceId"/> +<LinkButton OnClickAsync="@Execute">Execute</LinkButton> +<br/> +<InputCheckbox @bind-Value="@AutoRecurseSpaces"/> +<span> Auto-recurse into child spaces</span> +<br/> + +@if (RoomPowerLevels.Count == 0) { + <p>No data loaded.</p> +} +else { + <span>Loaded @LoadedSpaceRooms.Count spaces.</span> + <br/> + @if (SpaceRooms.Count > 0) { + <h3>Load more spaces:</h3> + @foreach (var room in SpaceRooms) { + <LinkButton OnClickAsync="@(() => LoadSpaceAsync(room.Key))">@room.Value</LinkButton> + } + } + + <h3>By event type:</h3> + <table class="table-striped table-hover table-bordered align-middle"> + <thead> + <td>Room</td> + @foreach (var key in OrderedEventTypes) { + <td>@key.Key + <br/> + ~ @Math.Round(key.Value, 2) + </td> + } + </thead> + <tbody> + @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Events!.Values.Average())) { + <tr> + <td>@roomName</td> + @foreach (var eventType in OrderedEventTypes) { + if (!powerLevels.Events!.ContainsKey(eventType.Key)) { + <td style="background-color: #ff000044;">-</td> + continue; + } + + <td>@(powerLevels.Events![eventType.Key])</td> + } + </tr> + } + </tbody> + </table> + <br/> + <h3>By user:</h3> + <table class="table-striped table-hover table-bordered align-middle"> + <thead> + <td>Room</td> + @foreach (var key in OrderedUsers) { + <td>@key.Key + <br/> + ~ @Math.Round(key.Value, 2) + </td> + } + </thead> + <tbody> + @foreach (var (roomName, powerLevels) in RoomPowerLevels.OrderByDescending(x => x.Value.Users!.Values.Average())) { + <tr> + <td>@roomName</td> + @foreach (var eventType in OrderedUsers) { + if (!powerLevels.Users!.ContainsKey(eventType.Key)) { + <td style="background-color: #ff000044;">-</td> + continue; + } + + <td>@(powerLevels.Users![eventType.Key])</td> + } + </tr> + } + </tbody> + </table> +} + +@code { + + [Parameter, SupplyParameterFromQuery] + public string? SpaceId { get; set; } + + [Parameter, SupplyParameterFromQuery] + public bool AutoRecurseSpaces { get; set; } + + private AuthenticatedHomeserverGeneric? Homeserver { get; set; } + private List<AuthenticatedHomeserverGeneric> AllHomeservers { get; set; } = []; + private Dictionary<string, List<GenericRoom>> JoinedHomeserversByRoom { get; set; } = []; + + private Dictionary<string, RoomPowerLevelEventContent> RoomPowerLevels { get; set; } = []; + private Dictionary<string, string> SpaceRooms { get; set; } = []; + private List<string> LoadedSpaceRooms { get; set; } = []; + + private Dictionary<string, double> OrderedEventTypes { get; set; } = new(); + private Dictionary<string, double> OrderedUsers { get; set; } = new(); + + protected override async Task OnInitializedAsync() { + if (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true) is not AuthenticatedHomeserverGeneric hs) return; + Homeserver = hs; + await foreach (var server in sessionStore.TryGetAllHomeservers()) { + AllHomeservers.Add(server); + var joinedRooms = await server.GetJoinedRooms(); + foreach (var room in joinedRooms) { + if (!JoinedHomeserversByRoom.ContainsKey(room.RoomId)) { + JoinedHomeserversByRoom[room.RoomId] = []; + } + + JoinedHomeserversByRoom[room.RoomId].Add(room); + } + } + + if (!string.IsNullOrWhiteSpace(SpaceId)) { + await Execute(); + } + } + + private async Task Execute() { + RoomPowerLevels = []; + SpaceRooms = []; + await LoadSpaceAsync(SpaceId); + } + + private async Task<GenericRoom> GetJoinedRoomAsync(string roomId) { + var room = Homeserver.GetRoom(roomId); + if (await room.IsJoinedAsync()) return room; + + if (JoinedHomeserversByRoom.TryGetValue(roomId, out var rooms)) { + foreach (var r in rooms) { + if (await r.IsJoinedAsync()) return r; + } + } + + foreach (var hs in AllHomeservers) { + if (hs == Homeserver) continue; + room = hs.GetRoom(roomId); + if (await room.IsJoinedAsync()) return room; + } + + Console.WriteLine($"Not joined to room {roomId} on any known homeserver."); + return room; // not null, in case we can preview the room + } + + private async Task LoadSpaceAsync(string spaceId) { + LoadedSpaceRooms.Add(spaceId); + SpaceRooms.Remove(spaceId); + + var space = (await GetJoinedRoomAsync(spaceId)).AsSpace(); + RoomPowerLevels[await space.GetNameOrFallbackAsync()] = AddFakeEvents(await space.GetPowerLevelsAsync()); + var children = space.GetChildrenAsync(); + await foreach (var childRoom in children) { + var child = await GetJoinedRoomAsync(childRoom.RoomId); + try { + var powerlevels = await child.GetPowerLevelsAsync(); + RoomPowerLevels[await child.GetNameOrFallbackAsync()] = AddFakeEvents(powerlevels!); + if (await child.GetRoomType() == SpaceRoom.TypeName) { + if (AutoRecurseSpaces) + await LoadSpaceAsync(child.RoomId); + else + SpaceRooms.Add(child.RoomId, await child.GetNameOrFallbackAsync()); + } + + OrderedEventTypes = RoomPowerLevels + .SelectMany(x => x.Value.Events!) + .GroupBy(x => x.Key) + .ToDictionary(x => x.Key, x => x.Average(y => y.Value)) + .OrderByDescending(x => x.Value) + .ToDictionary(x => x.Key, x => x.Value); + + OrderedUsers = RoomPowerLevels + .SelectMany(x => x.Value.Users!) + .GroupBy(x => x.Key) + .ToDictionary(x => x.Key, x => x.Average(y => y.Value)) + .OrderByDescending(x => x.Value) + .ToDictionary(x => x.Key, x => x.Value); + StateHasChanged(); + } + catch (Exception ex) { + Console.WriteLine($"Failed to get power levels for room {child.RoomId}: {ex}"); + } + } + } + + private RoomPowerLevelEventContent AddFakeEvents(RoomPowerLevelEventContent powerlevels) { + powerlevels.Events ??= []; + powerlevels.Events["[user_default]"] = powerlevels.UsersDefault ?? 0; + powerlevels.Events["[event_default]"] = powerlevels.EventsDefault ?? 0; + powerlevels.Events["[state_default]"] = powerlevels.StateDefault ?? 100; + powerlevels.Events["[ban]"] = powerlevels.Ban ?? 100; + powerlevels.Events["[invite]"] = powerlevels.Invite ?? 100; + powerlevels.Events["[kick]"] = powerlevels.Kick ?? 100; + powerlevels.Events["[ping_room]"] = powerlevels.NotificationsPl?.Room ?? 100; + powerlevels.Events["[redact]"] = powerlevels.Redact ?? 100; + return powerlevels; + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor b/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor
index ac3c651..d6ae945 100644 --- a/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor +++ b/MatrixUtils.Web/Pages/Tools/Room/SpaceRestrictedJoins.razor
@@ -10,7 +10,7 @@ <p><InputCheckbox @bind-Value="@ChangeKnocking"/> Change knock access: <InputCheckbox @bind-Value="@Knocking"/></p> <br/> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> <br/> @@ -40,7 +40,7 @@ } private async Task Execute() { - var space = hs.GetRoom(RoomId).AsSpace; + var space = hs.GetRoom(RoomId).AsSpace(); await foreach (var room in space.GetChildrenAsync()) { log.Add($"Got room {room.RoomId}"); if (ChangeGuestAccess) { diff --git a/MatrixUtils.Web/Pages/Tools/User/CopyPowerlevel.razor b/MatrixUtils.Web/Pages/Tools/User/CopyPowerlevel.razor
index e5ffd5b..acc86a2 100644 --- a/MatrixUtils.Web/Pages/Tools/User/CopyPowerlevel.razor +++ b/MatrixUtils.Web/Pages/Tools/User/CopyPowerlevel.razor
@@ -12,7 +12,7 @@ } <br/> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> @foreach (var line in Enumerable.Reverse(log)) { <p>@line</p> @@ -42,7 +42,7 @@ private async Task Execute() { foreach (var hs in hss) { var rooms = await hs.GetJoinedRooms(); - var tasks = rooms.Select(x=>ApplyPowerlevelsInRoom(hs, x)).ToAsyncEnumerable(); + var tasks = rooms.Select(x => ApplyPowerlevelsInRoom(hs, x)).ToAsyncResultEnumerable(); await foreach (var a in tasks) { if (!string.IsNullOrWhiteSpace(a)) { log.Add(a); @@ -62,12 +62,11 @@ log.Add("I am same PL in " + room.RoomId); continue; } - + pls.SetUserPowerLevel(ahs.WhoAmI.UserId, pls.GetUserPowerLevel(hs.WhoAmI.UserId)); await room.SendStateEventAsync(RoomPowerLevelEventContent.EventId, pls); log.Add($"Updated powerlevel of {room.RoomId} to {pls.GetUserPowerLevel(ahs.WhoAmI.UserId)}"); } - } catch (MatrixException e) { return $"Failed to update PLs in {room.RoomId}: {e.Message}"; @@ -75,6 +74,7 @@ catch (Exception e) { return $"Failed to update PLs in {room.RoomId}: {e.Message}"; } + StateHasChanged(); return ""; } diff --git a/MatrixUtils.Web/Pages/Tools/User/MassJoinRoom.razor b/MatrixUtils.Web/Pages/Tools/User/MassJoinRoom.razor
index c373a37..ee17f1d 100644 --- a/MatrixUtils.Web/Pages/Tools/User/MassJoinRoom.razor +++ b/MatrixUtils.Web/Pages/Tools/User/MassJoinRoom.razor
@@ -13,7 +13,7 @@ } <br/> -<LinkButton OnClick="Execute">Execute</LinkButton> +<LinkButton OnClickAsync="Execute">Execute</LinkButton> <br/> @foreach (var line in Enumerable.Reverse(log)) { <p>@line</p> @@ -42,23 +42,24 @@ } private async Task Execute() { - // foreach (var hs in hss) { - // var rooms = await hs.GetJoinedRooms(); - var tasks = hss.Select(ExecuteInvite).ToAsyncEnumerable(); + // foreach (var hs in hss) { + // var rooms = await hs.GetJoinedRooms(); + var tasks = hss.Select(ExecuteInvite).ToAsyncResultEnumerable(); await foreach (var a in tasks) { if (!string.IsNullOrWhiteSpace(a)) { log.Add(a); StateHasChanged(); } } - tasks = hss.Select(ExecuteJoin).ToAsyncEnumerable(); + + tasks = hss.Select(ExecuteJoin).ToAsyncResultEnumerable(); await foreach (var a in tasks) { if (!string.IsNullOrWhiteSpace(a)) { log.Add(a); StateHasChanged(); } } - // } + // } } private async Task<string> ExecuteInvite(AuthenticatedHomeserverGeneric hs) { @@ -69,6 +70,7 @@ if (joinRule.JoinRule == RoomJoinRulesEventContent.JoinRules.Public) return "Room is public, no invite needed"; } catch { } + var pls = await room.GetPowerLevelsAsync(); if (pls.GetUserPowerLevel(hs.WhoAmI.UserId) < pls.Invite) return "I do not have permission to send invite in " + room.RoomId; await room.InviteUsersAsync(hss.Select(x => x.WhoAmI.UserId).ToList()); @@ -80,6 +82,7 @@ catch (Exception e) { return $"Failed to invite in {room.RoomId}: {e.Message}"; } + StateHasChanged(); return ""; } @@ -92,6 +95,7 @@ if (mse?.Membership == "join") return $"User {hs.WhoAmI.UserId} already in room"; } catch { } + await room.JoinAsync(); } catch (MatrixException e) { @@ -100,6 +104,7 @@ catch (Exception e) { return $"Failed to join {hs.WhoAmI.UserId} to {room.RoomId}: {e.Message}"; } + StateHasChanged(); return ""; } diff --git a/MatrixUtils.Web/Pages/Tools/User/StickerManager.razor b/MatrixUtils.Web/Pages/Tools/User/StickerManager.razor new file mode 100644
index 0000000..0e838c7 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/User/StickerManager.razor
@@ -0,0 +1,80 @@ +@page "/Tools/User/StickerManager" +@using System.Diagnostics +@using ArcaneLibs.Extensions +@using LibMatrix.EventTypes.Common +@using LibMatrix.EventTypes.Spec +@inject ILogger<StickerManager> Logger +<h3>Sticker/emoji manager</h3> + +@if (TotalStepsProgress is not null) { + <SimpleProgressIndicator ObservableProgress="@TotalStepsProgress"/> + <br/> +} +@if (_observableProgressState is not null) { + <SimpleProgressIndicator ObservableProgress="@_observableProgressState"/> + <br/> +} + +@code { + + private AuthenticatedHomeserverGeneric Homeserver { get; set; } = null!; + private Msc2545EmoteRoomsAccountDataEventContent? EnabledEmoteRooms { get; set; } + private Dictionary<string, StickerRoom> StickerRooms { get; set; } = []; + + private SimpleProgressIndicator.ObservableProgressState? _observableProgressState; + + private SimpleProgressIndicator.ObservableProgressState? TotalStepsProgress { get; set; } = new() { + Label = "Authenticating with Matrix...", + Max = 2, + Value = 0 + }; + + protected override async Task OnInitializedAsync() { + if (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true) is not { } hs) + return; + Homeserver = hs; + TotalStepsProgress?.Next("Fetching enabled emote packs..."); + _ = hs.GetAccountDataOrNullAsync<Msc2545EmoteRoomsAccountDataEventContent>(Msc2545EmoteRoomsAccountDataEventContent.EventId) + .ContinueWith(r => { + EnabledEmoteRooms = r.Result; + StateHasChanged(); + }); + + TotalStepsProgress?.Next("Getting joined rooms..."); + _observableProgressState = new() { + Label = "Loading rooms...", + Max = 1, + Value = 0 + }; + var rooms = await hs.GetJoinedRooms(); + _observableProgressState.Max.Value = rooms.Count; + StateHasChanged(); + + var ss = new SemaphoreSlim(32, 32); + var ss1 = new SemaphoreSlim(1, 1); + var roomScanTasks = rooms.Select(async room => { + // await Task.Delay(Random.Shared.Next(100, 1000 + (rooms.Count * 100))); + // await ss.WaitAsync(); + var state = await room.GetFullStateAsListAsync(); + StickerRoom sr = new(); + foreach (var evt in state) { + if (evt.Type == RoomEmotesEventContent.EventId) { } + } + + // ss.Release(); + // await ss1.WaitAsync(); + Console.WriteLine("Got state for room " + room.RoomId); + // _observableProgressState.Next($"Got state for room {room.RoomId}"); + // await Task.Delay(1); + // ss1.Release(); + return room.RoomId; + }) + .ToList(); + await foreach (var roomScanResult in roomScanTasks.ToAsyncResultEnumerable()) { + _observableProgressState.Label.Value = roomScanResult; + } + } + + private class StickerRoom { } + +} \ No newline at end of file