titanium_model/
automod.rs

1//! AutoMod types for Discord's automatic moderation system.
2//!
3//! AutoMod allows guilds to automatically filter and moderate content.
4
5use crate::Snowflake;
6use serde::{Deserialize, Serialize};
7use serde_repr::{Deserialize_repr, Serialize_repr};
8
9/// An AutoMod rule.
10#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct AutoModRule {
12    /// The ID of this rule.
13    pub id: Snowflake,
14
15    /// The ID of the guild which this rule belongs to.
16    pub guild_id: Snowflake,
17
18    /// The rule name.
19    pub name: String,
20
21    /// The user which first created this rule.
22    pub creator_id: Snowflake,
23
24    /// The rule event type.
25    pub event_type: AutoModEventType,
26
27    /// The rule trigger type.
28    pub trigger_type: AutoModTriggerType,
29
30    /// The rule trigger metadata.
31    pub trigger_metadata: AutoModTriggerMetadata,
32
33    /// The actions which will execute when the rule is triggered.
34    pub actions: Vec<AutoModAction>,
35
36    /// Whether the rule is enabled.
37    pub enabled: bool,
38
39    /// The role IDs that should not be affected by the rule.
40    #[serde(default)]
41    pub exempt_roles: Vec<Snowflake>,
42
43    /// The channel IDs that should not be affected by the rule.
44    #[serde(default)]
45    pub exempt_channels: Vec<Snowflake>,
46}
47
48/// AutoMod event types.
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
50#[repr(u8)]
51pub enum AutoModEventType {
52    /// When a member sends or edits a message.
53    MessageSend = 1,
54    /// When a member edits their profile.
55    MemberUpdate = 2,
56}
57
58/// AutoMod trigger types.
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
60#[repr(u8)]
61pub enum AutoModTriggerType {
62    /// Check if content contains words from a user defined list.
63    Keyword = 1,
64    /// Check if content represents generic spam.
65    Spam = 3,
66    /// Check if content contains words from internal pre-defined wordsets.
67    KeywordPreset = 4,
68    /// Check if content contains more unique mentions than allowed.
69    MentionSpam = 5,
70    /// Check if member profile contains words from a user defined list.
71    MemberProfile = 6,
72}
73
74/// Metadata for AutoMod triggers.
75#[derive(Debug, Clone, Default, Deserialize, Serialize)]
76pub struct AutoModTriggerMetadata {
77    /// Substrings which will be searched for in content.
78    #[serde(default)]
79    pub keyword_filter: Vec<String>,
80
81    /// Regular expression patterns which will be matched against content.
82    #[serde(default)]
83    pub regex_patterns: Vec<String>,
84
85    /// The internally pre-defined wordsets which will be searched for.
86    #[serde(default)]
87    pub presets: Vec<AutoModKeywordPresetType>,
88
89    /// Substrings which should not trigger the rule.
90    #[serde(default)]
91    pub allow_list: Vec<String>,
92
93    /// Total number of unique role and user mentions allowed per message.
94    #[serde(default)]
95    pub mention_total_limit: Option<u32>,
96
97    /// Whether to automatically detect mention raids.
98    #[serde(default)]
99    pub mention_raid_protection_enabled: bool,
100}
101
102/// Pre-defined keyword preset types.
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
104#[repr(u8)]
105pub enum AutoModKeywordPresetType {
106    /// Words that may be considered forms of swearing or cursing.
107    Profanity = 1,
108    /// Words that refer to sexually explicit behavior or activity.
109    SexualContent = 2,
110    /// Personal insults or words that may be considered hate speech.
111    Slurs = 3,
112}
113
114/// An action which will execute whenever a rule is triggered.
115#[derive(Debug, Clone, Deserialize, Serialize)]
116pub struct AutoModAction {
117    /// The type of action.
118    #[serde(rename = "type")]
119    pub action_type: AutoModActionType,
120
121    /// Additional metadata needed during execution.
122    #[serde(default)]
123    pub metadata: Option<AutoModActionMetadata>,
124}
125
126/// AutoMod action types.
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
128#[repr(u8)]
129pub enum AutoModActionType {
130    /// Blocks a member's message and prevents it from being posted.
131    BlockMessage = 1,
132    /// Logs user content to a specified channel.
133    SendAlertMessage = 2,
134    /// Timeout user for a specified duration.
135    Timeout = 3,
136    /// Prevents a member from using text, voice, or other interactions.
137    BlockMemberInteraction = 4,
138}
139
140/// Metadata for AutoMod actions.
141#[derive(Debug, Clone, Default, Deserialize, Serialize)]
142pub struct AutoModActionMetadata {
143    /// Channel to which user content should be logged.
144    #[serde(default)]
145    pub channel_id: Option<Snowflake>,
146
147    /// Timeout duration in seconds.
148    #[serde(default)]
149    pub duration_seconds: Option<u64>,
150
151    /// Additional explanation that will be shown to members.
152    #[serde(default)]
153    pub custom_message: Option<String>,
154}
155
156/// Sent when a rule is triggered and an action is executed.
157#[derive(Debug, Clone, Deserialize, Serialize)]
158pub struct AutoModActionExecution {
159    /// ID of the guild in which action was executed.
160    pub guild_id: Snowflake,
161
162    /// Action which was executed.
163    pub action: AutoModAction,
164
165    /// ID of the rule which action belongs to.
166    pub rule_id: Snowflake,
167
168    /// Trigger type of rule which was triggered.
169    pub rule_trigger_type: AutoModTriggerType,
170
171    /// ID of the user which generated the content which triggered the rule.
172    pub user_id: Snowflake,
173
174    /// ID of the channel in which user content was posted.
175    #[serde(default)]
176    pub channel_id: Option<Snowflake>,
177
178    /// ID of any user message which content belongs to.
179    #[serde(default)]
180    pub message_id: Option<Snowflake>,
181
182    /// ID of any system auto moderation messages posted as a result of this action.
183    #[serde(default)]
184    pub alert_system_message_id: Option<Snowflake>,
185
186    /// User-generated text content.
187    #[serde(default)]
188    pub content: String,
189
190    /// Word or phrase configured in the rule that triggered the rule.
191    #[serde(default)]
192    pub matched_keyword: Option<String>,
193
194    /// Substring in content that triggered the rule.
195    #[serde(default)]
196    pub matched_content: Option<String>,
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202
203    #[test]
204    fn test_automod_action_type() {
205        let json = "1";
206        let action_type: AutoModActionType = crate::json::from_str(json).unwrap();
207        assert_eq!(action_type, AutoModActionType::BlockMessage);
208    }
209
210    #[test]
211    fn test_automod_trigger_metadata() {
212        let json = r#"{
213            "keyword_filter": ["badword"],
214            "regex_patterns": ["\\d+"],
215            "allow_list": ["exception"]
216        }"#;
217
218        let metadata: AutoModTriggerMetadata = crate::json::from_str(json).unwrap();
219        assert_eq!(metadata.keyword_filter.len(), 1);
220    }
221}