Many small changes/fixes, and switching autoreporting to webhook

This commit is contained in:
Noikoio 2018-04-05 15:46:15 -07:00
parent 6f2ba92009
commit f4ba54e39b
4 changed files with 49 additions and 39 deletions

View file

@ -1,6 +1,9 @@
using Newtonsoft.Json.Linq;
using Discord;
using Discord.Webhook;
using Newtonsoft.Json.Linq;
using Noikoio.RegexBot.ConfigItem;
using System;
using System.Text.RegularExpressions;
namespace Noikoio.RegexBot.Module.ModLogs
{
@ -10,16 +13,21 @@ namespace Noikoio.RegexBot.Module.ModLogs
class GuildState
{
// Event reporting
private readonly EntityName _rptTarget;
private DiscordWebhookClient _rptTarget;
private LogEntry.LogType _rptTypes;
private ulong _rptIgnore;
/// <summary>
/// Target reporting channel.
/// Webhook for log reporting.
/// </summary>
public EntityName? RptTarget => _rptTarget;
public DiscordWebhookClient RptTarget => _rptTarget;
/// <summary>
/// Event types to send to the reporting channel.
/// </summary>
public LogEntry.LogType RptTypes => _rptTypes;
/// <summary>
/// Channel for AutoReporting to ignore.
/// </summary>
public ulong RptIgnore => _rptIgnore;
// Query command
private readonly string _qCmd; // command name
@ -45,19 +53,21 @@ namespace Noikoio.RegexBot.Module.ModLogs
var arcfg = cfgRoot["AutoReporting"];
if (arcfg == null)
{
_rptTarget = default(EntityName); // NOTE: Change this if EntityName becomes a class later
_rptTarget = null;
_rptTypes = LogEntry.LogType.None;
_rptIgnore = 0;
}
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.");
string whurl = arcfg["WebhookUrl"]?.Value<string>();
if (whurl == null) throw new RuleImportException("Webhook URL for log reporting is not specified.");
var wrx = WebhookUrlParts.Match(whurl);
if (!wrx.Success) throw new RuleImportException("Webhook URL for log reporting is not valid.");
var wid = ulong.Parse(wrx.Groups[1].Value);
var wtk = wrx.Groups[2].Value;
_rptTarget = new DiscordWebhookClient(wid, wtk,
new Discord.Rest.DiscordRestConfig() { DefaultRetryMode = RetryMode.RetryRatelimit });
// TODO figure out how to hook up the webhook client's log event
// TODO make optional
string rpval = arcfg["Events"]?.Value<string>();
@ -69,6 +79,13 @@ namespace Noikoio.RegexBot.Module.ModLogs
{
throw new RuleImportException(ex.Message);
}
var ignoreId = arcfg["CacheIgnore"]?.Value<string>();
if (string.IsNullOrWhiteSpace(ignoreId)) _rptIgnore = 0;
else if (!ulong.TryParse(ignoreId, out _rptIgnore))
{
throw new RuleImportException("CacheIgnore was not set to a valid channel ID.");
}
}
else
{
@ -112,5 +129,8 @@ namespace Noikoio.RegexBot.Module.ModLogs
throw new RuleImportException("Section for QueryCommand is not correctly defined.");
}
}
private static Regex WebhookUrlParts =
new Regex(@"https?:\/\/discordapp.com\/api\/webhooks\/(\d+)\/([^/]+)?", RegexOptions.Compiled);
}
}

View file

@ -38,7 +38,8 @@ namespace Noikoio.RegexBot.Module.ModLogs
#region Event handling
private async Task Client_MessageReceived(SocketMessage arg)
{
if (arg.Author.IsBot) return;
if (arg.Author.IsWebhook) return;
if (arg.Channel is IDMChannel) return; // No DMs
await AddOrUpdateCacheItemAsync(arg);
}
@ -46,13 +47,11 @@ namespace Noikoio.RegexBot.Module.ModLogs
private async Task Client_MessageUpdated(
Cacheable<IMessage, ulong> before, SocketMessage after, ISocketMessageChannel channel)
{
if (after.Author.IsBot) return;
if (after.Author.IsWebhook) return;
// We only want channel messages
if (after is SocketUserMessage afterMsg && !(afterMsg is IDMChannel))
{
if (after.Author.IsBot) return;
// We're not interested in all message updates, only those that leave a timestamp.
if (!afterMsg.EditedTimestamp.HasValue) return;
}
@ -88,11 +87,9 @@ namespace Noikoio.RegexBot.Module.ModLogs
// Check if this feature is enabled before doing anything else.
var cfg = _outGetConfig(guildId);
if (cfg == null) return;
if (isDelete && (cfg.RptTypes & LogEntry.LogType.MsgDelete) == 0) return;
if (!isDelete && (cfg.RptTypes & LogEntry.LogType.MsgEdit) == 0) return;
// Ignore if it's a message being deleted withing the reporting channel.
if (isDelete && cfg.RptTarget.Value.Id.Value == ch.Id) return;
if (cfg.RptIgnore != 0 && ch.Id == cfg.RptIgnore) return; // ignored channel
if (isDelete && (cfg.RptTypes & LogEntry.LogType.MsgDelete) == 0) return; // not reporting deletions
if (!isDelete && (cfg.RptTypes & LogEntry.LogType.MsgEdit) == 0) return; // not reporting edits
// Regardless of delete or edit, it is necessary to get the equivalent database information.
EntityCache.CacheUser ucd = null;
@ -131,16 +128,9 @@ namespace Noikoio.RegexBot.Module.ModLogs
cacheMsg = "**Database error. See log.**";
}
// Find target channel, prepare and send out message
var g = _dClient.GetGuild(guildId);
var rptTargetChannel = g?.GetTextChannel(cfg.RptTarget.Value.Id.Value);
if (rptTargetChannel == null)
{
await _outLog($"WARNING: Reporting channel {cfg.RptTarget.Value.ToString()} could not be determined.");
return;
}
// Prepare and send out message
var em = CreateReportEmbed(isDelete, ucd, messageId, ch, (cacheMsg, editMsg));
await rptTargetChannel.SendMessageAsync("", embed: em);
await cfg.RptTarget.SendMessageAsync("", embeds: new Embed[] { em });
}
const int ReportCutoffLength = 500;
@ -173,8 +163,7 @@ namespace Noikoio.RegexBot.Module.ModLogs
Fields = new System.Collections.Generic.List<EmbedFieldBuilder>(),
Footer = new EmbedFooterBuilder()
{
Text = "User ID: " + ucd?.UserId.ToString() ?? "Unknown",
IconUrl = _dClient.CurrentUser.GetAvatarUrl()
Text = "User ID: " + ucd?.UserId.ToString() ?? "Unknown"
},
Timestamp = DateTimeOffset.UtcNow
};

View file

@ -40,8 +40,7 @@ namespace Noikoio.RegexBot.Module.ModLogs
}
var conf = new GuildState((JObject)configSection);
if (conf.RptTypes != LogEntry.LogType.None)
await Log("Enabled event autoreporting to " + conf.RptTarget);
if (conf.RptTypes != LogEntry.LogType.None) await Log("Enabled event autoreporting.");
return conf;
}

View file

@ -8,7 +8,8 @@ Sample within a [server definition](serverdef.html):
"ModLogs": {
"AutoReporting": {
"Channel": "#99999999:mod-events",
"Events": "msgedit,msgdelete"
"Events": "msgedit,msgdelete",
"CacheIgnore": 1230000000000
}
}
```
@ -24,9 +25,10 @@ The following values can be defined within the `ModLogs` object:
As its name implies, the `AutoReporting` section allows the bot operator to configure automatic reporting of one or more events as they occur to a designated reporting channel. Omitting this section in configuration disables this function.
The following values are accepted within this object:
* Channel (*string*) - **Required.** The channel name in which to report events.
* The channel ID is currently required to be specified (see [EntityList](entitylist.html)). This limitation will be removed in a future update.
* Events (*string*) - **Required** for now. A comma-separated list of event types to be sent to the reporting channel.
* WebhookUrl (*string*) - **Required.** A webhook URL to be used by the bot for sending events.
* Events (*string*) - **Required** at the moment. A comma-separated list of event types to be sent to the reporting channel.
* CacheIgnore (*number*) - Channel (ID) to ignore for MsgEdit and MsgDelete autoreporting. (Optional.)
* It is **highly recommended** that the reporting channel be specified, otherwise deleting a report within it will cause another report to appear.
#### Event types
All events fall into one of a number of categories.