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
|