diff options
Diffstat (limited to 'ExampleBots/ModerationBot')
6 files changed, 126 insertions, 9 deletions
diff --git a/ExampleBots/ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs b/ExampleBots/ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs index f578f53..cd0bf6b 100644 --- a/ExampleBots/ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs +++ b/ExampleBots/ModerationBot/Commands/DbgAllRoomsArePolicyListsCommand.cs @@ -14,9 +14,9 @@ public class DbgAllRoomsArePolicyListsCommand private GenericRoom logRoom { get; set; } public async Task<bool> CanInvoke(CommandContext ctx) { -#if !DEBUG - return false; -#endif +// #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"); diff --git a/ExampleBots/ModerationBot/Commands/DbgAniRainbowTest.cs b/ExampleBots/ModerationBot/Commands/DbgAniRainbowTest.cs new file mode 100644 index 0000000..b2216d1 --- /dev/null +++ b/ExampleBots/ModerationBot/Commands/DbgAniRainbowTest.cs @@ -0,0 +1,48 @@ +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 Description { get; } = "[Debug] animated rainbow :)"; + private GenericRoom logRoom { get; set; } + + public async Task<bool> 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<RoomMessageEventContent>(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/ExampleBots/ModerationBot/Commands/JoinSpaceMembersCommand.cs b/ExampleBots/ModerationBot/Commands/JoinSpaceMembersCommand.cs index da77b05..6564e71 100644 --- a/ExampleBots/ModerationBot/Commands/JoinSpaceMembersCommand.cs +++ b/ExampleBots/ModerationBot/Commands/JoinSpaceMembersCommand.cs @@ -30,6 +30,7 @@ public class JoinSpaceMembersCommand(IServiceProvider services, HomeserverProvid 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 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]; @@ -47,6 +48,7 @@ public class JoinSpaceMembersCommand(IServiceProvider services, HomeserverProvid var room = ctx.Homeserver.GetRoom(roomId); var tasks = new List<Task<bool>>(); 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)); @@ -59,8 +61,8 @@ public class JoinSpaceMembersCommand(IServiceProvider services, HomeserverProvid private async Task<bool> JoinRoom(GenericRoom memberRoom, string reason, List<string> servers) { try { - await memberRoom.JoinAsync(servers.ToArray(), reason); - await logRoom.SendMessageEventAsync(MessageFormatter.FormatSuccess($"Joined room {memberRoom.RoomId}")); + 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)); diff --git a/ExampleBots/ModerationBot/Commands/ReloadPoliciesCommand.cs b/ExampleBots/ModerationBot/Commands/ReloadPoliciesCommand.cs new file mode 100644 index 0000000..b876145 --- /dev/null +++ b/ExampleBots/ModerationBot/Commands/ReloadPoliciesCommand.cs @@ -0,0 +1,37 @@ +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 Description { get; } = "Reload policies"; + + public async Task<bool> 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<BotData>("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<BotData>("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(); + } +} diff --git a/ExampleBots/ModerationBot/ModerationBot.cs b/ExampleBots/ModerationBot/ModerationBot.cs index 7c95229..2424eee 100644 --- a/ExampleBots/ModerationBot/ModerationBot.cs +++ b/ExampleBots/ModerationBot/ModerationBot.cs @@ -1,5 +1,6 @@ using ArcaneLibs.Extensions; using LibMatrix; +using LibMatrix.EventTypes; using LibMatrix.EventTypes.Spec; using LibMatrix.EventTypes.Spec.State; using LibMatrix.EventTypes.Spec.State.Policy; @@ -29,6 +30,7 @@ public class ModerationBot(AuthenticatedHomeserverGeneric hs, ILogger<Moderation } private async Task Run(CancellationToken cancellationToken) { + return; if (Directory.Exists("bot_data/cache")) Directory.GetFiles("bot_data/cache").ToList().ForEach(File.Delete); @@ -112,8 +114,10 @@ public class ModerationBot(AuthenticatedHomeserverGeneric hs, ILogger<Moderation if (@event != null && ( @event.MappedType.IsAssignableTo(typeof(BasePolicy)) || @event.MappedType.IsAssignableTo(typeof(PolicyRuleEventContent)) - )) + )) { + await LogPolicyChange(@event); await engine.ReloadActivePolicyListById(@event.RoomId); + } var rules = await engine.GetMatchingPolicies(@event); foreach (var matchedRule in rules) { @@ -264,6 +268,32 @@ public class ModerationBot(AuthenticatedHomeserverGeneric hs, ILogger<Moderation await syncHelper.RunSyncLoopAsync(); } + private async Task LogPolicyChange(StateEventResponse changeEvent) { + var room = hs.GetRoom(changeEvent.RoomId!); + var message = MessageFormatter.FormatWarning($"Policy change detected in {MessageFormatter.HtmlFormatMessageLink(changeEvent.RoomId, changeEvent.EventId, [hs.ServerName], await room.GetNameOrFallbackAsync())}!"); + message = message.ConcatLine(new RoomMessageEventContent(body: $"Policy type: {changeEvent.Type} -> {changeEvent.MappedType.Name}") { + FormattedBody = $"Policy type: {changeEvent.Type} -> {changeEvent.MappedType.Name}" + }); + var isUpdated = changeEvent.Unsigned.PrevContent is { Count: > 0 }; + var isRemoved = changeEvent.RawContent is not { Count: > 0 }; + // if (isUpdated) { + // message = message.ConcatLine(MessageFormatter.FormatSuccess("Rule updated!")); + // message = message.ConcatLine(MessageFormatter.FormatSuccessJson("Old rule:", changeEvent.Unsigned.PrevContent!)); + // } + // else if (isRemoved) { + // message = message.ConcatLine(MessageFormatter.FormatWarningJson("Rule removed!", changeEvent.Unsigned.PrevContent!)); + // } + // else { + // message = message.ConcatLine(MessageFormatter.FormatSuccess("New rule added!")); + // } + message = message.ConcatLine(MessageFormatter.FormatSuccessJson($"{(isUpdated ? "Updated" : isRemoved ? "Removed" : "New")} rule: {changeEvent.StateKey}", changeEvent.RawContent!)); + if (isRemoved || isUpdated) { + message = message.ConcatLine(MessageFormatter.FormatSuccessJson("Old content: ", changeEvent.Unsigned.PrevContent!)); + } + + await _logRoom.SendMessageEventAsync(message); + } + /// <summary>Triggered when the application host is performing a graceful shutdown.</summary> /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param> public async Task StopAsync(CancellationToken cancellationToken) { diff --git a/ExampleBots/ModerationBot/PolicyEngine.cs b/ExampleBots/ModerationBot/PolicyEngine.cs index 114b90d..0d0ed65 100644 --- a/ExampleBots/ModerationBot/PolicyEngine.cs +++ b/ExampleBots/ModerationBot/PolicyEngine.cs @@ -62,12 +62,12 @@ public class PolicyEngine(AuthenticatedHomeserverGeneric hs, ILogger<ModerationB await foreach (var policyList in loadTasks.ToAsyncEnumerable()) { policyLists.Add(policyList); - if (policyList.Policies.Count >= 256 || policyLists.Count == PolicyListAccountData.Count) { + if (false || policyList.Policies.Count >= 256 || policyLists.Count == PolicyListAccountData.Count) { var progressMsgContent = MessageFormatter.FormatSuccess($"{policyLists.Count}/{PolicyListAccountData.Count} policy lists loaded, " + $"{policyLists.Sum(x => x.Policies.Count)} policies total, {sw.Elapsed} elapsed.") .SetReplaceRelation<RoomMessageEventContent>(progressMessage.EventId); - _logRoom?.SendMessageEventAsync(progressMsgContent); + await _logRoom?.SendMessageEventAsync(progressMsgContent); } } @@ -253,7 +253,7 @@ public class PolicyEngine(AuthenticatedHomeserverGeneric hs, ILogger<ModerationB 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].MappedType.Name}"; + raw += $"\n{stateGroup.Count} | {type} | {stateGroup[0].MappedType.Name}"; html += $"<tr><td>{stateGroup.Count}</td><td>{type}</td><td>{stateGroup[0].MappedType.Name}</td></tr>"; } |