diff --git a/crates/teloxide-core/src/types.rs b/crates/teloxide-core/src/types.rs index 533f7afc..420e8fee 100644 --- a/crates/teloxide-core/src/types.rs +++ b/crates/teloxide-core/src/types.rs @@ -30,9 +30,12 @@ pub use force_reply::*; pub use forum_topic::*; pub use forum_topic_closed::*; pub use forum_topic_created::*; +pub use forum_topic_edited::*; pub use forum_topic_reopened::*; pub use game::*; pub use game_high_score::*; +pub use general_forum_topic_hidden::*; +pub use general_forum_topic_unhidden::*; pub use inline_keyboard_button::*; pub use inline_keyboard_markup::*; pub use inline_query::*; @@ -113,6 +116,7 @@ pub use voice::*; pub use web_app_data::*; pub use web_app_info::*; pub use webhook_info::*; +pub use write_access_allowed::*; mod allowed_update; mod animation; @@ -142,9 +146,12 @@ mod force_reply; mod forum_topic; mod forum_topic_closed; mod forum_topic_created; +mod forum_topic_edited; mod forum_topic_reopened; mod game; mod game_high_score; +mod general_forum_topic_hidden; +mod general_forum_topic_unhidden; mod inline_keyboard_button; mod inline_keyboard_markup; mod input_file; @@ -200,6 +207,7 @@ mod voice; mod web_app_data; mod web_app_info; mod webhook_info; +mod write_access_allowed; mod inline_query; mod inline_query_result; diff --git a/crates/teloxide-core/src/types/chat.rs b/crates/teloxide-core/src/types/chat.rs index 9c9e31e6..0b86aa56 100644 --- a/crates/teloxide-core/src/types/chat.rs +++ b/crates/teloxide-core/src/types/chat.rs @@ -30,6 +30,21 @@ pub struct Chat { /// /// [`GetChat`]: crate::payloads::GetChat pub message_auto_delete_time: Option, + + /// `true`, if non-administrators can only get the list of bots and + /// administrators in the chat. Returned only in [`GetChat`]. + /// + /// [`GetChat`]: crate::payloads::GetChat + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub has_hidden_members: bool, + + /// `true`, if aggressive anti-spam checks are enabled in the supergroup. + /// The field is only available to chat administrators. Returned only in + /// [`GetChat`]. + /// + /// [`GetChat`]: crate::payloads::GetChat + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub has_aggressive_anti_spam_enabled: bool, } #[serde_with_macros::skip_serializing_none] diff --git a/crates/teloxide-core/src/types/forum_topic_edited.rs b/crates/teloxide-core/src/types/forum_topic_edited.rs new file mode 100644 index 00000000..b6df3cf1 --- /dev/null +++ b/crates/teloxide-core/src/types/forum_topic_edited.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; + +/// This object represents a service message about an edited forum topic. +/// +/// [The official docs](https://core.telegram.org/bots/api#forumtopicedited). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct ForumTopicEdited { + /// New name of the topic, if it was edited + pub name: Option, + + /// New identifier of the custom emoji shown as the topic icon, if it was + /// edited; an empty string if the icon was removed + pub icon_custom_emoji_id: Option, +} diff --git a/crates/teloxide-core/src/types/general_forum_topic_hidden.rs b/crates/teloxide-core/src/types/general_forum_topic_hidden.rs new file mode 100644 index 00000000..c1863688 --- /dev/null +++ b/crates/teloxide-core/src/types/general_forum_topic_hidden.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +/// This object represents a service message about General forum topic hidden in +/// the chat. Currently holds no information. +/// +/// [The official docs](https://core.telegram.org/bots/api#generalforumtopichidden). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct GeneralForumTopicHidden; diff --git a/crates/teloxide-core/src/types/general_forum_topic_unhidden.rs b/crates/teloxide-core/src/types/general_forum_topic_unhidden.rs new file mode 100644 index 00000000..ce85bfde --- /dev/null +++ b/crates/teloxide-core/src/types/general_forum_topic_unhidden.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +/// This object represents a service message about General forum topic unhidden +/// in the chat. Currently holds no information. +/// +/// [The official docs](https://core.telegram.org/bots/api#generalforumtopicunhidden). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct GeneralForumTopicUnhidden; diff --git a/crates/teloxide-core/src/types/input_media.rs b/crates/teloxide-core/src/types/input_media.rs index f9953db7..e6a05b4c 100644 --- a/crates/teloxide-core/src/types/input_media.rs +++ b/crates/teloxide-core/src/types/input_media.rs @@ -41,11 +41,15 @@ pub struct InputMediaPhoto { /// List of special entities that appear in the caption, which can be /// specified instead of `parse_mode`. pub caption_entities: Option>, + + /// Pass `true` if the photo needs to be covered with a spoiler animation. + #[serde(skip_serializing_if = "std::ops::Not::not")] + pub has_spoiler: bool, } impl InputMediaPhoto { pub const fn new(media: InputFile) -> Self { - Self { media, caption: None, parse_mode: None, caption_entities: None } + Self { media, caption: None, parse_mode: None, caption_entities: None, has_spoiler: false } } pub fn media(mut self, val: InputFile) -> Self { @@ -73,6 +77,14 @@ impl InputMediaPhoto { self.caption_entities = Some(val.into_iter().collect()); self } + + /// Sets [`has_spoiler`] to `true`. + /// + /// [`has_spoiler`]: InputMediaPhoto::has_spoiler + pub fn spoiler(mut self) -> Self { + self.has_spoiler = true; + self + } } /// Represents a video to be sent. @@ -117,6 +129,10 @@ pub struct InputMediaVideo { /// Pass `true`, if the uploaded video is suitable for streaming. pub supports_streaming: Option, + + /// Pass `true` if the video needs to be covered with a spoiler animation. + #[serde(skip_serializing_if = "std::ops::Not::not")] + pub has_spoiler: bool, } impl InputMediaVideo { @@ -131,6 +147,7 @@ impl InputMediaVideo { height: None, duration: None, supports_streaming: None, + has_spoiler: false, } } @@ -184,6 +201,14 @@ impl InputMediaVideo { self.supports_streaming = Some(val); self } + + /// Sets [`has_spoiler`] to `true`. + /// + /// [`has_spoiler`]: InputMediaVideo::has_spoiler + pub fn spoiler(mut self) -> Self { + self.has_spoiler = true; + self + } } /// Represents an animation file (GIF or H.264/MPEG-4 AVC video without @@ -226,6 +251,11 @@ pub struct InputMediaAnimation { /// Animation duration. pub duration: Option, + + /// Pass `true` if the animation needs to be covered with a spoiler + /// animation. + #[serde(skip_serializing_if = "std::ops::Not::not")] + pub has_spoiler: bool, } impl InputMediaAnimation { @@ -239,6 +269,7 @@ impl InputMediaAnimation { height: None, duration: None, caption_entities: None, + has_spoiler: false, } } @@ -287,6 +318,14 @@ impl InputMediaAnimation { self.duration = Some(val); self } + + /// Sets [`has_spoiler`] to `true`. + /// + /// [`has_spoiler`]: InputMediaAnimation::has_spoiler + pub fn spoiler(mut self) -> Self { + self.has_spoiler = true; + self + } } /// Represents an audio file to be treated as music to be sent. diff --git a/crates/teloxide-core/src/types/message.rs b/crates/teloxide-core/src/types/message.rs index 00927091..bb40f989 100644 --- a/crates/teloxide-core/src/types/message.rs +++ b/crates/teloxide-core/src/types/message.rs @@ -6,11 +6,12 @@ use url::Url; use crate::types::{ Animation, Audio, BareChatId, Chat, ChatId, Contact, Dice, Document, ForumTopicClosed, - ForumTopicCreated, ForumTopicReopened, Game, InlineKeyboardMarkup, Invoice, Location, + ForumTopicCreated, ForumTopicEdited, ForumTopicReopened, Game, GeneralForumTopicHidden, + GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location, MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef, MessageId, PassportData, PhotoSize, Poll, ProximityAlertTriggered, Sticker, SuccessfulPayment, True, User, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, VideoChatStarted, VideoNote, - Voice, WebAppData, + Voice, WebAppData, WriteAccessAllowed, }; /// This object represents a message. @@ -58,12 +59,16 @@ pub enum MessageKind { Invoice(MessageInvoice), SuccessfulPayment(MessageSuccessfulPayment), ConnectedWebsite(MessageConnectedWebsite), + WriteAccessAllowed(WriteAccessAllowed), PassportData(MessagePassportData), Dice(MessageDice), ProximityAlertTriggered(MessageProximityAlertTriggered), ForumTopicCreated(ForumTopicCreated), + ForumTopicEdited(ForumTopicEdited), ForumTopicClosed(ForumTopicClosed), ForumTopicReopened(ForumTopicReopened), + GeneralForumTopicHidden(GeneralForumTopicHidden), + GeneralForumTopicUnhidden(GeneralForumTopicUnhidden), VideoChatScheduled(MessageVideoChatScheduled), VideoChatStarted(MessageVideoChatStarted), VideoChatEnded(MessageVideoChatEnded), @@ -339,6 +344,10 @@ pub struct MediaAnimation { /// bot commands, etc. that appear in the caption. #[serde(default = "Vec::new")] pub caption_entities: Vec, + + /// `true`, if the message media is covered by a spoiler animation. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub has_media_spoiler: bool, // Note: for backward compatibility telegram also sends `document` field, but we ignore it } @@ -415,6 +424,10 @@ pub struct MediaPhoto { #[serde(default = "Vec::new")] pub caption_entities: Vec, + /// `true`, if the message media is covered by a spoiler animation. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub has_media_spoiler: bool, + /// The unique identifier of a media message group this message belongs /// to. pub media_group_id: Option, @@ -458,6 +471,10 @@ pub struct MediaVideo { #[serde(default = "Vec::new")] pub caption_entities: Vec, + /// `true`, if the message media is covered by a spoiler animation. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub has_media_spoiler: bool, + /// The unique identifier of a media message group this message belongs /// to. pub media_group_id: Option, @@ -767,6 +784,35 @@ mod getters { } } + /// Returns `true` if the message media is covered by a spoiler + /// animation. + /// + /// Getter for [`MediaPhoto::has_media_spoiler`], + /// [`MediaVideo::has_media_spoiler`] and + /// [`MediaAnimation::has_media_spoiler`]. + #[must_use] + pub fn has_media_spoiler(&self) -> bool { + self.common() + .map(|m| match m.media_kind { + MediaKind::Animation(MediaAnimation { has_media_spoiler, .. }) + | MediaKind::Photo(MediaPhoto { has_media_spoiler, .. }) + | MediaKind::Video(MediaVideo { has_media_spoiler, .. }) => has_media_spoiler, + MediaKind::Audio(_) + | MediaKind::Contact(_) + | MediaKind::Document(_) + | MediaKind::Game(_) + | MediaKind::Venue(_) + | MediaKind::Location(_) + | MediaKind::Poll(_) + | MediaKind::Sticker(_) + | MediaKind::Text(_) + | MediaKind::VideoNote(_) + | MediaKind::Voice(_) + | MediaKind::Migration(_) => false, + }) + .unwrap_or(false) + } + #[must_use] pub fn audio(&self) -> Option<&types::Audio> { match &self.kind { diff --git a/crates/teloxide-core/src/types/reply_keyboard_markup.rs b/crates/teloxide-core/src/types/reply_keyboard_markup.rs index 649d9ee2..37ba29bb 100644 --- a/crates/teloxide-core/src/types/reply_keyboard_markup.rs +++ b/crates/teloxide-core/src/types/reply_keyboard_markup.rs @@ -11,6 +11,7 @@ use crate::types::KeyboardButton; /// [Introduction to bots]: https://core.telegram.org/bots#keyboards #[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Default)] +// FIXME: unoption bools? pub struct KeyboardMarkup { /// Array of button rows, each represented by an Array of /// [`KeyboardButton`] objects @@ -18,6 +19,12 @@ pub struct KeyboardMarkup { /// [`KeyboardButton`]: crate::types::KeyboardButton pub keyboard: Vec>, + /// Requests clients to always show the keyboard when the regular keyboard + /// is hidden. Defaults to `false`, in which case the custom keyboard + /// can be hidden and opened with a keyboard icon. + #[serde(skip_serializing_if = "std::ops::Not::not")] + pub is_persistent: bool, + /// Requests clients to resize the keyboard vertically for optimal fit /// (e.g., make the keyboard smaller if there are just two rows of /// buttons). Defaults to `false`, in which case the custom keyboard is @@ -56,6 +63,7 @@ impl KeyboardMarkup { { Self { keyboard: keyboard.into_iter().map(<_>::into_iter).map(<_>::collect).collect(), + is_persistent: false, resize_keyboard: None, one_time_keyboard: None, input_field_placeholder: None, @@ -80,6 +88,14 @@ impl KeyboardMarkup { self } + /// Sets [`is_persistent`] to `true`. + /// + /// [`is_persistent`]: KeyboardMarkup::is_persistent + pub fn persistent(mut self) -> Self { + self.is_persistent = true; + self + } + pub fn resize_keyboard(mut self, val: T) -> Self where T: Into>, diff --git a/crates/teloxide-core/src/types/write_access_allowed.rs b/crates/teloxide-core/src/types/write_access_allowed.rs new file mode 100644 index 00000000..64854413 --- /dev/null +++ b/crates/teloxide-core/src/types/write_access_allowed.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +/// This object represents a service message about a user allowing a bot added +/// to the attachment menu to write messages. Currently holds no information. +/// +/// [The official docs](https://core.telegram.org/bots/api#writeaccessallowed). +#[serde_with_macros::skip_serializing_none] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct WriteAccessAllowed;