From af6d1c7e11b2e9b4108ae8b693650b2a18cd2001 Mon Sep 17 00:00:00 2001 From: Rory& Date: Thu, 30 Oct 2025 02:49:12 +0100 Subject: Old work --- ModerationBot/Commands/BanMediaCommand.cs | 112 +++++++++++++++++++++ .../Commands/DbgAllRoomsArePolicyListsCommand.cs | 60 +++++++++++ ModerationBot/Commands/DbgAniRainbowTest.cs | 50 +++++++++ .../Commands/DbgDumpActivePoliciesCommand.cs | 39 +++++++ .../Commands/DbgDumpAllStateTypesCommand.cs | 69 +++++++++++++ ModerationBot/Commands/JoinRoomCommand.cs | 48 +++++++++ ModerationBot/Commands/JoinSpaceMembersCommand.cs | 73 ++++++++++++++ ModerationBot/Commands/ReloadPoliciesCommand.cs | 38 +++++++ 8 files changed, 489 insertions(+) create mode 100644 ModerationBot/Commands/BanMediaCommand.cs create mode 100644 ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs create mode 100644 ModerationBot/Commands/DbgAniRainbowTest.cs create mode 100644 ModerationBot/Commands/DbgDumpActivePoliciesCommand.cs create mode 100644 ModerationBot/Commands/DbgDumpAllStateTypesCommand.cs create mode 100644 ModerationBot/Commands/JoinRoomCommand.cs create mode 100644 ModerationBot/Commands/JoinSpaceMembersCommand.cs create mode 100644 ModerationBot/Commands/ReloadPoliciesCommand.cs (limited to 'ModerationBot/Commands') diff --git a/ModerationBot/Commands/BanMediaCommand.cs b/ModerationBot/Commands/BanMediaCommand.cs new file mode 100644 index 0000000..07c9858 --- /dev/null +++ b/ModerationBot/Commands/BanMediaCommand.cs @@ -0,0 +1,112 @@ +using System.Security.Cryptography; +using ArcaneLibs.Extensions; +using LibMatrix; +using LibMatrix.EventTypes.Spec; +using LibMatrix.Helpers; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; +using ModerationBot.Services; +using ModerationBot.StateEventTypes.Policies.Implementations; + +namespace ModerationBot.Commands; + +public class BanMediaCommand(HomeserverResolverService hsResolver, PolicyEngine engine, ModerationBotRoomProvider roomProvider) : ICommand { + public string Name { get; } = "banmedia"; + public string[]? Aliases { get; } + public string Description { get; } = "Create a policy banning a piece of media, must be used in reply to a message"; + public bool Unlisted { get; } + + public async Task CanInvoke(CommandContext ctx) { + //check if user is admin in control room + var controlRoom = await roomProvider.GetControlRoomAsync(); + var logRoom = await roomProvider.GetLogRoomAsync(); + var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasStatePermission(ctx.MessageEvent.Sender, "m.room.ban"); + if (!isAdmin) { + // await ctx.Reply("You do not have permission to use this command!"); + await 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 policyRoom = await roomProvider.GetDefaultPolicyRoomAsync(); + var logRoom = await roomProvider.GetLogRoomAsync(); + + //check if reply + var messageContent = ctx.MessageEvent.TypedContent as RoomMessageEventContent; + if (messageContent?.RelatesTo is { InReplyTo: not null }) { + try { + await logRoom.SendMessageEventAsync( + new RoomMessageEventContent( + body: $"User {MessageFormatter.HtmlFormatMention(ctx.MessageEvent.Sender)} is trying to ban media {messageContent!.RelatesTo!.InReplyTo!.EventId}", + messageType: "m.text")); + + //get replied message + var repliedMessage = await ctx.Room.GetEventAsync(messageContent.RelatesTo!.InReplyTo!.EventId); + + //check if recommendation is in list + if (ctx.Args.Length < 2) { + await ctx.Room.SendMessageEventAsync(MessageFormatter.FormatError("You must specify a recommendation type and reason!")); + return; + } + + var recommendation = ctx.Args[0]; + + if (recommendation is not ("ban" or "kick" or "mute" or "redact" or "spoiler" or "warn" or "warn_admins")) { + await ctx.Room.SendMessageEventAsync( + MessageFormatter.FormatError( + $"Invalid recommendation type {recommendation}, must be `warn_admins`, `warn`, `spoiler`, `redact`, `mute`, `kick` or `ban`!")); + return; + } + + //hash file + var mxcUri = (repliedMessage.TypedContent as RoomMessageEventContent).Url!; + var resolvedUri = await hsResolver.ResolveMediaUri(mxcUri.Split('/')[2], mxcUri); + var hashAlgo = SHA3_256.Create(); + var uriHash = hashAlgo.ComputeHash(mxcUri.AsBytes().ToArray()); + byte[]? fileHash = null; + + try { + fileHash = await hashAlgo.ComputeHashAsync(await ctx.Homeserver.ClientHttpClient.GetStreamAsync(resolvedUri)); + } + catch (Exception ex) { + await logRoom.SendMessageEventAsync( + MessageFormatter.FormatException($"Error calculating file hash for {mxcUri} via {mxcUri.Split('/')[2]}, retrying via {ctx.Homeserver.BaseUrl}...", + ex)); + try { + resolvedUri = await hsResolver.ResolveMediaUri(ctx.Homeserver.BaseUrl, mxcUri); + fileHash = await hashAlgo.ComputeHashAsync(await ctx.Homeserver.ClientHttpClient.GetStreamAsync(resolvedUri)); + } + catch (Exception ex2) { + await ctx.Room.SendMessageEventAsync(MessageFormatter.FormatException("Error calculating file hash", ex2)); + await logRoom.SendMessageEventAsync( + MessageFormatter.FormatException($"Error calculating file hash via {ctx.Homeserver.BaseUrl}!", ex2)); + } + } + + MediaPolicyFile policy; + await policyRoom.SendStateEventAsync("gay.rory.moderation.rule.media", Guid.NewGuid().ToString(), policy = new MediaPolicyFile { + Entity = Convert.ToBase64String(uriHash), + FileHash = Convert.ToBase64String(fileHash), + Reason = string.Join(' ', ctx.Args[1..]), + Recommendation = recommendation, + }); + + await ctx.Room.SendMessageEventAsync(MessageFormatter.FormatSuccessJson("Media policy created", policy)); + await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccessJson("Media policy created", policy)); + } + catch (Exception e) { + await logRoom.SendMessageEventAsync(MessageFormatter.FormatException("Error creating policy", e)); + await ctx.Room.SendMessageEventAsync(MessageFormatter.FormatException("Error creating policy", e)); + await using var stream = new MemoryStream(e.ToString().AsBytes().ToArray()); + await logRoom.SendFileAsync("error.log.cs", stream); + } + } + else { + await ctx.Room.SendMessageEventAsync(MessageFormatter.FormatError("This command must be used in reply to a message!")); + } + } +} diff --git a/ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs b/ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs new file mode 100644 index 0000000..78e1979 --- /dev/null +++ b/ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs @@ -0,0 +1,60 @@ +using LibMatrix.EventTypes.Spec; +using LibMatrix.Helpers; +using LibMatrix.RoomTypes; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; + +namespace ModerationBot.Commands; + +public class DbgAllRoomsArePolicyListsCommand + (IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand { + public string Name { get; } = "dbg-allroomsarepolicy"; + public string[]? Aliases { get; } + public string Description { get; } = "[Debug] mark all rooms as trusted policy rooms"; + public bool Unlisted { get; } + private GenericRoom logRoom { get; set; } + + public async Task CanInvoke(CommandContext ctx) { +// #if !DEBUG +// return false; +// #endif + + //check if user is admin in control room + var botData = await ctx.Homeserver.GetAccountDataAsync("gay.rory.moderation_bot_data"); + var controlRoom = ctx.Homeserver.GetRoom(botData.ControlRoom); + var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasStatePermission(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("gay.rory.moderation_bot_data"); + logRoom = ctx.Homeserver.GetRoom(botData.LogRoom ?? botData.ControlRoom); + + var joinedRooms = await ctx.Homeserver.GetJoinedRooms(); + + await ctx.Homeserver.SetAccountDataAsync("gay.rory.moderation_bot.policy_lists", joinedRooms.ToDictionary(x => x.RoomId, x => new PolicyList() { + Trusted = true + })); + + await engine.ReloadActivePolicyLists(); + } + + private async Task JoinRoom(GenericRoom memberRoom, string reason, List servers) { + try { + await memberRoom.JoinAsync(servers.ToArray(), reason); + await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccess($"Joined room {memberRoom.RoomId}")); + } + catch (Exception e) { + await logRoom.SendMessageEventAsync(MessageFormatter.FormatException($"Failed to join {memberRoom.RoomId}", e)); + } + + return true; + } +} diff --git a/ModerationBot/Commands/DbgAniRainbowTest.cs b/ModerationBot/Commands/DbgAniRainbowTest.cs new file mode 100644 index 0000000..eed6fa5 --- /dev/null +++ b/ModerationBot/Commands/DbgAniRainbowTest.cs @@ -0,0 +1,50 @@ +using System.Diagnostics; +using LibMatrix.EventTypes.Spec; +using LibMatrix.Helpers; +using LibMatrix.RoomTypes; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; + +namespace ModerationBot.Commands; + +public class DbgAniRainbowTest(IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand { + public string Name { get; } = "dbg-ani-rainbow"; + public string[]? Aliases { get; } + public string Description { get; } = "[Debug] animated rainbow :)"; + public bool Unlisted { get; } + private GenericRoom logRoom { get; set; } + + public async Task CanInvoke(CommandContext ctx) { + return ctx.Room.RoomId == "!DoHEdFablOLjddKWIp:rory.gay"; + } + + public async Task Invoke(CommandContext ctx) { + //255 long string + // var rainbow = "🟥🟧🟨🟩🟦🟪"; + var rainbow = "M"; + var chars = rainbow; + for (var i = 0; i < 76; i++) { + chars += rainbow[i%rainbow.Length]; + } + + var msg = new MessageBuilder(msgType: "m.notice").WithRainbowString(chars).Build(); + var msgEvent = await ctx.Room.SendMessageEventAsync(msg); + + Task.Run(async () => { + + int i = 0; + while (true) { + msg = new MessageBuilder(msgType: "m.notice").WithRainbowString(chars, offset: i+=5).Build(); + // .SetReplaceRelation(msgEvent.EventId); + // msg.Body = ""; + // msg.FormattedBody = ""; + var sw = Stopwatch.StartNew(); + await ctx.Room.SendMessageEventAsync(msg); + await Task.Delay(sw.Elapsed); + } + + }); + + } +} \ No newline at end of file diff --git a/ModerationBot/Commands/DbgDumpActivePoliciesCommand.cs b/ModerationBot/Commands/DbgDumpActivePoliciesCommand.cs new file mode 100644 index 0000000..81e81a0 --- /dev/null +++ b/ModerationBot/Commands/DbgDumpActivePoliciesCommand.cs @@ -0,0 +1,39 @@ +using ArcaneLibs.Extensions; +using LibMatrix.EventTypes.Spec; +using LibMatrix.RoomTypes; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; + +namespace ModerationBot.Commands; + +public class DbgDumpActivePoliciesCommand(IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand { + public string Name { get; } = "dbg-dumppolicies"; + public string[]? Aliases { get; } + public string Description { get; } = "[Debug] Dump all active policies"; + public bool Unlisted { get; } + private GenericRoom logRoom { get; set; } + + public async Task CanInvoke(CommandContext ctx) { +#if !DEBUG + return false; +#endif + + //check if user is admin in control room + var botData = await ctx.Homeserver.GetAccountDataAsync("gay.rory.moderation_bot_data"); + var controlRoom = ctx.Homeserver.GetRoom(botData.ControlRoom); + var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasStatePermission(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) { + await ctx.Room.SendFileAsync("all.json", new MemoryStream(engine.ActivePolicies.ToJson().AsBytes().ToArray()), contentType: "application/json"); + await ctx.Room.SendFileAsync("by-type.json", new MemoryStream(engine.ActivePoliciesByType.ToJson().AsBytes().ToArray()), contentType: "application/json"); + } +} \ No newline at end of file diff --git a/ModerationBot/Commands/DbgDumpAllStateTypesCommand.cs b/ModerationBot/Commands/DbgDumpAllStateTypesCommand.cs new file mode 100644 index 0000000..ac2036a --- /dev/null +++ b/ModerationBot/Commands/DbgDumpAllStateTypesCommand.cs @@ -0,0 +1,69 @@ +using ArcaneLibs.Extensions; +using LibMatrix; +using LibMatrix.EventTypes.Spec; +using LibMatrix.RoomTypes; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; + +namespace ModerationBot.Commands; + +public class DbgDumpAllStateTypesCommand(IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand { + public string Name { get; } = "dbg-dumpstatetypes"; + public string[]? Aliases { get; } + public string Description { get; } = "[Debug] Dump all state types we can find"; + public bool Unlisted { get; } + private GenericRoom logRoom { get; set; } + + public async Task CanInvoke(CommandContext ctx) { +#if !DEBUG + return false; +#endif + + //check if user is admin in control room + var botData = await ctx.Homeserver.GetAccountDataAsync("gay.rory.moderation_bot_data"); + var controlRoom = ctx.Homeserver.GetRoom(botData.ControlRoom); + var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasStatePermission(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("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 states) { + string raw = "Count | State type | Mapped type", html = ""; + 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} | {StateEvent.GetStateEventType(stateGroup[0].Type).Name}"; + html += $""; + } + + html += "
CountState typeMapped type
{stateGroup.Count}{type}{StateEvent.GetStateEventType(stateGroup[0].Type).Name}
"; + return (raw, html); + } +} \ No newline at end of file diff --git a/ModerationBot/Commands/JoinRoomCommand.cs b/ModerationBot/Commands/JoinRoomCommand.cs new file mode 100644 index 0000000..e604a4e --- /dev/null +++ b/ModerationBot/Commands/JoinRoomCommand.cs @@ -0,0 +1,48 @@ +using LibMatrix.EventTypes.Spec; +using LibMatrix.Helpers; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; + +namespace ModerationBot.Commands; + +public class JoinRoomCommand(IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand { + public string Name { get; } = "join"; + public string[]? Aliases { get; } + public string Description { get; } = "Join arbitrary rooms"; + public bool Unlisted { get; } + + public async Task CanInvoke(CommandContext ctx) { + //check if user is admin in control room + var botData = await ctx.Homeserver.GetAccountDataAsync("gay.rory.moderation_bot_data"); + var controlRoom = ctx.Homeserver.GetRoom(botData.ControlRoom); + var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasStatePermission(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("gay.rory.moderation_bot_data"); + var policyRoom = ctx.Homeserver.GetRoom(botData.DefaultPolicyRoom ?? botData.ControlRoom); + var logRoom = ctx.Homeserver.GetRoom(botData.LogRoom ?? botData.ControlRoom); + + await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccess($"Joining room {ctx.Args[0]} with reason: {string.Join(' ', ctx.Args[1..])}")); + var roomId = ctx.Args[0]; + var servers = new List() { ctx.Homeserver.ServerName }; + if (roomId.StartsWith('[')) { } + + if (roomId.StartsWith('#')) { + var res = await ctx.Homeserver.ResolveRoomAliasAsync(roomId); + roomId = res.RoomId; + servers.AddRange(servers); + } + + await ctx.Homeserver.JoinRoomAsync(roomId, servers, string.Join(' ', ctx.Args[1..])); + await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccess($"Resolved room {ctx.Args[0]} to {roomId} with servers: {string.Join(", ", servers)}")); + } +} \ No newline at end of file diff --git a/ModerationBot/Commands/JoinSpaceMembersCommand.cs b/ModerationBot/Commands/JoinSpaceMembersCommand.cs new file mode 100644 index 0000000..86ecf7e --- /dev/null +++ b/ModerationBot/Commands/JoinSpaceMembersCommand.cs @@ -0,0 +1,73 @@ +using ArcaneLibs.Extensions; +using LibMatrix.EventTypes.Spec; +using LibMatrix.Helpers; +using LibMatrix.RoomTypes; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; + +namespace ModerationBot.Commands; + +public class JoinSpaceMembersCommand(IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand { + public string Name { get; } = "joinspacemembers"; + public string[]? Aliases { get; } + public string Description { get; } = "Join all rooms in space"; + public bool Unlisted { get; } + private GenericRoom logRoom { get; set; } + + public async Task CanInvoke(CommandContext ctx) { + //check if user is admin in control room + var botData = await ctx.Homeserver.GetAccountDataAsync("gay.rory.moderation_bot_data"); + var controlRoom = ctx.Homeserver.GetRoom(botData.ControlRoom); + var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasStatePermission(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("gay.rory.moderation_bot_data"); + logRoom = ctx.Homeserver.GetRoom(botData.LogRoom ?? botData.ControlRoom); + var currentRooms = (await ctx.Homeserver.GetJoinedRooms()).Select(x => x.RoomId).ToList(); + + await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccess($"Joining space children of {ctx.Args[0]} with reason: {string.Join(' ', ctx.Args[1..])}")); + var roomId = ctx.Args[0]; + var servers = new List() { ctx.Homeserver.ServerName }; + if (roomId.StartsWith('[')) { } + + if (roomId.StartsWith('#')) { + var res = await ctx.Homeserver.ResolveRoomAliasAsync(roomId); + roomId = res.RoomId; + servers.AddRange(servers); + } + + var room = ctx.Homeserver.GetRoom(roomId); + var tasks = new List>(); + await foreach (var memberRoom in room.AsSpace.GetChildrenAsync()) { + if (currentRooms.Contains(memberRoom.RoomId)) continue; + servers.Add(room.RoomId.Split(':', 2)[1]); + servers = servers.Distinct().ToList(); + tasks.Add(JoinRoom(memberRoom, string.Join(' ', ctx.Args[1..]), servers)); + } + + await foreach (var b in tasks.ToAsyncEnumerable()) { + await Task.Delay(50); + } + } + + private async Task JoinRoom(GenericRoom memberRoom, string reason, List servers) { + try { + var resp = await memberRoom.JoinAsync(servers.ToArray(), reason, checkIfAlreadyMember: false); + await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccess($"Joined room {memberRoom.RoomId} (resp={resp.RoomId})")); + } + catch (Exception e) { + await logRoom.SendMessageEventAsync(MessageFormatter.FormatException($"Failed to join {memberRoom.RoomId}", e)); + } + + return true; + } +} \ No newline at end of file diff --git a/ModerationBot/Commands/ReloadPoliciesCommand.cs b/ModerationBot/Commands/ReloadPoliciesCommand.cs new file mode 100644 index 0000000..2934185 --- /dev/null +++ b/ModerationBot/Commands/ReloadPoliciesCommand.cs @@ -0,0 +1,38 @@ +using LibMatrix.EventTypes.Spec; +using LibMatrix.Helpers; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using ModerationBot.AccountData; + +namespace ModerationBot.Commands; + +public class ReloadPoliciesCommand(IServiceProvider services, HomeserverProviderService hsProvider, HomeserverResolverService hsResolver, PolicyEngine engine) : ICommand { + public string Name { get; } = "reloadpolicies"; + public string[]? Aliases { get; } + public string Description { get; } = "Reload policies"; + public bool Unlisted { get; } + + public async Task CanInvoke(CommandContext ctx) { + if (ctx.MessageEvent.Sender == "@cadence:cadence.moe") return true; + //check if user is admin in control room + var botData = await ctx.Homeserver.GetAccountDataAsync("gay.rory.moderation_bot_data"); + var controlRoom = ctx.Homeserver.GetRoom(botData.ControlRoom); + var isAdmin = (await controlRoom.GetPowerLevelsAsync())!.UserHasStatePermission(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("gay.rory.moderation_bot_data"); + var policyRoom = ctx.Homeserver.GetRoom(botData.DefaultPolicyRoom ?? botData.ControlRoom); + var logRoom = ctx.Homeserver.GetRoom(botData.LogRoom ?? botData.ControlRoom); + + await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccess($"Reloading policy lists due to manual invocation!!!!")); + await engine.ReloadActivePolicyLists(); + } +} \ No newline at end of file -- cgit 1.5.1