From 6af6bc9629742f792e1f2cd6c68e46a755f710eb Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 31 Mar 2018 18:05:54 +0200 Subject: [PATCH] Silence user command, along with many improvements and bug fixes --- .../Database/ServerSettings/ServerSetting.cs | 7 +- .../ServerSettings/ServerSettingHandler.cs | 5 +- DeukBot4/Logger.cs | 4 +- .../Commands/ModeratorCommands.cs | 81 ++++++++++++++++++- .../Commands/RolePermissionCommands.cs | 39 ++++++++- .../RequestStructure/CommandRequest.cs | 2 +- .../RequestStructure/ParameterMatcher.cs | 44 +++++++--- .../RequestStructure/RequestParameter.cs | 4 +- DeukBot4/Program.cs | 2 + DeukBot4/Utilities/TimespanParser.cs | 37 +++++++++ 10 files changed, 202 insertions(+), 23 deletions(-) create mode 100644 DeukBot4/Utilities/TimespanParser.cs diff --git a/DeukBot4/Database/ServerSettings/ServerSetting.cs b/DeukBot4/Database/ServerSettings/ServerSetting.cs index 738c1ae..6bd655a 100644 --- a/DeukBot4/Database/ServerSettings/ServerSetting.cs +++ b/DeukBot4/Database/ServerSettings/ServerSetting.cs @@ -1,4 +1,5 @@ -using DeukBot4.Utilities; +using System.Threading.Tasks; +using DeukBot4.Utilities; using Npgsql; namespace DeukBot4.Database.ServerSettings @@ -14,7 +15,7 @@ namespace DeukBot4.Database.ServerSettings public ulong ServerId { get; } public ulong MutedRoleId { get; } - public void SetMutedRoleId(ulong id) + public async Task SetMutedRoleId(ulong id) { using (var conn = new DatabaseConnection()) { @@ -24,7 +25,7 @@ namespace DeukBot4.Database.ServerSettings cmd.CommandText = "UPDATE server_settings SET muted_role = @val WHERE server_id = @key"; cmd.Parameters.AddWithValue("val", id.ToLong()); cmd.Parameters.AddWithValue("key", ServerId.ToLong()); - cmd.ExecuteNonQuery(); + await cmd.ExecuteNonQueryAsync(); } } } diff --git a/DeukBot4/Database/ServerSettings/ServerSettingHandler.cs b/DeukBot4/Database/ServerSettings/ServerSettingHandler.cs index dff2eb4..decee29 100644 --- a/DeukBot4/Database/ServerSettings/ServerSettingHandler.cs +++ b/DeukBot4/Database/ServerSettings/ServerSettingHandler.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using DeukBot4.Utilities; using Discord; using Npgsql; @@ -16,7 +17,7 @@ namespace DeukBot4.Database.ServerSettings using (var cmd = new NpgsqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "SELECT server_id muted_role FROM server_settings"; + cmd.CommandText = "SELECT server_id, muted_role FROM server_settings"; var reader = cmd.ExecuteReader(); while (reader.Read()) { diff --git a/DeukBot4/Logger.cs b/DeukBot4/Logger.cs index 9770d5e..c13247f 100644 --- a/DeukBot4/Logger.cs +++ b/DeukBot4/Logger.cs @@ -21,14 +21,14 @@ namespace DeukBot4 public static async Task Log(object o, LogSeverity severity) { Console.ForegroundColor = Colors[severity]; - Console.WriteLine($"[{severity}] {DateTime.UtcNow.ToShortTimeString()}: {o.ToString()}"); + Console.WriteLine($"[{severity}] {DateTime.UtcNow:u}: {o.ToString()}"); Console.ResetColor(); } public static async Task LogDiscord(LogMessage message) { Console.ForegroundColor = Colors[message.Severity]; - Console.WriteLine($"[{message.Severity}] {DateTime.UtcNow.ToShortTimeString()}: {message.Message}"); + Console.WriteLine($"[{message.Severity}] {DateTime.UtcNow:u}: {message.Message}"); Console.ResetColor(); } diff --git a/DeukBot4/MessageHandlers/CommandHandler/Commands/ModeratorCommands.cs b/DeukBot4/MessageHandlers/CommandHandler/Commands/ModeratorCommands.cs index a68c460..033d317 100644 --- a/DeukBot4/MessageHandlers/CommandHandler/Commands/ModeratorCommands.cs +++ b/DeukBot4/MessageHandlers/CommandHandler/Commands/ModeratorCommands.cs @@ -1,6 +1,10 @@ -using System.Threading.Tasks; +using System; +using System.Linq; +using System.Threading.Tasks; +using DeukBot4.Database.ServerSettings; using DeukBot4.MessageHandlers.CommandHandler.RequestStructure; using DeukBot4.MessageHandlers.Permissions; +using DeukBot4.Utilities; using Discord; using Discord.WebSocket; @@ -55,6 +59,13 @@ namespace DeukBot4.MessageHandlers.CommandHandler } [Command("ban", PermissionLevel.Moderator)] + [CommandHelp("Bans a user from the server", + "Bans a user from the server. Will not work on people with a helper role, or higher.\n" + + "Usage: \n" + + "``ban {User Mention} {optional: Reason}``\n" + + "``ban {User ID} {optional: Reason}``")] + [CommandParameters(ParameterMatcher.ParameterType.User, ParameterMatcher.ParameterType.Remainder)] + [BlockUsageInPm, RequireParameterMatch] public async Task BanUser(CommandRequest request) { // get the server channel object out of message. Return if it's somehow not a server channel @@ -90,5 +101,73 @@ namespace DeukBot4.MessageHandlers.CommandHandler await channel.Guild.AddBanAsync(user, 0, reason); await request.SendMessageAsync($"User was banned: {user.Username}"); } + + [Command("silence", PermissionLevel.Helper)] + [Command("mute", PermissionLevel.Helper)] + [CommandParameters(ParameterMatcher.ParameterType.User, ParameterMatcher.ParameterType.Timespan)] + [CommandParameters(ParameterMatcher.ParameterType.User, ParameterMatcher.ParameterType.Number)] + [BlockUsageInPm] + public async Task SilenceUser(CommandRequest request) + { + // get the server channel object out of message. Return if it's somehow not a server channel + if (!(request.OriginalMessage.Channel is IGuildChannel channel)) + return; + + // get the id of the user, this parses the string to an id + var user = await request.Parameters[0].AsDiscordUser(channel.Guild); + if (user == null) + { + await request.SendMessageAsync("I can't find that user on the server"); + return; + } + + var silencedRoleId = ServerSettingHandler.GetSettings(channel.GuildId).MutedRoleId; + if (silencedRoleId == 0) + { + await request.SendMessageAsync( + "No silenced role has been set. The server owner should do ``!silencedrole {role id}`` to set one first."); + return; + } + + var silencedRole = channel.Guild.GetRole(silencedRoleId); + if (silencedRole == null) + { + await request.SendMessageAsync( + "Can't find the silenced role. Has it been deleted?"); + return; + } + + await user.AddRoleAsync(silencedRole); + + TimeSpan span; + if (request.Parameters[1].Type == ParameterMatcher.ParameterType.Number) + { + var minutes = request.Parameters[1].AsInt(); + if (!minutes.HasValue) + return; + + span = TimeSpan.FromMinutes(minutes.Value); + } + else if (request.Parameters[1].Type == ParameterMatcher.ParameterType.Timespan) + { + var sp = TimespanParser.Parse(request.Parameters[1].AsString()); + if (sp.HasValue) + { + span = sp.Value; + } + else + { + Console.WriteLine("this"); + return; + } + } + else + { + return; + } + + await Task.Delay(span); + await user.RemoveRoleAsync(silencedRole); + } } } \ No newline at end of file diff --git a/DeukBot4/MessageHandlers/CommandHandler/Commands/RolePermissionCommands.cs b/DeukBot4/MessageHandlers/CommandHandler/Commands/RolePermissionCommands.cs index 63abd0c..3b4ea21 100644 --- a/DeukBot4/MessageHandlers/CommandHandler/Commands/RolePermissionCommands.cs +++ b/DeukBot4/MessageHandlers/CommandHandler/Commands/RolePermissionCommands.cs @@ -2,6 +2,7 @@ using System.Text; using System.Threading.Tasks; using DeukBot4.Database; +using DeukBot4.Database.ServerSettings; using DeukBot4.MessageHandlers.CommandHandler.RequestStructure; using DeukBot4.MessageHandlers.Permissions; using Discord; @@ -31,28 +32,32 @@ namespace DeukBot4.MessageHandlers.CommandHandler } [Command("adminrole", PermissionLevel.ServerOwner)] - [CommandParameters(new []{ParameterMatcher.ParameterType.Number})] + [CommandParameters(ParameterMatcher.ParameterType.Number)] + [BlockUsageInPm] public async Task SetAdminRole(CommandRequest request) { await SetRolePermission(request, PermissionLevel.Admin); } [Command("moderatorrole", PermissionLevel.ServerOwner)] - [CommandParameters(new []{ParameterMatcher.ParameterType.Number})] + [CommandParameters(ParameterMatcher.ParameterType.Number)] + [BlockUsageInPm] public async Task SetModRole(CommandRequest request) { await SetRolePermission(request, PermissionLevel.Moderator); } [Command("helperrole", PermissionLevel.ServerOwner)] - [CommandParameters(new []{ParameterMatcher.ParameterType.Number})] + [CommandParameters(ParameterMatcher.ParameterType.Number)] + [BlockUsageInPm] public async Task SetHelperRole(CommandRequest request) { await SetRolePermission(request, PermissionLevel.Helper); } [Command("blockedrole", PermissionLevel.ServerOwner)] - [CommandParameters(new []{ParameterMatcher.ParameterType.Number})] + [CommandParameters(ParameterMatcher.ParameterType.Number)] + [BlockUsageInPm] public async Task SetBannedRole(CommandRequest request) { await SetRolePermission(request, PermissionLevel.Banned); @@ -98,5 +103,31 @@ namespace DeukBot4.MessageHandlers.CommandHandler } } + [Command("silencedrole", PermissionLevel.ServerOwner)] + [CommandParameters(ParameterMatcher.ParameterType.Number)] + [BlockUsageInPm, RequireParameterMatch] + public async Task SetSilencedRole(CommandRequest request) + { + var val = request.Parameters[0].AsUlong(); + if (!val.HasValue) + { + await request.SendMessageAsync("Invalid role ID"); + return; + } + + if (!(request.OriginalMessage.Channel is IGuildChannel channel)) + return; + + var role = channel.Guild.GetRole(val.Value); + if (role == null) + { + await request.SendMessageAsync("No role by that ID exists on the server"); + return; + } + + var setting = ServerSettingHandler.GetSettings(channel.GuildId); + await setting.SetMutedRoleId(val.Value); + } + } } \ No newline at end of file diff --git a/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/CommandRequest.cs b/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/CommandRequest.cs index 9660cf7..67f280a 100644 --- a/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/CommandRequest.cs +++ b/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/CommandRequest.cs @@ -16,7 +16,7 @@ namespace DeukBot4.MessageHandlers.CommandHandler.RequestStructure public Command Command { get; } public SocketMessage OriginalMessage { get; } - public RequestParameter[] Parameters { get; private set; } + public RequestParameter[] Parameters { get; } public PermissionLevel RequestPermissions { get; } private CommandRequest(SocketMessage message, Command command, PermissionLevel requestPermissions, RequestParameter[] parameters) diff --git a/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/ParameterMatcher.cs b/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/ParameterMatcher.cs index cce29a7..c379146 100644 --- a/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/ParameterMatcher.cs +++ b/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/ParameterMatcher.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Discord.Net.Udp; namespace DeukBot4.MessageHandlers.CommandHandler.RequestStructure { @@ -13,6 +14,7 @@ namespace DeukBot4.MessageHandlers.CommandHandler.RequestStructure Number, Remainder, User, + Timespan, } public static string[] GenerateRegex(Command command) @@ -23,24 +25,31 @@ namespace DeukBot4.MessageHandlers.CommandHandler.RequestStructure var commandParameterType = command.ParameterTypes[index]; var builder = new StringBuilder(); - builder.Append(GetParameterRegex(commandParameterType[index])); + for (var i = 0; i < commandParameterType.Length; i++) + { + var parameterType = commandParameterType[i]; + builder.Append(GetParameterRegex(parameterType, i + 1)); + } + arr[index] = builder.ToString(); } return arr; } - private static string GetParameterRegex(ParameterType type) + private static string GetParameterRegex(ParameterType type, int index) { switch (type) { case ParameterType.Word: - return " *(\\w+)"; + return $" *(?<{index}>\\w+)"; case ParameterType.Number: - return " *(\\d+)"; + return $" *(?<{index}>\\d+)(?:$| |\n)"; case ParameterType.Remainder: - return " *(.*)"; + return $" *(?<{index}>.*)"; case ParameterType.User: - return " *<@(?\\d+)>|(?\\d+)"; + return $" *(?:<@(?<{index}>\\d+)>|(?<{index}>\\d+)(?:$| |\n))"; + case ParameterType.Timespan: + return $" *(?<{index}>\\d+[smhd])"; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } @@ -48,12 +57,29 @@ namespace DeukBot4.MessageHandlers.CommandHandler.RequestStructure public static RequestParameter[] GetParameterValues(Command command, string parameterString) { - foreach (var pattern in command.ParametersMatchers) + for (var index = 0; index < command.ParametersMatchers.Length; index++) { - var matches = Regex.Match(parameterString, pattern); + var parameterTypes = command.ParameterTypes[index]; + var pattern = command.ParametersMatchers[index]; + Match matches; + try + { + matches = Regex.Match(parameterString, pattern); + } + catch (Exception e) + { + Logger.LogError(e.ToString()); + return command.RequireParameterMatch ? null : new RequestParameter[0]; + } if (matches.Success) { - return matches.Groups.Skip(1).Select(x => new RequestParameter(x.Value)).ToArray(); + var arr = new RequestParameter[matches.Groups.Count - 1]; + for (var i = 1; i < matches.Groups.Count; i++) + { + var group = matches.Groups[i]; + arr[i - 1] = new RequestParameter(group.Value, parameterTypes[i - 1]); + } + return arr; } } diff --git a/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/RequestParameter.cs b/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/RequestParameter.cs index 761d6c3..ca5abe6 100644 --- a/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/RequestParameter.cs +++ b/DeukBot4/MessageHandlers/CommandHandler/RequestStructure/RequestParameter.cs @@ -7,10 +7,12 @@ namespace DeukBot4.MessageHandlers.CommandHandler.RequestStructure { public class RequestParameter { + public ParameterMatcher.ParameterType Type { get; } private readonly string _value; - public RequestParameter(string value) + public RequestParameter(string value, ParameterMatcher.ParameterType type) { + Type = type; _value = value; } diff --git a/DeukBot4/Program.cs b/DeukBot4/Program.cs index b9060ce..80402c1 100644 --- a/DeukBot4/Program.cs +++ b/DeukBot4/Program.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using DeukBot4.Database; +using DeukBot4.Database.ServerSettings; using DeukBot4.MessageHandlers; using DeukBot4.MessageHandlers.CommandHandler; using Discord; @@ -26,6 +27,7 @@ namespace DeukBot4 DatabaseConnection.ConnectionString = Settings.DatabaseConnectionString; DatabaseInitializer.Initialize(); + ServerSettingHandler.OnBotStartUp(); CommandHandler.Build(); Client = new DiscordSocketClient(); diff --git a/DeukBot4/Utilities/TimespanParser.cs b/DeukBot4/Utilities/TimespanParser.cs new file mode 100644 index 0000000..3e237d5 --- /dev/null +++ b/DeukBot4/Utilities/TimespanParser.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; + +namespace DeukBot4.Utilities +{ + public static class TimespanParser + { + public static TimeSpan? Parse(string s) + { + var timeIndicator = s.Last(); + var numberStr = s.Remove(s.Length - 1, 1); + if (!int.TryParse(numberStr, out var number)) + { + return null; + } + + switch (timeIndicator) + { + case 's': + return TimeSpan.FromSeconds(number); + break; + case 'm': + return TimeSpan.FromMinutes(number); + break; + case 'h': + return TimeSpan.FromHours(number); + break; + case 'd': + return TimeSpan.FromDays(number); + break; + default: + return null; + } + + } + } +} \ No newline at end of file