[Feature] AutoMod support (#2578)

* initial implementation

* update models

* somewhat working auto mod action executed event

* made some properties optional

* comments, rest entity, guild methods

* add placeholder methods

* started working on rule cache

* working events

* started working on rule builder

* working state

* fix null issue

* commentsssss

* public automod rules collection in a socketgulild

* forgot nullability

* update limits

* add Download func to cacheable user

* Apply suggestions from code review

* Update src/Discord.Net.Rest/DiscordRestApiClient.cs

* missing xml doc

* reworkkkk

* fix the `;` lol

---------

Co-authored-by: Quin Lynch <lynchquin@gmail.com>
Co-authored-by: Casmir <68127614+csmir@users.noreply.github.com>
This commit is contained in:
Misha133
2023-02-16 19:08:47 +03:00
committed by GitHub
parent 0c27395efd
commit 673b02dd36
26 changed files with 1478 additions and 1 deletions

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
public enum AutoModActionType
{
/// <summary>
/// Blocks the content of a message according to the rule.
/// </summary>
BlockMessage = 1,
/// <summary>
/// Logs user content to a specified channel.
/// </summary>
SendAlertMessage = 2,
/// <summary>
/// Timeout user for a specified duration.
/// </summary>
Timeout = 3,
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// An enum indecating in what event context a rule should be checked.
/// </summary>
public enum AutoModEventType
{
/// <summary>
/// When a member sends or edits a message in the guild.
/// </summary>
MessageSend = 1
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents an action that will be preformed if a user breaks an <see cref="IAutoModRule"/>.
/// </summary>
public class AutoModRuleAction
{
/// <summary>
/// Gets the type for this action.
/// </summary>
public AutoModActionType Type { get; }
/// <summary>
/// Get the channel id on which to post alerts. <see langword="null"/> if no channel has been provided.
/// </summary>
public ulong? ChannelId { get; }
/// <summary>
/// Gets the duration of which a user will be timed out for breaking this rule. <see langword="null"/> if no timeout duration has been provided.
/// </summary>
public TimeSpan? TimeoutDuration { get; }
internal AutoModRuleAction(AutoModActionType type, ulong? channelId, int? duration)
{
Type = type;
ChannelId = channelId;
TimeoutDuration = duration.HasValue ? TimeSpan.FromSeconds(duration.Value) : null;
}
}
}

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Provides properties used to modify a <see cref="IAutoModRule"/>.
/// </summary>
public class AutoModRuleProperties
{
/// <summary>
/// Returns the max keyword count for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxKeywordCount = 1000;
/// <summary>
/// Returns the max keyword length for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxKeywordLength = 60;
/// <summary>
/// Returns the max regex pattern count for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxRegexPatternCount = 10;
/// <summary>
/// Returns the max regex pattern length for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxRegexPatternLength = 260;
/// <summary>
/// Returns the max allowlist keyword count for a <see cref="AutoModTriggerType.Keyword"/> AutoMod rule allowed by Discord.
/// </summary>
public const int MaxAllowListCountKeyword = 100;
/// <summary>
/// Returns the max allowlist keyword count for a <see cref="AutoModTriggerType.KeywordPreset"/> AutoMod rule allowed by Discord.
/// </summary>
public const int MaxAllowListCountKeywordPreset = 1000;
/// <summary>
/// Returns the max allowlist keyword length for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxAllowListEntryLength = 60;
/// <summary>
/// Returns the max mention limit for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxMentionLimit = 50;
/// <summary>
/// Returns the max exempt role count for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxExemptRoles = 20;
/// <summary>
/// Returns the max exempt channel count for an AutoMod rule allowed by Discord.
/// </summary>
public const int MaxExemptChannels = 50;
/// <summary>
/// Returns the max timeout duration in seconds for an auto moderation rule action.
/// </summary>
public const int MaxTimeoutSeconds = 2419200;
/// <summary>
/// Gets or sets the name for the rule.
/// </summary>
public Optional<string> Name { get; set; }
/// <summary>
/// Gets or sets the event type for the rule.
/// </summary>
public Optional<AutoModEventType> EventType { get; set; }
/// <summary>
/// Gets or sets the trigger type for the rule.
/// </summary>
public Optional<AutoModTriggerType> TriggerType { get; set; }
/// <summary>
/// Gets or sets the keyword filter for the rule.
/// </summary>
public Optional<string[]> KeywordFilter { get; set; }
/// <summary>
/// Gets or sets regex patterns for the rule.
/// </summary>
public Optional<string[]> RegexPatterns { get; set; }
/// <summary>
/// Gets or sets the allow list for the rule.
/// </summary>
public Optional<string[]> AllowList { get; set; }
/// <summary>
/// Gets or sets total mention limit for the rule.
/// </summary>
public Optional<int> MentionLimit { get; set; }
/// <summary>
/// Gets or sets the presets for the rule. Empty if the rule has no presets.
/// </summary>
public Optional<KeywordPresetTypes[]> Presets { get; set; }
/// <summary>
/// Gets or sets the actions for the rule.
/// </summary>
public Optional<AutoModRuleActionProperties[]> Actions { get; set; }
/// <summary>
/// Gets or sets whether or not the rule is enabled.
/// </summary>
public Optional<bool> Enabled { get; set; }
/// <summary>
/// Gets or sets the exempt roles for the rule. Empty if the rule has no exempt roles.
/// </summary>
public Optional<ulong[]> ExemptRoles { get; set; }
/// <summary>
/// Gets or sets the exempt channels for the rule. Empty if the rule has no exempt channels.
/// </summary>
public Optional<ulong[]> ExemptChannels { get; set; }
}
/// <summary>
/// Provides properties used to modify a <see cref="AutoModRuleAction"/>.
/// </summary>
public class AutoModRuleActionProperties
{
/// <summary>
/// Gets or sets the type for this action.
/// </summary>
public AutoModActionType Type { get; set; }
/// <summary>
/// Get or sets the channel id on which to post alerts.
/// </summary>
public ulong? ChannelId { get; set; }
/// <summary>
/// Gets or sets the duration of which a user will be timed out for breaking this rule.
/// </summary>
public TimeSpan? TimeoutDuration { get; set; }
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// An enum representing the type of content which can trigger the rule.
/// </summary>
public enum AutoModTriggerType
{
/// <summary>
/// Check if content contains words from a user defined list of keywords.
/// </summary>
Keyword = 1,
/// <summary>
/// Check if content contains any harmful links.
/// </summary>
HarmfulLink = 2,
/// <summary>
/// Check if content represents generic spam.
/// </summary>
Spam = 3,
/// <summary>
/// Check if content contains words from internal pre-defined wordsets.
/// </summary>
KeywordPreset = 4,
/// <summary>
/// Check if content contains more unique mentions than allowed.
/// </summary>
MentionSpam = 5,
}
}

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a auto mod rule within a guild.
/// </summary>
public interface IAutoModRule : ISnowflakeEntity, IDeletable
{
/// <summary>
/// Gets the guild id on which this rule exists.
/// </summary>
ulong GuildId { get; }
/// <summary>
/// Get the name of this rule.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the id of the user who created this use.
/// </summary>
ulong CreatorId { get; }
/// <summary>
/// Gets the event type on which this rule is triggered.
/// </summary>
AutoModEventType EventType { get; }
/// <summary>
/// Gets the trigger type on which this rule executes.
/// </summary>
AutoModTriggerType TriggerType { get; }
/// <summary>
/// Gets the keyword filter for this rule.
/// </summary>
/// <remarks>
/// This collection will be empty if <see cref="TriggerType"/> is not
/// <see cref="AutoModTriggerType.Keyword"/>.
/// </remarks>
public IReadOnlyCollection<string> KeywordFilter { get; }
/// <summary>
/// Gets regex patterns for this rule. Empty if the rule has no regexes.
/// </summary>
/// <remarks>
/// This collection will be empty if <see cref="TriggerType"/> is not
/// <see cref="AutoModTriggerType.Keyword"/>.
/// </remarks>
public IReadOnlyCollection<string> RegexPatterns { get; }
/// <summary>
/// Gets the allow list patterns for this rule. Empty if the rule has no allowed terms.
/// </summary>
/// <remarks>
/// This collection will be empty if <see cref="TriggerType"/> is not
/// <see cref="AutoModTriggerType.Keyword"/>.
/// </remarks>
public IReadOnlyCollection<string> AllowList { get; }
/// <summary>
/// Gets the preset keyword types for this rule. Empty if the rule has no presets.
/// </summary>
/// <remarks>
/// This collection will be empty if <see cref="TriggerType"/> is not
/// <see cref="AutoModTriggerType.KeywordPreset"/>.
/// </remarks>
public IReadOnlyCollection<KeywordPresetTypes> Presets { get; }
/// <summary>
/// Gets the total mention limit for this rule.
/// </summary>
/// <remarks>
/// This property will be <see langword="null"/> if <see cref="TriggerType"/> is not
/// <see cref="AutoModTriggerType.MentionSpam"/>.
/// </remarks>
public int? MentionTotalLimit { get; }
/// <summary>
/// Gets a collection of actions that will be preformed if a user breaks this rule.
/// </summary>
IReadOnlyCollection<AutoModRuleAction> Actions { get; }
/// <summary>
/// Gets whether or not this rule is enabled.
/// </summary>
bool Enabled { get; }
/// <summary>
/// Gets a collection of role ids that are exempt from this rule. Empty if the rule has no exempt roles.
/// </summary>
IReadOnlyCollection<ulong> ExemptRoles { get; }
/// <summary>
/// Gets a collection of channel ids that are exempt from this rule. Empty if the rule has no exempt channels.
/// </summary>
IReadOnlyCollection<ulong> ExemptChannels { get; }
/// <summary>
/// Modifies this rule.
/// </summary>
/// <param name="func">The delegate containing the properties to modify the rule with.</param>
/// <param name="options">The options to be used when sending the request.</param>
Task ModifyAsync(Action<AutoModRuleProperties> func, RequestOptions options = null);
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// An enum representing preset filter types.
/// </summary>
public enum KeywordPresetTypes
{
/// <summary>
/// Words that may be considered forms of swearing or cursing.
/// </summary>
Profanity = 1,
/// <summary>
/// Words that refer to sexually explicit behavior or activity.
/// </summary>
SexualContent = 2,
/// <summary>
/// Personal insults or words that may be considered hate speech.
/// </summary>
Slurs = 3,
}
}

View File

@@ -1267,5 +1267,29 @@ namespace Discord
/// A task that represents the asynchronous creation operation. The task result contains a <see cref="WelcomeScreen"/>.
/// </returns>
Task<WelcomeScreen> ModifyWelcomeScreenAsync(bool enabled, WelcomeScreenChannelProperties[] channels, string description = null, RequestOptions options = null);
/// <summary>
/// Get a list of all rules currently configured for the guild.
/// </summary>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains a collection of <see cref="IAutoModRule"/>.
/// </returns>
Task<IAutoModRule[]> GetAutoModRulesAsync(RequestOptions options = null);
/// <summary>
/// Gets a single rule configured in a guild. Returns <see langword="null"/> if the rule was not found.
/// </summary>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains a <see cref="IAutoModRule"/>.
/// </returns>
Task<IAutoModRule> GetAutoModRuleAsync(ulong ruleId, RequestOptions options = null);
/// <summary>
/// Creates a new auto moderation rule.
/// </summary>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the created <see cref="IAutoModRule"/>.
/// </returns>
Task<IAutoModRule> CreateAutoModRuleAsync(Action<AutoModRuleProperties> props, RequestOptions options = null);
}
}

View File

@@ -48,13 +48,25 @@ namespace Discord
/// This intent includes GUILD_SCHEDULED_EVENT_CREATE, GUILD_SCHEDULED_EVENT_UPDATE, GUILD_SCHEDULED_EVENT_DELETE, GUILD_SCHEDULED_EVENT_USER_ADD, GUILD_SCHEDULED_EVENT_USER_REMOVE
/// </summary>
GuildScheduledEvents = 1 << 16,
/// <summary>
/// This intent includes AUTO_MODERATION_RULE_CREATE, AUTO_MODERATION_RULE_UPDATE, AUTO_MODERATION_RULE_DELETE
/// </summary>
AutoModerationConfiguration = 1 << 20,
/// <summary>
/// This intent includes AUTO_MODERATION_ACTION_EXECUTION
/// </summary>
AutoModerationActionExecution = 1 << 21,
/// <summary>
/// This intent includes all but <see cref="GuildMembers"/> and <see cref="GuildPresences"/>
/// which are privileged and must be enabled in the Developer Portal.
/// </summary>
AllUnprivileged = Guilds | GuildBans | GuildEmojis | GuildIntegrations | GuildWebhooks | GuildInvites |
GuildVoiceStates | GuildMessages | GuildMessageReactions | GuildMessageTyping | DirectMessages |
DirectMessageReactions | DirectMessageTyping | GuildScheduledEvents,
DirectMessageReactions | DirectMessageTyping | GuildScheduledEvents | AutoModerationConfiguration |
AutoModerationActionExecution,
/// <summary>
/// This intent includes all of them, including privileged ones.
/// </summary>