diff --git a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRule.cs b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRule.cs
new file mode 100644
index 000000000..d65a70caa
--- /dev/null
+++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRule.cs
@@ -0,0 +1,102 @@
+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.
+ ///
+ public string[] RegexPatterns { get; }
+
+ ///
+ /// Gets the allow list for the rule.
+ ///
+ public string[] AllowList { get; }
+
+ ///
+ /// Gets total mention limit for the rule.
+ ///
+ public int? MentionLimit { get; }
+
+ ///
+ /// Gets the presets for the rule.
+ ///
+ 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.
+ ///
+ public ulong[] ExemptRoles { get; }
+
+ ///
+ /// Gets the exempt channels for the rule.
+ ///
+ 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 17b789877..dd5e5faa0 100644
--- a/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs
+++ b/src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs
@@ -1,5 +1,8 @@
+using Newtonsoft.Json.Linq;
+
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Linq;
namespace Discord;
@@ -24,10 +27,9 @@ public class AutoModRuleBuilder
private const int MaxExemptRoles = 20;
private const int MaxExemptChannels = 50;
- private List _keywordFilter = new ();
- private List _regexPatterns = new ();
- private List _allowList = new ();
- private List _actions = new ();
+ private List _keywordFilter = new();
+ private List _regexPatterns = new();
+ private List _allowList = new();
private List _exemptRoles = new();
private List _exemptChannels = new();
@@ -123,8 +125,8 @@ public class AutoModRuleBuilder
get { return _exemptChannels; }
set
{
- if (value.Count > MaxExemptRoles)
- throw new ArgumentException(message: $"Exempt channels count must be less than or equal to {MaxExemptRoles}.", paramName: nameof(RegexPatterns));
+ if (value.Count > MaxExemptChannels)
+ throw new ArgumentException(message: $"Exempt channels count must be less than or equal to {MaxExemptChannels}.", paramName: nameof(RegexPatterns));
_exemptChannels = value;
}
@@ -133,7 +135,17 @@ public class AutoModRuleBuilder
///
///
///
- public HashSet Presets = new ();
+ 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;
+ }
+ }
///
///
@@ -143,12 +155,12 @@ public class AutoModRuleBuilder
///
///
///
- public AutoModEventType EventType { get; set; }
+ public AutoModEventType EventType { get; set; } = AutoModEventType.MessageSend;
///
///
///
- public AutoModTriggerType TriggerType { get; }
+ public AutoModTriggerType TriggerType { get; }
///
///
@@ -165,13 +177,14 @@ public class AutoModRuleBuilder
throw new ArgumentException(message: $"Mention limit must be less than or equal to {MaxMentionLimit}.", paramName: nameof(MentionLimit));
_mentionLimit = value;
}
-
}
///
///
///
- public List Actions;
+ public List Actions = new();
+
+ private HashSet _presets = new();
///
///
@@ -186,6 +199,224 @@ public class AutoModRuleBuilder
{
TriggerType = type;
}
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder WithName(string name)
+ {
+ Name = name;
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder WithEnabled(bool enabled)
+ {
+ Enabled = enabled;
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder WithEventType(AutoModEventType eventType)
+ {
+ EventType = eventType;
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder WithMentionLimit(int limit)
+ {
+ MentionLimit = limit;
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder AddKeywordFilter(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;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder AddAllowList(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;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder AddExemptRole(IRole role)
+ {
+ AddExemptRole(role.Id);
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder AddExemptRole(ulong roleId)
+ {
+ ExemptRoles.Add(roleId);
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder AddExemptChannel(IMessageChannel channel)
+ {
+ AddExemptChannel(channel.Id);
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder AddExemptChannel(ulong channelId)
+ {
+ ExemptChannels.Add(channelId);
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public AutoModRuleBuilder AddAction(AutoModRuleActionBuilder builder)
+ {
+ Actions.Add(builder);
+ return this;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ 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
+ };
+
+ ///
+ ///
+ ///
+ ///
+ 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());
+ }
+
}
///
@@ -205,17 +436,23 @@ public class AutoModRuleActionBuilder
///
/// 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 })
+ if (value is { TotalSeconds: > MaxTimeoutSeconds })
throw new ArgumentException(message: $"Field count must be less than or equal to {MaxTimeoutSeconds}.", paramName: nameof(TimeoutDuration));
_timeoutDuration = value;
@@ -225,18 +462,13 @@ public class AutoModRuleActionBuilder
///
///
///
- public AutoModRuleActionBuilder()
- {
-
- }
-
- ///
- ///
- ///
- public AutoModRuleActionBuilder(AutoModActionType type, ulong? channelId, TimeSpan? duration)
+ 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/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
index 80330b042..d8feb69dd 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(AutoModRuleBuilder builder, RequestOptions options = null);
+ Task CreateAutoModRuleAsync(AutoModRule props, RequestOptions options = null);
}
}
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index bb100e24e..13771af71 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -2129,7 +2129,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);
- return await SendJsonAsync("POST", () => $"guilds/{guildId}/auto-moderation", args, new BucketIds(guildId), options: options);
+ return await SendJsonAsync("POST", () => $"guilds/{guildId}/auto-moderation/rules", args, new BucketIds(guildId), options: options);
}
public async Task ModifyGuildAutoModRuleAsync(ulong guildId, ulong ruleId, ModifyAutoModRuleParams args, RequestOptions options)
@@ -2139,7 +2139,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);
- return await SendJsonAsync("PATCH", () => $"guilds/{guildId}/auto-moderation/{ruleId}", args, new BucketIds(guildId), options: options);
+ return await SendJsonAsync("PATCH", () => $"guilds/{guildId}/auto-moderation/rules/{ruleId}", args, new BucketIds(guildId), options: options);
}
public async Task DeleteGuildAutoModRuleAsync(ulong guildId, ulong ruleId, RequestOptions options)
diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
index a8d337b2a..41ce8141b 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(AutoModRuleBuilder builder, RequestOptions options = null)
+ public async Task CreateAutoModRuleAsync(AutoModRule props, RequestOptions options = null)
{
- var rule = await GuildHelper.CreateAutoModRuleAsync(this, builder.ToProperties(), Discord, options);
+ var rule = await GuildHelper.CreateAutoModRuleAsync(this, props.ToProperties(), Discord, options);
return RestAutoModRule.Create(Discord, rule);
}
@@ -1581,8 +1581,8 @@ namespace Discord.Rest
=> await GetAutoModRulesAsync(options).ConfigureAwait(false);
///
- async Task IGuild.CreateAutoModRuleAsync(AutoModRuleBuilder builder, RequestOptions options)
- => await CreateAutoModRuleAsync(builder, options).ConfigureAwait(false);
+ async Task IGuild.CreateAutoModRuleAsync(AutoModRule 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 cc65a2356..914e66c0c 100644
--- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
+++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
@@ -215,17 +215,18 @@ namespace Discord.Rest
};
}
- public static API.Rest.CreateAutoModRuleParams ToProperties(this AutoModRuleBuilder builder)
+ public static API.Rest.CreateAutoModRuleParams ToProperties(this AutoModRule builder)
{
return new API.Rest.CreateAutoModRuleParams
{
+ Name = builder.Name,
TriggerMetadata = new API.TriggerMetadata
{
- KeywordFilter = builder.KeywordFilter?.ToArray(),
- AllowList = builder.AllowList?.ToArray(),
+ KeywordFilter = builder.KeywordFilter ?? Optional.Unspecified,
+ AllowList = builder.AllowList ?? Optional.Unspecified,
MentionLimit = builder.MentionLimit ?? Optional.Unspecified,
- Presets = builder.Presets?.ToArray(),
- RegexPatterns = builder.RegexPatterns?.ToArray(),
+ Presets = builder.Presets ?? Optional.Unspecified,
+ RegexPatterns = builder.RegexPatterns ?? Optional.Unspecified,
},
TriggerType = builder.TriggerType,
Actions = builder.Actions?.Select(x => new API.AutoModAction
@@ -239,8 +240,8 @@ namespace Discord.Rest
}).ToArray(),
Enabled = builder.Enabled,
EventType = builder.EventType,
- ExemptChannels = builder.ExemptChannels?.ToArray() ?? Optional.Unspecified,
- ExemptRoles = builder.ExemptRoles?.ToArray() ?? Optional .Unspecified,
+ 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 271cbb36b..1496c101f 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(AutoModRuleBuilder builder, RequestOptions options = null)
+ public async Task CreateAutoModRuleAsync(AutoModRule props, RequestOptions options = null)
{
- var rule = await GuildHelper.CreateAutoModRuleAsync(this, builder.ToProperties(), Discord, options);
+ var rule = await GuildHelper.CreateAutoModRuleAsync(this, props.ToProperties(), Discord, options);
return AddOrUpdateAutoModRule(rule);
}
@@ -2130,8 +2130,8 @@ namespace Discord.WebSocket
=> await GetAutoModRulesAsync(options).ConfigureAwait(false);
///
- async Task IGuild.CreateAutoModRuleAsync(AutoModRuleBuilder builder, RequestOptions options)
- => await CreateAutoModRuleAsync(builder, options).ConfigureAwait(false);
+ async Task IGuild.CreateAutoModRuleAsync(AutoModRule props, RequestOptions options)
+ => await CreateAutoModRuleAsync(props, options).ConfigureAwait(false);
#endregion
}