From 7dc7047ea16733328e7675ebc9fb011fc448ca98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=8B=D1=80=D1=86=D0=B5=D0=B2=20=D0=92=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=20=D0=98=D0=B3=D0=BE=D1=80=D0=B5=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 14:14:05 +0300 Subject: [PATCH] Add request for multiple users --- crates/teloxide-core/src/types.rs | 4 +-- .../src/types/keyboard_button.rs | 32 ++++++++--------- .../src/types/keyboard_button_request_user.rs | 34 ++++++++++++++----- crates/teloxide-core/src/types/message.rs | 16 ++++----- crates/teloxide-core/src/types/user_shared.rs | 15 -------- .../teloxide-core/src/types/users_shared.rs | 15 ++++++++ 6 files changed, 67 insertions(+), 49 deletions(-) delete mode 100644 crates/teloxide-core/src/types/user_shared.rs create mode 100644 crates/teloxide-core/src/types/users_shared.rs diff --git a/crates/teloxide-core/src/types.rs b/crates/teloxide-core/src/types.rs index f142825d..50f7c9f6 100644 --- a/crates/teloxide-core/src/types.rs +++ b/crates/teloxide-core/src/types.rs @@ -116,7 +116,7 @@ pub use unit_true::*; pub use update::*; pub use user::*; pub use user_profile_photos::*; -pub use user_shared::*; +pub use users_shared::*; pub use venue::*; pub use video::*; pub use video_chat_ended::*; @@ -219,7 +219,7 @@ mod unit_true; mod update; mod user; mod user_profile_photos; -mod user_shared; +mod users_shared; mod venue; mod video; mod video_chat_ended; diff --git a/crates/teloxide-core/src/types/keyboard_button.rs b/crates/teloxide-core/src/types/keyboard_button.rs index 2139b97e..60470977 100644 --- a/crates/teloxide-core/src/types/keyboard_button.rs +++ b/crates/teloxide-core/src/types/keyboard_button.rs @@ -1,7 +1,7 @@ use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use crate::types::{ - KeyboardButtonPollType, KeyboardButtonRequestChat, KeyboardButtonRequestUser, True, WebAppInfo, + KeyboardButtonPollType, KeyboardButtonRequestChat, KeyboardButtonRequestUsers, True, WebAppInfo, }; /// This object represents one button of the reply keyboard. @@ -68,10 +68,10 @@ pub enum ButtonRequest { /// [`chat_shared`]: crate::types::MessageKind::ChatShared RequestChat(KeyboardButtonRequestChat), - /// If this variant is used, pressing the button will open a list of - /// suitable users. Tapping on any user will send their identifier to the - /// bot in a “user_shared” service message. - RequestUser(KeyboardButtonRequestUser), + /// If specified, pressing the button will open a list of suitable users. + /// Identifiers of selected users will be sent to the bot in a + /// “users_shared” service message. Available in private chats only. + RequestUsers(KeyboardButtonRequestUsers), /// If this variant is used, the user will be asked to create a poll and /// send it to the bot when the button is pressed. @@ -110,10 +110,10 @@ struct RawRequest { chat: Option, /// If specified, pressing the button will open a list of suitable users. - /// Tapping on any user will send their identifier to the bot in a - /// “user_shared” service message. Available in private chats only. - #[serde(rename = "request_user")] - user: Option, + /// Identifiers of selected users will be sent to the bot in a + /// “users_shared” service message. Available in private chats only. + #[serde(rename = "request_users")] + users: Option, /// If specified, the user will be asked to create a poll and /// send it to the bot when the button is pressed. Available in private @@ -134,11 +134,11 @@ impl<'de> Deserialize<'de> for ButtonRequest { { let raw = RawRequest::deserialize(deserializer)?; match raw { - RawRequest { contact, location, chat, user, poll, web_app } + RawRequest { contact, location, chat, users, poll, web_app } if 1 < (contact.is_some() as u8 + location.is_some() as u8 + chat.is_some() as u8 - + user.is_some() as u8 + + users.is_some() as u8 + poll.is_some() as u8 + web_app.is_some() as u8) => { @@ -150,7 +150,7 @@ impl<'de> Deserialize<'de> for ButtonRequest { RawRequest { contact: Some(True), .. } => Ok(Self::Contact), RawRequest { location: Some(True), .. } => Ok(Self::Location), RawRequest { chat: Some(request_chat), .. } => Ok(Self::RequestChat(request_chat)), - RawRequest { user: Some(request_user), .. } => Ok(Self::RequestUser(request_user)), + RawRequest { users: Some(request_users), .. } => Ok(Self::RequestUsers(request_users)), RawRequest { poll: Some(poll_type), .. } => Ok(Self::Poll(poll_type)), RawRequest { web_app: Some(web_app), .. } => Ok(Self::WebApp(web_app)), @@ -158,11 +158,11 @@ impl<'de> Deserialize<'de> for ButtonRequest { contact: None, location: None, chat: None, - user: None, + users: None, poll: None, web_app: None, } => Err(D::Error::custom( - "Either one of `request_contact`, `request_chat`, `request_user`, \ + "Either one of `request_contact`, `request_chat`, `request_users`, \ `request_location`, `request_poll` and `web_app` fields is required", )), } @@ -178,7 +178,7 @@ impl Serialize for ButtonRequest { contact: None, location: None, chat: None, - user: None, + users: None, poll: None, web_app: None, }; @@ -187,7 +187,7 @@ impl Serialize for ButtonRequest { Self::Contact => raw.contact = Some(True), Self::Location => raw.location = Some(True), Self::RequestChat(request_chat) => raw.chat = Some(request_chat.clone()), - Self::RequestUser(request_user) => raw.user = Some(request_user.clone()), + Self::RequestUsers(request_users) => raw.users = Some(request_users.clone()), Self::Poll(poll_type) => raw.poll = Some(poll_type.clone()), Self::WebApp(web_app) => raw.web_app = Some(web_app.clone()), }; diff --git a/crates/teloxide-core/src/types/keyboard_button_request_user.rs b/crates/teloxide-core/src/types/keyboard_button_request_user.rs index 843b86d1..8df5cc4a 100644 --- a/crates/teloxide-core/src/types/keyboard_button_request_user.rs +++ b/crates/teloxide-core/src/types/keyboard_button_request_user.rs @@ -1,15 +1,17 @@ use serde::{Deserialize, Serialize}; -/// This object defines the criteria used to request a suitable user. The -/// identifier of the selected user will be shared with the bot when the +/// This object defines the criteria used to request a suitable users. The +/// identifiers of the selected users will be shared with the bot when the /// corresponding button is pressed. More about requesting users » +/// +/// [More about requesting users »]: https://core.telegram.org/bots/features#chat-and-user-selection #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] -pub struct KeyboardButtonRequestUser { - /// identifier of the request, which will be received back in the - /// [`UserShared`] object. Must be unique within the message. +pub struct KeyboardButtonRequestUsers { + /// Identifier of the request, which will be received back in the + /// [`UsersShared`] object. Must be unique within the message. /// - /// [`UserShared`]: crate::types::UserShared + /// [`UsersShared`]: crate::types::UsersShared pub request_id: i32, /// Pass `true` to request a bot, pass `false` to request a regular user. If @@ -22,12 +24,16 @@ pub struct KeyboardButtonRequestUser { /// applied. #[serde(default, skip_serializing_if = "Option::is_none")] pub user_is_premium: Option, + + /// The maximum number of users to be selected; 1-10. Defaults to 1. + #[serde(default = "de_max_quantity_default")] + pub max_quantity: u8, } -impl KeyboardButtonRequestUser { +impl KeyboardButtonRequestUsers { /// Creates a new [`KeyboardButtonRequestUser`]. pub fn new(request_id: i32) -> Self { - Self { request_id, user_is_bot: None, user_is_premium: None } + Self { request_id, user_is_bot: None, user_is_premium: None, max_quantity: 1 } } /// Setter for `user_is_bot` field @@ -41,4 +47,16 @@ impl KeyboardButtonRequestUser { self.user_is_premium = Some(value); self } + + /// Setter for `max_quantity` field, the value must be in the range 1..=10 + pub fn max_quantity(mut self, value: u8) -> Self { + assert!((1..=10).contains(&value)); + + self.max_quantity = value; + self + } +} + +fn de_max_quantity_default() -> u8 { + 1 } diff --git a/crates/teloxide-core/src/types/message.rs b/crates/teloxide-core/src/types/message.rs index 2990b1aa..b2696028 100644 --- a/crates/teloxide-core/src/types/message.rs +++ b/crates/teloxide-core/src/types/message.rs @@ -10,7 +10,7 @@ use crate::types::{ GeneralForumTopicHidden, GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location, MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef, MessageId, PassportData, PhotoSize, Poll, ProximityAlertTriggered, Sticker, Story, SuccessfulPayment, ThreadId, True, - User, UserShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, + User, UsersShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed, }; @@ -61,7 +61,7 @@ pub enum MessageKind { MessageAutoDeleteTimerChanged(MessageMessageAutoDeleteTimerChanged), Pinned(MessagePinned), ChatShared(MessageChatShared), - UserShared(MessageUserShared), + UsersShared(MessageUsersShared), Invoice(MessageInvoice), SuccessfulPayment(MessageSuccessfulPayment), ConnectedWebsite(MessageConnectedWebsite), @@ -256,9 +256,9 @@ pub struct MessageChatShared { } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MessageUserShared { - /// A chat was shared with the bot. - pub user_shared: UserShared, +pub struct MessageUsersShared { + /// Users were shared with the bot + pub users_shared: UsersShared, } #[serde_with::skip_serializing_none] @@ -682,7 +682,7 @@ mod getters { MessageDice, MessageEntity, MessageGroupChatCreated, MessageId, MessageInvoice, MessageLeftChatMember, MessageNewChatMembers, MessageNewChatPhoto, MessageNewChatTitle, MessagePassportData, MessagePinned, MessageProximityAlertTriggered, - MessageSuccessfulPayment, MessageSupergroupChatCreated, MessageUserShared, + MessageSuccessfulPayment, MessageSupergroupChatCreated, MessageUsersShared, MessageVideoChatParticipantsInvited, PhotoSize, User, }; @@ -1306,9 +1306,9 @@ mod getters { } #[must_use] - pub fn shared_user(&self) -> Option<&types::UserShared> { + pub fn shared_users(&self) -> Option<&types::UsersShared> { match &self.kind { - UserShared(MessageUserShared { user_shared }) => Some(user_shared), + UsersShared(MessageUsersShared { users_shared }) => Some(users_shared), _ => None, } } diff --git a/crates/teloxide-core/src/types/user_shared.rs b/crates/teloxide-core/src/types/user_shared.rs deleted file mode 100644 index 1fd0cefe..00000000 --- a/crates/teloxide-core/src/types/user_shared.rs +++ /dev/null @@ -1,15 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::types::UserId; - -/// Information about the chat whose identifier was shared with the bot using a -/// [`KeyboardButtonRequestUser`] button. -/// -/// [`KeyboardButtonRequestUser`]: crate::types::KeyboardButtonRequestUser -#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct UserShared { - /// Identifier of the request. - pub request_id: i32, - /// Identifier of the shared user. - pub user_id: UserId, -} diff --git a/crates/teloxide-core/src/types/users_shared.rs b/crates/teloxide-core/src/types/users_shared.rs new file mode 100644 index 00000000..46b20679 --- /dev/null +++ b/crates/teloxide-core/src/types/users_shared.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; + +use crate::types::UserId; + +/// This object contains information about the users whose identifiers were +/// shared with the bot using a [KeyboardButtonRequestUsers] button. +/// +/// [KeyboardButtonRequestUsers]: crate::types::KeyboardButtonRequestUsers +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct UsersShared { + /// Identifier of the request + pub request_id: i32, + /// Identifiers of the shared users + pub user_ids: Vec, +}