diff --git a/Commands/DbgDumpAllStateTypesCommand.cs b/Commands/DbgDumpAllStateTypesCommand.cs
new file mode 100644
index 0000000..e9a645e
--- /dev/null
+++ b/Commands/DbgDumpAllStateTypesCommand.cs
@@ -0,0 +1,73 @@
+using System.Buffers.Text;
+using System.Security.Cryptography;
+using ArcaneLibs.Extensions;
+using LibMatrix;
+using LibMatrix.EventTypes.Spec;
+using LibMatrix.Helpers;
+using LibMatrix.RoomTypes;
+using LibMatrix.Services;
+using LibMatrix.Utilities.Bot.Interfaces;
+using ModerationBot.AccountData;
+using ModerationBot.StateEventTypes;
+
+namespace ModerationBot.Commands;
+
+public class DbgDumpAllStateTypesCommand
+ (IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand {
+ public string Name { get; } = "dbg-dumpstatetypes";
+ public string Description { get; } = "[Debug] Dump all state types we can find";
+ private GenericRoom logRoom { get; set; }
+
+ public async Task<bool> CanInvoke(CommandContext ctx) {
+#if !DEBUG
+ return false;
+#endif
+
+ //check if user is admin in control room
+ var botData = await ctx.Homeserver.GetAccountDataAsync<BotData>("gay.rory.moderation_bot_data");
+ var controlRoom = ctx.Homeserver.GetRoom(botData.ControlRoom);
+ var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasPermission(ctx.MessageEvent.Sender, "m.room.ban");
+ if (!isAdmin) {
+ // await ctx.Reply("You do not have permission to use this command!");
+ await ctx.Homeserver.GetRoom(botData.LogRoom!).SendMessageEventAsync(
+ new RoomMessageEventContent(body: $"User {ctx.MessageEvent.Sender} tried to use command {Name} but does not have permission!", messageType: "m.text"));
+ }
+
+ return isAdmin;
+ }
+
+ public async Task Invoke(CommandContext ctx) {
+ var botData = await ctx.Homeserver.GetAccountDataAsync<BotData>("gay.rory.moderation_bot_data");
+ logRoom = ctx.Homeserver.GetRoom(botData.LogRoom ?? botData.ControlRoom);
+
+
+ var joinedRooms = await ctx.Homeserver.GetJoinedRooms();
+
+ var tasks = joinedRooms.Select(GetStateTypes).ToAsyncEnumerable();
+ await foreach (var (room, (raw, html)) in tasks) {
+ await ctx.Room.SendMessageEventAsync(new RoomMessageEventContent("m.text") {
+ Body = $"States for {room.RoomId}:\n{raw}",
+ FormattedBody = $"States for {room.RoomId}:\n{html}",
+ Format = "org.matrix.custom.html"
+ });
+ }
+ }
+
+ private async Task<(GenericRoom room, (string raw, string html))> GetStateTypes(GenericRoom memberRoom) {
+ var states = await memberRoom.GetFullStateAsListAsync();
+
+ return (memberRoom, SummariseStateTypeCounts(states));
+ }
+
+ private static (string Raw, string Html) SummariseStateTypeCounts(IList<StateEventResponse> states) {
+ string raw = "Count | State type | Mapped type", html = "<table><tr><th>Count</th><th>State type</th><th>Mapped type</th></tr>";
+ var groupedStates = states.GroupBy(x => x.Type).ToDictionary(x => x.Key, x => x.ToList()).OrderByDescending(x => x.Value.Count);
+ foreach (var (type, stateGroup) in groupedStates) {
+ raw += $"{stateGroup.Count} | {type} | {stateGroup[0].GetType.Name}";
+ html += $"<tr><td>{stateGroup.Count}</td><td>{type}</td><td>{stateGroup[0].GetType.Name}</td></tr>";
+ }
+
+ html += "</table>";
+ return (raw, html);
+ }
+}
\ No newline at end of file
|