tg_flows/types/
chat_permissions.rs

1use serde::{Deserialize, Serialize};
2use std::ops::Not;
3
4bitflags::bitflags! {
5    /// Describes actions that a non-administrator user is allowed to take in a
6    /// chat.
7    ///
8    /// [The official docs](https://core.telegram.org/bots/api#chatpermissions).
9    ///
10    /// ## Examples
11    ///
12    /// ```
13    /// use teloxide_core::types::ChatPermissions;
14    ///
15    /// // No permissions, nothing is allowed
16    /// let _ = ChatPermissions::empty();
17    ///
18    /// // All permissions, everything is allowed
19    /// let _ = ChatPermissions::all();
20    ///
21    /// // One particular permission
22    /// let permissions_v0 = ChatPermissions::INVITE_USERS;
23    ///
24    /// // Check what is permitted
25    /// assert!(permissions_v0.contains(ChatPermissions::INVITE_USERS));
26    /// assert!(!permissions_v0.contains(ChatPermissions::SEND_MESSAGES));
27    ///
28    /// // Union, add permissions
29    /// let permissions_v1 = permissions_v0 | ChatPermissions::SEND_MEDIA_MESSAGES;
30    /// assert!(permissions_v1.contains(ChatPermissions::INVITE_USERS));
31    /// assert!(permissions_v1.contains(ChatPermissions::SEND_MEDIA_MESSAGES));
32    ///
33    /// // Implied by `SEND_MEDIA_MESSAGES`
34    /// assert!(permissions_v1.contains(ChatPermissions::SEND_MESSAGES));
35    ///
36    /// // Difference, remove permissions
37    /// let permissions_v2 = permissions_v1 - ChatPermissions::SEND_MEDIA_MESSAGES;
38    /// assert!(!permissions_v2.contains(ChatPermissions::SEND_MEDIA_MESSAGES));
39    ///
40    /// // Removing `SEND_MEDIA_MESSAGES` also removes `SEND_MESSAGES` and vice versa
41    /// // because `SEND_MESSAGES` is implied by `SEND_MEDIA_MESSAGES`
42    /// assert!(!permissions_v2.contains(ChatPermissions::SEND_MESSAGES));
43    ///
44    /// let permissions_v3 = permissions_v1 - ChatPermissions::SEND_MESSAGES;
45    /// assert!(!permissions_v3.contains(ChatPermissions::SEND_MEDIA_MESSAGES));
46    /// ```
47    #[derive(Serialize, Deserialize)]
48    #[serde(from = "ChatPermissionsRaw", into = "ChatPermissionsRaw")]
49    pub struct ChatPermissions: u16 {
50        /// Set if the user is allowed to send text messages, contacts,
51        /// locations and venues.
52        const SEND_MESSAGES = 1;
53
54        /// Set if the user is allowed to send audios, documents,
55        /// photos, videos, video notes and voice notes, implies
56        /// `SEND_MESSAGES`.
57        const SEND_MEDIA_MESSAGES = (1 << 1) | Self::SEND_MESSAGES.bits;
58
59        /// Set if the user is allowed to send polls, implies
60        /// `SEND_MESSAGES`.
61        const SEND_POLLS = (1 << 2) | Self::SEND_MESSAGES.bits;
62
63        /// Set if the user is allowed to send animations, games, stickers and
64        /// use inline bots, implies `SEND_MEDIA_MESSAGES`.
65        const SEND_OTHER_MESSAGES = (1 << 3) | Self::SEND_MEDIA_MESSAGES.bits;
66
67        /// Set if the user is allowed to add web page previews to
68        /// their messages, implies `SEND_MEDIA_MESSAGES`.
69        const ADD_WEB_PAGE_PREVIEWS = (1 << 4) | Self::SEND_MEDIA_MESSAGES.bits;
70
71        /// Set if the user is allowed to change the chat title, photo and
72        /// other settings. Ignored in public supergroups.
73        const CHANGE_INFO = (1 << 5);
74
75        /// Set if the user is allowed to invite new users to the chat.
76        const INVITE_USERS = (1 << 6);
77
78        /// Set if the user is allowed to pin messages. Ignored in public
79        /// supergroups.
80        const PIN_MESSAGES = (1 << 7);
81
82        /// Set if the user is allowed to create, rename, close, and reopen forum topics.
83        const MANAGE_TOPICS = (1 << 8);
84    }
85}
86
87impl ChatPermissions {
88    /// Checks for [`SEND_MESSAGES`] permission.
89    ///
90    /// [`SEND_MESSAGES`]: ChatPermissions::SEND_MESSAGES
91    pub fn can_send_messages(&self) -> bool {
92        self.contains(ChatPermissions::SEND_MESSAGES)
93    }
94
95    /// Checks for [`SEND_MEDIA_MESSAGES`] permission.
96    ///
97    /// [`SEND_MEDIA_MESSAGES`]: ChatPermissions::SEND_MEDIA_MESSAGES
98    pub fn can_send_media_messages(&self) -> bool {
99        self.contains(ChatPermissions::SEND_MEDIA_MESSAGES)
100    }
101
102    /// Checks for [`SEND_POLLS`] permission.
103    ///
104    /// [`SEND_POLLS`]: ChatPermissions::SEND_POLLS
105    pub fn can_send_polls(&self) -> bool {
106        self.contains(ChatPermissions::SEND_POLLS)
107    }
108
109    /// Checks for [`SEND_OTHER_MESSAGES`] permission.
110    ///
111    /// [`SEND_OTHER_MESSAGES`]: ChatPermissions::SEND_OTHER_MESSAGES
112    pub fn can_send_other_messages(&self) -> bool {
113        self.contains(ChatPermissions::SEND_OTHER_MESSAGES)
114    }
115
116    /// Checks for [`ADD_WEB_PAGE_PREVIEWS`] permission.
117    ///
118    /// [`ADD_WEB_PAGE_PREVIEWS`]: ChatPermissions::ADD_WEB_PAGE_PREVIEWS
119    pub fn can_add_web_page_previews(&self) -> bool {
120        self.contains(ChatPermissions::ADD_WEB_PAGE_PREVIEWS)
121    }
122
123    /// Checks for [`CHANGE_INFO`] permission.
124    ///
125    /// [`CHANGE_INFO`]: ChatPermissions::CHANGE_INFO
126    pub fn can_change_info(&self) -> bool {
127        self.contains(ChatPermissions::CHANGE_INFO)
128    }
129
130    /// Checks for [`INVITE_USERS`] permission.
131    ///
132    /// [`INVITE_USERS`]: ChatPermissions::INVITE_USERS
133    pub fn can_invite_users(&self) -> bool {
134        self.contains(ChatPermissions::INVITE_USERS)
135    }
136
137    /// Checks for [`PIN_MESSAGES`] permission.
138    ///
139    /// [`PIN_MESSAGES`]: ChatPermissions::PIN_MESSAGES
140    pub fn can_pin_messages(&self) -> bool {
141        self.contains(ChatPermissions::PIN_MESSAGES)
142    }
143
144    /// Checks for [`MANAGE_TOPICS`] permission.
145    ///
146    /// [`MANAGE_TOPICS`]: ChatPermissions::MANAGE_TOPICS
147    pub fn can_manage_topics(&self) -> bool {
148        self.contains(ChatPermissions::MANAGE_TOPICS)
149    }
150}
151
152/// Helper for (de)serialization
153#[derive(Serialize, Deserialize)]
154struct ChatPermissionsRaw {
155    #[serde(default, skip_serializing_if = "Not::not")]
156    can_send_messages: bool,
157
158    #[serde(default, skip_serializing_if = "Not::not")]
159    can_send_media_messages: bool,
160
161    #[serde(default, skip_serializing_if = "Not::not")]
162    can_send_polls: bool,
163
164    #[serde(default, skip_serializing_if = "Not::not")]
165    can_send_other_messages: bool,
166
167    #[serde(default, skip_serializing_if = "Not::not")]
168    can_add_web_page_previews: bool,
169
170    #[serde(default, skip_serializing_if = "Not::not")]
171    can_change_info: bool,
172
173    #[serde(default, skip_serializing_if = "Not::not")]
174    can_invite_users: bool,
175
176    #[serde(default, skip_serializing_if = "Not::not")]
177    can_pin_messages: bool,
178
179    // HACK: do not `skip_serializing_if = "Not::not"`, from tg docs:
180    //       > If omitted defaults to the value of `can_pin_messages`
181    //       but we don't have two different values for "absent" and "false"...
182    //       or did they mean that `can_pin_messages` implies `can_manage_topics`?..
183    #[serde(default)]
184    can_manage_topics: bool,
185}
186
187impl From<ChatPermissions> for ChatPermissionsRaw {
188    fn from(this: ChatPermissions) -> Self {
189        Self {
190            can_send_messages: this.can_send_messages(),
191            can_send_media_messages: this.can_send_media_messages(),
192            can_send_polls: this.can_send_polls(),
193            can_send_other_messages: this.can_send_other_messages(),
194            can_add_web_page_previews: this.can_add_web_page_previews(),
195            can_change_info: this.can_change_info(),
196            can_invite_users: this.can_invite_users(),
197            can_pin_messages: this.can_pin_messages(),
198            can_manage_topics: this.can_manage_topics(),
199        }
200    }
201}
202
203impl From<ChatPermissionsRaw> for ChatPermissions {
204    fn from(
205        ChatPermissionsRaw {
206            can_send_messages,
207            can_send_media_messages,
208            can_send_polls,
209            can_send_other_messages,
210            can_add_web_page_previews,
211            can_change_info,
212            can_invite_users,
213            can_pin_messages,
214            can_manage_topics,
215        }: ChatPermissionsRaw,
216    ) -> Self {
217        let mut this = Self::empty();
218
219        if can_send_messages {
220            this |= Self::SEND_MESSAGES;
221        }
222        if can_send_media_messages {
223            this |= Self::SEND_MEDIA_MESSAGES
224        }
225        if can_send_polls {
226            this |= Self::SEND_POLLS;
227        }
228        if can_send_other_messages {
229            this |= Self::SEND_OTHER_MESSAGES;
230        }
231        if can_add_web_page_previews {
232            this |= Self::ADD_WEB_PAGE_PREVIEWS;
233        }
234        if can_change_info {
235            this |= Self::CHANGE_INFO;
236        }
237        if can_invite_users {
238            this |= Self::INVITE_USERS;
239        }
240        if can_pin_messages {
241            this |= Self::PIN_MESSAGES;
242        }
243        // FIXME: should we do `|| can_pin_messages` here? (the same tg doc weirdness)
244        if can_manage_topics {
245            this |= Self::MANAGE_TOPICS
246        }
247
248        this
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::ChatPermissions;
255
256    #[test]
257    fn serialization() {
258        let permissions = ChatPermissions::SEND_MEDIA_MESSAGES | ChatPermissions::PIN_MESSAGES;
259        let expected = r#"{"can_send_messages":true,"can_send_media_messages":true,"can_pin_messages":true,"can_manage_topics":false}"#;
260        let actual = serde_json::to_string(&permissions).unwrap();
261        assert_eq!(expected, actual);
262    }
263
264    #[test]
265    fn deserialization() {
266        let json =
267            r#"{"can_send_messages":true,"can_send_media_messages":true,"can_pin_messages":true}"#;
268        let expected = ChatPermissions::SEND_MEDIA_MESSAGES | ChatPermissions::PIN_MESSAGES;
269        let actual = serde_json::from_str(json).unwrap();
270        assert_eq!(expected, actual);
271    }
272}