twilight_model/channel/message/
allowed_mentions.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::{
    id::{
        marker::{RoleMarker, UserMarker},
        Id,
    },
    util::is_false,
};
use serde::{Deserialize, Serialize};

/// Allowed mentions (pings).
///
/// Filters mentions to only ping one's specified here, regardless of the message's content[^1].
///
/// Mentions can be clicked to reveal additional context, whilst only requiring an ID to create. See
/// [Discord Docs/Message Formatting].
///
/// [`AllowedMentions::default`] disallows all pings.
///
/// [^1]: Messages must still contain mentions, e.g. `@everyone`!
///
/// [Discord Docs/Message Formatting]: https://discord.com/developers/docs/reference#message-formatting
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct AllowedMentions {
    /// List of allowed mention types.
    ///
    /// [`MentionType::Roles`] and [`MentionType::Users`] allows all roles and users to be
    /// mentioned; they are mutually exclusive with the [`roles`] and [`users`] fields.
    ///
    /// [`roles`]: Self::roles
    /// [`users`]: Self::users
    #[serde(default)]
    pub parse: Vec<MentionType>,
    /// For replies, whether to mention the message author.
    ///
    /// Defaults to false.
    #[serde(default, skip_serializing_if = "is_false")]
    pub replied_user: bool,
    /// List of roles to mention.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub roles: Vec<Id<RoleMarker>>,
    /// List of users to mention.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub users: Vec<Id<UserMarker>>,
}

/// Allowed mention type.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[non_exhaustive]
#[serde(rename_all = "lowercase")]
pub enum MentionType {
    /// `@everyone` and `@here` mentions.
    Everyone,
    /// Role mentions.
    Roles,
    /// User mentions.
    Users,
}

#[cfg(test)]
mod tests {
    use super::{AllowedMentions, MentionType};
    use crate::id::Id;
    use serde_test::Token;

    #[test]
    fn minimal() {
        let value = AllowedMentions {
            parse: Vec::new(),
            users: Vec::new(),
            roles: Vec::new(),
            replied_user: false,
        };

        serde_test::assert_tokens(
            &value,
            &[
                Token::Struct {
                    name: "AllowedMentions",
                    len: 1,
                },
                Token::Str("parse"),
                Token::Seq { len: Some(0) },
                Token::SeqEnd,
                Token::StructEnd,
            ],
        );
    }

    #[test]
    fn full() {
        let value = AllowedMentions {
            parse: Vec::from([MentionType::Everyone]),
            users: Vec::from([Id::new(100)]),
            roles: Vec::from([Id::new(200)]),
            replied_user: true,
        };

        serde_test::assert_tokens(
            &value,
            &[
                Token::Struct {
                    name: "AllowedMentions",
                    len: 4,
                },
                Token::Str("parse"),
                Token::Seq { len: Some(1) },
                Token::UnitVariant {
                    name: "MentionType",
                    variant: "everyone",
                },
                Token::SeqEnd,
                Token::Str("replied_user"),
                Token::Bool(true),
                Token::Str("roles"),
                Token::Seq { len: Some(1) },
                Token::NewtypeStruct { name: "Id" },
                Token::Str("200"),
                Token::SeqEnd,
                Token::Str("users"),
                Token::Seq { len: Some(1) },
                Token::NewtypeStruct { name: "Id" },
                Token::Str("100"),
                Token::SeqEnd,
                Token::StructEnd,
            ],
        );
    }
}