Skip to content

Commit

Permalink
feat(http, model, validate): support automod custom messages (twiligh…
Browse files Browse the repository at this point in the history
…t-rs#2161)

Add support for the new `custom_message` field available on AutoMod
`BLOCK_MESSAGE` actions.

Discord API Docs:
discord/discord-api-docs#5955
  • Loading branch information
suneettipirneni authored Feb 26, 2023
1 parent bd3d025 commit 94ab90d
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -36,6 +37,10 @@ struct CreateAutoModerationRuleFieldsAction {
struct CreateAutoModerationRuleFieldsActionMetadata {
/// Channel to which user content should be logged.
pub channel_id: Option<Id<ChannelMarker>>,
/// Additional explanation that will be shown to members whenever their message is blocked.
///
/// Maximum value length is 150 characters.
pub custom_message: Option<String>,
/// Timeout duration in seconds.
///
/// Maximum value is 2419200 seconds, or 4 weeks.
Expand Down Expand Up @@ -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<Self, ValidationError> {
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
Expand Down
11 changes: 10 additions & 1 deletion twilight-model/src/guild/auto_moderation/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Id<ChannelMarker>>,
/// 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<String>,
/// Timeout duration in seconds.
///
/// Maximum value is 2419200 seconds, or 4 weeks.
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions twilight-model/src/guild/auto_moderation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,15 @@ mod tests {
kind: AutoModerationActionType::SendAlertMessage,
metadata: Some(AutoModerationActionMetadata {
channel_id: Some(ACTION_CHANNEL_ID),
custom_message: None,
duration_seconds: None,
}),
},
AutoModerationAction {
kind: AutoModerationActionType::Timeout,
metadata: Some(AutoModerationActionMetadata {
channel_id: None,
custom_message: None,
duration_seconds: Some(120),
}),
},
Expand Down
52 changes: 52 additions & 0 deletions twilight-validate/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -532,6 +547,31 @@ pub fn audit_reason(audit_reason: impl AsRef<str>) -> 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<str>,
) -> 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`].
Expand Down Expand Up @@ -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());
Expand Down

0 comments on commit 94ab90d

Please sign in to comment.