diff --git a/NadekoBot/Classes/IncidentsHandler.cs b/NadekoBot/Classes/IncidentsHandler.cs index 1743e020..0791fa6c 100644 --- a/NadekoBot/Classes/IncidentsHandler.cs +++ b/NadekoBot/Classes/IncidentsHandler.cs @@ -1,16 +1,15 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace NadekoBot.Classes { - class IncidentsHandler { + internal static class IncidentsHandler { public static void Add(ulong serverId, string text) { Directory.CreateDirectory("data/incidents"); - File.AppendAllText($"data/incidents/{serverId}.txt", text + "\n--------------------------"); + File.AppendAllText($"data/incidents/{serverId}.txt", text + "\n--------------------------\n"); + var def = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"INCIDENT: {text}"); + Console.ForegroundColor = def; } } } diff --git a/NadekoBot/Classes/Permissions/PermissionsHandler.cs b/NadekoBot/Classes/Permissions/PermissionsHandler.cs index 05561e39..23d42c59 100644 --- a/NadekoBot/Classes/Permissions/PermissionsHandler.cs +++ b/NadekoBot/Classes/Permissions/PermissionsHandler.cs @@ -301,15 +301,15 @@ namespace NadekoBot.Classes.Permissions { Task.Run(() => WriteServerToJson(serverPerms)); } - public static void SetServerWordPermission(Server server, string word, bool value) { + public static void SetServerWordPermission(Server server, bool value) { var serverPerms = PermissionsDict.GetOrAdd(server.Id, new ServerPermissions(server.Id, server.Name)); - serverPerms.Permissions.Words.Add(word); + serverPerms.Permissions.FilterWords = value; Task.Run(() => WriteServerToJson(serverPerms)); } - public static void SetChannelWordPermission(Channel channel, string word, bool value) { + public static void SetChannelWordPermission(Channel channel, bool value) { var server = channel.Server; var serverPerms = PermissionsDict.GetOrAdd(server.Id, new ServerPermissions(server.Id, server.Name)); @@ -317,7 +317,7 @@ namespace NadekoBot.Classes.Permissions { if (!serverPerms.ChannelPermissions.ContainsKey(channel.Id)) serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name)); - serverPerms.ChannelPermissions[channel.Id].Words.Add(word); + serverPerms.ChannelPermissions[channel.Id].FilterWords = value; Task.Run(() => WriteServerToJson(serverPerms)); } @@ -340,6 +340,23 @@ namespace NadekoBot.Classes.Permissions { serverPerms.ChannelPermissions[channel.Id].FilterInvites = value; Task.Run(() => WriteServerToJson(serverPerms)); } + + public static void AddFilteredWord(Server server, string word) { + var serverPerms = PermissionsDict.GetOrAdd(server.Id, + new ServerPermissions(server.Id, server.Name)); + if (serverPerms.Words.Contains(word)) + throw new InvalidOperationException("That word is already banned."); + serverPerms.Words.Add(word); + Task.Run(() => WriteServerToJson(serverPerms)); + } + public static void RemoveFilteredWord(Server server, string word) { + var serverPerms = PermissionsDict.GetOrAdd(server.Id, + new ServerPermissions(server.Id, server.Name)); + if (!serverPerms.Words.Contains(word)) + throw new InvalidOperationException("That word is not banned."); + serverPerms.Words.Remove(word); + Task.Run(() => WriteServerToJson(serverPerms)); + } } /// /// Holds a permission list @@ -358,19 +375,18 @@ namespace NadekoBot.Classes.Permissions { /// public Dictionary Commands { get; set; } /// - /// Banned words, usually profanities, like word "java" - /// - public HashSet Words { get; set; } - /// /// Should the bot filter invites to other discord servers (and ref links in the future) /// public bool FilterInvites { get; set; } + /// + /// Should the bot filter words which are specified in the Words hashset + /// + public bool FilterWords { get; set; } public Permissions(string name) { Name = name; Modules = new Dictionary(); Commands = new Dictionary(); - Words = new HashSet(); } public override string ToString() { @@ -408,6 +424,10 @@ namespace NadekoBot.Classes.Permissions { /// Permission object bound to the id of something/role name /// public Permissions Permissions { get; set; } + /// + /// Banned words, usually profanities, like word "java" + /// + public HashSet Words { get; set; } public Dictionary UserPermissions { get; set; } public Dictionary ChannelPermissions { get; set; } @@ -422,6 +442,7 @@ namespace NadekoBot.Classes.Permissions { UserPermissions = new Dictionary(); ChannelPermissions = new Dictionary(); RolePermissions = new Dictionary(); + Words = new HashSet(); } } } \ No newline at end of file diff --git a/NadekoBot/Commands/FilterWordsCommand.cs b/NadekoBot/Commands/FilterWordsCommand.cs new file mode 100644 index 00000000..ba029138 --- /dev/null +++ b/NadekoBot/Commands/FilterWordsCommand.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using NadekoBot.Classes; +using NadekoBot.Classes.Permissions; +using NadekoBot.Modules; +using ServerPermissions = NadekoBot.Classes.Permissions.ServerPermissions; + +namespace NadekoBot.Commands { + internal class FilterWords : DiscordCommand { + public FilterWords(DiscordModule module) : base(module) { + NadekoBot.Client.MessageReceived += async (sender, args) => { + if (args.Channel.IsPrivate) return; + try { + ServerPermissions serverPerms; + if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return; + + var wordsInMessage = args.Message.RawText.Split(' '); + if (serverPerms.Words.Any(w => wordsInMessage.Contains(w))) { + await args.Message.Delete(); + IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " + + $"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel. " + + $"Full message: [[{args.Message.Text}]]"); + if (serverPerms.Verbose) + await args.Channel.SendMessage($"{args.User.Mention} One or more of the words you used " + + $"in that sentence are not allowed here."); + } + } catch { } + }; + } + + private static bool IsChannelOrServerFiltering(Channel channel, out ServerPermissions serverPerms) { + if (!PermissionsHandler.PermissionsDict.TryGetValue(channel.Server.Id, out serverPerms)) return false; + + if (serverPerms.Permissions.FilterWords) + return true; + + Permissions perms; + return serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perms) && perms.FilterWords; + } + + internal override void Init(CommandGroupBuilder cgb) { + cgb.CreateCommand(Module.Prefix + "cfw") + .Alias(Module.Prefix + "channelfilterwords") + .Description("Enables or disables automatic deleting of messages containing banned words on the channel." + + "If no channel supplied, it will default to current one. Use ALL to apply to all existing channels at once." + + "\n**Usage**: ;cfi enable #general-chat") + .Parameter("bool") + .Parameter("channel", ParameterType.Optional) + .Do(async e => { + try { + var state = PermissionHelper.ValidateBool(e.GetArg("bool")); + var chanStr = e.GetArg("channel")?.ToLowerInvariant().Trim(); + + if (chanStr != "all") { + var chan = string.IsNullOrWhiteSpace(chanStr) + ? e.Channel + : PermissionHelper.ValidateChannel(e.Server, chanStr); + PermissionsHandler.SetChannelWordPermission(chan, state); + await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel."); + return; + } + //all channels + + foreach (var curChannel in e.Server.TextChannels) { + PermissionsHandler.SetChannelWordPermission(curChannel, state); + } + await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels."); + + } catch (Exception ex) { + await e.Channel.SendMessage($"💢 Error: {ex.Message}"); + } + }); + + cgb.CreateCommand(Module.Prefix + "afw") + .Alias(Module.Prefix + "addfilteredword") + .Description("Adds a new word to the list of filtered words" + + "\n**Usage**: ;aw poop") + .Parameter("word", ParameterType.Unparsed) + .Do(async e => { + try { + var word = e.GetArg("word"); + if (string.IsNullOrWhiteSpace(word)) + return; + PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim()); + await e.Channel.SendMessage($"Successfully added new filtered word."); + + } catch (Exception ex) { + await e.Channel.SendMessage($"💢 Error: {ex.Message}"); + } + }); + + cgb.CreateCommand(Module.Prefix + "rfw") + .Alias(Module.Prefix + "removefilteredword") + .Description("Removes the word from the list of filtered words" + + "\n**Usage**: ;rw poop") + .Parameter("word", ParameterType.Unparsed) + .Do(async e => { + try { + var word = e.GetArg("word"); + if (string.IsNullOrWhiteSpace(word)) + return; + PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim()); + await e.Channel.SendMessage($"Successfully removed filtered word."); + + } catch (Exception ex) { + await e.Channel.SendMessage($"💢 Error: {ex.Message}"); + } + }); + + cgb.CreateCommand(Module.Prefix + "lfw") + .Alias(Module.Prefix + "listfilteredwords") + .Description("Shows a list of filtered words" + + "\n**Usage**: ;lfw") + .Do(async e => { + try { + ServerPermissions serverPerms; + if (!PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out serverPerms)) + return; + await e.Channel.SendMessage($"There are `{serverPerms.Words.Count}` filtered words.\n" + + string.Join("\n", serverPerms.Words)); + } catch (Exception ex) { + await e.Channel.SendMessage($"💢 Error: {ex.Message}"); + } + }); + + cgb.CreateCommand(Module.Prefix + "sfw") + .Alias(Module.Prefix + "serverfilterwords") + .Description("Enables or disables automatic deleting of messages containing forbidden words on the server.\n**Usage**: ;sfi disable") + .Parameter("bool") + .Do(async e => { + try { + var state = PermissionHelper.ValidateBool(e.GetArg("bool")); + PermissionsHandler.SetServerWordPermission(e.Server, state); + await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server."); + + } catch (Exception ex) { + await e.Channel.SendMessage($"💢 Error: {ex.Message}"); + } + }); + } + } +} diff --git a/NadekoBot/Modules/Permissions.cs b/NadekoBot/Modules/Permissions.cs index 9a929964..157f38d6 100644 --- a/NadekoBot/Modules/Permissions.cs +++ b/NadekoBot/Modules/Permissions.cs @@ -15,6 +15,7 @@ namespace NadekoBot.Modules { public PermissionModule() { commands.Add(new FilterInvitesCommand(this)); + commands.Add(new FilterWords(this)); } public override void Install(ModuleManager manager) {