From ae7b8574fbc8eb4c27a300efe3a16549aa27fb15 Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Thu, 16 Jun 2022 20:49:46 -0300 Subject: [PATCH] initial implementation --- .../AutoModeration/AutoModActionType.cs | 26 +++++ .../Guilds/AutoModeration/AutoModEventType.cs | 19 ++++ .../AutoModeration/AutoModRuleAction.cs | 36 ++++++ .../AutoModeration/AutoModRuleProperties.cs | 78 +++++++++++++ .../AutoModeration/AutoModTriggerType.cs | 34 ++++++ .../Guilds/AutoModeration/IAutoModRule.cs | 84 ++++++++++++++ .../AutoModeration/KeywordPresetTypes.cs | 29 +++++ .../API/Common/ActionMetadata.cs | 18 +++ .../API/Common/AutoModAction.cs | 18 +++ .../API/Common/AutoModerationRule.cs | 45 ++++++++ .../API/Common/TriggerMetadata.cs | 18 +++ .../API/Rest/CreateAutoModRuleParams.cs | 20 ++++ .../API/Rest/ModifyAutoModRuleParams.cs | 20 ++++ src/Discord.Net.Rest/DiscordRestApiClient.cs | 52 +++++++++ .../Entities/Guilds/GuildHelper.cs | 37 +++++++ .../BaseSocketClient.Events.cs | 19 ++++ .../DiscordSocketClient.cs | 28 +++++ .../Entities/Guilds/SocketAutoModRule.cs | 104 ++++++++++++++++++ .../Entities/Guilds/SocketGuild.cs | 1 + 19 files changed, 686 insertions(+) create mode 100644 src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModActionType.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModEventType.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleAction.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModTriggerType.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/AutoModeration/IAutoModRule.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/AutoModeration/KeywordPresetTypes.cs create mode 100644 src/Discord.Net.Rest/API/Common/ActionMetadata.cs create mode 100644 src/Discord.Net.Rest/API/Common/AutoModAction.cs create mode 100644 src/Discord.Net.Rest/API/Common/AutoModerationRule.cs create mode 100644 src/Discord.Net.Rest/API/Common/TriggerMetadata.cs create mode 100644 src/Discord.Net.Rest/API/Rest/CreateAutoModRuleParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyAutoModRuleParams.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Guilds/SocketAutoModRule.cs diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModActionType.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModActionType.cs new file mode 100644 index 000000000..29e95d918 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModActionType.cs @@ -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 + { + /// + /// Blocks the content of a message according to the rule. + /// + BlockMessage = 1, + + /// + /// Logs user content to a specified channel. + /// + SendAlertMessage = 2, + + /// + /// Timeout user for a specified duration. + /// + Timeout = 3, + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModEventType.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModEventType.cs new file mode 100644 index 000000000..3585dece1 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModEventType.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// An enum indecating in what event context a rule should be checked. + /// + public enum AutoModEventType + { + /// + /// When a member sends or edits a message in the guild + /// + MessageSend = 1 + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleAction.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleAction.cs new file mode 100644 index 000000000..7d7f3622a --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleAction.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents an action that will be preformed if a user breaks an . + /// + public class AutoModRuleAction + { + /// + /// Gets the type for this action. + /// + public AutoModActionType Type { get; } + + /// + /// Get the channel id on which to post alerts. + /// + public ulong? ChannelId { get; } + + /// + /// Gets the duration of which a user will be timed out for breaking this rule. + /// + public TimeSpan? TimeoutDuration { get; } + + internal AutoModRuleAction(AutoModActionType type, ulong? channelId, int? duration) + { + Type = type; + ChannelId = channelId; + TimeoutDuration = duration.HasValue ? TimeSpan.FromSeconds(duration.Value) : null; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs new file mode 100644 index 000000000..e91276947 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Provides properties used to modify a . + /// + public class AutoModRuleProperties + { + /// + /// Gets or sets the name for the rule. + /// + public Optional Name { get; set; } + + /// + /// Gets or sets the event type for the rule. + /// + public Optional EventType { get; set; } + + /// + /// Gets or sets the trigger type for the rule. + /// + public Optional TriggerType { get; set; } + + /// + /// Gets or sets the keyword filter for the rule. + /// + public Optional KeywordFilter { get; set; } + + /// + /// Gets or sets the presets for the rule. + /// + public Optional Presets { get; set; } + + /// + /// Gets or sets the actions for the rule. + /// + public Optional Actions { get; set; } + + /// + /// Gets or sets whether or not the rule is enabled. + /// + public Optional Enabled { get; set; } + + /// + /// Gets or sets the exempt roles for the rule. + /// + public Optional ExemptRoles { get; set; } + + /// + /// Gets or sets the exempt channels for the rule. + /// + public Optional ExemptChannels { get; set; } + } + + public class AutoModRuleActionProperties + { + /// + /// Gets or sets the type for this action. + /// + public AutoModActionType Type { get; set; } + + /// + /// Get or sets the channel id on which to post alerts. + /// + public ulong? ChannelId { get; set; } + + /// + /// Gets or sets the duration of which a user will be timed out for breaking this rule. + /// + public TimeSpan? TimeoutDuration { get; set; } + } + +} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModTriggerType.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModTriggerType.cs new file mode 100644 index 000000000..8922d697a --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModTriggerType.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// An enum representing the type of content which can trigger the rule. + /// + public enum AutoModTriggerType + { + /// + /// Check if content contains words from a user defined list of keywords + /// + Keyword = 1, + + /// + /// Check if content contains any harmful links + /// + HarmfulLink = 2, + + /// + /// Check if content represents generic spam + /// + Spam = 3, + + /// + /// Check if content contains words from internal pre-defined wordsets + /// + KeywordPreset = 4, + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/IAutoModRule.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/IAutoModRule.cs new file mode 100644 index 000000000..b28cc7c05 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/IAutoModRule.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a auto mod rule within a guild. + /// + public interface IAutoModRule : ISnowflakeEntity, IDeletable + { + /// + /// Gets the guild id on which this rule exists. + /// + ulong GuildId { get; } + + /// + /// Get the name of this rule. + /// + string Name { get; } + + /// + /// Gets the id of the user who created this use. + /// + ulong CreatorId { get; } + + /// + /// Gets the event type on which this rule is triggered. + /// + AutoModEventType EventType { get; } + + /// + /// Gets the trigger type on which this rule executes. + /// + AutoModTriggerType TriggerType { get; } + + /// + /// Gets the keyword filter for this rule. + /// + /// + /// This collection will be empty if is not + /// . + /// + public IReadOnlyCollection KeywordFilter { get; } + + /// + /// Gets the preset keyword types for this rule. + /// + /// + /// This collection will be empty if is not + /// . + /// + public IReadOnlyCollection Presets { get; } + + /// + /// Gets a collection of actions that will be preformed if a user breaks this rule. + /// + IReadOnlyCollection Actions { get; } + + /// + /// Gets whether or not this rule is enabled. + /// + bool Enabled { get; } + + /// + /// Gets a collection of role ids that are exempt from this rule. + /// + IReadOnlyCollection ExemptRoles { get; } + + /// + /// Gets a collection of channel ids that are exempt from this rule. + /// + IReadOnlyCollection ExemptChannels { get; } + + /// + /// Modifies this rule. + /// + /// The delegate containing the properties to modify the rule with. + /// The options to be used when sending the request. + Task ModifyAsync(Action func, RequestOptions options = null); + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/KeywordPresetTypes.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/KeywordPresetTypes.cs new file mode 100644 index 000000000..a399cdc6f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/KeywordPresetTypes.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// An enum representing preset filter types. + /// + public enum KeywordPresetTypes + { + /// + /// Words that may be considered forms of swearing or cursing. + /// + Profanity = 1, + + /// + /// Words that refer to sexually explicit behavior or activity. + /// + SexualContent = 2, + + /// + /// Personal insults or words that may be considered hate speech. + /// + Slurs = 3, + } +} diff --git a/src/Discord.Net.Rest/API/Common/ActionMetadata.cs b/src/Discord.Net.Rest/API/Common/ActionMetadata.cs new file mode 100644 index 000000000..148c54cdd --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ActionMetadata.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class ActionMetadata + { + [JsonProperty("channel_id")] + public Optional ChannelId { get; set; } + + [JsonProperty("duration_seconds")] + public Optional DurationSeconds { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/AutoModAction.cs b/src/Discord.Net.Rest/API/Common/AutoModAction.cs new file mode 100644 index 000000000..a6fec3c01 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AutoModAction.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class AutoModAction + { + [JsonProperty("type")] + public AutoModActionType Type { get; set; } + + [JsonProperty("metadata")] + public Optional Metadata { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/AutoModerationRule.cs b/src/Discord.Net.Rest/API/Common/AutoModerationRule.cs new file mode 100644 index 000000000..f30af5bee --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AutoModerationRule.cs @@ -0,0 +1,45 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class AutoModerationRule + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("creator_id")] + public ulong CreatorId { get; set; } + + [JsonProperty("event_type")] + public AutoModEventType EventType { get; set; } + + [JsonProperty("trigger_type")] + public AutoModTriggerType TriggerType { get; set; } + + [JsonProperty("trigger_metadata")] + public TriggerMetadata TriggerMetadata { get; set; } + + [JsonProperty("actions")] + public AutoModAction[] Actions { get; set; } + + [JsonProperty("enabled")] + public bool Enabled { get; set; } + + [JsonProperty("exempt_roles")] + public ulong[] ExemptRoles { get; set; } + + [JsonProperty("exempt_channels")] + public ulong[] ExemptChannels { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/TriggerMetadata.cs b/src/Discord.Net.Rest/API/Common/TriggerMetadata.cs new file mode 100644 index 000000000..c10108459 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/TriggerMetadata.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class TriggerMetadata + { + [JsonProperty("keyword_filter")] + public string[] KeywordFilter { get; set; } + + [JsonProperty("presets")] + public KeywordPresetTypes[] Presets { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/CreateAutoModRuleParams.cs b/src/Discord.Net.Rest/API/Rest/CreateAutoModRuleParams.cs new file mode 100644 index 000000000..d126d4078 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/CreateAutoModRuleParams.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Rest +{ + internal class CreateAutoModRuleParams + { + public string Name { get; set; } + public AutoModEventType EventType { get; set; } + public AutoModTriggerType TriggerType { get; set; } + public Optional TriggerMetadata { get; set; } + public AutoModAction[] Actions { get; set; } + public Optional Enabled { get; set; } + public Optional ExemptRoles { get; set; } + public Optional ExemptChannels { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyAutoModRuleParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyAutoModRuleParams.cs new file mode 100644 index 000000000..3cdb4eac5 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyAutoModRuleParams.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Rest +{ + internal class ModifyAutoModRuleParams + { + public Optional Name { get; set; } + public Optional EventType { get; set; } + public Optional TriggerType { get; set; } + public Optional TriggerMetadata { get; set; } + public Optional Actions { get; set; } + public Optional Enabled { get; set; } + public Optional ExemptRoles { get; set; } + public Optional ExemptChannels { get; set; } + } +} diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index e179675ba..08adbc509 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -2074,6 +2074,58 @@ namespace Discord.API #endregion + #region Guild AutoMod + + public async Task GetGuildAutoModRulesAsync(ulong guildId, RequestOptions options) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendAsync("GET", () => $"guilds/{guildId}/auto-moderation/rules", new BucketIds(guildId), options: options); + } + + public async Task GetGuildAutoModRuleAsync(ulong guildId, ulong ruleId, RequestOptions options) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(ruleId, 0, nameof(ruleId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendAsync("GET", () => $"guilds/{guildId}/auto-moderation/rules/{ruleId}", new BucketIds(guildId), options: options); + } + + public async Task CreateGuildAutoModRuleAsync(ulong guildId, CreateAutoModRuleParams args, RequestOptions options) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendJsonAsync("POST", () => $"guilds/{guildId}/auto-moderation", args, new BucketIds(guildId), options: options); + } + + public async Task ModifyGuildAutoModRuleAsync(ulong guildId, ulong ruleId, ModifyAutoModRuleParams args, RequestOptions options) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(ruleId, 0, nameof(ruleId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendJsonAsync("PATCH", () => $"guilds/{guildId}/auto-moderation/{ruleId}", args, new BucketIds(guildId), options: options); + } + + public async Task DeleteGuildAutoModRuleAsync(ulong guildId, ulong ruleId, RequestOptions options) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(ruleId, 0, nameof(ruleId)); + + options = RequestOptions.CreateOrClone(options); + + await SendAsync("DELETE", () => $"guilds/{guildId}/auto-moderation/rules/{ruleId}", new BucketIds(guildId), options: options); + } + + #endregion + #region Users public async Task GetUserAsync(ulong userId, RequestOptions options = null) { diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 8bab35937..943f83b75 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -943,5 +943,42 @@ namespace Discord.Rest } #endregion + + #region Auto Mod + public static Task ModifyRuleAsync(BaseDiscordClient client, IAutoModRule rule, Action func, RequestOptions options) + { + var args = new AutoModRuleProperties(); + func(args); + + var apiArgs = new API.Rest.ModifyAutoModRuleParams + { + Actions = args.Actions.IsSpecified ? args.Actions.Value.Select(x => new API.AutoModAction() + { + Type = x.Type, + Metadata = x.ChannelId.HasValue || x.TimeoutDuration.HasValue ? new API.ActionMetadata + { + ChannelId = x.ChannelId ?? Optional.Unspecified, + DurationSeconds = x.TimeoutDuration.HasValue ? (int)Math.Floor(x.TimeoutDuration.Value.TotalSeconds) : Optional.Unspecified + } : Optional.Unspecified + }).ToArray() : Optional.Unspecified, + Enabled = args.Enabled, + EventType = args.EventType, + ExemptChannels = args.ExemptChannels, + ExemptRoles = args.ExemptRoles, + Name = args.Name, + TriggerType = args.TriggerType, + TriggerMetadata = args.KeywordFilter.IsSpecified || args.Presets.IsSpecified ? new API.TriggerMetadata + { + KeywordFilter = args.KeywordFilter.GetValueOrDefault(Array.Empty()), + Presets = args.Presets.GetValueOrDefault(Array.Empty()) + } : Optional.Unspecified + }; + + return client.ApiClient.ModifyGuildAutoModRuleAsync(rule.GuildId, rule.Id, apiArgs, options); + } + + public static Task DeleteRuleAsync(BaseDiscordClient client, IAutoModRule rule, RequestOptions options) + => client.ApiClient.DeleteGuildAutoModRuleAsync(rule.GuildId, rule.Id, options); + #endregion } } diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs index c47591418..fca975629 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs @@ -877,5 +877,24 @@ namespace Discord.WebSocket } internal readonly AsyncEvent> _guildStickerDeleted = new AsyncEvent>(); #endregion + + #region AutoModeration + + public event Func AutoModRuleCreated + { + add => _autoModRuleCreated.Add(value); + remove => _autoModRuleCreated.Remove(value); + } + internal readonly AsyncEvent> _autoModRuleCreated = new AsyncEvent>(); + + public event Func AutoModRuleDelted + { + add => _autoModRuleDeleted.Add(value); + remove => _autoModRuleDeleted.Remove(value); + } + internal readonly AsyncEvent> _autoModRuleDeleted = new AsyncEvent>(); + + //public event Func + #endregion } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 5743d9abd..99f51b8f4 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -2839,6 +2839,34 @@ namespace Discord.WebSocket #endregion + #region Auto Moderation + + case "AUTO_MODERATION_RULE_CREATE": + { + + } + break; + + case "AUTO_MODERATION_RULE_UPDATE": + { + + } + break; + + case "AUTO_MODERATION_RULE_DELETE": + { + + } + break; + + case "AUTO_MODERATION_RULE_EXECUTE": + { + + } + break; + + #endregion + #region Ignored (User only) case "CHANNEL_PINS_ACK": await _gatewayLogger.DebugAsync("Ignored Dispatch (CHANNEL_PINS_ACK)").ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketAutoModRule.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketAutoModRule.cs new file mode 100644 index 000000000..5dab651f8 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketAutoModRule.cs @@ -0,0 +1,104 @@ +using Discord.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.AutoModerationRule; + +namespace Discord.WebSocket +{ + public class SocketAutoModRule : SocketEntity, IAutoModRule + { + /// + /// Gets the guild that this rule is in. + /// + public SocketGuild Guild { get; } + + /// + public string Name { get; private set; } + + /// + /// Gets the creator of this rule. + /// + public SocketGuildUser Creator { get; private set; } + + /// + public AutoModEventType EventType { get; private set; } + + /// + public AutoModTriggerType TriggerType { get; private set; } + + /// + public IReadOnlyCollection KeywordFilter { get; private set; } + + /// + public IReadOnlyCollection Presets { get; private set; } + + /// + public IReadOnlyCollection Actions { get; private set; } + + /// + public bool Enabled { get; private set; } + + /// + /// Gets the roles that are exempt from this rule. + /// + public IReadOnlyCollection ExemptRoles { get; private set; } + + /// + /// Gets the channels that are exempt from this rule. + /// + public IReadOnlyCollection ExemptChannels { get; private set; } + + /// + public DateTimeOffset CreatedAt + => SnowflakeUtils.FromSnowflake(Id); + + private ulong _creatorId; + + internal SocketAutoModRule(DiscordSocketClient discord, ulong id, SocketGuild guild) + : base(discord, id) + { + Guild = guild; + } + + internal static SocketAutoModRule Create(DiscordSocketClient discord, SocketGuild guild, Model model) + { + var entity = new SocketAutoModRule(discord, model.Id, guild); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + Name = model.Name; + _creatorId = model.CreatorId; + Creator ??= Guild.GetUser(_creatorId); + EventType = model.EventType; + TriggerType = model.TriggerType; + KeywordFilter = model.TriggerMetadata.KeywordFilter.ToImmutableArray(); + Presets = model.TriggerMetadata.Presets.ToImmutableArray(); + Actions = model.Actions.Select(x => new AutoModRuleAction(x.Type, x.Metadata.GetValueOrDefault()?.ChannelId.ToNullable(), x.Metadata.GetValueOrDefault()?.DurationSeconds.ToNullable())).ToImmutableArray(); + Enabled = model.Enabled; + ExemptRoles = model.ExemptRoles.Select(x => Guild.GetRole(x)).ToImmutableArray(); + ExemptChannels = model.ExemptChannels.Select(x => Guild.GetChannel(x)).ToImmutableArray(); + } + + /// + public Task ModifyAsync(Action func, RequestOptions options = null) + => GuildHelper.ModifyRuleAsync(Discord, this, func, options); + + /// + public Task DeleteAsync(RequestOptions options = null) + => GuildHelper.DeleteRuleAsync(Discord, this, options); + + #region IAutoModRule + IReadOnlyCollection IAutoModRule.ExemptRoles => ExemptRoles.Select(x => x.Id).ToImmutableArray(); + IReadOnlyCollection IAutoModRule.ExemptChannels => ExemptChannels.Select(x => x.Id).ToImmutableArray(); + ulong IAutoModRule.GuildId => Guild.Id; + ulong IAutoModRule.CreatorId => _creatorId; + #endregion + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 9ce2f507a..811dd8b1c 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -43,6 +43,7 @@ namespace Discord.WebSocket private ConcurrentDictionary _voiceStates; private ConcurrentDictionary _stickers; private ConcurrentDictionary _events; + //private ConcurrentDictionary _automodRules; private ImmutableArray _emotes; private AudioClient _audioClient;