From 30439d6d28873ff99c030c33abfe3018bf2f7b2c Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 7 Nov 2022 01:19:47 +0100 Subject: [PATCH 1/6] Add missing fields for `Restricted` chat member These fields are present in the docs, and I tested it manually by calling the `get_chat_member` method with the changed `teloxide-core` code that parsing still works fine for the `Restricted` chat member. There are however some potential logic bugs here described bellow. I fixed some of them, but others are still outstanding. \# Logic bugs \## Shared permission fields in `Administrator` and `Restricted` The current code of `teloxide-core` at the time of this writing doesn't take into account the shared permission fields of `Administrator` and `Restricted` because just were no such fields in `Restricted` struct. This bug is fixed by this PR. \## Deceiving behavior of `ChatMemberKind::Member` The existing getter methods of `ChatMember` assume that if the `ChatMemberKind` is `Member`, then the member has all rights for all fields of `Restricted` struct. And there is also a similar problem with `Administrator` struct. The existing getter methods of `ChatMember` assume that if the `ChatMemberKind` is `Member`, then the member has no rights for all fields of `Administrator` struct. This isn't always true. Regular members *may or may not have* `can_invite_users` permission, for example. This is determined by the default chat parmissions. See bellow. \# General decieving behavior of permission getters The default chat permissions seem to override any cofigurations of `Restricted` chat members. For example, if the `Restricted` chat member has `can_invite_users` set to `true`, but the default chat permissions have `can_invite_users` set to `false`, then the effective `can_invite_users` permission of such a user is `false` (verified experimentally). Therefore, the getters for the permission fields of the `ChatMember` type actually don't make sense. They don't show the effective permissions of the user. Maybe we could make that clear in their docs, but the problem is that these getters don't have enough context to decide what to return for regular `ChatMemberKind::Member`. I am not sure how to proceed here. For example, these getters could return `Option` values, and always return `None` for `ChatMemberKind::Member`. I didn't fix that bug in this PR, because I believe it requires a more careful consideration, larger and potentially breaking changes, that I am not ready to do. \# Intentionally left as not in scope of this PR Telegram added topics feature recenenty, and consequently they added `can_manage_topics` field both to `Administrator` and `Restricted` structs. This field is not present in the current code of `teloxide-core` at the time of this writing, and I think it should be added in a separate PR that covers topics API as a whole. Also, one discrapancy with the new `can_manage_topics` field is with its type and documentation. Here is how this field looks like in `ChatMemberAdministrator` **and** `ChatAdministratorRights`: ``` can_manage_topics Boolean Optional. True, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only ``` Here is how this field looks like in `ChatMemberRestricted`: ``` can_manage_topics Boolean True, if the user is allowed to create forum topics ``` Here is how this field looks like in `ChatPermissions`: ``` can_manage_topics Boolean Optional. True, if the user is allowed to create forum topics. If omitted defaults to the value of can_pin_messages ```` There is something subtle between the semantics of `can_manage_topics` for regular users and administrators according to the difference in their documentation. I didn't dig into that rabbit hole, so I intentionally didn't include topics feature changes in this PR. --- crates/teloxide-core/src/types/chat_member.rs | 69 ++++++++++++++----- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/crates/teloxide-core/src/types/chat_member.rs b/crates/teloxide-core/src/types/chat_member.rs index 79c2e79f..71a39b43 100644 --- a/crates/teloxide-core/src/types/chat_member.rs +++ b/crates/teloxide-core/src/types/chat_member.rs @@ -101,6 +101,9 @@ pub struct Restricted { /// Date when restrictions will be lifted for this user. pub until_date: UntilDate, + /// `true` if the user is a member of the chat at the moment of the request. + pub is_member: bool, + /// `true` if the user can send text messages, contacts, locations and /// venues. pub can_send_messages: bool, @@ -116,6 +119,19 @@ pub struct Restricted { /// `true` if the user is allowed to add web page previews to their /// messages. pub can_add_web_page_previews: bool, + + /// `true` if the user is allowed to change the chat title, photo + /// and other settings. + pub can_change_info: bool, + + /// `true` if the user is allowed to invite new users to the chat. + pub can_invite_users: bool, + + /// `true` if the user is allowed to pin messages. + pub can_pin_messages: bool, + + /// `true` if the user is allowed to send polls. + pub can_send_polls: bool, } /// User that was banned in the chat and can't return to it or view chat @@ -334,17 +350,17 @@ impl ChatMemberKind { /// /// I.e. returns `true` if the user /// - is the owner of the chat - /// - is an administrator in the given chat and has the [`can_change_info`] - /// privilege. + /// - is an administrator in the given chat and has the + /// [`Administrator::can_change_info`] privilege. + /// - is restricted, but does have [`Restricted::can_change_info`] privilege /// Returns `false` otherwise. - /// - /// [`can_change_info`]: Administrator::can_change_info #[must_use] pub fn can_change_info(&self) -> bool { match self { Self::Owner(_) => true, - Self::Administrator(Administrator { can_change_info, .. }) => *can_change_info, - Self::Member | Self::Restricted(_) | Self::Left | Self::Banned(_) => false, + Self::Administrator(Administrator { can_change_info, .. }) + | Self::Restricted(Restricted { can_change_info, .. }) => *can_change_info, + Self::Member | Self::Left | Self::Banned(_) => false, } } @@ -437,17 +453,18 @@ impl ChatMemberKind { /// /// I.e. returns `true` if the user /// - is the owner of the chat - /// - is an administrator in the given chat and has the [`can_invite_users`] - /// privilege. + /// - is an administrator in the given chat and has the + /// [`Administrator::can_invite_users`] privilege. + /// - is restricted, but does have [`Restricted::can_invite_users`] + /// privilege /// Returns `false` otherwise. - /// - /// [`can_invite_users`]: Administrator::can_invite_users #[must_use] pub fn can_invite_users(&self) -> bool { match &self { Self::Owner(_) => true, - Self::Administrator(Administrator { can_invite_users, .. }) => *can_invite_users, - Self::Member | Self::Restricted(_) | Self::Left | Self::Banned(_) => false, + Self::Administrator(Administrator { can_invite_users, .. }) + | Self::Restricted(Restricted { can_invite_users, .. }) => *can_invite_users, + Self::Member | Self::Left | Self::Banned(_) => false, } } @@ -475,11 +492,11 @@ impl ChatMemberKind { /// /// I.e. returns `true` if the user /// - is the owner of the chat (even if the chat is not a supergroup) - /// - is an administrator in the given chat and has the [`can_pin_messages`] - /// privilege. + /// - is an administrator in the given chat and has the + /// [`Administrator::can_pin_messages`] privilege. + /// - is restricted, but does have [`Restricted::can_pin_messages`] + /// privilege /// Returns `false` otherwise. - /// - /// [`can_pin_messages`]: Administrator::can_pin_messages #[must_use] pub fn can_pin_messages(&self) -> bool { match self { @@ -487,7 +504,8 @@ impl ChatMemberKind { Self::Administrator(Administrator { can_pin_messages, .. }) => { can_pin_messages.unwrap_or_default() } - Self::Member | Self::Restricted(_) | Self::Left | Self::Banned(_) => false, + Self::Restricted(Restricted { can_pin_messages, .. }) => *can_pin_messages, + Self::Member | Self::Left | Self::Banned(_) => false, } } @@ -592,6 +610,23 @@ impl ChatMemberKind { Self::Left | Self::Banned(_) => false, } } + + /// Returns `true` if the user is allowed to send polls. + /// + /// I.e. returns **`false`** if the user + /// - has left or has been banned from the chat + /// - is restricted and doesn't have the [`can_send_polls`] right + /// Returns `true` otherwise. + /// + /// [`can_send_polls`]: Restricted::can_send_polls + #[must_use] + pub fn can_send_polls(&self) -> bool { + match &self { + Self::Restricted(Restricted { can_send_polls, .. }) => *can_send_polls, + Self::Owner(_) | Self::Administrator(_) | Self::Member => true, + Self::Left | Self::Banned(_) => false, + } + } } #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] From c65996eb75dc5d594541bb0ef15f8b10d0c394ac Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 12 Nov 2022 01:39:59 +0100 Subject: [PATCH 2/6] =?UTF-8?q?Update=20`is=5Fpresent()`=20to=20take=20`is?= =?UTF-8?q?=5Fmember`=20into=20account=20=F0=9F=92=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/teloxide-core/src/types/chat_member.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/teloxide-core/src/types/chat_member.rs b/crates/teloxide-core/src/types/chat_member.rs index 71a39b43..fc967436 100644 --- a/crates/teloxide-core/src/types/chat_member.rs +++ b/crates/teloxide-core/src/types/chat_member.rs @@ -266,7 +266,10 @@ impl ChatMemberKind { /// [banned]: ChatMemberKind::Banned #[must_use] pub fn is_present(&self) -> bool { - !(self.is_left() || self.is_banned()) + let is_restricted_non_member = + matches!(self, Self::Restricted(Restricted { is_member: false, .. })); + + !(self.is_left() || self.is_banned() || is_restricted_non_member) } } From 1c6fc4aae059ee01376cda5c7db4df8b63669f23 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 14 Nov 2022 23:13:33 +0100 Subject: [PATCH 3/6] Update the docs of `is_present()` method --- crates/teloxide-core/src/types/chat_member.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/teloxide-core/src/types/chat_member.rs b/crates/teloxide-core/src/types/chat_member.rs index fc967436..735d3334 100644 --- a/crates/teloxide-core/src/types/chat_member.rs +++ b/crates/teloxide-core/src/types/chat_member.rs @@ -260,10 +260,14 @@ impl ChatMemberKind { } /// Returns `true` if the user is currently present in the chat. i.e. if the - /// user **hasn't** [left] or been [banned]. + /// user **hasn't** [left] or been [banned]. It returns `false` if the user + /// left the chat, but was [restricted]. + /// + /// /// /// [left]: ChatMemberKind::Left /// [banned]: ChatMemberKind::Banned + /// [restricted]: ChatMemberKind::Restricted #[must_use] pub fn is_present(&self) -> bool { let is_restricted_non_member = From 660c58c95c7488d13f4cdc6f668aaa22fae614c4 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 14 Nov 2022 23:13:40 +0100 Subject: [PATCH 4/6] Update the changelog --- CHANGELOG.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e84df63..031fb5b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## unreleased +### Changed + +- The methods `ChatMember::{can_pin_messages, can_invite_users, can_change_info}` now take into account the permissions of `Restricted` chat member kind. +- The method `ChatMemberKind::is_present` now takes into account the value of `Restricted::is_member` field. + +### Added + +- `Restricted::{is_member, can_change_info, can_invite_users, can_pin_messages, can_send_polls}` fields. +- `ChatMember::can_send_polls` method. + ## 0.11.1 - 2022-10-31 ### Added @@ -305,14 +315,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Export `teloxide_macros::teloxide` in `prelude`. - `dispatching::dialogue::serializer::{JSON -> Json, CBOR -> Cbor}` - Allow `bot_name` be `N`, where `N: Into + ...` in `commands_repl` & `commands_repl_with_listener`. -- 'Edit methods' (namely `edit_message_live_location`, `stop_message_live_location`, `edit_message_text`, - `edit_message_caption`, `edit_message_media` and `edit_message_reply_markup`) are split into common and inline +- 'Edit methods' (namely `edit_message_live_location`, `stop_message_live_location`, `edit_message_text`, + `edit_message_caption`, `edit_message_media` and `edit_message_reply_markup`) are split into common and inline versions (e.g.: `edit_message_text` and `edit_inline_message_text`). Instead of `ChatOrInlineMessage` common versions - accept `chat_id: impl Into` and `message_id: i32` whereas inline versions accept + accept `chat_id: impl Into` and `message_id: i32` whereas inline versions accept `inline_message_id: impl Into`. Also note that return type of inline versions is `True` ([issue 253], [pr 257]) -- `ChatOrInlineMessage` is renamed to `TargetMessage`, it's `::Chat` variant is renamed to `::Common`, - `#[non_exhaustive]` annotation is removed from the enum, type of `TargetMessage::Inline::inline_message_id` changed - `i32` => `String`. `TargetMessage` now implements `From`, `get_game_high_scores` and `set_game_score` use +- `ChatOrInlineMessage` is renamed to `TargetMessage`, it's `::Chat` variant is renamed to `::Common`, + `#[non_exhaustive]` annotation is removed from the enum, type of `TargetMessage::Inline::inline_message_id` changed + `i32` => `String`. `TargetMessage` now implements `From`, `get_game_high_scores` and `set_game_score` use `Into` to accept `String`s. ([issue 253], [pr 257]) - Remove `ResponseResult` from `prelude`. From 170941e7977972e854029f7007ca2d51e64cd9a6 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 14 Nov 2022 23:16:07 +0100 Subject: [PATCH 5/6] Improve spacing --- crates/teloxide-core/src/types/chat_member.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/teloxide-core/src/types/chat_member.rs b/crates/teloxide-core/src/types/chat_member.rs index 735d3334..d4af17ea 100644 --- a/crates/teloxide-core/src/types/chat_member.rs +++ b/crates/teloxide-core/src/types/chat_member.rs @@ -260,10 +260,8 @@ impl ChatMemberKind { } /// Returns `true` if the user is currently present in the chat. i.e. if the - /// user **hasn't** [left] or been [banned]. It returns `false` if the user - /// left the chat, but was [restricted]. - /// - /// + /// user **hasn't** [left] or been [banned]. It also returns `false` if the + /// user left the chat, but was [restricted]. /// /// [left]: ChatMemberKind::Left /// [banned]: ChatMemberKind::Banned From d0b71c358ee465d539f8e416dca682649285fce6 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 14 Nov 2022 23:20:50 +0100 Subject: [PATCH 6/6] Move changelog entries into teloxide-core's changelog file --- CHANGELOG.md | 10 ---------- crates/teloxide-core/CHANGELOG.md | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 031fb5b8..353e0c0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## unreleased -### Changed - -- The methods `ChatMember::{can_pin_messages, can_invite_users, can_change_info}` now take into account the permissions of `Restricted` chat member kind. -- The method `ChatMemberKind::is_present` now takes into account the value of `Restricted::is_member` field. - -### Added - -- `Restricted::{is_member, can_change_info, can_invite_users, can_pin_messages, can_send_polls}` fields. -- `ChatMember::can_send_polls` method. - ## 0.11.1 - 2022-10-31 ### Added diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index a0f27f5d..c9e9d582 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -7,9 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## unreleased +### Changed + +- The methods `ChatMember::{can_pin_messages, can_invite_users, can_change_info}` now take into account the permissions of `Restricted` chat member kind ([#764][pr764]) +- The method `ChatMemberKind::is_present` now takes into account the value of `Restricted::is_member` field ([#764][pr764]) + +### Added + +- `Restricted::{is_member, can_change_info, can_invite_users, can_pin_messages, can_send_polls}` fields ([#764][pr764]) +- `ChatMember::can_send_polls` method ([#764][pr764]) + +[pr764]: https://github.com/teloxide/teloxide/pull/764 + ## 0.8.0 - 2022-10-03 -### Added +### Added - Support for Telegram Bot API [version 6.2](https://core.telegram.org/bots/api#august-12-2022) ([#251][pr251]) @@ -37,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [pr244]: https://github.com/teloxide/teloxide-core/pull/246 -### Fixed +### Fixed - `SetWebhook` request can now properly send certificate ([#250][pr250]) - Serialization of `InputSticker::Webm` ([#252][pr252])