diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRule.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRule.cs deleted file mode 100644 index 31a7e0088..000000000 --- a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRule.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Discord -{ - /// - /// Provides properties used to create a . - /// - public class AutoModRule - { - /// - /// Gets the name for the rule. - /// - public string Name { get; } - - /// - /// Gets the event type for the rule. - /// - public AutoModEventType EventType { get; } - - /// - /// Gets the trigger type for the rule. - /// - public AutoModTriggerType TriggerType { get; } - - /// - /// Gets the keyword filter for the rule. - /// - public string[] KeywordFilter { get; } - - /// - /// Gets regex patterns for the rule. Empty if the rule has no regexes. - /// - public string[] RegexPatterns { get; } - - /// - /// Gets the allow list for the rule. Empty if the rule has no allowed terms. - /// - public string[] AllowList { get; } - - /// - /// Gets total mention limit for the rule. if not provided. - /// - public int? MentionLimit { get; } - - /// - /// Gets the presets for the rule. Empty if the rule has no presets. - /// - public KeywordPresetTypes[] Presets { get; } - - /// - /// Gets the actions for the rule. - /// - public AutoModRuleAction[] Actions { get; } - - /// - /// Gets whether or not the rule is enabled. - /// - public bool Enabled { get; } - - /// - /// Gets the exempt roles for the rule. Empty if the rule has no exempt roles. - /// - public ulong[] ExemptRoles { get; } - - /// - /// Gets the exempt channels for the rule. Empty if the rule has no exempt channels. - /// - public ulong[] ExemptChannels { get; } - - internal AutoModRule(string name, - AutoModEventType eventType, - AutoModTriggerType triggerType, - string[] keywordFilter, - string[] regexPatterns, - string[] allowList, - int? mentionLimit, - KeywordPresetTypes[] presets, - AutoModRuleAction[] actions, - bool enabled, - ulong[] exemptRoles, - ulong[] exemptChannels) - { - Name = name; - EventType = eventType; - TriggerType = triggerType; - KeywordFilter = keywordFilter; - RegexPatterns = regexPatterns; - AllowList = allowList; - MentionLimit = mentionLimit; - Presets = presets; - Actions = actions; - Enabled = enabled; - ExemptRoles = exemptRoles; - ExemptChannels = exemptChannels; - } - } - -} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs index 06af6c393..e69de29bb 100644 --- a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs @@ -1,508 +0,0 @@ -using Newtonsoft.Json.Linq; - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; - -namespace Discord; - -/// -/// A builder used to create a . -/// -public class AutoModRuleBuilder -{ - /// - /// Returns the max keyword count for an AutoMod rule allowed by Discord. - /// - public const int MaxKeywordCount = 1000; - - /// - /// Returns the max keyword length for an AutoMod rule allowed by Discord. - /// - public const int MaxKeywordLength = 60; - - /// - /// Returns the max regex pattern count for an AutoMod rule allowed by Discord. - /// - public const int MaxRegexPatternCount = 10; - - /// - /// Returns the max regex pattern length for an AutoMod rule allowed by Discord. - /// - public const int MaxRegexPatternLength = 260; - - /// - /// Returns the max allowlist keyword count for a AutoMod rule allowed by Discord. - /// - public const int MaxAllowListCountKeyword = 100; - - /// - /// Returns the max allowlist keyword count for a AutoMod rule allowed by Discord. - /// - public const int MaxAllowListCountKeywordPreset = 1000; - - /// - /// Returns the max allowlist keyword length for an AutoMod rule allowed by Discord. - /// - public const int MaxAllowListEntryLength = 60; - - /// - /// Returns the max mention limit for an AutoMod rule allowed by Discord. - /// - public const int MaxMentionLimit = 50; - - /// - /// Returns the max exempt role count for an AutoMod rule allowed by Discord. - /// - public const int MaxExemptRoles = 20; - - /// - /// Returns the max exempt channel count for an AutoMod rule allowed by Discord. - /// - public const int MaxExemptChannels = 50; - - private List _keywordFilter = new(); - private List _regexPatterns = new(); - private List _allowList = new(); - - private List _exemptRoles = new(); - private List _exemptChannels = new(); - private HashSet _presets = new(); - - private int? _mentionLimit; - - /// - /// Gets or sets the list of of an . - /// - public List KeywordFilter - { - get { return _keywordFilter; } - set - { - if (TriggerType != AutoModTriggerType.Keyword) - throw new ArgumentException(message: $"Keyword filter can only be used with 'Keyword' trigger type.", paramName: nameof(KeywordFilter)); - - if (value.Count > MaxKeywordCount) - throw new ArgumentException(message: $"Keyword count must be less than or equal to {MaxKeywordCount}.", paramName: nameof(KeywordFilter)); - - if (value.Any(x => x.Length > MaxKeywordLength)) - throw new ArgumentException(message: $"Keyword length must be less than or equal to {MaxKeywordLength}.", paramName: nameof(KeywordFilter)); - - _keywordFilter = value; - } - } - - /// - /// Gets or sets the list of of an . - /// - public List RegexPatterns - { - get { return _regexPatterns; } - set - { - if (TriggerType != AutoModTriggerType.Keyword) - throw new ArgumentException(message: $"Regex patterns can only be used with 'Keyword' trigger type.", paramName: nameof(RegexPatterns)); - - if (value.Count > MaxRegexPatternCount) - throw new ArgumentException(message: $"Regex pattern count must be less than or equal to {MaxRegexPatternCount}.", paramName: nameof(RegexPatterns)); - - if (value.Any(x => x.Length > MaxRegexPatternLength)) - throw new ArgumentException(message: $"Regex pattern must be less than or equal to {MaxRegexPatternLength}.", paramName: nameof(RegexPatterns)); - - _regexPatterns = value; - } - } - - /// - /// Gets or sets the list of of an . - /// - public List AllowList - { - get { return _allowList; } - set - { - if (TriggerType is not AutoModTriggerType.Keyword or AutoModTriggerType.KeywordPreset) - throw new ArgumentException(message: $"Allow list can only be used with 'Keyword' or 'KeywordPreset' trigger type.", paramName: nameof(AllowList)); - - if (TriggerType == AutoModTriggerType.Keyword && value.Count > MaxAllowListCountKeyword) - throw new ArgumentException(message: $"Allow list entry count must be less than or equal to {MaxAllowListCountKeyword}.", paramName: nameof(AllowList)); - - if (TriggerType == AutoModTriggerType.KeywordPreset && value.Count > MaxAllowListCountKeywordPreset) - throw new ArgumentException(message: $"Allow list entry count must be less than or equal to {MaxAllowListCountKeywordPreset}.", paramName: nameof(AllowList)); - - if (value.Any(x => x.Length > MaxAllowListEntryLength)) - throw new ArgumentException(message: $"Allow list entry length must be less than or equal to {MaxAllowListEntryLength}.", paramName: nameof(AllowList)); - - _allowList = value; - } - } - - /// - /// Gets or sets the list of of an . - /// - public List ExemptRoles - { - get { return _exemptRoles; } - set - { - if (value.Count > MaxExemptRoles) - throw new ArgumentException(message: $"Exempt roles count must be less than or equal to {MaxExemptRoles}.", paramName: nameof(RegexPatterns)); - - _exemptRoles = value; - } - } - - /// - /// Gets or sets the list of of an . - /// - public List ExemptChannels - { - get { return _exemptChannels; } - set - { - if (value.Count > MaxExemptChannels) - throw new ArgumentException(message: $"Exempt channels count must be less than or equal to {MaxExemptChannels}.", paramName: nameof(RegexPatterns)); - - _exemptChannels = value; - } - } - - /// - /// Gets or sets the hashset of of an . - /// - public HashSet Presets - { - get => _presets; - set - { - if (TriggerType != AutoModTriggerType.KeywordPreset) - throw new ArgumentException(message: $"Keyword presets scan only be used with 'KeywordPreset' trigger type.", paramName: nameof(AllowList)); - - _presets = value; - } - } - - /// - /// Gets or sets the name of an . - /// - public string Name { get; set; } - - /// - /// Gets or sets the event type of an . - /// - public AutoModEventType EventType { get; set; } = AutoModEventType.MessageSend; - - /// - /// Gets the trigger type of an . - /// - public AutoModTriggerType TriggerType { get; } - - /// - /// Gets or sets the mention limit of an . - /// - public int? MentionLimit - { - get => _mentionLimit; - set - { - if (TriggerType != AutoModTriggerType.Keyword) - throw new ArgumentException(message: $"MentionLimit can only be used with 'MentionSpam' trigger type.", paramName: nameof(MentionLimit)); - - if (value is not null && value > MaxMentionLimit) - throw new ArgumentException(message: $"Mention limit must be less than or equal to {MaxMentionLimit}.", paramName: nameof(MentionLimit)); - _mentionLimit = value; - } - } - - /// - /// Gets or sets the list of of an . - /// - public List Actions = new(); - - /// - /// Gets or sets the enabled status of an . - /// - public bool Enabled { get; set; } = false; - - /// - /// Initializes a new instance of used to create a new . - /// - /// The trigger type of an - public AutoModRuleBuilder(AutoModTriggerType type) - { - TriggerType = type; - } - - /// - /// Sets the name of an . - /// - /// The current builder. - public AutoModRuleBuilder WithName(string name) - { - Name = name; - return this; - } - - /// - /// Sets the enabled status of an . - /// - /// The current builder. - public AutoModRuleBuilder WithEnabled(bool enabled) - { - Enabled = enabled; - return this; - } - - /// - /// Sets the event type of an . - /// - /// The current builder. - public AutoModRuleBuilder WithEventType(AutoModEventType eventType) - { - EventType = eventType; - return this; - } - - /// - /// Sets the mention limit of an . - /// - /// The current builder. - public AutoModRuleBuilder WithMentionLimit(int limit) - { - MentionLimit = limit; - return this; - } - - /// - /// Adds a keyword to an . - /// - /// The current builder. - public AutoModRuleBuilder AddKeyword(string keyword) - { - if (TriggerType != AutoModTriggerType.Keyword) - throw new ArgumentException(message: $"Keyword filter can only be used with 'Keyword' trigger type."); - - if (KeywordFilter.Count >= MaxKeywordCount) - throw new ArgumentException(message: $"Keyword count must be less than or equal to {MaxKeywordCount}."); - - if (keyword.Length > MaxKeywordLength) - throw new ArgumentException(message: $"Keyword length must be less than or equal to {MaxKeywordLength}."); - - KeywordFilter.Add(keyword); - - return this; - } - - /// - /// Adds a allow list keyword to an . - /// - /// The current builder. - public AutoModRuleBuilder AddAllowListKeyword(string keyword) - { - if (TriggerType is not AutoModTriggerType.Keyword or AutoModTriggerType.KeywordPreset) - throw new ArgumentException(message: $"Allow list can only be used with 'Keyword' or 'KeywordPreset' trigger type."); - - if (TriggerType == AutoModTriggerType.Keyword && AllowList.Count >= MaxAllowListCountKeyword) - throw new ArgumentException(message: $"Allow list entry count must be less than or equal to {MaxAllowListCountKeyword}."); - - if (TriggerType == AutoModTriggerType.KeywordPreset && AllowList.Count > MaxAllowListCountKeywordPreset) - throw new ArgumentException(message: $"Allow list entry count must be less than or equal to {MaxAllowListCountKeywordPreset}."); - - if (keyword.Length > MaxAllowListEntryLength) - throw new ArgumentException(message: $"Allow list entry length must be less than or equal to {MaxAllowListEntryLength}."); - - AllowList.Add(keyword); - - return this; - } - - /// - /// Adds a to an . - /// - /// The current builder. - public AutoModRuleBuilder AddKeywordPreset(KeywordPresetTypes type) - { - if (TriggerType != AutoModTriggerType.KeywordPreset) - throw new ArgumentException(message: $"Keyword presets scan only be used with 'KeywordPreset' trigger type.", paramName: nameof(AllowList)); - - Presets.Add(type); - return this; - } - - /// - /// Adds a regex pattern to an . - /// - /// The current builder. - public AutoModRuleBuilder AddRegexPattern(string regex) - { - if (TriggerType != AutoModTriggerType.Keyword) - throw new ArgumentException(message: $"Regex patterns can only be used with 'Keyword' trigger type."); - - if (RegexPatterns.Count >= MaxRegexPatternCount) - throw new ArgumentException(message: $"Regex pattern count must be less than or equal to {MaxRegexPatternCount}."); - - if (regex.Length > MaxRegexPatternLength) - throw new ArgumentException(message: $"Regex pattern must be less than or equal to {MaxRegexPatternLength}."); - - RegexPatterns.Add(regex); - - return this; - } - - /// - /// Adds an exempt to an . - /// - /// The current builder. - public AutoModRuleBuilder AddExemptRole(IRole role) - { - AddExemptRole(role.Id); - return this; - } - - /// - /// Adds a exempt role with id keyword to an . - /// - /// The current builder. - public AutoModRuleBuilder AddExemptRole(ulong roleId) - { - ExemptRoles.Add(roleId); - return this; - } - - /// - /// Adds an exempt keyword to an . - /// - /// The current builder. - public AutoModRuleBuilder AddExemptChannel(IMessageChannel channel) - { - AddExemptChannel(channel.Id); - return this; - } - - /// - /// Adds an exempt channel with id keyword to an . - /// - /// The current builder. - public AutoModRuleBuilder AddExemptChannel(ulong channelId) - { - ExemptChannels.Add(channelId); - return this; - } - - /// - /// Adds an to an . - /// - /// The current builder. - public AutoModRuleBuilder AddAction(AutoModRuleActionBuilder builder) - { - Actions.Add(builder); - return this; - } - - /// - /// Creates a new instance of with data from a . - /// - /// The new builder. - public static AutoModRuleBuilder FromAutoModRule(IAutoModRule rule) - => new(rule.TriggerType) - { - Name = rule.Name, - AllowList = rule.AllowList.ToList(), - RegexPatterns = rule.RegexPatterns.ToList(), - KeywordFilter = rule.KeywordFilter.ToList(), - Presets = new HashSet(rule.Presets), - ExemptChannels = rule.ExemptChannels.ToList(), - ExemptRoles = rule.ExemptRoles.ToList(), - Actions = rule.Actions.Select(AutoModRuleActionBuilder.FromModel).ToList(), - MentionLimit = rule.MentionTotalLimit, - Enabled = rule.Enabled, - EventType = rule.EventType - }; - - /// - /// Builds the into ready to be sent. - /// - /// - public AutoModRule Build() - { - if (string.IsNullOrWhiteSpace(Name)) - throw new ArgumentException("Name of the rule must not be empty", paramName: nameof(Name)); - - Preconditions.AtLeast(1, Actions.Count, nameof(Actions), "Auto moderation rule must have at least 1 action"); - - if(TriggerType is AutoModTriggerType.Keyword) - Preconditions.AtLeast(1, KeywordFilter.Count + RegexPatterns.Count, nameof(KeywordFilter), "Auto moderation rule must have at least 1 keyword or regex pattern"); - - if(TriggerType is AutoModTriggerType.MentionSpam && MentionLimit is null) - throw new ArgumentException("Mention limit must not be empty", paramName: nameof(MentionLimit)); - - return new(Name, - EventType, - TriggerType, - KeywordFilter.ToArray(), - RegexPatterns.ToArray(), - AllowList.ToArray(), - MentionLimit, - Presets.ToArray(), - Actions.Select(x => new AutoModRuleAction(x.Type, x.ChannelId, (int?)x.TimeoutDuration?.TotalSeconds)).ToArray(), - Enabled, - ExemptRoles.ToArray(), - ExemptChannels.ToArray()); - } - -} - -/// -/// Represents an action that will be preformed if a user breaks an . -/// -public class AutoModRuleActionBuilder -{ - private const int MaxTimeoutSeconds = 2419200; - - private TimeSpan? _timeoutDuration; - - /// - /// Gets or sets the type for this action. - /// - public AutoModActionType Type { get; } - - /// - /// Get or sets the channel id on which to post alerts. - /// - /// - /// This property will be if is not - /// - public ulong? ChannelId { get; set; } - - /// - /// Gets or sets the duration of which a user will be timed out for breaking this rule. - /// - /// - /// This property will be if is not - /// - public TimeSpan? TimeoutDuration - { - get => _timeoutDuration; - set - { - if (value is { TotalSeconds: > MaxTimeoutSeconds }) - throw new ArgumentException(message: $"Field count must be less than or equal to {MaxTimeoutSeconds}.", paramName: nameof(TimeoutDuration)); - - _timeoutDuration = value; - } - } - - /// - /// Creates a new instance of used to define actions of an . - /// - public AutoModRuleActionBuilder(AutoModActionType type, ulong? channelId = null, TimeSpan? duration = null) - { - Type = type; - ChannelId = channelId; - TimeoutDuration = duration; - } - - internal static AutoModRuleActionBuilder FromModel(AutoModRuleAction action) - => new(action.Type, action.ChannelId, action.TimeoutDuration); -} diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs index 71d9650b5..9af9832e5 100644 --- a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs +++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleProperties.cs @@ -11,6 +11,61 @@ namespace Discord /// public class AutoModRuleProperties { + /// + /// Returns the max keyword count for an AutoMod rule allowed by Discord. + /// + public const int MaxKeywordCount = 1000; + + /// + /// Returns the max keyword length for an AutoMod rule allowed by Discord. + /// + public const int MaxKeywordLength = 60; + + /// + /// Returns the max regex pattern count for an AutoMod rule allowed by Discord. + /// + public const int MaxRegexPatternCount = 10; + + /// + /// Returns the max regex pattern length for an AutoMod rule allowed by Discord. + /// + public const int MaxRegexPatternLength = 260; + + /// + /// Returns the max allowlist keyword count for a AutoMod rule allowed by Discord. + /// + public const int MaxAllowListCountKeyword = 100; + + /// + /// Returns the max allowlist keyword count for a AutoMod rule allowed by Discord. + /// + public const int MaxAllowListCountKeywordPreset = 1000; + + /// + /// Returns the max allowlist keyword length for an AutoMod rule allowed by Discord. + /// + public const int MaxAllowListEntryLength = 60; + + /// + /// Returns the max mention limit for an AutoMod rule allowed by Discord. + /// + public const int MaxMentionLimit = 50; + + /// + /// Returns the max exempt role count for an AutoMod rule allowed by Discord. + /// + public const int MaxExemptRoles = 20; + + /// + /// Returns the max exempt channel count for an AutoMod rule allowed by Discord. + /// + public const int MaxExemptChannels = 50; + + /// + /// Returns the max timeout duration in seconds for an auto moderation rule action. + /// + public const int MaxTimeoutSeconds = 2419200; + /// /// Gets or sets the name for the rule. /// diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index 9f7c02bd5..a0b95759d 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -1290,6 +1290,6 @@ namespace Discord /// /// A task that represents the asynchronous creation operation. The task result contains the created . /// - Task CreateAutoModRuleAsync(AutoModRule props, RequestOptions options = null); + Task CreateAutoModRuleAsync(Action props, RequestOptions options = null); } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 1706608c6..bd7fbc70c 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -1039,7 +1039,7 @@ namespace Discord.Rest { Enabled = enabled, Description = description, - WelcomeChannels = channels?.Select(ch => new API.WelcomeScreenChannel + WelcomeChannels = channels?.Select(ch => new API.WelcomeScreenChannel { ChannelId = ch.Id, Description = ch.Description, @@ -1050,7 +1050,7 @@ namespace Discord.Rest var model = await client.ApiClient.ModifyGuildWelcomeScreenAsync(args, guild.Id, options); - if(model.WelcomeChannels.Length == 0) + if (model.WelcomeChannels.Length == 0) return null; return new WelcomeScreen(model.Description.GetValueOrDefault(null), model.WelcomeChannels.Select( @@ -1064,8 +1064,123 @@ namespace Discord.Rest #region Auto Mod - public static async Task CreateAutoModRuleAsync(IGuild guild, CreateAutoModRuleParams args, BaseDiscordClient client, RequestOptions options) - => await client.ApiClient.CreateGuildAutoModRuleAsync(guild.Id, args, options); + public static async Task CreateAutoModRuleAsync(IGuild guild, Action func, BaseDiscordClient client, RequestOptions options) + { + var args = new AutoModRuleProperties(); + func(args); + + if (!args.TriggerType.IsSpecified) + throw new ArgumentException(message: $"AutoMod rule must have a specified type.", paramName: nameof(args.TriggerType)); + + if (!args.Name.IsSpecified || string.IsNullOrWhiteSpace(args.Name.Value)) + throw new ArgumentException("Name of the rule must not be empty", paramName: nameof(args.Name)); + + Preconditions.AtLeast(1, args.Actions.GetValueOrDefault(Array.Empty()).Length, nameof(args.Actions), "Auto moderation rule must have at least 1 action"); + + #region Keyword Validations + + if (args.RegexPatterns.IsSpecified) + { + if (args.TriggerType.Value is not AutoModTriggerType.Keyword) + throw new ArgumentException(message: $"Regex patterns can only be used with 'Keyword' trigger type.", paramName: nameof(args.RegexPatterns)); + + Preconditions.AtMost(args.RegexPatterns.Value.Length, AutoModRuleProperties.MaxRegexPatternCount, nameof(args.RegexPatterns), $"Regex pattern count must be less than or equal to {AutoModRuleProperties.MaxRegexPatternCount}."); + + if (args.RegexPatterns.Value.Any(x => x.Length > AutoModRuleProperties.MaxRegexPatternLength)) + throw new ArgumentException(message: $"Regex pattern must be less than or equal to {AutoModRuleProperties.MaxRegexPatternLength}.", paramName: nameof(args.RegexPatterns)); + } + + if (args.KeywordFilter.IsSpecified) + { + if (args.TriggerType.Value != AutoModTriggerType.Keyword) + throw new ArgumentException(message: $"Keyword filter can only be used with 'Keyword' trigger type.", paramName: nameof(args.KeywordFilter)); + + Preconditions.AtMost(args.KeywordFilter.Value.Length, AutoModRuleProperties.MaxKeywordCount, nameof(args.KeywordFilter), $"Keyword count must be less than or equal to {AutoModRuleProperties.MaxKeywordCount}"); + + if (args.KeywordFilter.Value.Any(x => x.Length > AutoModRuleProperties.MaxKeywordLength)) + throw new ArgumentException(message: $"Keyword length must be less than or equal to {AutoModRuleProperties.MaxKeywordLength}.", paramName: nameof(args.KeywordFilter)); + } + + if (args.TriggerType.Value is AutoModTriggerType.Keyword) + Preconditions.AtLeast(args.KeywordFilter.GetValueOrDefault(Array.Empty()).Length + args.RegexPatterns.GetValueOrDefault(Array.Empty()).Length, 1, "KeywordFilter & RegexPatterns","Auto moderation rule must have at least 1 keyword or regex pattern"); + + if (args.AllowList.IsSpecified) + { + if (args.TriggerType.Value is not AutoModTriggerType.Keyword or AutoModTriggerType.KeywordPreset) + throw new ArgumentException(message: $"Allow list can only be used with 'Keyword' or 'KeywordPreset' trigger type.", paramName: nameof(args.AllowList)); + + if (args.TriggerType.Value is AutoModTriggerType.Keyword) + Preconditions.AtMost(args.AllowList.Value.Length, AutoModRuleProperties.MaxAllowListCountKeyword, nameof(args.AllowList), $"Allow list entry count must be less than or equal to {AutoModRuleProperties.MaxAllowListCountKeyword}."); + + if (args.TriggerType.Value is AutoModTriggerType.KeywordPreset) + Preconditions.AtMost(args.AllowList.Value.Length, AutoModRuleProperties.MaxAllowListCountKeywordPreset, nameof(args.AllowList), $"Allow list entry count must be less than or equal to {AutoModRuleProperties.MaxAllowListCountKeywordPreset}."); + + if (args.AllowList.Value.Any(x => x.Length > AutoModRuleProperties.MaxAllowListEntryLength)) + throw new ArgumentException(message: $"Allow list entry length must be less than or equal to {AutoModRuleProperties.MaxAllowListEntryLength}.", paramName: nameof(args.AllowList)); + + } + + if (args.TriggerType.Value is not AutoModTriggerType.KeywordPreset && args.Presets.IsSpecified) + throw new ArgumentException(message: $"Keyword presets scan only be used with 'KeywordPreset' trigger type.", paramName: nameof(args.Presets)); + + #endregion + + if (args.MentionLimit.IsSpecified) + { + if (args.TriggerType.Value is AutoModTriggerType.MentionSpam) + { + Preconditions.AtMost(args.MentionLimit.Value, AutoModRuleProperties.MaxMentionLimit, nameof(args.MentionLimit), $"Mention limit must be less or equal to {AutoModRuleProperties.MaxMentionLimit}"); + Preconditions.AtLeast(args.MentionLimit.Value, 1, nameof(args.MentionLimit), $"Mention limit must be greater or equal to 1"); + } + else + { + throw new ArgumentException(message: $"MentionLimit can only be used with 'MentionSpam' trigger type.", paramName: nameof(args.MentionLimit)); + } + } + + if (args.ExemptRoles.IsSpecified) + Preconditions.AtMost(args.ExemptRoles.Value.Length, AutoModRuleProperties.MaxExemptRoles, nameof(args.ExemptRoles), $"Exempt roles count must be less than or equal to {AutoModRuleProperties.MaxExemptRoles}."); + + if (args.ExemptChannels.IsSpecified) + Preconditions.AtMost(args.ExemptChannels.Value.Length, AutoModRuleProperties.MaxExemptChannels, nameof(args.ExemptChannels), $"Exempt channels count must be less than or equal to {AutoModRuleProperties.MaxExemptChannels}."); + + if (!args.Actions.IsSpecified && args.Actions.Value.Length == 0) + { + throw new ArgumentException(message: $"At least 1 action must be set for an auto moderation rule.", paramName: nameof(args.Actions)); + } + + if (args.Actions.Value.Any(x => x.TimeoutDuration.GetValueOrDefault().TotalSeconds > AutoModRuleProperties.MaxTimeoutSeconds)) + throw new ArgumentException(message: $"Field count must be less than or equal to {AutoModRuleProperties.MaxTimeoutSeconds}.", paramName: nameof(AutoModRuleActionProperties.TimeoutDuration)); + + var props = new CreateAutoModRuleParams + { + EventType = args.EventType.GetValueOrDefault(AutoModEventType.MessageSend), + Enabled = args.Enabled.GetValueOrDefault(true), + ExemptRoles = args.ExemptRoles.GetValueOrDefault(), + ExemptChannels = args.ExemptChannels.GetValueOrDefault(), + Name = args.Name.Value, + TriggerType = args.TriggerType.Value, + Actions = args.Actions.Value.Select(x => new AutoModAction + { + Metadata = new ActionMetadata + { + ChannelId = x.ChannelId ?? Optional.Unspecified, + DurationSeconds = (int?)x.TimeoutDuration?.TotalSeconds ?? Optional.Unspecified + }, + Type = x.Type + }).ToArray(), + TriggerMetadata = new TriggerMetadata + { + AllowList = args.AllowList, + KeywordFilter = args.KeywordFilter, + MentionLimit = args.MentionLimit, + Presets = args.Presets, + RegexPatterns = args.RegexPatterns, + }, + }; + + return await client.ApiClient.CreateGuildAutoModRuleAsync(guild.Id, props, options); + } public static async Task GetAutoModRuleAsync(ulong ruleId, IGuild guild, BaseDiscordClient client, RequestOptions options) => await client.ApiClient.GetGuildAutoModRuleAsync(guild.Id, ruleId, options); diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 41ce8141b..9cd0de423 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -1217,9 +1217,9 @@ namespace Discord.Rest } /// - public async Task CreateAutoModRuleAsync(AutoModRule props, RequestOptions options = null) + public async Task CreateAutoModRuleAsync(Action props, RequestOptions options = null) { - var rule = await GuildHelper.CreateAutoModRuleAsync(this, props.ToProperties(), Discord, options); + var rule = await GuildHelper.CreateAutoModRuleAsync(this, props, Discord, options); return RestAutoModRule.Create(Discord, rule); } @@ -1581,7 +1581,7 @@ namespace Discord.Rest => await GetAutoModRulesAsync(options).ConfigureAwait(false); /// - async Task IGuild.CreateAutoModRuleAsync(AutoModRule props, RequestOptions options) + async Task IGuild.CreateAutoModRuleAsync(Action props, RequestOptions options) => await CreateAutoModRuleAsync(props, options).ConfigureAwait(false); #endregion diff --git a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs index 914e66c0c..f5a88486b 100644 --- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs +++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs @@ -214,35 +214,5 @@ namespace Discord.Rest Id = interaction.Id, }; } - - public static API.Rest.CreateAutoModRuleParams ToProperties(this AutoModRule builder) - { - return new API.Rest.CreateAutoModRuleParams - { - Name = builder.Name, - TriggerMetadata = new API.TriggerMetadata - { - KeywordFilter = builder.KeywordFilter ?? Optional.Unspecified, - AllowList = builder.AllowList ?? Optional.Unspecified, - MentionLimit = builder.MentionLimit ?? Optional.Unspecified, - Presets = builder.Presets ?? Optional.Unspecified, - RegexPatterns = builder.RegexPatterns ?? Optional.Unspecified, - }, - TriggerType = builder.TriggerType, - Actions = builder.Actions?.Select(x => new API.AutoModAction - { - Metadata = new API.ActionMetadata - { - ChannelId = x.ChannelId ?? Optional.Unspecified, - DurationSeconds = (int?)x.TimeoutDuration?.TotalSeconds ?? Optional.Unspecified - }, - Type = x.Type, - }).ToArray(), - Enabled = builder.Enabled, - EventType = builder.EventType, - ExemptChannels = builder.ExemptChannels ?? Optional.Unspecified, - ExemptRoles = builder.ExemptRoles ?? Optional.Unspecified, - }; - } } } diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 3fdb5ff38..3f29bbc37 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -1867,9 +1867,9 @@ namespace Discord.WebSocket } /// - public async Task CreateAutoModRuleAsync(AutoModRule props, RequestOptions options = null) + public async Task CreateAutoModRuleAsync(Action props, RequestOptions options = null) { - var rule = await GuildHelper.CreateAutoModRuleAsync(this, props.ToProperties(), Discord, options); + var rule = await GuildHelper.CreateAutoModRuleAsync(this, props, Discord, options); return AddOrUpdateAutoModRule(rule); } @@ -2138,7 +2138,7 @@ namespace Discord.WebSocket => await GetAutoModRulesAsync(options).ConfigureAwait(false); /// - async Task IGuild.CreateAutoModRuleAsync(AutoModRule props, RequestOptions options) + async Task IGuild.CreateAutoModRuleAsync(Action props, RequestOptions options) => await CreateAutoModRuleAsync(props, options).ConfigureAwait(false); #endregion