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

[Feature] AutoMod custom block message #2613

Merged
merged 1 commit into from
Feb 26, 2023
Merged
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
Expand Up @@ -21,16 +21,23 @@ public class AutoModRuleAction
/// </summary>
public ulong? ChannelId { get; }

/// <summary>
/// Gets the custom message that will be shown to members whenever their message is blocked.
/// <see langword="null"/> if no message has been set.
/// </summary>
public Optional<string> CustomMessage { get; set; }

/// <summary>
/// Gets the duration of which a user will be timed out for breaking this rule. <see langword="null"/> if no timeout duration has been provided.
/// </summary>
public TimeSpan? TimeoutDuration { get; }

internal AutoModRuleAction(AutoModActionType type, ulong? channelId, int? duration)
internal AutoModRuleAction(AutoModActionType type, ulong? channelId, int? duration, string customMessage)
{
Type = type;
ChannelId = channelId;
TimeoutDuration = duration.HasValue ? TimeSpan.FromSeconds(duration.Value) : null;
CustomMessage = customMessage;
}
}
}
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ public class AutoModRuleProperties
/// </summary>
public const int MaxTimeoutSeconds = 2419200;

/// <summary>
/// Returns the max custom message length AutoMod rule action allowed by Discord.
/// </summary>
public const int MaxCustomBlockMessageLength = 50;


/// <summary>
/// Gets or sets the name for the rule.
/// </summary>
Expand Down Expand Up @@ -146,6 +152,11 @@ public class AutoModRuleActionProperties
/// Gets or sets the duration of which a user will be timed out for breaking this rule.
/// </summary>
public TimeSpan? TimeoutDuration { get; set; }

/// <summary>
/// Gets or sets the custom message that will be shown to members whenever their message is blocked.
/// </summary>
public Optional<string> CustomMessage { get; set; }
}

}
3 changes: 3 additions & 0 deletions src/Discord.Net.Rest/API/Common/ActionMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ internal class ActionMetadata

[JsonProperty("duration_seconds")]
public Optional<int> DurationSeconds { get; set; }

[JsonProperty("custom_message")]
public Optional<string> CustomMessage { get; set; }
}
}
21 changes: 13 additions & 8 deletions src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,16 +1071,16 @@ public static async Task<AutoModerationRule> CreateAutoModRuleAsync(IGuild guild
var args = new AutoModRuleProperties();
func(args);

#region Validations

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)
Expand Down Expand Up @@ -1124,9 +1124,7 @@ public static async Task<AutoModerationRule> CreateAutoModRuleAsync(IGuild guild

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)
Expand Down Expand Up @@ -1154,6 +1152,11 @@ public static async Task<AutoModerationRule> CreateAutoModRuleAsync(IGuild guild
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));

if (args.Actions.Value.Any(x => x.CustomMessage.IsSpecified && x.CustomMessage.Value.Length > AutoModRuleProperties.MaxCustomBlockMessageLength))
throw new ArgumentException(message: $"Custom message length must be less than or equal to {AutoModRuleProperties.MaxCustomBlockMessageLength}.", paramName: nameof(AutoModRuleActionProperties.CustomMessage));

#endregion

var props = new CreateAutoModRuleParams
{
EventType = args.EventType.GetValueOrDefault(AutoModEventType.MessageSend),
Expand All @@ -1167,7 +1170,8 @@ public static async Task<AutoModerationRule> CreateAutoModRuleAsync(IGuild guild
Metadata = new ActionMetadata
{
ChannelId = x.ChannelId ?? Optional<ulong>.Unspecified,
DurationSeconds = (int?)x.TimeoutDuration?.TotalSeconds ?? Optional<int>.Unspecified
DurationSeconds = (int?)x.TimeoutDuration?.TotalSeconds ?? Optional<int>.Unspecified,
CustomMessage = x.CustomMessage,
},
Type = x.Type
}).ToArray(),
Expand Down Expand Up @@ -1203,7 +1207,8 @@ public static Task<AutoModerationRule> ModifyRuleAsync(BaseDiscordClient client,
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
DurationSeconds = x.TimeoutDuration.HasValue ? (int)Math.Floor(x.TimeoutDuration.Value.TotalSeconds) : Optional<int>.Unspecified,
CustomMessage = x.CustomMessage,
} : Optional<API.ActionMetadata>.Unspecified
}).ToArray() : Optional<API.AutoModAction[]>.Unspecified,
Enabled = args.Enabled,
Expand Down
11 changes: 10 additions & 1 deletion src/Discord.Net.Rest/Entities/Guilds/RestAutoModRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,16 @@ internal void Update(Model model)
MentionTotalLimit = model.TriggerMetadata.MentionLimit.IsSpecified
? model.TriggerMetadata.MentionLimit.Value
: null;
Actions = model.Actions.Select(x => new AutoModRuleAction(x.Type, x.Metadata.GetValueOrDefault()?.ChannelId.ToNullable(), x.Metadata.GetValueOrDefault()?.DurationSeconds.ToNullable())).ToImmutableArray();
Actions = model.Actions.Select(x => new AutoModRuleAction(
x.Type,
x.Metadata.GetValueOrDefault()?.ChannelId.ToNullable(),
x.Metadata.GetValueOrDefault()?.DurationSeconds.ToNullable(),
x.Metadata.IsSpecified
? x.Metadata.Value.CustomMessage.IsSpecified
? x.Metadata.Value.CustomMessage.Value
: null
: null
)).ToImmutableArray();
Enabled = model.Enabled;
ExemptRoles = model.ExemptRoles.ToImmutableArray();
ExemptChannels = model.ExemptChannels.ToImmutableArray();
Expand Down
12 changes: 9 additions & 3 deletions src/Discord.Net.WebSocket/DiscordSocketClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2895,7 +2895,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty

var rule = guild.AddOrUpdateAutoModRule(data);

await TimedInvokeAsync(_autoModRuleCreated, nameof(AutoModRuleCreated), rule);
await TimedInvokeAsync(_autoModRuleCreated, nameof(AutoModRuleCreated), rule);
}
break;

Expand Down Expand Up @@ -2942,8 +2942,14 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty
? data.Action.Metadata.Value.DurationSeconds.IsSpecified
? data.Action.Metadata.Value.DurationSeconds.Value
: null
: null,
data.Action.Metadata.IsSpecified
? data.Action.Metadata.Value.CustomMessage.IsSpecified
? data.Action.Metadata.Value.CustomMessage.Value
: null
: null);


var member = guild.GetUser(data.UserId);

var cacheableUser = new Cacheable<SocketGuildUser, ulong>(member,
Expand All @@ -2965,7 +2971,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty
channel != null,
async () =>
{
if(data.ChannelId.IsSpecified)
if (data.ChannelId.IsSpecified)
return await GetChannelAsync(data.ChannelId.Value).ConfigureAwait(false) as ISocketMessageChannel;
return null;
});
Expand All @@ -2980,7 +2986,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty
cachedMsg is not null,
async () =>
{
if(data.MessageId.IsSpecified)
if (data.MessageId.IsSpecified)
return (await channel!.GetMessageAsync(data.MessageId.Value).ConfigureAwait(false)) as IUserMessage;
return null;
});
Expand Down
11 changes: 10 additions & 1 deletion src/Discord.Net.WebSocket/Entities/Guilds/SocketAutoModRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,16 @@ internal void Update(Model model)
MentionTotalLimit = model.TriggerMetadata.MentionLimit.IsSpecified
? model.TriggerMetadata.MentionLimit.Value
: null;
Actions = model.Actions.Select(x => new AutoModRuleAction(x.Type, x.Metadata.GetValueOrDefault()?.ChannelId.ToNullable(), x.Metadata.GetValueOrDefault()?.DurationSeconds.ToNullable())).ToImmutableArray();
Actions = model.Actions.Select(x => new AutoModRuleAction(
x.Type,
x.Metadata.GetValueOrDefault()?.ChannelId.ToNullable(),
x.Metadata.GetValueOrDefault()?.DurationSeconds.ToNullable(),
x.Metadata.IsSpecified
? x.Metadata.Value.CustomMessage.IsSpecified
? x.Metadata.Value.CustomMessage.Value
: null
: null
)).ToImmutableArray();
Enabled = model.Enabled;
ExemptRoles = model.ExemptRoles.Select(x => Guild.GetRole(x)).ToImmutableArray();
ExemptChannels = model.ExemptChannels.Select(x => Guild.GetChannel(x)).ToImmutableArray();
Expand Down