Removed manual module name setting

Modules will now be named based on their existing class name.
Their respective configuration sections are now also defined by the
same value. Documentation has been updated to reflect this.
This commit is contained in:
Noikoio 2018-03-21 23:27:19 -07:00
parent 8e80e0241b
commit 287bb33d77
21 changed files with 33 additions and 106 deletions

View file

@ -13,8 +13,8 @@ namespace Noikoio.RegexBot
{
private readonly DiscordSocketClient _client;
private readonly AsyncLogger _logger;
public abstract string Name { get; }
public string Name => this.GetType().Name;
protected DiscordSocketClient Client => _client;
public BotModule(DiscordSocketClient client)
@ -80,25 +80,4 @@ namespace Noikoio.RegexBot
public sealed override int GetHashCode() => base.GetHashCode();
public sealed override string ToString() => base.ToString();
}
/// <summary>
/// Indicates which section under an individual Discord guild configuration should be passed to the
/// module's <see cref="BotModule.ProcessConfiguration(JToken)"/> method during configuration load.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class ConfigSectionAttribute : Attribute
{
private readonly string _sectionName;
public string SectionName => _sectionName;
public ConfigSectionAttribute(string sectionName)
{
if (string.IsNullOrWhiteSpace(sectionName))
{
throw new ArgumentNullException("Configuration section name cannot be blank.");
}
_sectionName = sectionName;
}
}
}

View file

@ -162,16 +162,12 @@ namespace Noikoio.RegexBot
Dictionary<BotModule, object> customConfs = new Dictionary<BotModule, object>();
foreach (var item in _bot.Modules)
{
var attr = item.GetType().GetTypeInfo()
.GetMethod("ProcessConfiguration").GetCustomAttribute<ConfigSectionAttribute>();
if (attr == null)
{
await SLog("No additional configuration for " + item.Name);
continue;
}
var section = sconf[attr.SectionName];
var confSection = item.Name;
var section = sconf[confSection];
if (section == null)
{
// Section not in config. Do not call loader method.
await SLog("Additional configuration not defined for " + item.Name);
continue;
}
@ -191,8 +187,7 @@ namespace Noikoio.RegexBot
customConfs.Add(item, result);
}
// Switch to using new data
// Switch to new configuration
List<Tuple<Regex, string[]>> rulesfinal = new List<Tuple<Regex, string[]>>();
newservers.Add(new ServerConfig(sid, mods, new ReadOnlyDictionary<BotModule, object>(customConfs)));
}

View file

@ -15,8 +15,6 @@ namespace Noikoio.RegexBot.EntityCache
{
private readonly DatabaseConfig _db;
public override string Name => nameof(EntityCache);
public Module(DiscordSocketClient client) : base(client)
{
if (RegexBot.Config.DatabaseAvailable)

View file

@ -16,15 +16,12 @@ namespace Noikoio.RegexBot.Module.AutoMod
/// </remarks>
class AutoMod : BotModule
{
public override string Name => "AutoMod";
public AutoMod(DiscordSocketClient client) : base(client)
{
client.MessageReceived += CMessageReceived;
client.MessageUpdated += CMessageUpdated;
}
[ConfigSection("automod")]
public override async Task<object> ProcessConfiguration(JToken configSection)
{
List<ConfigItem> rules = new List<ConfigItem>();

View file

@ -22,8 +22,6 @@ namespace Noikoio.RegexBot.Module.AutoRespond
partial class AutoRespond : BotModule
{
#region BotModule implementation
public override string Name => "AutoRespond";
public AutoRespond(DiscordSocketClient client) : base(client)
{
client.MessageReceived += Client_MessageReceived;
@ -41,8 +39,7 @@ namespace Noikoio.RegexBot.Module.AutoRespond
foreach (var def in defs)
await Task.Run(async () => await ProcessMessage(arg, def));
}
[ConfigSection("autoresponses")]
public override async Task<object> ProcessConfiguration(JToken configSection)
{
var responses = new List<ConfigItem>();

View file

@ -12,8 +12,6 @@ namespace Noikoio.RegexBot.Module.DMLogger
/// </summary>
class DMLogger : BotModule
{
public override string Name => nameof(DMLogger);
public DMLogger(DiscordSocketClient client) : base(client)
{
client.MessageReceived += Client_MessageReceived;

View file

@ -14,8 +14,6 @@ namespace Noikoio.RegexBot.Module.EntryAutoRole
/// </summary>
class EntryAutoRole : BotModule
{
public override string Name => "EntryAutoRole";
private List<AutoRoleEntry> _roleWaitlist;
private object _roleWaitLock = new object();
@ -37,8 +35,7 @@ namespace Noikoio.RegexBot.Module.EntryAutoRole
_workerCancel = new CancellationTokenSource();
Task.Factory.StartNew(Worker, _workerCancel.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
[ConfigSection("EntryAutoRole")]
public override Task<object> ProcessConfiguration(JToken configSection)
{
if (configSection.Type != JTokenType.Object)

View file

@ -25,7 +25,7 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
// "notifymsg" - Message to send to the target user being acted upon. Default message is used
// if the value is not specified. If a blank value is given, the feature is disabled.
// Takes the special values $s for server name and $r for reason text.
protected BanKick(CommandListener l, string label, JObject conf, CommandMode mode) : base(l, label, conf)
protected BanKick(ModCommands l, string label, JObject conf, CommandMode mode) : base(l, label, conf)
{
_mode = mode;
_forceReason = conf["forcereason"]?.Value<bool>() ?? false;
@ -199,13 +199,13 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
class Ban : BanKick
{
public Ban(CommandListener l, string label, JObject conf)
public Ban(ModCommands l, string label, JObject conf)
: base(l, label, conf, CommandMode.Ban) { }
}
class Kick : BanKick
{
public Kick(CommandListener l, string label, JObject conf)
public Kick(ModCommands l, string label, JObject conf)
: base(l, label, conf, CommandMode.Kick) { }
}
}

View file

@ -7,7 +7,7 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
class ConfReload : Command
{
// No configuration.
public ConfReload(CommandListener l, string label, JObject conf) : base(l, label, conf) { }
public ConfReload(ModCommands l, string label, JObject conf) : base(l, label, conf) { }
// Usage: (command)
public override async Task Invoke(SocketGuild g, SocketMessage msg)

View file

@ -19,7 +19,7 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
// "role" - string; The given role that applies to this command.
// "successmsg" - string; Messages to display on command success. Overrides default.
protected RoleManipulation(CommandListener l, string label, JObject conf, CommandMode mode) : base(l, label, conf)
protected RoleManipulation(ModCommands l, string label, JObject conf, CommandMode mode) : base(l, label, conf)
{
_mode = mode;
var rolestr = conf["role"]?.Value<string>();
@ -123,11 +123,11 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
class RoleAdd : RoleManipulation
{
public RoleAdd(CommandListener l, string label, JObject conf) : base(l, label, conf, CommandMode.Add) { }
public RoleAdd(ModCommands l, string label, JObject conf) : base(l, label, conf, CommandMode.Add) { }
}
class RoleDel : RoleManipulation
{
public RoleDel(CommandListener l, string label, JObject conf) : base(l, label, conf, CommandMode.Del) { }
public RoleDel(ModCommands l, string label, JObject conf) : base(l, label, conf, CommandMode.Del) { }
}
}

View file

@ -9,7 +9,7 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
{
// No configuration at the moment.
// TODO: Whitelist/blacklist - to limit which channels it can "say" into
public Say(CommandListener l, string label, JObject conf) : base(l, label, conf) {
public Say(ModCommands l, string label, JObject conf) : base(l, label, conf) {
DefaultUsageMsg = $"{this.Trigger} [channel] [message]\n"
+ "Displays the given message exactly as specified to the given channel.";
}

View file

@ -10,7 +10,7 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
// No configuration.
// TODO bring in some options from BanKick. Particularly custom success msg.
// TODO when ModLogs fully implemented, add a reason?
public Unban(CommandListener l, string label, JObject conf) : base(l, label, conf) {
public Unban(ModCommands l, string label, JObject conf) : base(l, label, conf) {
DefaultUsageMsg = $"{this.Trigger} [user or user ID]\n"
+ "Unbans the given user, allowing them to rejoin the server.";
}

View file

@ -16,20 +16,20 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
/// <summary>
/// Base class for a command within the module.
/// After implementing, don't forget to add a reference to
/// <see cref="CreateInstance(CommandListener, JProperty)"/>.
/// <see cref="CreateInstance(ModCommands, JProperty)"/>.
/// </summary>
[DebuggerDisplay("Command def: {Label}")]
abstract class Command
{
private readonly CommandListener _mod;
private readonly ModCommands _mod;
private readonly string _label;
private readonly string _command;
protected CommandListener Module => _mod;
protected ModCommands Module => _mod;
public string Label => _label;
public string Trigger => _command;
public Command(CommandListener l, string label, JObject conf)
public Command(ModCommands l, string label, JObject conf)
{
_mod = l;
_label = label;
@ -58,7 +58,7 @@ namespace Noikoio.RegexBot.Module.ModCommands.Commands
{ "delrole", typeof(RoleDel) }
});
public static Command CreateInstance(CommandListener root, JProperty def)
public static Command CreateInstance(ModCommands root, JProperty def)
{
string label = def.Name;
if (string.IsNullOrWhiteSpace(label)) throw new RuleImportException("Label cannot be blank.");

View file

@ -16,7 +16,7 @@ namespace Noikoio.RegexBot.Module.ModCommands
public ReadOnlyDictionary<string, Command> Commands => _cmdInstances;
public ConfigItem(CommandListener instance, JToken inconf)
public ConfigItem(ModCommands instance, JToken inconf)
{
if (inconf.Type != JTokenType.Object)
{

View file

@ -17,11 +17,9 @@ namespace Noikoio.RegexBot.Module.ModCommands
/// done in a way that would easily allow for flexibility and modifications during runtime.
/// Thus, reinventing the wheel right here.
/// </remarks>
class CommandListener : BotModule
class ModCommands : BotModule
{
public override string Name => "ModCommands";
public CommandListener(DiscordSocketClient client) : base(client)
public ModCommands(DiscordSocketClient client) : base(client)
{
client.MessageReceived += Client_MessageReceived;
}
@ -34,7 +32,6 @@ namespace Noikoio.RegexBot.Module.ModCommands
if (arg.Channel is IGuildChannel) await CommandCheckInvoke(arg);
}
[ConfigSection("ModCommands")]
public override async Task<object> ProcessConfiguration(JToken configSection)
{
// Constructor throws exception on config errors

View file

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Discord.WebSocket;
using Newtonsoft.Json.Linq;
namespace Noikoio.RegexBot.Module.ModLogs
{
/// <summary>
/// Listens for Discord-based events and writes them to the log (database).
/// Additionally writes certain messages to a designated logging channel if configured.
/// </summary>
class EventListener : BotModule
{
public override string Name => "ModLogs";
public EventListener(DiscordSocketClient client) : base(client)
{
}
[ConfigSection("modlogs")]
public override Task<object> ProcessConfiguration(JToken configSection)
{
throw new NotImplementedException();
}
}
}

View file

@ -11,8 +11,6 @@ namespace Noikoio.RegexBot.Module.ModLogs
/// </summary>
class ModLogs : BotModule
{
public override string Name => "ModLogs";
private readonly MessageCache _msgCacheInstance;
public ModLogs(DiscordSocketClient client) : base(client)
@ -26,8 +24,7 @@ namespace Noikoio.RegexBot.Module.ModLogs
// TODO add handlers for detecting joins, leaves, bans, kicks, user edits (nick/username/discr)
// TODO add handler for processing the log query command
}
[ConfigSection("ModLogs")]
public override async Task<object> ProcessConfiguration(JToken configSection)
{
if (configSection.Type != JTokenType.Object)

View file

@ -56,7 +56,7 @@ namespace Noikoio.RegexBot
{
new Module.DMLogger.DMLogger(_client),
new Module.AutoMod.AutoMod(_client),
new Module.ModCommands.CommandListener(_client),
new Module.ModCommands.ModCommands(_client),
new Module.AutoRespond.AutoRespond(_client),
new Module.EntryAutoRole.EntryAutoRole(_client),

View file

@ -6,7 +6,7 @@ AutoMod is set up by defining rules within a JSON object named `automod` within
Sample within a [server definition](serverdef.html):
```
"automod": {
"AutoMod": {
"Delete bilingual pirates": {
"regex": [ "pira(te|cy)", "pirat(a|ería)", ],
"response": [

View file

@ -6,7 +6,7 @@ This may seem like a redundant feature, given that the same can be accomplished
Sample within a [server definition](serverdef.html):
```
"autorespond": {
"AutoRespond": {
"Help command": {
"regex": "^!help$",
"reply": "You can't be helped. Try again in 45 minutes.",

View file

@ -26,8 +26,8 @@ The following is a list of accepted members within a server definition.
* id (*integer*) - **Required.** A value containing the server's [unique ID](https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-).
* name (*string*) - Preferably a readable version of the server's name. Not used for anything other than internal logging.
* moderators (*[entity list](entitylist.html)*) - A list of entities to consider as moderators. Actions done by members of this list are able to execute *ModCommands* commands and are exempt from certain *AutoMod* rules. See their respective pages for more details.
* [automod](automod.html) - See respective page.
* [autoresponses](autorespond.html) - See respective page.
* [AutoMod](automod.html) - See respective page.
* [AutoRespond](autorespond.html) - See respective page.
* [EntryAutoRole](entryautorole.html) - See respective page.
* [ModCommands](modcommands.html) - See respective page.
* [ModLogs](modlogs.html) - See respective page.