From 94ab90d1c60e407cf7db2ab13ba4945ae4056b83 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Sun, 26 Feb 2023 08:58:05 -0500 Subject: [PATCH] feat(http, model, validate): support automod custom messages (#2161) Add support for the new `custom_message` field available on AutoMod `BLOCK_MESSAGE` actions. Discord API Docs: https://github.com/discord/discord-api-docs/pull/5955 --- .../create_auto_moderation_rule.rs | 33 ++++++++++++ .../src/guild/auto_moderation/action.rs | 11 +++- .../src/guild/auto_moderation/mod.rs | 2 + twilight-validate/src/request.rs | 52 +++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/twilight-http/src/request/guild/auto_moderation/create_auto_moderation_rule.rs b/twilight-http/src/request/guild/auto_moderation/create_auto_moderation_rule.rs index 8f7d9f55e21..9b0eadd6d88 100644 --- a/twilight-http/src/request/guild/auto_moderation/create_auto_moderation_rule.rs +++ b/twilight-http/src/request/guild/auto_moderation/create_auto_moderation_rule.rs @@ -18,6 +18,7 @@ use twilight_model::{ }; use twilight_validate::request::{ audit_reason as validate_audit_reason, + auto_moderation_block_action_custom_message_limit as validate_auto_moderation_block_action_custom_message_limit, auto_moderation_metadata_mention_total_limit as validate_auto_moderation_metadata_mention_total_limit, ValidationError, }; @@ -36,6 +37,10 @@ struct CreateAutoModerationRuleFieldsAction { struct CreateAutoModerationRuleFieldsActionMetadata { /// Channel to which user content should be logged. pub channel_id: Option>, + /// Additional explanation that will be shown to members whenever their message is blocked. + /// + /// Maximum value length is 150 characters. + pub custom_message: Option, /// Timeout duration in seconds. /// /// Maximum value is 2419200 seconds, or 4 weeks. @@ -138,6 +143,34 @@ impl<'a> CreateAutoModerationRule<'a> { self } + /// Append an action of type [`BlockMessage`] with an explanation for blocking messages. + /// + /// # Errors + /// + /// Returns a [`AutoModerationBlockActionCustomMessageLimit`] if the custom message length + /// is invalid. + /// + /// [`AutoModerationBlockActionCustomMessageLimit`]: twilight_validate::request::ValidationErrorType::AutoModerationBlockActionCustomMessageLimit + /// [`BlockMessage`]: AutoModerationActionType::BlockMessage + pub fn action_block_message_with_explanation( + mut self, + custom_message: &'a str, + ) -> Result { + validate_auto_moderation_block_action_custom_message_limit(custom_message)?; + + self.fields.actions.get_or_insert_with(Vec::new).push( + CreateAutoModerationRuleFieldsAction { + kind: AutoModerationActionType::BlockMessage, + metadata: CreateAutoModerationRuleFieldsActionMetadata { + custom_message: Some(String::from(custom_message)), + ..Default::default() + }, + }, + ); + + Ok(self) + } + /// Append an action of type [`SendAlertMessage`]. /// /// [`SendAlertMessage`]: AutoModerationActionType::SendAlertMessage diff --git a/twilight-model/src/guild/auto_moderation/action.rs b/twilight-model/src/guild/auto_moderation/action.rs index d40229d1c8f..5c9fa34b39e 100644 --- a/twilight-model/src/guild/auto_moderation/action.rs +++ b/twilight-model/src/guild/auto_moderation/action.rs @@ -20,6 +20,11 @@ pub struct AutoModerationActionMetadata { /// Channel to which user content should be logged. #[serde(skip_serializing_if = "Option::is_none")] pub channel_id: Option>, + /// Additional explanation that will be shown to members whenever their message is blocked. + /// + /// Maximum value length is 150 characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub custom_message: Option, /// Timeout duration in seconds. /// /// Maximum value is 2419200 seconds, or 4 weeks. @@ -78,7 +83,11 @@ mod tests { use std::{fmt::Debug, hash::Hash}; assert_fields!(AutoModerationAction: kind, metadata); - assert_fields!(AutoModerationActionMetadata: channel_id, duration_seconds); + assert_fields!( + AutoModerationActionMetadata: channel_id, + custom_message, + duration_seconds + ); assert_impl_all!( AutoModerationAction: Clone, Debug, diff --git a/twilight-model/src/guild/auto_moderation/mod.rs b/twilight-model/src/guild/auto_moderation/mod.rs index cc284333f50..b2dbef80de0 100644 --- a/twilight-model/src/guild/auto_moderation/mod.rs +++ b/twilight-model/src/guild/auto_moderation/mod.rs @@ -122,6 +122,7 @@ mod tests { kind: AutoModerationActionType::SendAlertMessage, metadata: Some(AutoModerationActionMetadata { channel_id: Some(ACTION_CHANNEL_ID), + custom_message: None, duration_seconds: None, }), }, @@ -129,6 +130,7 @@ mod tests { kind: AutoModerationActionType::Timeout, metadata: Some(AutoModerationActionMetadata { channel_id: None, + custom_message: None, duration_seconds: Some(120), }), }, diff --git a/twilight-validate/src/request.rs b/twilight-validate/src/request.rs index a4ca29eac28..94ec94a7911 100644 --- a/twilight-validate/src/request.rs +++ b/twilight-validate/src/request.rs @@ -12,6 +12,9 @@ use twilight_model::util::Timestamp; /// The maximum audit log reason length in UTF-16 codepoints. pub const AUDIT_REASON_MAX: usize = 512; +/// Maximum length of an auto moderation block action's custom message. +pub const AUTO_MODERATION_ACTION_BLOCK_CUSTOM_MESSAGE_LENGTH_MAX: usize = 150; + /// Maximum amount of mentions that triggers an auto moderation action. pub const AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT: u8 = 50; @@ -177,6 +180,13 @@ impl Display for ValidationError { Display::fmt(&AUDIT_REASON_MAX, f) } + ValidationErrorType::AutoModerationBlockActionCustomMessageLimit { len } => { + f.write_str("provided auto moderation block action custom message length is ")?; + Display::fmt(len, f)?; + f.write_str(", but it must be at most ")?; + + Display::fmt(&AUTO_MODERATION_ACTION_BLOCK_CUSTOM_MESSAGE_LENGTH_MAX, f) + } ValidationErrorType::AutoModerationMetadataMentionTotalLimit { limit } => { f.write_str("provided auto moderation metadata mention_total_limit is ")?; Display::fmt(limit, f)?; @@ -388,6 +398,11 @@ pub enum ValidationErrorType { /// Invalid length. len: usize, }, + /// Provided block action custom message was too long. + AutoModerationBlockActionCustomMessageLimit { + /// Invalid limit. + len: usize, + }, /// Provided limit was too large. AutoModerationMetadataMentionTotalLimit { /// Invalid limit. @@ -532,6 +547,31 @@ pub fn audit_reason(audit_reason: impl AsRef) -> Result<(), ValidationError } } +/// Ensure that an auto moderation block action's `custom_message` is correct. +/// +/// The length must be at most [`AUTO_MODERATION_ACTION_BLOCK_CUSTOM_MESSAGE_LENGTH_MAX`]. +/// This is based on [this documentation entry]. +/// +/// # Errors +/// +/// Returns an error of type [`AutoModerationBlockActionCustomMessageLimit`] if the +/// length is invalid. +/// +/// [`AutoModerationBlockActionCustomMessageLimit`]: ValidationErrorType::AutoModerationBlockActionCustomMessageLimit +/// [this documentation entry]: https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata +pub fn auto_moderation_block_action_custom_message_limit( + custom_message: impl AsRef, +) -> Result<(), ValidationError> { + let len = custom_message.as_ref().chars().count(); + if len <= AUTO_MODERATION_ACTION_BLOCK_CUSTOM_MESSAGE_LENGTH_MAX { + Ok(()) + } else { + Err(ValidationError { + kind: ValidationErrorType::AutoModerationBlockActionCustomMessageLimit { len }, + }) + } +} + /// Ensure that an auto moderation rule's `mention_total_limit` is correct. /// /// The length must be at most [`AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT`]. @@ -1128,6 +1168,18 @@ mod tests { assert!(audit_reason("a".repeat(513)).is_err()); } + #[test] + fn auto_moderation_block_action_custom_message() { + assert!(auto_moderation_block_action_custom_message_limit("").is_ok()); + assert!(auto_moderation_block_action_custom_message_limit("a".repeat(150)).is_ok()); + assert!(matches!( + auto_moderation_block_action_custom_message_limit("a".repeat(151)) + .unwrap_err() + .kind, + ValidationErrorType::AutoModerationBlockActionCustomMessageLimit { len: 151 } + )); + } + #[test] fn auto_moderation_metadata_mention_total() { assert!(auto_moderation_metadata_mention_total_limit(0).is_ok());