Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto Moderation update & validation #112

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
namespace Disqord;

public static partial class Discord
{
public static partial class Limits
{
/// <summary>
/// Represents limits for auto moderation rules.
/// </summary>
public static class AutoModerationRule
{
/// <summary>
/// The maximum amount of exempt roles.
/// </summary>
public const int MaxExemptRoleAmount = 20;

/// <summary>
/// The maximum amount of exempt channels.
/// </summary>
public const int MaxExemptChannelAmount = 50;

/// <summary>
/// Represents limits for auto moderation rule trigger metadata.
/// </summary>
public static class TriggerMetadata
{
/// <summary>
/// The maximum amount of keyword filters.
/// </summary>
public const int MaxKeywordFilterAmount = 1000;

/// <summary>
/// The maximum length of keyword filters.
/// </summary>
public const int MaxKeywordFilterLength = 60;

/// <summary>
/// The maximum amount of regex patterns.
/// </summary>
public const int MaxRegexPatternsAmount = 10;

/// <summary>
/// The maximum length of regex patterns.
/// </summary>
public const int MaxRegexPatternLength = 260;

/// <summary>
/// The maximum amount of allow list substrings when the trigger type is <see cref="AutoModerationRuleTrigger.Keyword"/>.
/// </summary>
public const int MaxKeywordAllowListAmount = 100;

/// <summary>
/// The maximum amount of allow list substrings when the trigger type is <see cref="AutoModerationRuleTrigger.KeywordPreset"/>.
/// </summary>
public const int MaxKeywordPresetAllowListAmount = 1000;

/// <summary>
/// The maximum length of the allowed substring when the trigger type is <see cref="AutoModerationRuleTrigger.Keyword"/>.
/// </summary>
public const int MaxKeywordAllowedSubStringLength = 60;

/// <summary>
/// The maximum length of the allowed substring when the trigger type is <see cref="AutoModerationRuleTrigger.KeywordPreset"/>.
/// </summary>
public const int MaxKeywordPresetAllowedSubStringLength = 60;

/// <summary>
/// The maximum limit of mentions when the trigger type is <see cref="AutoModerationRuleTrigger.MentionSpam"/>.
/// </summary>
public const int MaxMentionLimit = 50;
}

/// <summary>
/// Represents limits for auto moderation rule action metadata.
/// </summary>
public static class ActionMetadata
{
/// <summary>
/// The maximum amount of a custom message.
/// </summary>
public const int MaxCustomMessageLength = 150;

/// <summary>
/// The maximum duration of seconds when the action type is <see cref="AutoModerationActionType.Timeout"/>.
/// </summary>
public const int MaxDurationSeconds = 2419200;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ namespace Disqord;
[EditorBrowsable(EditorBrowsableState.Never)]
public static class LocalAutoModerationActionMetadataExtensions
{
public static TActionMetadata WithCustomMessage<TActionMetadata>(this TActionMetadata metadata, string customMessage)
where TActionMetadata : LocalAutoModerationActionMetadata
{
metadata.CustomMessage = customMessage;
return metadata;
}

public static TActionMetadata WithChannelId<TActionMetadata>(this TActionMetadata metadata, Snowflake channelId)
where TActionMetadata : LocalAutoModerationActionMetadata
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,22 @@ namespace Disqord;

public class LocalAutoModerationAction : ILocalConstruct<LocalAutoModerationAction>, IJsonConvertible<AutoModerationActionJsonModel>
{
public static LocalAutoModerationAction BlockMessage()
public static LocalAutoModerationAction BlockMessage(string? customMessage)
{
return new LocalAutoModerationAction
var action = new LocalAutoModerationAction
{
Type = AutoModerationActionType.BlockMessage
Type = AutoModerationActionType.BlockMessage,
};

if (customMessage != null)
{
action.Metadata = new LocalAutoModerationActionMetadata
{
CustomMessage = customMessage
};
}

return action;
}

public static LocalAutoModerationAction SendAlertMessage(Snowflake channelId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ public enum AutoModerationRuleTrigger
/// </summary>
Keyword = 1,

/// <summary>
/// The trigger checks for harmful links.
/// </summary>
HarmfulLink = 2,

/// <summary>
/// The trigger checks for generic spam.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,36 @@ public class AutoModerationActionJsonModel : JsonModel

[JsonProperty("metadata")]
public Optional<AutoModerationActionMetadataJsonModel> Metadata;
}

protected override void OnValidate()
{
if (Type != AutoModerationActionType.BlockMessage)
OptionalGuard.HasValue(Metadata);

OptionalGuard.CheckValue(Metadata, metadata =>
{
switch (Type)
{
case AutoModerationActionType.BlockMessage:
{
OptionalGuard.CheckValue(metadata.CustomMessage, message =>
{
Guard.HasSizeLessThanOrEqualTo(message, Discord.Limits.AutoModerationRule.ActionMetadata.MaxCustomMessageLength);
});
break;
}
case AutoModerationActionType.SendAlertMessage:
{
OptionalGuard.HasValue(metadata.ChannelId);
break;
}
case AutoModerationActionType.Timeout:
{
OptionalGuard.HasValue(metadata.DurationSeconds);
Guard.IsBetweenOrEqualTo(metadata.DurationSeconds.Value, 0, Discord.Limits.AutoModerationRule.ActionMetadata.MaxDurationSeconds);
break;
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,76 @@ public class CreateAutoModerationRuleJsonRestRequestContent : JsonModelRestReque
[JsonProperty("exempt_channels")]
public Optional<Snowflake[]> ExemptChannels;

/// <inheritdoc />
protected override void OnValidate()
{
// TODO: Add validation when docs pr is merged
OptionalGuard.CheckValue(ExemptRoles, roles =>
{
Guard.HasSizeLessThanOrEqualTo(roles, Discord.Limits.AutoModerationRule.MaxExemptRoleAmount);
});

OptionalGuard.CheckValue(ExemptChannels, channels =>
{
Guard.HasSizeLessThanOrEqualTo(channels, Discord.Limits.AutoModerationRule.MaxExemptChannelAmount);
});

if (Trigger != AutoModerationRuleTrigger.Spam)
OptionalGuard.HasValue(TriggerMetadata);

OptionalGuard.CheckValue(TriggerMetadata, metadata =>
{
switch (Trigger)
{
case AutoModerationRuleTrigger.Keyword:
{
OptionalGuard.CheckValue(metadata.KeywordFilter, filters =>
{
Guard.HasSizeLessThanOrEqualTo(filters, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxKeywordFilterAmount);

for (var i = 0; i < filters.Length; i++)
Guard.HasSizeBetweenOrEqualTo(filters[i], 1, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxKeywordFilterLength);
});

OptionalGuard.CheckValue(metadata.RegexPatterns, patterns =>
{
Guard.HasSizeLessThanOrEqualTo(patterns, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxRegexPatternsAmount);

for (var i = 0; i < patterns.Length; i++)
Guard.HasSizeBetweenOrEqualTo(patterns[i], 1, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxRegexPatternLength);
});

OptionalGuard.CheckValue(metadata.AllowList, allowList =>
{
Guard.HasSizeLessThanOrEqualTo(allowList, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxKeywordAllowListAmount);

for (var i = 0; i < allowList.Length; i++)
Guard.HasSizeBetweenOrEqualTo(allowList[i], 1, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxKeywordAllowedSubStringLength);
});
break;
}

case AutoModerationRuleTrigger.KeywordPreset:
{
OptionalGuard.CheckValue(metadata.AllowList, allowList =>
{
Guard.HasSizeLessThanOrEqualTo(allowList, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxKeywordPresetAllowListAmount);

for (var i = 0; i < allowList.Length; i++)
Guard.HasSizeBetweenOrEqualTo(allowList[i], 1, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxKeywordPresetAllowedSubStringLength);
});
break;
}

case AutoModerationRuleTrigger.MentionSpam:
{
OptionalGuard.HasValue(metadata.MentionTotalLimit);
Guard.IsBetweenOrEqualTo(metadata.MentionTotalLimit.Value, 1, Discord.Limits.AutoModerationRule.TriggerMetadata.MaxMentionLimit);
break;
}
}
});

for (int i = 0; i < Actions.Length; i++)
Actions[i].Validate();
}
}
Loading