From c4dc24f6be88e0a0e1ded53fb2defddd68fa3322 Mon Sep 17 00:00:00 2001 From: Nikolay Kochulin Date: Sat, 16 Nov 2019 18:08:32 +0000 Subject: [PATCH] Basic verb command --- ...{CommandRouter.cs => ChatCommandRouter.cs} | 0 JetKarmaBot/Commands/AwardTypeCommand.cs | 55 ++++++++++ .../Commands/AwardTypeManage/TestCommand.cs | 23 ++++ JetKarmaBot/JetKarmaBot.cs | 17 ++- JetKarmaBot/Program.cs | 1 + JetKarmaBot/Services/LogInfo.cs | 9 ++ JetKarmaBot/VerbCommandRouter.cs | 102 ++++++++++++++++++ JetKarmaBot/lang/be-BY.json | 2 + JetKarmaBot/lang/en-US.json | 2 + JetKarmaBot/lang/ru-RU.json | 2 + 10 files changed, 203 insertions(+), 10 deletions(-) rename JetKarmaBot/{CommandRouter.cs => ChatCommandRouter.cs} (100%) create mode 100644 JetKarmaBot/Commands/AwardTypeCommand.cs create mode 100644 JetKarmaBot/Commands/AwardTypeManage/TestCommand.cs create mode 100644 JetKarmaBot/VerbCommandRouter.cs diff --git a/JetKarmaBot/CommandRouter.cs b/JetKarmaBot/ChatCommandRouter.cs similarity index 100% rename from JetKarmaBot/CommandRouter.cs rename to JetKarmaBot/ChatCommandRouter.cs diff --git a/JetKarmaBot/Commands/AwardTypeCommand.cs b/JetKarmaBot/Commands/AwardTypeCommand.cs new file mode 100644 index 0000000..613c79f --- /dev/null +++ b/JetKarmaBot/Commands/AwardTypeCommand.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JetKarmaBot.Services; +using Perfusion; +using Telegram.Bot; +using Telegram.Bot.Args; + +namespace JetKarmaBot.Commands +{ + public class AwardTypeCommand : IChatCommand + { + public IReadOnlyCollection Names => new[] { "at" }; + + public string Description => "Manage custom award types."; + + public string DescriptionID => "jetkarmabot.at.help"; + + public VerbCommandRouter Router; + [Inject] TelegramBotClient Client { get; set; } + [Inject] Localization Locale { get; set; } + [Inject] KarmaContextFactory Db { get; set; } + + public AwardTypeCommand(IContainer c, VerbCommandRouter r) + { + Router = r; + r.Add(c.GetInstance()); + } + + public IReadOnlyCollection Arguments => new[] { + new ChatCommandArgument() { + Name="verb", + Required=true, + Type=ChatCommandArgumentType.String, + Description="The action to perform.", + DescriptionID="jetkarmabot.at.verbhelp" + } + }; + + public async Task Execute(CommandString cmd, MessageEventArgs args) + { + using (var db = Db.GetContext()) + { + var currentLocale = Locale[(await db.Chats.FindAsync(args.Message.Chat.Id)).Locale]; + if (!await Router.Process(cmd, args)) + { + await Client.SendTextMessageAsync( + args.Message.Chat.Id, + currentLocale["jetkarmabot.at.err"], + replyToMessageId: args.Message.MessageId); + } + return true; + } + } + } +} \ No newline at end of file diff --git a/JetKarmaBot/Commands/AwardTypeManage/TestCommand.cs b/JetKarmaBot/Commands/AwardTypeManage/TestCommand.cs new file mode 100644 index 0000000..4c0459f --- /dev/null +++ b/JetKarmaBot/Commands/AwardTypeManage/TestCommand.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Telegram.Bot.Args; + +namespace JetKarmaBot.Commands.AwardTypeManage +{ + public class TestCommand : IChatCommand + { + public IReadOnlyCollection Names => new[] { "test" }; + + public string Description => "test"; + + public string DescriptionID => "test"; + + public IReadOnlyCollection Arguments => Array.Empty(); + + public Task Execute(CommandString cmd, MessageEventArgs messageEventArgs) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/JetKarmaBot/JetKarmaBot.cs b/JetKarmaBot/JetKarmaBot.cs index 77b9ecf..c1da837 100644 --- a/JetKarmaBot/JetKarmaBot.cs +++ b/JetKarmaBot/JetKarmaBot.cs @@ -84,18 +84,15 @@ namespace JetKarmaBot async Task InitCommands(IContainer c) { - c.Add(); - c.Add(); - c.Add(); - c.Add(); - c.Add(); - c.Add(); Commands = c.GetInstance(); await Commands.Start(); - foreach (IChatCommand cmd in c.GetInstances()) - { - Commands.Add(cmd); - } + Commands.Add(c.GetInstance()); + Commands.Add(c.GetInstance()); + Commands.Add(c.GetInstance()); + Commands.Add(c.GetInstance()); + Commands.Add(c.GetInstance()); + Commands.Add(c.GetInstance()); + Commands.Add(c.GetInstance()); } #endregion diff --git a/JetKarmaBot/Program.cs b/JetKarmaBot/Program.cs index ed77599..1bfec8e 100644 --- a/JetKarmaBot/Program.cs +++ b/JetKarmaBot/Program.cs @@ -29,6 +29,7 @@ namespace JetKarmaBot var dbOptions = new DbContextOptionsBuilder() .UseMySql(cfg.ConnectionString + (cfg.ConnectionString.EndsWith(";") ? "" : ";") + "TreatTinyAsBoolean=false"); c.AddInfo(new LogInfo()); + c.AddInfo(new VerbInfo()); if (cfg.SqlDebug) { dbOptions = dbOptions.UseLoggerFactory(c.GetInstance()); diff --git a/JetKarmaBot/Services/LogInfo.cs b/JetKarmaBot/Services/LogInfo.cs index 6a55117..3afd0a1 100644 --- a/JetKarmaBot/Services/LogInfo.cs +++ b/JetKarmaBot/Services/LogInfo.cs @@ -19,4 +19,13 @@ namespace JetKarmaBot + (t.GenericTypeArguments.Length > 0 ? "<" + string.Join(",", t.GenericTypeArguments.Select(getTypeName)) + ">" : ""); } } + public class VerbInfo : ObjectInfo + { + public override ObjectInfo Clone() => new VerbInfo(); + + public override object GetInstance(IContainer c, Type requester = null) + { + return c.ResolveObject(new VerbCommandRouter(requester != null ? requester.Name : "")); + } + } } \ No newline at end of file diff --git a/JetKarmaBot/VerbCommandRouter.cs b/JetKarmaBot/VerbCommandRouter.cs new file mode 100644 index 0000000..7687c4c --- /dev/null +++ b/JetKarmaBot/VerbCommandRouter.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using JetKarmaBot.Commands; +using NLog; +using Perfusion; +using Telegram.Bot.Args; + +namespace JetKarmaBot +{ + public class VerbCommandRouter + { + Dictionary commands = new Dictionary(); + [Inject] private Logger log; + string superCommand; + public VerbCommandRouter(string supercommand) + { + superCommand = supercommand; + } + + public Task Process(CommandString cs, MessageEventArgs args) + { + log.Debug($"(verb for {superCommand}) Processing verb"); + if (cs.Parameters.Length < 1) + { + log.Debug($"(verb for {superCommand}) too few arguments"); + return Task.FromResult(false); + } + CommandString ncs = new CommandString(cs.Parameters[0], cs.Parameters.Skip(1).ToArray()); + try + { + if (commands.ContainsKey(ncs.Command)) + { + log.Debug($"(verb for {superCommand}) Handling via {commands[ncs.Command].GetType().Name}"); + return commands[ncs.Command].Execute(ncs, args); + } + } + catch (Exception e) + { + log.Error($"(verb for {superCommand}) Error while handling verb {ncs.Command}!"); + log.Error(e); + return Task.FromResult(true); //Don't trigger message + } + + return Task.FromResult(false); + } + + public void Add(IChatCommand c) + { + log.ConditionalTrace($"(verb for {superCommand}) Adding command {c.GetType().Name}"); + foreach (var name in c.Names) + { + log.ConditionalTrace($"(verb for {superCommand}) Mounting {c.GetType().Name} to {name}"); + if (commands.ContainsKey(name)) + throw new Exception($"command collision for name {name}, commands {commands[name].GetType()} and {c.GetType()}"); + commands[name] = c; + } + } + + internal string GetHelpText(Locale loc) + { + List pieces = new List(); + foreach (IChatCommand c in commands.Values.Distinct()) + { + string build = ""; + List names = c.Names.ToList(); + for (int i = 0; i < names.Count - 1; i++) + { + build = build + "/" + names[i] + "\n"; + } + build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " " + getLocalizedCMDDesc(c, loc) + ""; + pieces.Add(build); + } + return string.Join("\n", pieces); + } + + internal string GetHelpTextFor(string commandname, Locale loc) + { + IChatCommand c = commands[commandname]; + string build = ""; + List names = c.Names.ToList(); + for (int i = 0; i < names.Count - 1; i++) + { + build = build + "/" + names[i] + "\n"; + } + build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " " + getLocalizedCMDDesc(c, loc) + "\n"; + build += string.Join("\n", c.Arguments.Select(ca => (!ca.Required ? "[" : "") + ca.Name + (!ca.Required ? "]" : "") + ": " + getLocalizedCMDArgDesc(ca, loc) + "")); + return build; + } + private string getLocalizedCMDDesc(IChatCommand cmd, Locale loc) + { + if (loc.ContainsKey(cmd.DescriptionID)) return loc[cmd.DescriptionID]; + else return cmd.Description; + } + private string getLocalizedCMDArgDesc(ChatCommandArgument arg, Locale loc) + { + if (loc.ContainsKey(arg.DescriptionID)) return loc[arg.DescriptionID]; + else return arg.Description; + } + } +} \ No newline at end of file diff --git a/JetKarmaBot/lang/be-BY.json b/JetKarmaBot/lang/be-BY.json index a4dcad1..2c411a8 100644 --- a/JetKarmaBot/lang/be-BY.json +++ b/JetKarmaBot/lang/be-BY.json @@ -39,6 +39,8 @@ "jetkarmabot.leaderboard.help": "Табліца лідэраў па колькасці ўзнагарод", "jetkarmabot.leaderboard.awardtypehelp": "Тып ўзнагароды, па якой падасца справаздачу.", "jetkarmabot.leaderboard.specifictext": "Перадавікі ў намінацыі \"{0}\":", + "jetkarmabot.at.help": "Кіруе карыстацкімі тыпамі узнагарод.", + "jetkarmabot.at.verbhelp": "Дзеянне, якое выканаць.", "jetkarmabot.star.nominative": "зорачка", "jetkarmabot.star.accusative": "зорачку" } diff --git a/JetKarmaBot/lang/en-US.json b/JetKarmaBot/lang/en-US.json index b7d1a96..efd3014 100644 --- a/JetKarmaBot/lang/en-US.json +++ b/JetKarmaBot/lang/en-US.json @@ -38,6 +38,8 @@ "jetkarmabot.leaderboard.help": "Shows the people with the most of a specific award.", "jetkarmabot.leaderboard.awardtypehelp": "The awardtype to show a leaderboard for.", "jetkarmabot.leaderboard.specifictext": "Leaderboard for {0}:", + "jetkarmabot.at.help": "Manages custom award types.", + "jetkarmabot.at.verbhelp": "The action to perform.", "jetkarmabot.star.nominative": "star", "jetkarmabot.star.accusative": "star" } diff --git a/JetKarmaBot/lang/ru-RU.json b/JetKarmaBot/lang/ru-RU.json index 9febf45..de5317e 100644 --- a/JetKarmaBot/lang/ru-RU.json +++ b/JetKarmaBot/lang/ru-RU.json @@ -38,6 +38,8 @@ "jetkarmabot.leaderboard.help": "Таблица лидеров по количеству наград", "jetkarmabot.leaderboard.awardtypehelp": "Тип награды, по которой покажется отчет.", "jetkarmabot.leaderboard.specifictext": "Передовики в номинации \"{0}\":", + "jetkarmabot.at.help": "Управляет пользовательскими типами наград.", + "jetkarmabot.at.verbhelp": "Действие, которое выполнить.", "jetkarmabot.star.nominative": "звездочка", "jetkarmabot.star.accusative": "звездочку" }