Browse Source

started working on rule builder

pull/2578/head
Misha133 2 years ago
parent
commit
8b76ac2b17
9 changed files with 318 additions and 21 deletions
  1. +242
    -0
      src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs
  2. +1
    -1
      src/Discord.Net.Core/Entities/Guilds/IGuild.cs
  3. +16
    -0
      src/Discord.Net.Rest/API/Rest/CreateAutoModRuleParams.cs
  4. +2
    -4
      src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
  5. +7
    -2
      src/Discord.Net.Rest/Entities/Guilds/RestAutoModRule.cs
  6. +6
    -5
      src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
  7. +29
    -0
      src/Discord.Net.Rest/Extensions/EntityExtensions.cs
  8. +5
    -3
      src/Discord.Net.WebSocket/Entities/Guilds/SocketAutoModRule.cs
  9. +10
    -6
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs

+ 242
- 0
src/Discord.Net.Core/Entities/Guilds/AutoModeration/AutoModRuleBuilder.cs View File

@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Discord;

/// <summary>
/// A builder used to create a <see cref="IAutoModRule"/>.
/// </summary>
public class AutoModRuleBuilder
{
private const int MaxKeywordCount = 1000;
private const int MaxKeywordLength = 30;

private const int MaxRegexPatternCount = 10;
private const int MaxRegexPatternLength = 260;

private const int MaxAllowListCountKeyword = 100;
private const int MaxAllowListCountKeywordPreset = 1000;
private const int MaxAllowListEntryLength = 30;

private const int MaxMentionLimit = 50;

private const int MaxExemptRoles = 20;
private const int MaxExemptChannels = 50;

private List<string> _keywordFilter = new ();
private List<string> _regexPatterns = new ();
private List<string> _allowList = new ();
private List<AutoModRuleActionBuilder> _actions = new ();

private List<ulong> _exemptRoles = new();
private List<ulong> _exemptChannels = new();

private int? _mentionLimit;

/// <summary>
///
/// </summary>
public List<string> 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;
}
}

/// <summary>
///
/// </summary>
public List<string> 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;
}
}

/// <summary>
///
/// </summary>
public List<string> 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;
}
}

/// <summary>
///
/// </summary>
public List<ulong> 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;
}
}

/// <summary>
///
/// </summary>
public List<ulong> ExemptChannels
{
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));

_exemptChannels = value;
}
}

/// <summary>
///
/// </summary>
public HashSet<KeywordPresetTypes> Presets = new ();

/// <summary>
///
/// </summary>
public string Name { get; set; }

/// <summary>
///
/// </summary>
public AutoModEventType EventType { get; set; }

/// <summary>
///
/// </summary>
public AutoModTriggerType TriggerType { get; }

/// <summary>
///
/// </summary>
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;
}

}

/// <summary>
///
/// </summary>
public List<AutoModRuleActionBuilder> Actions;

/// <summary>
///
/// </summary>
public bool Enabled { get; set; } = false;

/// <summary>
///
/// </summary>
/// <param name="type"></param>
public AutoModRuleBuilder(AutoModTriggerType type)
{
TriggerType = type;
}
}

/// <summary>
/// Represents an action that will be preformed if a user breaks an <see cref="IAutoModRule"/>.
/// </summary>
public class AutoModRuleActionBuilder
{
private const int MaxTimeoutSeconds = 2419200;

private TimeSpan? _timeoutDuration;

/// <summary>
/// Gets or sets the type for this action.
/// </summary>
public AutoModActionType Type { get; }

/// <summary>
/// Get or sets the channel id on which to post alerts.
/// </summary>
public ulong? ChannelId { get; set; }

/// <summary>
/// Gets or sets the duration of which a user will be timed out for breaking this rule.
/// </summary>
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;
}
}

/// <summary>
///
/// </summary>
public AutoModRuleActionBuilder()
{

}

/// <summary>
///
/// </summary>
public AutoModRuleActionBuilder(AutoModActionType type, ulong? channelId, TimeSpan? duration)
{
Type = type;
ChannelId = channelId;
TimeoutDuration = duration;
}
}

+ 1
- 1
src/Discord.Net.Core/Entities/Guilds/IGuild.cs View File

@@ -1290,6 +1290,6 @@ namespace Discord
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the created <see cref="WelcomeScreen"/>.
/// </returns>
Task<IAutoModRule> CreateAutoModRuleAsync(RequestOptions options = null);
Task<IAutoModRule> CreateAutoModRuleAsync(AutoModRuleBuilder builder, RequestOptions options = null);
}
}

+ 16
- 0
src/Discord.Net.Rest/API/Rest/CreateAutoModRuleParams.cs View File

@@ -1,3 +1,4 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -8,13 +9,28 @@ namespace Discord.API.Rest
{
internal class CreateAutoModRuleParams
{
[JsonProperty("name")]
public string Name { get; set; }

[JsonProperty("event_type")]
public AutoModEventType EventType { get; set; }

[JsonProperty("trigger_type")]
public AutoModTriggerType TriggerType { get; set; }

[JsonProperty("trigger_metadata")]
public Optional<TriggerMetadata> TriggerMetadata { get; set; }

[JsonProperty("actions")]
public AutoModAction[] Actions { get; set; }

[JsonProperty("enabled")]
public Optional<bool> Enabled { get; set; }

[JsonProperty("exempt_roles")]
public Optional<ulong[]> ExemptRoles { get; set; }

[JsonProperty("exempt_channels")]
public Optional<ulong[]> ExemptChannels { get; set; }
}
}

+ 2
- 4
src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs View File

@@ -1064,10 +1064,8 @@ namespace Discord.Rest

#region Auto Mod

public static Task<AutoModerationRule> CreateAutoModRuleAsync(IGuild guild, BaseDiscordClient client, RequestOptions options)
{
throw new NotImplementedException();
}
public static async Task<AutoModerationRule> CreateAutoModRuleAsync(IGuild guild, CreateAutoModRuleParams args, BaseDiscordClient client, RequestOptions options)
=> await client.ApiClient.CreateGuildAutoModRuleAsync(guild.Id, args, options);

public static async Task<AutoModerationRule> GetAutoModRuleAsync(ulong ruleId, IGuild guild, BaseDiscordClient client, RequestOptions options)
=> await client.ApiClient.GetGuildAutoModRuleAsync(guild.Id, ruleId, options);


+ 7
- 2
src/Discord.Net.Rest/Entities/Guilds/RestAutoModRule.cs View File

@@ -89,8 +89,13 @@ public class RestAutoModRule : RestEntity<ulong>, IAutoModRule
}

/// <inheritdoc />
public Task ModifyAsync(Action<AutoModRuleProperties> func, RequestOptions options = null) => throw new NotImplementedException();
public async Task ModifyAsync(Action<AutoModRuleProperties> func, RequestOptions options = null)
{
var model = await GuildHelper.ModifyRuleAsync(Discord, this, func, options);
Update(model);
}

/// <inheritdoc />
public Task DeleteAsync(RequestOptions options = null) => throw new NotImplementedException();
public Task DeleteAsync(RequestOptions options = null)
=> GuildHelper.DeleteRuleAsync(Discord, this, options);
}

+ 6
- 5
src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs View File

@@ -1217,10 +1217,11 @@ namespace Discord.Rest
}

/// <inheritdoc cref="IGuild.CreateAutoModRuleAsync"/>
public async Task<RestAutoModRule> CreateAutoModRuleAsync(RequestOptions options = null)
public async Task<RestAutoModRule> CreateAutoModRuleAsync(AutoModRuleBuilder builder, RequestOptions options = null)
{
var rule = await GuildHelper.CreateAutoModRuleAsync(this, Discord, options);
throw new NotImplementedException();
var rule = await GuildHelper.CreateAutoModRuleAsync(this, builder.ToProperties(), Discord, options);

return RestAutoModRule.Create(Discord, rule);
}


@@ -1580,8 +1581,8 @@ namespace Discord.Rest
=> await GetAutoModRulesAsync(options).ConfigureAwait(false);

/// <inheritdoc/>
async Task<IAutoModRule> IGuild.CreateAutoModRuleAsync(RequestOptions options)
=> await CreateAutoModRuleAsync(options).ConfigureAwait(false);
async Task<IAutoModRule> IGuild.CreateAutoModRuleAsync(AutoModRuleBuilder builder, RequestOptions options)
=> await CreateAutoModRuleAsync(builder, options).ConfigureAwait(false);

#endregion
}


+ 29
- 0
src/Discord.Net.Rest/Extensions/EntityExtensions.cs View File

@@ -214,5 +214,34 @@ namespace Discord.Rest
Id = interaction.Id,
};
}

public static API.Rest.CreateAutoModRuleParams ToProperties(this AutoModRuleBuilder builder)
{
return new API.Rest.CreateAutoModRuleParams
{
TriggerMetadata = new API.TriggerMetadata
{
KeywordFilter = builder.KeywordFilter?.ToArray(),
AllowList = builder.AllowList?.ToArray(),
MentionLimit = builder.MentionLimit ?? Optional<int>.Unspecified,
Presets = builder.Presets?.ToArray(),
RegexPatterns = builder.RegexPatterns?.ToArray(),
},
TriggerType = builder.TriggerType,
Actions = builder.Actions?.Select(x => new API.AutoModAction
{
Metadata = new API.ActionMetadata
{
ChannelId = x.ChannelId ?? Optional<ulong>.Unspecified,
DurationSeconds = (int?)x.TimeoutDuration?.TotalSeconds ?? Optional<int>.Unspecified
},
Type = x.Type,
}).ToArray(),
Enabled = builder.Enabled,
EventType = builder.EventType,
ExemptChannels = builder.ExemptChannels?.ToArray() ?? Optional<ulong[]>.Unspecified,
ExemptRoles = builder.ExemptRoles?.ToArray() ?? Optional <ulong[]>.Unspecified,
};
}
}
}

+ 5
- 3
src/Discord.Net.WebSocket/Entities/Guilds/SocketAutoModRule.cs View File

@@ -3,7 +3,6 @@ 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;

@@ -101,8 +100,11 @@ namespace Discord.WebSocket
}

/// <inheritdoc/>
public Task ModifyAsync(Action<AutoModRuleProperties> func, RequestOptions options = null)
=> GuildHelper.ModifyRuleAsync(Discord, this, func, options);
public async Task ModifyAsync(Action<AutoModRuleProperties> func, RequestOptions options = null)
{
var model = await GuildHelper.ModifyRuleAsync(Discord, this, func, options);
Guild.AddOrUpdateAutoModRule(model);
}

/// <inheritdoc/>
public Task DeleteAsync(RequestOptions options = null)


+ 10
- 6
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -1827,7 +1827,10 @@ namespace Discord.WebSocket
return socketRule;
}

internal SocketAutoModRule GetAutoModRule(ulong id)
/// <summary>
/// Gets a single rule configured in a guild from cache. Returns <see langword="null"/> if the rule was not found.
/// </summary>
public SocketAutoModRule GetAutoModRule(ulong id)
{
return _automodRules.TryGetValue(id, out var rule) ? rule : null;
}
@@ -1864,10 +1867,11 @@ namespace Discord.WebSocket
}

/// <inheritdoc cref="IGuild.CreateAutoModRuleAsync"/>
public async Task<SocketAutoModRule> CreateAutoModRuleAsync(RequestOptions options = null)
public async Task<SocketAutoModRule> CreateAutoModRuleAsync(AutoModRuleBuilder builder, RequestOptions options = null)
{
var rule = await GuildHelper.CreateAutoModRuleAsync(this, Discord, options);
throw new NotImplementedException();
var rule = await GuildHelper.CreateAutoModRuleAsync(this, builder.ToProperties(), Discord, options);

return AddOrUpdateAutoModRule(rule);
}

#endregion
@@ -2126,8 +2130,8 @@ namespace Discord.WebSocket
=> await GetAutoModRulesAsync(options).ConfigureAwait(false);

/// <inheritdoc/>
async Task<IAutoModRule> IGuild.CreateAutoModRuleAsync(RequestOptions options)
=> await CreateAutoModRuleAsync(options).ConfigureAwait(false);
async Task<IAutoModRule> IGuild.CreateAutoModRuleAsync(AutoModRuleBuilder builder, RequestOptions options)
=> await CreateAutoModRuleAsync(builder, options).ConfigureAwait(false);

#endregion
}


Loading…
Cancel
Save