From 68eddc8a86d9b6fdf626590683c011a9a08cd044 Mon Sep 17 00:00:00 2001 From: Drummss <1509172+Drummss@users.noreply.github.com> Date: Thu, 15 Oct 2020 19:07:00 +0100 Subject: [PATCH] Custom Command Improvements ## Minor improvements for the custom command service and module. - Updated custom commands to use an updated command and subcommand structure. - Added a command that lets you list the custom commands your guild currently has stored. --- .../CustomCommands/CustomCommandsModule.cs | 406 +++++++++++------- .../Services/CustomCommandsService.cs | 16 + .../Services/ICustomCommandsService.cs | 5 + 3 files changed, 267 insertions(+), 160 deletions(-) diff --git a/src/Miki/Modules/CustomCommands/CustomCommandsModule.cs b/src/Miki/Modules/CustomCommands/CustomCommandsModule.cs index 4bc844a9..caf7b95c 100644 --- a/src/Miki/Modules/CustomCommands/CustomCommandsModule.cs +++ b/src/Miki/Modules/CustomCommands/CustomCommandsModule.cs @@ -32,231 +32,317 @@ namespace Miki.Modules.CustomCommands [Module("CustomCommands"), Emoji(AppProps.Emoji.Wrench)] public class CustomCommandsModule { - [Command("createcommand")] + [Command("customcommand", "cc")] [GuildOnly] [DefaultPermission(PermissionStatus.Deny)] - public async Task NewCustomCommandAsync(IContext e) + public class CustomCommand { - var commandName = e.GetArgumentPack().TakeRequired().ToLower(); + [Command("create", "add")] + public async Task CreateCommandAsync(IContext e) + { + await _CreateCommandAsync(e); + } - if (commandName.Contains(' ')) + [Command("remove", "del", "r", "d")] + public async Task RemoveCommandAsync(IContext e) { - throw new InvalidCharacterException(" "); + await _RemoveCommandAsync(e); } - - if (string.IsNullOrEmpty(commandName)) + + [Command("get")] + public async Task GetCommandAsync(IContext e) { - throw new ArgumentMissingException(typeof(string)); + await _GetCommandAsync(e); } - var commandHandler = e.GetService(); - if (commandHandler.GetCommand(commandName) != null) + [Command("storage")] + public async Task GetCommandStorageAsync(IContext e) { - throw new DuplicateCommandException(commandName); + await _GetCommandStorageAsync(e); } - if (!e.GetArgumentPack().CanTake) + [Command("list")] + public async Task ListCommandsAsync(IContext e) { - throw new ArgumentMissingException(typeof(CustomCommand)); + var service = e.GetService(); + var commands = await service.GetGuildCommands((long) e.GetGuild().Id); + + var embed = new EmbedBuilder() + .SetTitle($"{AppProps.Emoji.Gear} Custom Commands") + .SetColor(102, 117, 127); + + var commandString = "This server doesn't have any custom commands yet."; + + if (commands.Count > 0) + { + commandString = ""; + + commands.ForEach(x => commandString += (x + ", ")); + commandString = commandString.TrimEnd(',', ' ').AsCode(); + } + else + { + embed.AddField( + "Need help?", + "Check out our guide [here](https://miki.bot/guides/using-miscript-to-create-custom-commands/)!"); + } + + await embed + .SetDescription(commandString) + .ToEmbed() + .QueueAsync(e, e.GetChannel()); } - var scriptBody = e.GetArgumentPack().Pack.TakeAll().TrimStart('`').TrimEnd('`'); - var provider = new CodeProvider(scriptBody); - var sb = new StringBuilder(); - var locale = e.GetLocale(); + public static async Task _CreateCommandAsync(IContext e) + { + var commandName = e.GetArgumentPack().TakeRequired().ToLower(); + + if (commandName.Contains(' ')) + { + throw new InvalidCharacterException(" "); + } - sb.AppendLine(locale.GetString("customcommands_created", e.GetPrefixMatch() + commandName)); + if (string.IsNullOrEmpty(commandName)) + { + throw new ArgumentMissingException(typeof(string)); + } - var service = e.GetService(); + var commandHandler = e.GetService(); + if (commandHandler.GetCommand(commandName) != null) + { + throw new DuplicateCommandException(commandName); + } - try - { - var global = await CustomCommandsService.CreateGlobalAsync(e); - var information = BlockInformation.Compile(scriptBody, global); + if (!e.GetArgumentPack().CanTake) + { + throw new ArgumentMissingException(typeof(CustomCommand)); + } + + var scriptBody = e.GetArgumentPack().Pack.TakeAll().TrimStart('`').TrimEnd('`'); + var provider = new CodeProvider(scriptBody); + var sb = new StringBuilder(); + var locale = e.GetLocale(); + + sb.AppendLine(locale.GetString("customcommands_created", e.GetPrefixMatch() + commandName)); - if (information.Messages.Count > 0) + var service = e.GetService(); + + try { - sb.AppendLine(); - sb.AppendLine(e.GetLocale() - .GetString("customcommands_warnings") - .CapitalizeFirst() - .AsBold()); + var global = await CustomCommandsService.CreateGlobalAsync(e); + var information = BlockInformation.Compile(scriptBody, global); - foreach (var message in information.Messages) + if (information.Messages.Count > 0) { - if (message.Range.HasValue) - { - var range = message.Range.Value; + sb.AppendLine(); + sb.AppendLine(e.GetLocale() + .GetString("customcommands_warnings") + .CapitalizeFirst() + .AsBold()); - sb.Append(locale.GetString("customcommands_line", - range.StartLine, - range.StartColumn + 1)); - sb.Append(' '); - } - sb.AppendLine(message.Content); - - if (message.Range.HasValue) + foreach (var message in information.Messages) { - sb.AppendLine("```"); - sb.AppendLine(scriptBody.GetPeek(message.Range.Value)); - sb.AppendLine("```"); + if (message.Range.HasValue) + { + var range = message.Range.Value; + + sb.Append(locale.GetString("customcommands_line", + range.StartLine, + range.StartColumn + 1)); + sb.Append(' '); + } + sb.AppendLine(message.Content); + + if (message.Range.HasValue) + { + sb.AppendLine("```"); + sb.AppendLine(scriptBody.GetPeek(message.Range.Value)); + sb.AppendLine("```"); + } } } } - } - catch (MiScriptInvalidTokenException ex) - { - await CustomCommandsService.SendErrorAsync( - e, - "error_miscript_parse", - ex.Message, - provider, - ex.Range); - return; - } - catch (MiScriptException ex) - { - await CustomCommandsService.SendErrorAsync( - e, - "error_miscript_parse", - ex.Message, - provider, - ex.Position); - return; - } - catch (Exception ex) - { - await CustomCommandsService.SendErrorAsync( - e, - "error_miscript_parse", - "Internal error in MiScript: " + ex.Message, - provider); - return; + catch (MiScriptInvalidTokenException ex) + { + await CustomCommandsService.SendErrorAsync( + e, + "error_miscript_parse", + ex.Message, + provider, + ex.Range); + return; + } + catch (MiScriptException ex) + { + await CustomCommandsService.SendErrorAsync( + e, + "error_miscript_parse", + ex.Message, + provider, + ex.Position); + return; + } + catch (Exception ex) + { + await CustomCommandsService.SendErrorAsync( + e, + "error_miscript_parse", + "Internal error in MiScript: " + ex.Message, + provider); + return; + } + + try + { + var guildId = (long)e.GetGuild().Id; + + await service.UpdateBodyAsync(guildId, commandName, scriptBody); + } + catch (Exception ex) + { + Log.Error(ex); + } + + await e.SuccessEmbed(sb.ToString()) + .QueueAsync(e, e.GetChannel()); } - try + public static async Task _RemoveCommandAsync(IContext e) { + if (!e.GetArgumentPack().Take(out string commandName)) + { + return; + } + + var service = e.GetService(); + var context = e.GetService(); var guildId = (long)e.GetGuild().Id; - await service.UpdateBodyAsync(guildId, commandName, scriptBody); + var cmd = await context.CustomCommands.FindAsync(guildId, commandName); + if (cmd == null) + { + throw new CommandNullException(commandName); + } + + context.Remove(cmd); + await context.SaveChangesAsync(); + await service.RemoveCacheAsync(guildId, commandName); + + await e.SuccessEmbedResource("ok_command_deleted", commandName) + .QueueAsync(e, e.GetChannel()); } - catch (Exception ex) + + public static async Task _GetCommandAsync(IContext e) { - Log.Error(ex); + var commandName = e.GetArgumentPack().TakeRequired(); + var service = e.GetService(); + var guildId = (long)e.GetGuild().Id; + var code = await service.GetBodyAsync(guildId, commandName); + if (code == null) + { + return; + } + + var message = e.GetLocale().GetString("customcommands_code", commandName); + + await new EmbedBuilder() + .SetTitle(":gear: Custom Commands") + .SetDescription($"{message} ```lua\n{code}\n```") + .SetColor(102, 117, 127) + .ToEmbed() + .QueueAsync(e, e.GetChannel()); } - await e.SuccessEmbed(sb.ToString()) - .QueueAsync(e, e.GetChannel()); - } - - [Command("eval")] - [GuildOnly] - [RequiresScope("developer")] - public async Task EvalAsync(IContext e) - { - if (!e.GetArgumentPack().CanTake) + public static async Task _GetCommandStorageAsync(IContext e) { - return; - } + var service = e.GetService(); + var storage = await service.GetStorageAsync((long) e.GetGuild().Id); - var scriptBody = e.GetArgumentPack().Pack.TakeAll().TrimStart('`').TrimEnd('`'); - var service = e.GetService(); + var sb = new StringBuilder(); - await service.ExecuteCodeAsync(e, scriptBody); + if (storage.Count > 0) + { + var limit = 1800 / storage.Count; + + sb.AppendLine("```json"); + foreach (var (key, value) in storage) + { + var data = value.ToString(Formatting.None); + + if (data.Length > limit) + { + data = data.Substring(0, limit - 3) + "..."; + } + + sb.Append(key); + sb.Append(": "); + sb.AppendLine(data); + } + + sb.AppendLine("```"); + } + + var message = e.GetLocale().GetString("customcommands_storage"); + + await new EmbedBuilder() + .SetTitle(":gear: Custom Commands") + .SetDescription($"{message} {sb}") + .SetColor(102, 117, 127) + .ToEmbed() + .QueueAsync(e, e.GetChannel()); + } + } + + [Command("createcommand")] + [Obsolete("This will eventually be removed.")] + [GuildOnly] + [DefaultPermission(PermissionStatus.Deny)] + public async Task NewCustomCommandAsync(IContext e) + { + await CustomCommand._CreateCommandAsync(e); } [Command("removecommand")] + [Obsolete("This will eventually be removed.")] [GuildOnly] [DefaultPermission(PermissionStatus.Deny)] public async Task RemoveCommandAsync(IContext e) { - if (!e.GetArgumentPack().Take(out string commandName)) - { - return; - } - - var service = e.GetService(); - var context = e.GetService(); - var guildId = (long)e.GetGuild().Id; - - var cmd = await context.CustomCommands.FindAsync(guildId, commandName); - if (cmd == null) - { - throw new CommandNullException(commandName); - } - - context.Remove(cmd); - await context.SaveChangesAsync(); - await service.RemoveCacheAsync(guildId, commandName); - - await e.SuccessEmbedResource("ok_command_deleted", commandName) - .QueueAsync(e, e.GetChannel()); + await CustomCommand._RemoveCommandAsync(e); } [Command("getcommand")] + [Obsolete("This will eventually be removed.")] [GuildOnly] [DefaultPermission(PermissionStatus.Deny)] public async Task GetCommandAsync(IContext e) { - var commandName = e.GetArgumentPack().TakeRequired(); - var service = e.GetService(); - var guildId = (long)e.GetGuild().Id; - var code = await service.GetBodyAsync(guildId, commandName); - if (code == null) - { - return; - } - - var message = e.GetLocale().GetString("customcommands_code", commandName); - - await new EmbedBuilder() - .SetTitle(":gear: Custom Commands") - .SetDescription($"{message} ```lua\n{code}\n```") - .SetColor(102, 117, 127) - .ToEmbed() - .QueueAsync(e, e.GetChannel()); + CustomCommand._GetCommandAsync(e); } [Command("getcommandstorage")] + [Obsolete("This will eventually be removed.")] [GuildOnly] [DefaultPermission(PermissionStatus.Deny)] public async Task GetCommandStorageAsync(IContext e) { - var service = e.GetService(); - var storage = await service.GetStorageAsync((long) e.GetGuild().Id); - - var sb = new StringBuilder(); + await CustomCommand._GetCommandStorageAsync(e); + } - if (storage.Count > 0) + [Command("eval")] + [GuildOnly] + [RequiresScope("developer")] + public async Task EvalAsync(IContext e) + { + if (!e.GetArgumentPack().CanTake) { - var limit = 1800 / storage.Count; - - sb.AppendLine("```json"); - foreach (var (key, value) in storage) - { - var data = value.ToString(Formatting.None); - - if (data.Length > limit) - { - data = data.Substring(0, limit - 3) + "..."; - } - - sb.Append(key); - sb.Append(": "); - sb.AppendLine(data); - } - - sb.AppendLine("```"); + return; } - var message = e.GetLocale().GetString("customcommands_storage"); + var scriptBody = e.GetArgumentPack().Pack.TakeAll().TrimStart('`').TrimEnd('`'); + var service = e.GetService(); - await new EmbedBuilder() - .SetTitle(":gear: Custom Commands") - .SetDescription($"{message} {sb}") - .SetColor(102, 117, 127) - .ToEmbed() - .QueueAsync(e, e.GetChannel()); + await service.ExecuteCodeAsync(e, scriptBody); } [Command("getcommandinstructions")] diff --git a/src/Miki/Modules/CustomCommands/Services/CustomCommandsService.cs b/src/Miki/Modules/CustomCommands/Services/CustomCommandsService.cs index 86c089dd..3ae3d408 100644 --- a/src/Miki/Modules/CustomCommands/Services/CustomCommandsService.cs +++ b/src/Miki/Modules/CustomCommands/Services/CustomCommandsService.cs @@ -11,6 +11,7 @@ using Miki.Functional; using Miki.Modules.CustomCommands.Providers; using Miki.Modules.CustomCommands.Values; +using Miki.Patterns.Repositories; using Miki.Services; using Miki.Utility; using MiScript; @@ -66,12 +67,16 @@ public class CustomCommandsService : ICustomCommandsService private readonly IExtendedCacheClient cache; private readonly IUnitOfWork unitOfWork; private readonly IUserService userService; + + private readonly IAsyncRepository commandRepository; public CustomCommandsService(IExtendedCacheClient cache, IUnitOfWork unitOfWork, IUserService userService) { this.cache = cache; this.unitOfWork = unitOfWork; this.userService = userService; + + this.commandRepository = unitOfWork.GetRepository(); } /// @@ -345,6 +350,17 @@ public async ValueTask> GetStorageAsync(long guildId .Unwrap()); } + /// + public async ValueTask> GetGuildCommands(long guildId) + { + var commands = (await commandRepository.ListAsync()) + .Where(x => x.GuildId == guildId) + .Select(x => x.CommandName) + .ToList(); + + return commands; + } + /// /// Create the global context for the runtime. /// diff --git a/src/Miki/Modules/CustomCommands/Services/ICustomCommandsService.cs b/src/Miki/Modules/CustomCommands/Services/ICustomCommandsService.cs index df06c064..3ce069ed 100644 --- a/src/Miki/Modules/CustomCommands/Services/ICustomCommandsService.cs +++ b/src/Miki/Modules/CustomCommands/Services/ICustomCommandsService.cs @@ -44,5 +44,10 @@ public interface ICustomCommandsService /// Get the storage of the guild. /// ValueTask> GetStorageAsync(long guildId); + + /// + /// Get the custom commands for the guild. + /// + ValueTask> GetGuildCommands(long guildId); } } \ No newline at end of file