Make ChatPermissions into bitflags

This commit is contained in:
Maybe Waffle 2021-12-29 20:36:08 +03:00
parent fd3ef0bdf3
commit 62e9e8afd4
3 changed files with 178 additions and 80 deletions

View file

@ -43,11 +43,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `InputFile` and related structures now do **not** implement `PartialEq`, `Eq` and `Hash` ([#133][pr133]) - `InputFile` and related structures now do **not** implement `PartialEq`, `Eq` and `Hash` ([#133][pr133])
- How forwarded messages are represented ([#151][pr151]) - How forwarded messages are represented ([#151][pr151])
- `RequestError::InvalidJson` now has a `raw` field with raw json for easier debugability ([#150][pr150]) - `RequestError::InvalidJson` now has a `raw` field with raw json for easier debugability ([#150][pr150])
- `ChatPermissions` is now bitflags ([#157][pr157])
[pr115]: https://github.com/teloxide/teloxide-core/pull/115 [pr115]: https://github.com/teloxide/teloxide-core/pull/115
[pr125]: https://github.com/teloxide/teloxide-core/pull/125 [pr125]: https://github.com/teloxide/teloxide-core/pull/125
[pr134]: https://github.com/teloxide/teloxide-core/pull/134 [pr134]: https://github.com/teloxide/teloxide-core/pull/134
[pr150]: https://github.com/teloxide/teloxide-core/pull/150 [pr150]: https://github.com/teloxide/teloxide-core/pull/150
[pr157]: https://github.com/teloxide/teloxide-core/pull/157
### Fixed ### Fixed

View file

@ -42,9 +42,9 @@ once_cell = "1.5.0"
never = "0.1.0" never = "0.1.0"
chrono = { version = "0.4.19", default-features = false } chrono = { version = "0.4.19", default-features = false }
either = "1.6.1" either = "1.6.1"
bitflags = { version = "1.2" }
vecrem = { version = "0.1", optional = true } vecrem = { version = "0.1", optional = true }
bitflags = { version = "1.2", optional = true }
[dev-dependencies] [dev-dependencies]
pretty_env_logger = "0.4" pretty_env_logger = "0.4"
@ -66,7 +66,7 @@ nightly = []
throttle = ["vecrem"] throttle = ["vecrem"]
# Trace bot adaptor # Trace bot adaptor
trace_adaptor = ["bitflags"] trace_adaptor = []
# Erased bot adaptor # Erased bot adaptor
erased = [] erased = []

View file

@ -1,96 +1,192 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::Not;
/// Describes actions that a non-administrator user is allowed to take in a bitflags::bitflags! {
/// chat. /// Describes actions that a non-administrator user is allowed to take in a
/// /// chat.
/// [The official docs](https://core.telegram.org/bots/api#chatpermissions). ///
#[serde_with_macros::skip_serializing_none] /// [The official docs](https://core.telegram.org/bots/api#chatpermissions).
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] ///
pub struct ChatPermissions { /// ## Examples
/// `true`, if the user is allowed to send text messages, contacts, ///
/// locations and venues. /// ```
pub can_send_messages: Option<bool>, /// use teloxide_core::types::ChatPermissions;
///
/// // No permissions, nothing is allowed
/// let _ = ChatPermissions::empty();
///
/// // All permissions, everything is allowed
/// let _ = ChatPermissions::all();
///
/// // One particular permission
/// let permissions_v0 = ChatPermissions::INVITE_USERS;
///
/// // Check what is permitted
/// assert!(permissions_v0.contains(ChatPermissions::INVITE_USERS));
/// assert!(!permissions_v0.contains(ChatPermissions::SEND_MESSAGES));
///
/// // Union, add permissions
/// let permissions_v1 = permissions_v0 | ChatPermissions::SEND_MEDIA_MESSAGES;
/// assert!(permissions_v1.contains(ChatPermissions::INVITE_USERS));
/// assert!(permissions_v1.contains(ChatPermissions::SEND_MEDIA_MESSAGES));
///
/// // Implied by `SEND_MEDIA_MESSAGES`
/// assert!(permissions_v1.contains(ChatPermissions::SEND_MESSAGES));
///
/// // Difference, remove permissions
/// let permissions_v2 = permissions_v1 - ChatPermissions::SEND_MEDIA_MESSAGES;
/// assert!(!permissions_v2.contains(ChatPermissions::SEND_MEDIA_MESSAGES));
///
/// // Removing `SEND_MEDIA_MESSAGES` also removes `SEND_MESSAGES` and vice versa
/// // because `SEND_MESSAGES` is implied by `SEND_MEDIA_MESSAGES`
/// assert!(!permissions_v2.contains(ChatPermissions::SEND_MESSAGES));
///
/// let permissions_v3 = permissions_v1 - ChatPermissions::SEND_MESSAGES;
/// assert!(!permissions_v3.contains(ChatPermissions::SEND_MEDIA_MESSAGES));
/// ```
#[derive(Serialize, Deserialize)]
#[serde(from = "ChatPermissionsRaw", into = "ChatPermissionsRaw")]
pub struct ChatPermissions: u8 {
/// Set if the user is allowed to send text messages, contacts,
/// locations and venues.
const SEND_MESSAGES = 1;
/// `true`, if the user is allowed to send audios, documents, /// Set if the user is allowed to send audios, documents,
/// photos, videos, video notes and voice notes, implies /// photos, videos, video notes and voice notes, implies
/// `can_send_messages`. /// `SEND_MESSAGES`.
pub can_send_media_messages: Option<bool>, const SEND_MEDIA_MESSAGES = (1 << 1) | Self::SEND_MESSAGES.bits;
/// `true`, if the user is allowed to send polls, implies /// Set if the user is allowed to send polls, implies
/// `can_send_messages`. /// `SEND_MESSAGES`.
pub can_send_polls: Option<bool>, const SEND_POLLS = (1 << 2) | Self::SEND_MESSAGES.bits;
/// `true`, if the user is allowed to send animations, games, stickers and /// Set if the user is allowed to send animations, games, stickers and
/// use inline bots, implies `can_send_media_messages`. /// use inline bots, implies `SEND_MEDIA_MESSAGES`.
pub can_send_other_messages: Option<bool>, const SEND_OTHER_MESSAGES = (1 << 3) | Self::SEND_MEDIA_MESSAGES.bits;
/// `true`, if the user is allowed to add web page previews to /// Set if the user is allowed to add web page previews to
/// their messages, implies `can_send_media_messages`. /// their messages, implies `SEND_MEDIA_MESSAGES`.
pub can_add_web_page_previews: Option<bool>, const ADD_WEB_PAGE_PREVIEWS = (1 << 4) | Self::SEND_MEDIA_MESSAGES.bits;
/// `true`, if the user is allowed to change the chat title, photo and /// Set if the user is allowed to change the chat title, photo and
/// other settings. Ignored in public supergroups. /// other settings. Ignored in public supergroups.
pub can_change_info: Option<bool>, const CHANGE_INFO = (1 << 5);
/// `true`, if the user is allowed to invite new users to the chat. /// Set if the user is allowed to invite new users to the chat.
pub can_invite_users: Option<bool>, const INVITE_USERS = (1 << 6);
/// `true`, if the user is allowed to pin messages. Ignored in public /// Set if the user is allowed to pin messages. Ignored in public
/// supergroups. /// supergroups.
pub can_pin_messages: Option<bool>, const PIN_MESSAGES = (1 << 7);
}
} }
impl ChatPermissions { /// Helper for (de)serialization
pub const fn new() -> Self { #[derive(Serialize, Deserialize)]
Self { struct ChatPermissionsRaw {
can_send_messages: None, #[serde(default, skip_serializing_if = "Not::not")]
can_send_media_messages: None, can_send_messages: bool,
can_send_polls: None,
can_send_other_messages: None, #[serde(default, skip_serializing_if = "Not::not")]
can_add_web_page_previews: None, can_send_media_messages: bool,
can_change_info: None,
can_invite_users: None, #[serde(default, skip_serializing_if = "Not::not")]
can_pin_messages: None, can_send_polls: bool,
#[serde(default, skip_serializing_if = "Not::not")]
can_send_other_messages: bool,
#[serde(default, skip_serializing_if = "Not::not")]
can_add_web_page_previews: bool,
#[serde(default, skip_serializing_if = "Not::not")]
can_change_info: bool,
#[serde(default, skip_serializing_if = "Not::not")]
can_invite_users: bool,
#[serde(default, skip_serializing_if = "Not::not")]
can_pin_messages: bool,
}
impl Into<ChatPermissionsRaw> for ChatPermissions {
fn into(self) -> ChatPermissionsRaw {
ChatPermissionsRaw {
can_send_messages: self.contains(ChatPermissions::SEND_MESSAGES),
can_send_media_messages: self.contains(ChatPermissions::SEND_MEDIA_MESSAGES),
can_send_polls: self.contains(ChatPermissions::SEND_POLLS),
can_send_other_messages: self.contains(ChatPermissions::SEND_OTHER_MESSAGES),
can_add_web_page_previews: self.contains(ChatPermissions::ADD_WEB_PAGE_PREVIEWS),
can_change_info: self.contains(ChatPermissions::CHANGE_INFO),
can_invite_users: self.contains(ChatPermissions::INVITE_USERS),
can_pin_messages: self.contains(ChatPermissions::PIN_MESSAGES),
} }
} }
}
pub const fn can_send_messages(mut self, val: bool) -> Self { impl From<ChatPermissionsRaw> for ChatPermissions {
self.can_send_messages = Some(val); fn from(
self ChatPermissionsRaw {
} can_send_messages,
can_send_media_messages,
can_send_polls,
can_send_other_messages,
can_add_web_page_previews,
can_change_info,
can_invite_users,
can_pin_messages,
}: ChatPermissionsRaw,
) -> Self {
let mut this = Self::empty();
pub const fn can_send_media_messages(mut self, val: bool) -> Self { if can_send_messages {
self.can_send_media_messages = Some(val); this |= Self::SEND_MESSAGES;
self }
} if can_send_media_messages {
this |= Self::SEND_MEDIA_MESSAGES
}
if can_send_polls {
this |= Self::SEND_POLLS;
}
if can_send_other_messages {
this |= Self::SEND_OTHER_MESSAGES;
}
if can_add_web_page_previews {
this |= Self::ADD_WEB_PAGE_PREVIEWS;
}
if can_change_info {
this |= Self::CHANGE_INFO;
}
if can_invite_users {
this |= Self::INVITE_USERS;
}
if can_pin_messages {
this |= Self::PIN_MESSAGES;
}
pub const fn can_send_polls(mut self, val: bool) -> Self { this
self.can_send_polls = Some(val); }
self }
}
#[cfg(test)]
pub const fn can_send_other_messages(mut self, val: bool) -> Self { mod tests {
self.can_send_other_messages = Some(val); use super::ChatPermissions;
self
} #[test]
fn serialization() {
pub const fn can_add_web_page_previews(mut self, val: bool) -> Self { let permissions = ChatPermissions::SEND_MEDIA_MESSAGES | ChatPermissions::PIN_MESSAGES;
self.can_add_web_page_previews = Some(val); let expected =
self r#"{"can_send_messages":true,"can_send_media_messages":true,"can_pin_messages":true}"#;
} let actual = serde_json::to_string(&permissions).unwrap();
assert_eq!(expected, actual);
pub const fn can_change_info(mut self, val: bool) -> Self { }
self.can_change_info = Some(val);
self #[test]
} fn deserialization() {
let json =
pub const fn can_invite_users(mut self, val: bool) -> Self { r#"{"can_send_messages":true,"can_send_media_messages":true,"can_pin_messages":true}"#;
self.can_invite_users = Some(val); let expected = ChatPermissions::SEND_MEDIA_MESSAGES | ChatPermissions::PIN_MESSAGES;
self let actual = serde_json::from_str(json).unwrap();
} assert_eq!(expected, actual);
pub const fn can_pin_messages(mut self, val: bool) -> Self {
self.can_pin_messages = Some(val);
self
} }
} }