Added proper MessageCache configuration
Though it's now capable of loading configuration for the full ModLogs module, not all features are available yet.
This commit is contained in:
parent
419370c379
commit
6ca73a9b6b
4 changed files with 166 additions and 42 deletions
24
Module/ModLogs/EventType.cs
Normal file
24
Module/ModLogs/EventType.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Noikoio.RegexBot.Module.ModLogs
|
||||
{
|
||||
// Types of non-custom events that can be referenced by ModLogs in configuration.
|
||||
// Enum value names will show themselves to the user in the form of strings valid in configuration,
|
||||
// so try not to change those without good reason.
|
||||
[Flags]
|
||||
enum EventType
|
||||
{
|
||||
None = 0x0,
|
||||
Note = 0x1,
|
||||
Warn = 0x2,
|
||||
Kick = 0x4,
|
||||
Ban = 0x8,
|
||||
JoinGuild = 0x10,
|
||||
LeaveGuild = 0x20,
|
||||
NameChange = 0x40,
|
||||
MsgEdit = 0x80,
|
||||
MsgDelete = 0x100
|
||||
}
|
||||
}
|
127
Module/ModLogs/GuildConfig.cs
Normal file
127
Module/ModLogs/GuildConfig.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Noikoio.RegexBot.ConfigItem;
|
||||
using System;
|
||||
|
||||
namespace Noikoio.RegexBot.Module.ModLogs
|
||||
{
|
||||
/// <summary>
|
||||
/// ModLogs guild-specific configuration values.
|
||||
/// </summary>
|
||||
class GuildConfig
|
||||
{
|
||||
// Event reporting
|
||||
private readonly EntityName _rptTarget;
|
||||
private EventType _rptTypes;
|
||||
/// <summary>
|
||||
/// Target reporting channel.
|
||||
/// </summary>
|
||||
public EntityName? RptTarget => _rptTarget;
|
||||
/// <summary>
|
||||
/// Event types to send to the reporting channel.
|
||||
/// </summary>
|
||||
public EventType RptTypes => _rptTypes;
|
||||
|
||||
// Query command
|
||||
private readonly string _qCmd; // command name
|
||||
private readonly EntityList _qAccess; // list of those able to issue the command
|
||||
private readonly EventType _qDefaultAnswer; // default entry types to display
|
||||
/// <summary>
|
||||
/// Query command. The first word in an incoming message, including prefix, that triggers a query.
|
||||
/// </summary>
|
||||
public string QrCommand => _qCmd;
|
||||
/// <summary>
|
||||
/// List of users permitted to invoke the query command.
|
||||
/// If null, refer to the guild's Moderators list.
|
||||
/// </summary>
|
||||
public EntityList QrPermittedUsers => _qAccess;
|
||||
/// <summary>
|
||||
/// Event types to display in a query.
|
||||
/// </summary>
|
||||
public EventType QrTypes => _qDefaultAnswer;
|
||||
|
||||
public GuildConfig(JObject cfgRoot)
|
||||
{
|
||||
// AutoReporting settings
|
||||
var arcfg = cfgRoot["AutoReporting"];
|
||||
if (arcfg == null)
|
||||
{
|
||||
_rptTarget = default(EntityName); // NOTE: Change this if EntityName becomes a class later
|
||||
_rptTypes = EventType.None;
|
||||
}
|
||||
else if (arcfg.Type == JTokenType.Object)
|
||||
{
|
||||
string chval = arcfg["Channel"]?.Value<string>();
|
||||
if (chval == null) throw new RuleImportException("Reporting channel is not defined.");
|
||||
if (!string.IsNullOrWhiteSpace(chval) && chval[0] == '#')
|
||||
_rptTarget = new EntityName(chval.Substring(1, chval.Length-1), EntityType.Channel);
|
||||
else
|
||||
throw new RuleImportException("Reporting channel is not properly defined.");
|
||||
// Require the channel's ID for now.
|
||||
if (!_rptTarget.Id.HasValue) throw new RuleImportException("Reporting channel's ID must be specified.");
|
||||
|
||||
// TODO make optional
|
||||
string rpval = arcfg["Events"]?.Value<string>();
|
||||
_rptTypes = GetTypesFromString(rpval);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuleImportException("Section for AutoReporting is not correctly defined.");
|
||||
}
|
||||
|
||||
// QueryCommand settings
|
||||
var qccfg = cfgRoot["QueryCommand"];
|
||||
if (qccfg == null)
|
||||
{
|
||||
_qCmd = null;
|
||||
_qAccess = null;
|
||||
_qDefaultAnswer = EventType.None;
|
||||
}
|
||||
else if (arcfg.Type == JTokenType.Object)
|
||||
{
|
||||
_qCmd = arcfg["Command"]?.Value<string>();
|
||||
if (string.IsNullOrWhiteSpace(_qCmd))
|
||||
throw new RuleImportException("Query command option must have a value.");
|
||||
if (_qCmd.Contains(" "))
|
||||
throw new RuleImportException("Query command must not contain spaces.");
|
||||
|
||||
var acl = arcfg["AllowedUsers"];
|
||||
if (acl == null) _qAccess = null;
|
||||
else _qAccess = new EntityList(acl);
|
||||
|
||||
// TODO make optional
|
||||
string ansval = arcfg["DefaultEvents"]?.Value<string>();
|
||||
_qDefaultAnswer = GetTypesFromString(ansval);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuleImportException("Section for QueryCommand is not correctly defined.");
|
||||
}
|
||||
}
|
||||
|
||||
public static EventType GetTypesFromString(string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
throw new RuleImportException("Types are not properly defined.");
|
||||
|
||||
var strTypes = input.Split(
|
||||
new char[] { ' ', ',', '/', '+' }, // and more?
|
||||
StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
EventType endResult = EventType.None;
|
||||
foreach (var item in strTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = Enum.Parse<EventType>(item, true);
|
||||
endResult |= result;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
throw new RuleImportException($"Unable to determine the given event type \"{item}\"");
|
||||
}
|
||||
}
|
||||
|
||||
return endResult;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,9 +9,9 @@ using System.Threading.Tasks;
|
|||
namespace Noikoio.RegexBot.Module.ModLogs
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for <see cref="ModLogs"/>. Keeps a database-backed cache of recent messages and assists
|
||||
/// Helper class for <see cref="ModLogs"/>. Keeps a database-backed cache of recent messages for use
|
||||
/// in reporting message changes and deletions, if configured to do so.
|
||||
/// Does not manipulate the moderation log managed by the main class, but rather provides supplemental features.
|
||||
/// Despite its place, it does not manipulate moderation logs. It simply pulls from the same configuration.
|
||||
/// </summary>
|
||||
class MessageCache
|
||||
{
|
||||
|
@ -66,6 +66,7 @@ namespace Noikoio.RegexBot.Module.ModLogs
|
|||
|
||||
private async Task Client_MessageDeleted(Cacheable<Discord.IMessage, ulong> msg, ISocketMessageChannel channel)
|
||||
{
|
||||
if (channel is IDMChannel) return; // No DMs
|
||||
await ProcessReportMessage(true, msg.Id, channel, null);
|
||||
}
|
||||
#endregion
|
||||
|
@ -84,11 +85,13 @@ namespace Noikoio.RegexBot.Module.ModLogs
|
|||
else return;
|
||||
|
||||
// Check if this feature is enabled before doing anything else.
|
||||
var rptTarget = _outGetConfig(guildId) as ConfigItem.EntityName?;
|
||||
if (!rptTarget.HasValue) return;
|
||||
var cfg = _outGetConfig(guildId) as GuildConfig;
|
||||
if (cfg == null) return;
|
||||
if (isDelete && (cfg.RptTypes & EventType.MsgDelete) == 0) return;
|
||||
if (!isDelete && (cfg.RptTypes & EventType.MsgEdit) == 0) return;
|
||||
|
||||
// Ignore if it's a message being deleted withing the reporting channel.
|
||||
if (isDelete && rptTarget.Value.Id.Value == ch.Id) return;
|
||||
if (isDelete && cfg.RptTarget.Value.Id.Value == ch.Id) return;
|
||||
|
||||
// Regardless of delete or edit, it is necessary to get the equivalent database information.
|
||||
EntityCache.CacheUser ucd = null;
|
||||
|
@ -128,11 +131,11 @@ namespace Noikoio.RegexBot.Module.ModLogs
|
|||
}
|
||||
|
||||
// Find target channel, prepare and send out message
|
||||
var rptTargetChannel = _dClient.GetGuild(guildId)?.GetTextChannel(rptTarget.Value.Id.Value);
|
||||
var g = _dClient.GetGuild(guildId);
|
||||
var rptTargetChannel = g?.GetTextChannel(cfg.RptTarget.Value.Id.Value);
|
||||
if (rptTargetChannel == null)
|
||||
{
|
||||
await _outLog("Target channel not found.");
|
||||
// TODO make a more descriptive error message
|
||||
await _outLog($"WARNING: Reporting channel {cfg.RptTarget.Value.ToString()} could not be determined.");
|
||||
return;
|
||||
}
|
||||
var em = CreateReportEmbed(isDelete, ucd, messageId, ch, (cacheMsg, editMsg));
|
||||
|
|
|
@ -23,9 +23,11 @@ namespace Noikoio.RegexBot.Module.ModLogs
|
|||
// Do nothing if database unavailable. The user will be informed by ProcessConfiguration.
|
||||
if (!RegexBot.Config.DatabaseAvailable) return;
|
||||
|
||||
// MessageCache (reporting of MessageEdit, MessageDelete) handled by helper class
|
||||
_msgCacheInstance = new MessageCache(client, Log, GetConfig);
|
||||
|
||||
//throw new NotImplementedException();
|
||||
// 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")]
|
||||
|
@ -33,7 +35,6 @@ namespace Noikoio.RegexBot.Module.ModLogs
|
|||
{
|
||||
if (configSection.Type != JTokenType.Object)
|
||||
throw new RuleImportException("Configuration for this section is invalid.");
|
||||
var conf = (JObject)configSection;
|
||||
|
||||
if (!RegexBot.Config.DatabaseAvailable)
|
||||
{
|
||||
|
@ -41,38 +42,7 @@ namespace Noikoio.RegexBot.Module.ModLogs
|
|||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// MessageCache testing: will store an EntityName or die trying
|
||||
EntityName? mctarget = new EntityName(conf["mctarget"].Value<string>(), EntityType.Channel);
|
||||
await Log("Enabled MessageCache test on " + mctarget.Value.ToString());
|
||||
return mctarget;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// well, not really die
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concept:
|
||||
* "ModLogs": {
|
||||
* "AutoReporting": {
|
||||
* // behavior for how to output to the reporting channel
|
||||
* // MessageCache looks for configuration values within here.
|
||||
* "Channel": "something compatible with EntityName",
|
||||
* "Events": "perhaps a single string of separated event types"
|
||||
* },
|
||||
* "QueryOptions": {
|
||||
* // Behavior for the query command (which is defined here rather than ModTools)
|
||||
* // Need to stress in the documentation that "msgedit" and "msgdelete" events
|
||||
* // are not kept and cannot be queried
|
||||
* "QueryCommand": "!modlogs",
|
||||
* "Permission": "Moderators", // either a string that says "Moderators" or an EntityList
|
||||
* "DefaultQueryEvents": "another single string of separated event types",
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
return new GuildConfig((JObject)configSection);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue