using Discord; using Discord.WebSocket; using Noikoio.RegexBot.ConfigItem; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Threading.Tasks; namespace Noikoio.RegexBot.Feature.AutoMod.Responses { /// /// Base class for all Response classes. /// Contains helper methods for use by response code. /// [DebuggerDisplay("Response: {_cmdline}")] abstract class Response { private readonly Rule _rule; private readonly string _cmdline; protected Rule Rule => _rule; private DiscordSocketClient Client => _rule.Discord; public string CmdLine => _cmdline; public string CmdArg0 { get { int i = _cmdline.IndexOf(' '); if (i != -1) return _cmdline.Substring(0, i); return _cmdline; } } /// /// Deriving constructor should do validation of incoming . /// public Response(Rule rule, string cmdline) { _rule = rule; _cmdline = cmdline; } public abstract Task Invoke(SocketMessage msg); protected async Task Log(string text) { int dl = _cmdline.IndexOf(' '); var prefix = _cmdline.Substring(0, dl); await Rule.Logger(prefix + ": " + text); } #region Config loading private static readonly ReadOnlyDictionary _commands = new ReadOnlyDictionary( new Dictionary(StringComparer.OrdinalIgnoreCase) { // Define all accepted commands and their corresponding types here { "say", typeof(Say) }, { "send", typeof(Say) }, { "report", typeof(Report) }, { "addrole", typeof(RoleManipulation) }, { "grantrole", typeof(RoleManipulation) }, { "delrole", typeof(RoleManipulation) }, { "removerole", typeof(RoleManipulation) }, { "revokerole", typeof(RoleManipulation) }, { "delete", typeof(Remove) }, { "remove", typeof(Remove) }, { "kick", typeof(Kick) }, { "ban", typeof(Ban) } }); public static Response[] ReadConfiguration(Rule r, IEnumerable responses) { var result = new List(); foreach (var line in responses) { if (string.IsNullOrWhiteSpace(line)) throw new RuleImportException("Empty response line"); int i = line.IndexOf(' '); string basecmd; if (i != -1) basecmd = line.Substring(0, i); else basecmd = line; Type rt; if (!_commands.TryGetValue(basecmd, out rt)) throw new RuleImportException($"'{basecmd}' is not a valid response"); var newresponse = Activator.CreateInstance(rt, r, line) as Response; if (newresponse == null) throw new Exception("An unknown error occurred when attempting to create a new Response object."); result.Add(newresponse); } return result.ToArray(); } #endregion #region Helper methods /// /// Receives a string (beginning with @ or #) and returns an object /// suitable for sending out messages /// protected async Task GetMessageTargetAsync(string targetName, SocketMessage m) { const string AEShort = "Target name is too short."; EntityType et; if (targetName.Length <= 1) throw new ArgumentException(AEShort); if (targetName[0] == '#') et = EntityType.Channel; else if (targetName[0] == '@') et = EntityType.User; else throw new ArgumentException("Target is not specified to be either a channel or user."); targetName = targetName.Substring(1); if (targetName == "_") { if (et == EntityType.Channel) return m.Channel; else return await m.Author.GetOrCreateDMChannelAsync(); } EntityName ei = new EntityName(targetName, et); SocketGuild g = ((SocketGuildUser)m.Author).Guild; if (et == EntityType.Channel) { if (targetName.Length < 2 || targetName.Length > 100) throw new ArgumentException(AEShort); foreach (var ch in g.TextChannels) { if (ei.Id.HasValue) { if (ei.Id.Value == ch.Id) return ch; } else { if (string.Equals(ei.Name, ch.Name, StringComparison.OrdinalIgnoreCase)) return ch; } } } else { if (ei.Id.HasValue) { // The easy way return await Client.GetUser(ei.Id.Value).GetOrCreateDMChannelAsync(); } // The hard way foreach (var u in g.Users) { if (string.Equals(ei.Name, u.Username, StringComparison.OrdinalIgnoreCase) || string.Equals(ei.Name, u.Nickname, StringComparison.OrdinalIgnoreCase)) { return await u.GetOrCreateDMChannelAsync(); } } } return null; } protected string ProcessText(string input, SocketMessage m) { // Maybe in the future this will do more. // For now, replaces all instances of @_ with the message sender. return input .Replace("@_", m.Author.Mention) .Replace("@\\_", "@_"); } #endregion } }