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.
This commit is contained in:
Veetaha 2022-11-07 01:19:47 +01:00
parent 45538db820
commit 30439d6d28

View file

@ -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)]