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}