[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:
@@ -1062,5 +1062,170 @@ namespace Discord.Rest
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Auto Mod
|
||||
|
||||
public static async Task<AutoModerationRule> CreateAutoModRuleAsync(IGuild guild, Action<AutoModRuleProperties> 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<AutoModRuleActionProperties>()).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<string>()).Length + args.RegexPatterns.GetValueOrDefault(Array.Empty<string>()).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<ulong>.Unspecified,
|
||||
DurationSeconds = (int?)x.TimeoutDuration?.TotalSeconds ?? Optional<int>.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<AutoModerationRule> GetAutoModRuleAsync(ulong ruleId, IGuild guild, BaseDiscordClient client, RequestOptions options)
|
||||
=> await client.ApiClient.GetGuildAutoModRuleAsync(guild.Id, ruleId, options);
|
||||
|
||||
public static async Task<AutoModerationRule[]> GetAutoModRulesAsync(IGuild guild, BaseDiscordClient client, RequestOptions options)
|
||||
=> await client.ApiClient.GetGuildAutoModRulesAsync(guild.Id, options);
|
||||
|
||||
public static Task<AutoModerationRule> ModifyRuleAsync(BaseDiscordClient client, IAutoModRule rule, Action<AutoModRuleProperties> 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<ulong>.Unspecified,
|
||||
DurationSeconds = x.TimeoutDuration.HasValue ? (int)Math.Floor(x.TimeoutDuration.Value.TotalSeconds) : Optional<int>.Unspecified
|
||||
} : Optional<API.ActionMetadata>.Unspecified
|
||||
}).ToArray() : Optional<API.AutoModAction[]>.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<string>()),
|
||||
RegexPatterns = args.RegexPatterns.GetValueOrDefault(Array.Empty<string>()),
|
||||
AllowList = args.AllowList.GetValueOrDefault(Array.Empty<string>()),
|
||||
MentionLimit = args.MentionLimit,
|
||||
Presets = args.Presets.GetValueOrDefault(Array.Empty<KeywordPresetTypes>())
|
||||
} : Optional<API.TriggerMetadata>.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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user