diff --git a/README.md b/README.md index f5c23baf..391f9345 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ - + diff --git a/crates/teloxide-core/CHANGELOG.md b/crates/teloxide-core/CHANGELOG.md index ae3f911e..20a730fc 100644 --- a/crates/teloxide-core/CHANGELOG.md +++ b/crates/teloxide-core/CHANGELOG.md @@ -24,9 +24,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `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]) +- Support for Telegram Bot API [version 6.3](https://core.telegram.org/bots/api#november-5-2022) ([#789][pr789]) +- Support for Telegram Bot API [version 6.4](https://core.telegram.org/bots/api#december-30-2022) ([#809][pr809]) [pr764]: https://github.com/teloxide/teloxide/pull/764 +[pr764]: https://github.com/teloxide/teloxide/pull/789 [pr800]: https://github.com/teloxide/teloxide/pull/800 +[pr809]: https://github.com/teloxide/teloxide/pull/809 ### Deprecated diff --git a/crates/teloxide-core/README.md b/crates/teloxide-core/README.md index d4c80ba5..c06d2c43 100644 --- a/crates/teloxide-core/README.md +++ b/crates/teloxide-core/README.md @@ -12,7 +12,7 @@ - + diff --git a/crates/teloxide-core/schema.ron b/crates/teloxide-core/schema.ron index d814072e..8d209588 100644 --- a/crates/teloxide-core/schema.ron +++ b/crates/teloxide-core/schema.ron @@ -468,6 +468,11 @@ Schema( name: "caption_entities", ty: Option(ArrayOf(RawTy("MessageEntity"))), descr: Doc(md: "List of special entities that appear in the photo caption, which can be specified instead of _parse\\_mode_"), + ), + Param( + name: "has_spoiler", + ty: Option(bool), + descr: Doc(md: "Pass True if the photo needs to be covered with a spoiler animation"), ), Param( name: "disable_notification", @@ -780,6 +785,11 @@ Schema( ty: Option(ArrayOf(RawTy("MessageEntity"))), descr: Doc(md: "List of special entities that appear in the caption, which can be specified instead of _parse\\_mode_"), ), + Param( + name: "has_spoiler", + ty: Option(bool), + descr: Doc(md: "Pass True if the video needs to be covered with a spoiler animation"), + ), Param( name: "supports_streaming", ty: Option(bool), @@ -891,6 +901,11 @@ Schema( ty: Option(ArrayOf(RawTy("MessageEntity"))), descr: Doc(md: "List of special entities that appear in the photo caption, which can be specified instead of _parse\\_mode_"), ), + Param( + name: "has_spoiler", + ty: Option(bool), + descr: Doc(md: "Pass True if the animation needs to be covered with a spoiler animation"), + ), Param( name: "disable_notification", ty: Option(bool), @@ -1809,7 +1824,7 @@ Schema( name: "chat_id", ty: RawTy("Recipient"), descr: Doc(md: "Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)") - ), + ), Param( name: "action", ty: RawTy("ChatAction"), @@ -1827,6 +1842,11 @@ Schema( } ), ), + Param( + name: "message_thread_id", + ty: Option(i32), + descr: Doc(md: "Unique identifier for the target message thread; supergroups only") + ), ], ), Method( @@ -2631,13 +2651,13 @@ Schema( ), Param( name: "name", - ty: String, - descr: Doc(md: "Topic name, 1-128 characters") + ty: Option(String), + descr: Doc(md: "Topic name, 0-128 characters. If not specified or empty, the current name of the topic will be kept") ), Param( name: "icon_custom_emoji_id", - ty: String, - descr: Doc(md: "Unique identifier of the custom emoji shown as the topic icon. Use `getForumTopicIconStickers` to get all allowed custom emoji identifiers.") + ty: Option(String), + descr: Doc(md: "Unique identifier of the custom emoji shown as the topic icon. Use `getForumTopicIconStickers` to get all allowed custom emoji identifiers. Pass an empty string to remove the icon. If not specified, the current icon will be kept") ), ], ), @@ -2702,7 +2722,7 @@ Schema( names: ("unpinAllForumTopicMessages", "UnpinAllForumTopicMessages", "unpin_all_forum_topic_messages"), return_ty: True, doc: Doc(md: "Use this method to clear the list of pinned messages in a forum topic. The bot must be an administrator in the chat for this to work and must have the _can\\_pin\\_messages_ administrator right in the supergroup. Returns True on success."), - tg_doc: "https://core.telegram.org/bots/api#deleteforumtopic", + tg_doc: "https://core.telegram.org/bots/api#unpinallforumtopicmessages", tg_category: "Available methods", params: [ Param( @@ -2717,6 +2737,81 @@ Schema( ), ], ), + Method( + names: ("editGeneralForumTopic", "EditGeneralForumTopic", "edit_general_forum_topic"), + return_ty: True, + doc: Doc(md: "Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have _can\\_manage\\_topics_ administrator rights. Returns True on success."), + tg_doc: "https://core.telegram.org/bots/api#editgeneralforumtopic", + tg_category: "Available methods", + params: [ + Param( + name: "chat_id", + ty: RawTy("Recipient"), + descr: Doc(md: "Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)") + ), + Param( + name: "name", + ty: String, + descr: Doc(md: "New topic name, 1-128 characters"), + ), + ], + ), + Method( + names: ("closeGeneralForumTopic", "CloseGeneralForumTopic", "close_general_forum_topic"), + return_ty: True, + doc: Doc(md: "Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\\_manage\\_topics_ administrator rights. Returns True on success."), + tg_doc: "https://core.telegram.org/bots/api#closegeneralforumtopic", + tg_category: "Available methods", + params: [ + Param( + name: "chat_id", + ty: RawTy("Recipient"), + descr: Doc(md: "Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)") + ), + ], + ), + Method( + names: ("reopenGeneralForumTopic", "ReopenGeneralForumTopic", "reopen_general_forum_topic"), + return_ty: True, + doc: Doc(md: "Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\\_manage\\_topics_ administrator rights. The topic will be automatically unhidden if it was hidden. Returns True on success."), + tg_doc: "https://core.telegram.org/bots/api#reopengeneralforumtopic", + tg_category: "Available methods", + params: [ + Param( + name: "chat_id", + ty: RawTy("Recipient"), + descr: Doc(md: "Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)") + ), + ], + ), + Method( + names: ("hideGeneralForumTopic", "HideGeneralForumTopic", "hide_general_forum_topic"), + return_ty: True, + doc: Doc(md: "Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\\_manage\\_topics_ administrator rights. The topic will be automatically closed if it was open. Returns True on success."), + tg_doc: "https://core.telegram.org/bots/api#hidegeneralforumtopic", + tg_category: "Available methods", + params: [ + Param( + name: "chat_id", + ty: RawTy("Recipient"), + descr: Doc(md: "Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)") + ), + ], + ), + Method( + names: ("unhideGeneralForumTopic", "UnhideGeneralForumTopic", "unhide_general_forum_topic"), + return_ty: True, + doc: Doc(md: "Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\\_manage\\_topics_ administrator rights. Returns True on success."), + tg_doc: "https://core.telegram.org/bots/api#unhidegeneralforumtopic", + tg_category: "Available methods", + params: [ + Param( + name: "chat_id", + ty: RawTy("Recipient"), + descr: Doc(md: "Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)") + ), + ], + ), Method( names: ("answerCallbackQuery", "AnswerCallbackQuery", "answer_callback_query"), return_ty: True, diff --git a/crates/teloxide-core/src/adaptors/auto_send.rs b/crates/teloxide-core/src/adaptors/auto_send.rs index 2bd9c075..a613d486 100644 --- a/crates/teloxide-core/src/adaptors/auto_send.rs +++ b/crates/teloxide-core/src/adaptors/auto_send.rs @@ -127,6 +127,11 @@ where reopen_forum_topic, delete_forum_topic, unpin_all_forum_topic_messages, + edit_general_forum_topic, + close_general_forum_topic, + reopen_general_forum_topic, + hide_general_forum_topic, + unhide_general_forum_topic, answer_callback_query, set_my_commands, get_my_commands, diff --git a/crates/teloxide-core/src/adaptors/cache_me.rs b/crates/teloxide-core/src/adaptors/cache_me.rs index c2b3537f..ae940f37 100644 --- a/crates/teloxide-core/src/adaptors/cache_me.rs +++ b/crates/teloxide-core/src/adaptors/cache_me.rs @@ -151,6 +151,11 @@ where reopen_forum_topic, delete_forum_topic, unpin_all_forum_topic_messages, + edit_general_forum_topic, + close_general_forum_topic, + reopen_general_forum_topic, + hide_general_forum_topic, + unhide_general_forum_topic, answer_callback_query, set_my_commands, get_my_commands, diff --git a/crates/teloxide-core/src/adaptors/erased.rs b/crates/teloxide-core/src/adaptors/erased.rs index 2041d22c..4d06a22e 100644 --- a/crates/teloxide-core/src/adaptors/erased.rs +++ b/crates/teloxide-core/src/adaptors/erased.rs @@ -240,6 +240,11 @@ where reopen_forum_topic, delete_forum_topic, unpin_all_forum_topic_messages, + edit_general_forum_topic, + close_general_forum_topic, + reopen_general_forum_topic, + hide_general_forum_topic, + unhide_general_forum_topic, answer_callback_query, set_my_commands, get_my_commands, @@ -628,8 +633,6 @@ trait ErasableRequester<'a> { &self, chat_id: Recipient, message_thread_id: i32, - name: String, - icon_custom_emoji_id: String, ) -> ErasedRequest<'a, EditForumTopic, Self::Err>; fn close_forum_topic( @@ -656,6 +659,32 @@ trait ErasableRequester<'a> { message_thread_id: i32, ) -> ErasedRequest<'a, UnpinAllForumTopicMessages, Self::Err>; + fn edit_general_forum_topic( + &self, + chat_id: Recipient, + name: String, + ) -> ErasedRequest<'a, EditGeneralForumTopic, Self::Err>; + + fn close_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, CloseGeneralForumTopic, Self::Err>; + + fn reopen_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, ReopenGeneralForumTopic, Self::Err>; + + fn hide_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, HideGeneralForumTopic, Self::Err>; + + fn unhide_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, UnhideGeneralForumTopic, Self::Err>; + fn answer_callback_query( &self, callback_query_id: String, @@ -1350,11 +1379,8 @@ where &self, chat_id: Recipient, message_thread_id: i32, - name: String, - icon_custom_emoji_id: String, ) -> ErasedRequest<'a, EditForumTopic, Self::Err> { - Requester::edit_forum_topic(self, chat_id, message_thread_id, name, icon_custom_emoji_id) - .erase() + Requester::edit_forum_topic(self, chat_id, message_thread_id).erase() } fn close_forum_topic( @@ -1389,6 +1415,42 @@ where Requester::unpin_all_forum_topic_messages(self, chat_id, message_thread_id).erase() } + fn edit_general_forum_topic( + &self, + chat_id: Recipient, + name: String, + ) -> ErasedRequest<'a, EditGeneralForumTopic, Self::Err> { + Requester::edit_general_forum_topic(self, chat_id, name).erase() + } + + fn close_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, CloseGeneralForumTopic, Self::Err> { + Requester::close_general_forum_topic(self, chat_id).erase() + } + + fn reopen_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, ReopenGeneralForumTopic, Self::Err> { + Requester::reopen_general_forum_topic(self, chat_id).erase() + } + + fn hide_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, HideGeneralForumTopic, Self::Err> { + Requester::hide_general_forum_topic(self, chat_id).erase() + } + + fn unhide_general_forum_topic( + &self, + chat_id: Recipient, + ) -> ErasedRequest<'a, UnhideGeneralForumTopic, Self::Err> { + Requester::unhide_general_forum_topic(self, chat_id).erase() + } + fn answer_callback_query( &self, callback_query_id: String, diff --git a/crates/teloxide-core/src/adaptors/parse_mode.rs b/crates/teloxide-core/src/adaptors/parse_mode.rs index d69c275b..1d915c9a 100644 --- a/crates/teloxide-core/src/adaptors/parse_mode.rs +++ b/crates/teloxide-core/src/adaptors/parse_mode.rs @@ -149,6 +149,11 @@ impl Requester for DefaultParseMode { close_forum_topic, reopen_forum_topic, delete_forum_topic, + edit_general_forum_topic, + close_general_forum_topic, + reopen_general_forum_topic, + hide_general_forum_topic, + unhide_general_forum_topic, unpin_all_forum_topic_messages, answer_callback_query, set_my_commands, diff --git a/crates/teloxide-core/src/adaptors/throttle/requester_impl.rs b/crates/teloxide-core/src/adaptors/throttle/requester_impl.rs index a0d5965c..02b747e7 100644 --- a/crates/teloxide-core/src/adaptors/throttle/requester_impl.rs +++ b/crates/teloxide-core/src/adaptors/throttle/requester_impl.rs @@ -134,6 +134,11 @@ where reopen_forum_topic, delete_forum_topic, unpin_all_forum_topic_messages, + edit_general_forum_topic, + close_general_forum_topic, + reopen_general_forum_topic, + hide_general_forum_topic, + unhide_general_forum_topic, answer_callback_query, set_my_commands, get_my_commands, diff --git a/crates/teloxide-core/src/adaptors/trace.rs b/crates/teloxide-core/src/adaptors/trace.rs index 189e1c96..4dca2bc5 100644 --- a/crates/teloxide-core/src/adaptors/trace.rs +++ b/crates/teloxide-core/src/adaptors/trace.rs @@ -180,6 +180,11 @@ where reopen_forum_topic, delete_forum_topic, unpin_all_forum_topic_messages, + edit_general_forum_topic, + close_general_forum_topic, + reopen_general_forum_topic, + hide_general_forum_topic, + unhide_general_forum_topic, answer_callback_query, set_my_commands, get_my_commands, diff --git a/crates/teloxide-core/src/bot/api.rs b/crates/teloxide-core/src/bot/api.rs index 8a4b8140..7f1b4d32 100644 --- a/crates/teloxide-core/src/bot/api.rs +++ b/crates/teloxide-core/src/bot/api.rs @@ -675,21 +675,13 @@ impl Requester for Bot { type EditForumTopic = JsonRequest; - fn edit_forum_topic( - &self, - chat_id: C, - message_thread_id: i32, - name: N, - icon_custom_emoji_id: I, - ) -> Self::EditForumTopic + fn edit_forum_topic(&self, chat_id: C, message_thread_id: i32) -> Self::EditForumTopic where C: Into, - N: Into, - I: Into, { Self::EditForumTopic::new( self.clone(), - payloads::EditForumTopic::new(chat_id, message_thread_id, name, icon_custom_emoji_id), + payloads::EditForumTopic::new(chat_id, message_thread_id), ) } @@ -745,6 +737,67 @@ impl Requester for Bot { ) } + type EditGeneralForumTopic = JsonRequest; + + fn edit_general_forum_topic(&self, chat_id: C, name: N) -> Self::EditGeneralForumTopic + where + C: Into, + N: Into, + { + Self::EditGeneralForumTopic::new( + self.clone(), + payloads::EditGeneralForumTopic::new(chat_id, name), + ) + } + + type CloseGeneralForumTopic = JsonRequest; + + fn close_general_forum_topic(&self, chat_id: C) -> Self::CloseGeneralForumTopic + where + C: Into, + { + Self::CloseGeneralForumTopic::new( + self.clone(), + payloads::CloseGeneralForumTopic::new(chat_id), + ) + } + + type ReopenGeneralForumTopic = JsonRequest; + + fn reopen_general_forum_topic(&self, chat_id: C) -> Self::ReopenGeneralForumTopic + where + C: Into, + { + Self::ReopenGeneralForumTopic::new( + self.clone(), + payloads::ReopenGeneralForumTopic::new(chat_id), + ) + } + + type HideGeneralForumTopic = JsonRequest; + + fn hide_general_forum_topic(&self, chat_id: C) -> Self::HideGeneralForumTopic + where + C: Into, + { + Self::HideGeneralForumTopic::new( + self.clone(), + payloads::HideGeneralForumTopic::new(chat_id), + ) + } + + type UnhideGeneralForumTopic = JsonRequest; + + fn unhide_general_forum_topic(&self, chat_id: C) -> Self::UnhideGeneralForumTopic + where + C: Into, + { + Self::UnhideGeneralForumTopic::new( + self.clone(), + payloads::UnhideGeneralForumTopic::new(chat_id), + ) + } + type AnswerCallbackQuery = JsonRequest; fn answer_callback_query(&self, callback_query_id: C) -> Self::AnswerCallbackQuery diff --git a/crates/teloxide-core/src/codegen.rs b/crates/teloxide-core/src/codegen.rs index 5e90823e..fe956bce 100644 --- a/crates/teloxide-core/src/codegen.rs +++ b/crates/teloxide-core/src/codegen.rs @@ -78,11 +78,13 @@ pub fn ensure_files_contents<'a>( let mut err_count = 0; for (path, contents) in files_and_contents { - let old_contents = fs::read_to_string(path).unwrap(); + if path.exists() { + let old_contents = fs::read_to_string(path).unwrap(); - if normalize_newlines(&old_contents) == normalize_newlines(contents) { - // File is already up to date. - continue; + if normalize_newlines(&old_contents) == normalize_newlines(contents) { + // File is already up to date. + continue; + } } err_count += 1; diff --git a/crates/teloxide-core/src/lib.rs b/crates/teloxide-core/src/lib.rs index 7ac35e29..d76dac3b 100644 --- a/crates/teloxide-core/src/lib.rs +++ b/crates/teloxide-core/src/lib.rs @@ -1,7 +1,7 @@ //! Core part of the [`teloxide`] library. //! //! This library provides tools for making requests to the [Telegram Bot API] -//! (Currently, version `6.2` is supported) with ease. The library is fully +//! (Currently, version `6.4` is supported) with ease. The library is fully //! asynchronous and built using [`tokio`]. //! //!```toml diff --git a/crates/teloxide-core/src/local_macros.rs b/crates/teloxide-core/src/local_macros.rs index 15884d21..95b31eb0 100644 --- a/crates/teloxide-core/src/local_macros.rs +++ b/crates/teloxide-core/src/local_macros.rs @@ -931,11 +931,9 @@ macro_rules! requester_forward { (@method edit_forum_topic $body:ident $ty:ident) => { type EditForumTopic = $ty![EditForumTopic]; - fn edit_forum_topic(&self, chat_id: C, message_thread_id: i32, name: N, icon_custom_emoji_id: I) -> Self::EditForumTopic where C: Into, - N: Into, - I: Into { + fn edit_forum_topic(&self, chat_id: C, message_thread_id: i32) -> Self::EditForumTopic where C: Into { let this = self; - $body!(edit_forum_topic this (chat_id: C, message_thread_id: i32, name: N, icon_custom_emoji_id: I)) + $body!(edit_forum_topic this (chat_id: C, message_thread_id: i32)) } }; (@method close_forum_topic $body:ident $ty:ident) => { @@ -970,6 +968,47 @@ macro_rules! requester_forward { $body!(unpin_all_forum_topic_messages this (chat_id: C, message_thread_id: i32)) } }; + (@method edit_general_forum_topic $body:ident $ty:ident) => { + type EditGeneralForumTopic = $ty![EditGeneralForumTopic]; + + fn edit_general_forum_topic(&self, chat_id: C, name: N) -> Self::EditGeneralForumTopic where C: Into, + N: Into { + let this = self; + $body!(edit_general_forum_topic this (chat_id: C, name: N)) + } + }; + (@method close_general_forum_topic $body:ident $ty:ident) => { + type CloseGeneralForumTopic = $ty![CloseGeneralForumTopic]; + + fn close_general_forum_topic(&self, chat_id: C) -> Self::CloseGeneralForumTopic where C: Into { + let this = self; + $body!(close_general_forum_topic this (chat_id: C)) + } + }; + (@method reopen_general_forum_topic $body:ident $ty:ident) => { + type ReopenGeneralForumTopic = $ty![ReopenGeneralForumTopic]; + + fn reopen_general_forum_topic(&self, chat_id: C) -> Self::ReopenGeneralForumTopic where C: Into { + let this = self; + $body!(reopen_general_forum_topic this (chat_id: C)) + } + }; + (@method hide_general_forum_topic $body:ident $ty:ident) => { + type HideGeneralForumTopic = $ty![HideGeneralForumTopic]; + + fn hide_general_forum_topic(&self, chat_id: C) -> Self::HideGeneralForumTopic where C: Into { + let this = self; + $body!(hide_general_forum_topic this (chat_id: C)) + } + }; + (@method unhide_general_forum_topic $body:ident $ty:ident) => { + type UnhideGeneralForumTopic = $ty![UnhideGeneralForumTopic]; + + fn unhide_general_forum_topic(&self, chat_id: C) -> Self::UnhideGeneralForumTopic where C: Into { + let this = self; + $body!(unhide_general_forum_topic this (chat_id: C)) + } + }; (@method answer_callback_query $body:ident $ty:ident) => { type AnswerCallbackQuery = $ty![AnswerCallbackQuery]; diff --git a/crates/teloxide-core/src/payloads.rs b/crates/teloxide-core/src/payloads.rs index b74b1fb4..2f4d7e08 100644 --- a/crates/teloxide-core/src/payloads.rs +++ b/crates/teloxide-core/src/payloads.rs @@ -26,6 +26,7 @@ mod ban_chat_member; mod ban_chat_sender_chat; mod close; mod close_forum_topic; +mod close_general_forum_topic; mod copy_message; mod create_chat_invite_link; mod create_forum_topic; @@ -41,6 +42,7 @@ mod delete_sticker_from_set; mod delete_webhook; mod edit_chat_invite_link; mod edit_forum_topic; +mod edit_general_forum_topic; mod edit_message_caption; mod edit_message_caption_inline; mod edit_message_live_location; @@ -70,12 +72,14 @@ mod get_sticker_set; mod get_updates; mod get_user_profile_photos; mod get_webhook_info; +mod hide_general_forum_topic; mod kick_chat_member; mod leave_chat; mod log_out; mod pin_chat_message; mod promote_chat_member; mod reopen_forum_topic; +mod reopen_general_forum_topic; mod restrict_chat_member; mod revoke_chat_invite_link; mod send_animation; @@ -116,6 +120,7 @@ mod stop_message_live_location_inline; mod stop_poll; mod unban_chat_member; mod unban_chat_sender_chat; +mod unhide_general_forum_topic; mod unpin_all_chat_messages; mod unpin_all_forum_topic_messages; mod unpin_chat_message; @@ -132,6 +137,7 @@ pub use ban_chat_member::{BanChatMember, BanChatMemberSetters}; pub use ban_chat_sender_chat::{BanChatSenderChat, BanChatSenderChatSetters}; pub use close::{Close, CloseSetters}; pub use close_forum_topic::{CloseForumTopic, CloseForumTopicSetters}; +pub use close_general_forum_topic::{CloseGeneralForumTopic, CloseGeneralForumTopicSetters}; pub use copy_message::{CopyMessage, CopyMessageSetters}; pub use create_chat_invite_link::{CreateChatInviteLink, CreateChatInviteLinkSetters}; pub use create_forum_topic::{CreateForumTopic, CreateForumTopicSetters}; @@ -147,6 +153,7 @@ pub use delete_sticker_from_set::{DeleteStickerFromSet, DeleteStickerFromSetSett pub use delete_webhook::{DeleteWebhook, DeleteWebhookSetters}; pub use edit_chat_invite_link::{EditChatInviteLink, EditChatInviteLinkSetters}; pub use edit_forum_topic::{EditForumTopic, EditForumTopicSetters}; +pub use edit_general_forum_topic::{EditGeneralForumTopic, EditGeneralForumTopicSetters}; pub use edit_message_caption::{EditMessageCaption, EditMessageCaptionSetters}; pub use edit_message_caption_inline::{EditMessageCaptionInline, EditMessageCaptionInlineSetters}; pub use edit_message_live_location::{EditMessageLiveLocation, EditMessageLiveLocationSetters}; @@ -184,12 +191,14 @@ pub use get_sticker_set::{GetStickerSet, GetStickerSetSetters}; pub use get_updates::{GetUpdates, GetUpdatesSetters}; pub use get_user_profile_photos::{GetUserProfilePhotos, GetUserProfilePhotosSetters}; pub use get_webhook_info::{GetWebhookInfo, GetWebhookInfoSetters}; +pub use hide_general_forum_topic::{HideGeneralForumTopic, HideGeneralForumTopicSetters}; pub use kick_chat_member::{KickChatMember, KickChatMemberSetters}; pub use leave_chat::{LeaveChat, LeaveChatSetters}; pub use log_out::{LogOut, LogOutSetters}; pub use pin_chat_message::{PinChatMessage, PinChatMessageSetters}; pub use promote_chat_member::{PromoteChatMember, PromoteChatMemberSetters}; pub use reopen_forum_topic::{ReopenForumTopic, ReopenForumTopicSetters}; +pub use reopen_general_forum_topic::{ReopenGeneralForumTopic, ReopenGeneralForumTopicSetters}; pub use restrict_chat_member::{RestrictChatMember, RestrictChatMemberSetters}; pub use revoke_chat_invite_link::{RevokeChatInviteLink, RevokeChatInviteLinkSetters}; pub use send_animation::{SendAnimation, SendAnimationSetters}; @@ -236,6 +245,7 @@ pub use stop_message_live_location_inline::{ pub use stop_poll::{StopPoll, StopPollSetters}; pub use unban_chat_member::{UnbanChatMember, UnbanChatMemberSetters}; pub use unban_chat_sender_chat::{UnbanChatSenderChat, UnbanChatSenderChatSetters}; +pub use unhide_general_forum_topic::{UnhideGeneralForumTopic, UnhideGeneralForumTopicSetters}; pub use unpin_all_chat_messages::{UnpinAllChatMessages, UnpinAllChatMessagesSetters}; pub use unpin_all_forum_topic_messages::{ UnpinAllForumTopicMessages, UnpinAllForumTopicMessagesSetters, diff --git a/crates/teloxide-core/src/payloads/close_general_forum_topic.rs b/crates/teloxide-core/src/payloads/close_general_forum_topic.rs new file mode 100644 index 00000000..d211f0d8 --- /dev/null +++ b/crates/teloxide-core/src/payloads/close_general_forum_topic.rs @@ -0,0 +1,16 @@ +//! Generated by `codegen_payloads`, do not edit by hand. + +use serde::Serialize; + +use crate::types::{Recipient, True}; + +impl_payload! { + /// Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_manage\_topics_ administrator rights. Returns True on success. + #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)] + pub CloseGeneralForumTopic (CloseGeneralForumTopicSetters) => True { + required { + /// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) + pub chat_id: Recipient [into], + } + } +} diff --git a/crates/teloxide-core/src/payloads/edit_forum_topic.rs b/crates/teloxide-core/src/payloads/edit_forum_topic.rs index 8cbcf916..dd311dea 100644 --- a/crates/teloxide-core/src/payloads/edit_forum_topic.rs +++ b/crates/teloxide-core/src/payloads/edit_forum_topic.rs @@ -13,9 +13,11 @@ impl_payload! { pub chat_id: Recipient [into], /// Unique identifier for the target message thread of the forum topic pub message_thread_id: i32, - /// Topic name, 1-128 characters + } + optional { + /// Topic name, 0-128 characters. If not specified or empty, the current name of the topic will be kept pub name: String [into], - /// Unique identifier of the custom emoji shown as the topic icon. Use `getForumTopicIconStickers` to get all allowed custom emoji identifiers. + /// Unique identifier of the custom emoji shown as the topic icon. Use `getForumTopicIconStickers` to get all allowed custom emoji identifiers. Pass an empty string to remove the icon. If not specified, the current icon will be kept pub icon_custom_emoji_id: String [into], } } diff --git a/crates/teloxide-core/src/payloads/edit_general_forum_topic.rs b/crates/teloxide-core/src/payloads/edit_general_forum_topic.rs new file mode 100644 index 00000000..3f593e7c --- /dev/null +++ b/crates/teloxide-core/src/payloads/edit_general_forum_topic.rs @@ -0,0 +1,18 @@ +//! Generated by `codegen_payloads`, do not edit by hand. + +use serde::Serialize; + +use crate::types::{Recipient, True}; + +impl_payload! { + /// Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have _can\_manage\_topics_ administrator rights. Returns True on success. + #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)] + pub EditGeneralForumTopic (EditGeneralForumTopicSetters) => True { + required { + /// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) + pub chat_id: Recipient [into], + /// New topic name, 1-128 characters + pub name: String [into], + } + } +} diff --git a/crates/teloxide-core/src/payloads/hide_general_forum_topic.rs b/crates/teloxide-core/src/payloads/hide_general_forum_topic.rs new file mode 100644 index 00000000..014061a7 --- /dev/null +++ b/crates/teloxide-core/src/payloads/hide_general_forum_topic.rs @@ -0,0 +1,16 @@ +//! Generated by `codegen_payloads`, do not edit by hand. + +use serde::Serialize; + +use crate::types::{Recipient, True}; + +impl_payload! { + /// Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_manage\_topics_ administrator rights. The topic will be automatically closed if it was open. Returns True on success. + #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)] + pub HideGeneralForumTopic (HideGeneralForumTopicSetters) => True { + required { + /// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) + pub chat_id: Recipient [into], + } + } +} diff --git a/crates/teloxide-core/src/payloads/reopen_general_forum_topic.rs b/crates/teloxide-core/src/payloads/reopen_general_forum_topic.rs new file mode 100644 index 00000000..09fe1f2b --- /dev/null +++ b/crates/teloxide-core/src/payloads/reopen_general_forum_topic.rs @@ -0,0 +1,16 @@ +//! Generated by `codegen_payloads`, do not edit by hand. + +use serde::Serialize; + +use crate::types::{Recipient, True}; + +impl_payload! { + /// Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_manage\_topics_ administrator rights. The topic will be automatically unhidden if it was hidden. Returns True on success. + #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)] + pub ReopenGeneralForumTopic (ReopenGeneralForumTopicSetters) => True { + required { + /// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) + pub chat_id: Recipient [into], + } + } +} diff --git a/crates/teloxide-core/src/payloads/send_animation.rs b/crates/teloxide-core/src/payloads/send_animation.rs index b6bc5b7f..3c4e487d 100644 --- a/crates/teloxide-core/src/payloads/send_animation.rs +++ b/crates/teloxide-core/src/payloads/send_animation.rs @@ -42,6 +42,8 @@ impl_payload! { pub parse_mode: ParseMode, /// List of special entities that appear in the photo caption, which can be specified instead of _parse\_mode_ pub caption_entities: Vec [collect], + /// Pass True if the animation needs to be covered with a spoiler animation + pub has_spoiler: bool, /// Sends the message [silently]. Users will receive a notification with no sound. /// /// [silently]: https://telegram.org/blog/channels-2-0#silent-messages diff --git a/crates/teloxide-core/src/payloads/send_chat_action.rs b/crates/teloxide-core/src/payloads/send_chat_action.rs index a3acd43e..50b4c3db 100644 --- a/crates/teloxide-core/src/payloads/send_chat_action.rs +++ b/crates/teloxide-core/src/payloads/send_chat_action.rs @@ -29,5 +29,9 @@ impl_payload! { /// [video notes]: crate::payloads::SendVideoNote pub action: ChatAction, } + optional { + /// Unique identifier for the target message thread; supergroups only + pub message_thread_id: i32, + } } } diff --git a/crates/teloxide-core/src/payloads/send_photo.rs b/crates/teloxide-core/src/payloads/send_photo.rs index 77399f1c..70e97bea 100644 --- a/crates/teloxide-core/src/payloads/send_photo.rs +++ b/crates/teloxide-core/src/payloads/send_photo.rs @@ -32,6 +32,8 @@ impl_payload! { pub parse_mode: ParseMode, /// List of special entities that appear in the photo caption, which can be specified instead of _parse\_mode_ pub caption_entities: Vec [collect], + /// Pass True if the photo needs to be covered with a spoiler animation + pub has_spoiler: bool, /// Sends the message [silently]. Users will receive a notification with no sound. /// /// [silently]: https://telegram.org/blog/channels-2-0#silent-messages diff --git a/crates/teloxide-core/src/payloads/send_video.rs b/crates/teloxide-core/src/payloads/send_video.rs index 9eb0f307..2723e6e4 100644 --- a/crates/teloxide-core/src/payloads/send_video.rs +++ b/crates/teloxide-core/src/payloads/send_video.rs @@ -43,6 +43,8 @@ impl_payload! { pub parse_mode: ParseMode, /// List of special entities that appear in the caption, which can be specified instead of _parse\_mode_ pub caption_entities: Vec [collect], + /// Pass True if the video needs to be covered with a spoiler animation + pub has_spoiler: bool, /// Pass _True_, if the uploaded video is suitable for streaming pub supports_streaming: bool, /// Sends the message [silently]. Users will receive a notification with no sound. diff --git a/crates/teloxide-core/src/payloads/setters.rs b/crates/teloxide-core/src/payloads/setters.rs index d111970f..ac2a626f 100644 --- a/crates/teloxide-core/src/payloads/setters.rs +++ b/crates/teloxide-core/src/payloads/setters.rs @@ -5,13 +5,13 @@ pub use crate::payloads::{ AddStickerToSetSetters as _, AnswerCallbackQuerySetters as _, AnswerInlineQuerySetters as _, AnswerPreCheckoutQuerySetters as _, AnswerShippingQuerySetters as _, AnswerWebAppQuerySetters as _, ApproveChatJoinRequestSetters as _, BanChatMemberSetters as _, - BanChatSenderChatSetters as _, CloseForumTopicSetters as _, CloseSetters as _, - CopyMessageSetters as _, CreateChatInviteLinkSetters as _, CreateForumTopicSetters as _, - CreateInvoiceLinkSetters as _, CreateNewStickerSetSetters as _, + BanChatSenderChatSetters as _, CloseForumTopicSetters as _, CloseGeneralForumTopicSetters as _, + CloseSetters as _, CopyMessageSetters as _, CreateChatInviteLinkSetters as _, + CreateForumTopicSetters as _, CreateInvoiceLinkSetters as _, CreateNewStickerSetSetters as _, DeclineChatJoinRequestSetters as _, DeleteChatPhotoSetters as _, DeleteChatStickerSetSetters as _, DeleteForumTopicSetters as _, DeleteMessageSetters as _, DeleteMyCommandsSetters as _, DeleteStickerFromSetSetters as _, DeleteWebhookSetters as _, - EditChatInviteLinkSetters as _, EditForumTopicSetters as _, + EditChatInviteLinkSetters as _, EditForumTopicSetters as _, EditGeneralForumTopicSetters as _, EditMessageCaptionInlineSetters as _, EditMessageCaptionSetters as _, EditMessageLiveLocationInlineSetters as _, EditMessageLiveLocationSetters as _, EditMessageMediaInlineSetters as _, EditMessageMediaSetters as _, @@ -23,12 +23,13 @@ pub use crate::payloads::{ GetCustomEmojiStickersSetters as _, GetFileSetters as _, GetForumTopicIconStickersSetters as _, GetGameHighScoresSetters as _, GetMeSetters as _, GetMyCommandsSetters as _, GetMyDefaultAdministratorRightsSetters as _, GetStickerSetSetters as _, GetUpdatesSetters as _, - GetUserProfilePhotosSetters as _, GetWebhookInfoSetters as _, KickChatMemberSetters as _, - LeaveChatSetters as _, LogOutSetters as _, PinChatMessageSetters as _, - PromoteChatMemberSetters as _, ReopenForumTopicSetters as _, RestrictChatMemberSetters as _, - RevokeChatInviteLinkSetters as _, SendAnimationSetters as _, SendAudioSetters as _, - SendChatActionSetters as _, SendContactSetters as _, SendDiceSetters as _, - SendDocumentSetters as _, SendGameSetters as _, SendInvoiceSetters as _, + GetUserProfilePhotosSetters as _, GetWebhookInfoSetters as _, + HideGeneralForumTopicSetters as _, KickChatMemberSetters as _, LeaveChatSetters as _, + LogOutSetters as _, PinChatMessageSetters as _, PromoteChatMemberSetters as _, + ReopenForumTopicSetters as _, ReopenGeneralForumTopicSetters as _, + RestrictChatMemberSetters as _, RevokeChatInviteLinkSetters as _, SendAnimationSetters as _, + SendAudioSetters as _, SendChatActionSetters as _, SendContactSetters as _, + SendDiceSetters as _, SendDocumentSetters as _, SendGameSetters as _, SendInvoiceSetters as _, SendLocationSetters as _, SendMediaGroupSetters as _, SendMessageSetters as _, SendPhotoSetters as _, SendPollSetters as _, SendStickerSetters as _, SendVenueSetters as _, SendVideoNoteSetters as _, SendVideoSetters as _, SendVoiceSetters as _, @@ -40,6 +41,7 @@ pub use crate::payloads::{ SetStickerPositionInSetSetters as _, SetStickerSetThumbSetters as _, SetWebhookSetters as _, StopMessageLiveLocationInlineSetters as _, StopMessageLiveLocationSetters as _, StopPollSetters as _, UnbanChatMemberSetters as _, UnbanChatSenderChatSetters as _, - UnpinAllChatMessagesSetters as _, UnpinAllForumTopicMessagesSetters as _, - UnpinChatMessageSetters as _, UploadStickerFileSetters as _, + UnhideGeneralForumTopicSetters as _, UnpinAllChatMessagesSetters as _, + UnpinAllForumTopicMessagesSetters as _, UnpinChatMessageSetters as _, + UploadStickerFileSetters as _, }; diff --git a/crates/teloxide-core/src/payloads/unhide_general_forum_topic.rs b/crates/teloxide-core/src/payloads/unhide_general_forum_topic.rs new file mode 100644 index 00000000..640e4737 --- /dev/null +++ b/crates/teloxide-core/src/payloads/unhide_general_forum_topic.rs @@ -0,0 +1,16 @@ +//! Generated by `codegen_payloads`, do not edit by hand. + +use serde::Serialize; + +use crate::types::{Recipient, True}; + +impl_payload! { + /// Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the _can\_manage\_topics_ administrator rights. Returns True on success. + #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)] + pub UnhideGeneralForumTopic (UnhideGeneralForumTopicSetters) => True { + required { + /// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) + pub chat_id: Recipient [into], + } + } +} diff --git a/crates/teloxide-core/src/requests/requester.rs b/crates/teloxide-core/src/requests/requester.rs index 974c4f66..5c0c64d5 100644 --- a/crates/teloxide-core/src/requests/requester.rs +++ b/crates/teloxide-core/src/requests/requester.rs @@ -682,17 +682,9 @@ pub trait Requester { type EditForumTopic: Request; /// For Telegram documentation see [`EditForumTopic`]. - fn edit_forum_topic( - &self, - chat_id: C, - message_thread_id: i32, - name: N, - icon_custom_emoji_id: I, - ) -> Self::EditForumTopic + fn edit_forum_topic(&self, chat_id: C, message_thread_id: i32) -> Self::EditForumTopic where - C: Into, - N: Into, - I: Into; + C: Into; type CloseForumTopic: Request; @@ -726,6 +718,42 @@ pub trait Requester { where C: Into; + type EditGeneralForumTopic: Request; + + /// For Telegram documentation see [`EditGeneralForumTopic`]. + fn edit_general_forum_topic(&self, chat_id: C, name: N) -> Self::EditGeneralForumTopic + where + C: Into, + N: Into; + + type CloseGeneralForumTopic: Request; + + /// For Telegram documentation see [`CloseGeneralForumTopic`]. + fn close_general_forum_topic(&self, chat_id: C) -> Self::CloseGeneralForumTopic + where + C: Into; + + type ReopenGeneralForumTopic: Request; + + /// For Telegram documentation see [`ReopenGeneralForumTopic`]. + fn reopen_general_forum_topic(&self, chat_id: C) -> Self::ReopenGeneralForumTopic + where + C: Into; + + type HideGeneralForumTopic: Request; + + /// For Telegram documentation see [`HideGeneralForumTopic`]. + fn hide_general_forum_topic(&self, chat_id: C) -> Self::HideGeneralForumTopic + where + C: Into; + + type UnhideGeneralForumTopic: Request; + + /// For Telegram documentation see [`UnhideGeneralForumTopic`]. + fn unhide_general_forum_topic(&self, chat_id: C) -> Self::UnhideGeneralForumTopic + where + C: Into; + type AnswerCallbackQuery: Request; /// For Telegram documentation see [`AnswerCallbackQuery`]. @@ -1177,6 +1205,11 @@ macro_rules! forward_all { reopen_forum_topic, delete_forum_topic, unpin_all_forum_topic_messages, + edit_general_forum_topic, + close_general_forum_topic, + reopen_general_forum_topic, + hide_general_forum_topic, + unhide_general_forum_topic, answer_callback_query, set_my_commands, get_my_commands, 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..38da326b 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] @@ -579,6 +594,8 @@ mod tests { photo: None, pinned_message: None, message_auto_delete_time: None, + has_hidden_members: false, + has_aggressive_anti_spam_enabled: false, }; let actual = from_str(r#"{"id":-1,"type":"channel","username":"channel_name"}"#).unwrap(); assert_eq!(expected, actual); @@ -601,6 +618,8 @@ mod tests { photo: None, pinned_message: None, message_auto_delete_time: None, + has_hidden_members: false, + has_aggressive_anti_spam_enabled: false, }, from_str(r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#) .unwrap() @@ -623,6 +642,8 @@ mod tests { photo: None, pinned_message: None, message_auto_delete_time: None, + has_hidden_members: false, + has_aggressive_anti_spam_enabled: false, }; let json = to_string(&chat).unwrap(); diff --git a/crates/teloxide-core/src/types/forum_topic_closed.rs b/crates/teloxide-core/src/types/forum_topic_closed.rs index b3d45cf5..f3a57eb2 100644 --- a/crates/teloxide-core/src/types/forum_topic_closed.rs +++ b/crates/teloxide-core/src/types/forum_topic_closed.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; /// This object represents a service message about a forum topic closed in the /// chat. Currently holds no information. /// -/// [The official docs](https://core.telegram.org/bots/api#forumtopiccreated). +/// [The official docs](https://core.telegram.org/bots/api#forumtopicclosed). #[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct ForumTopicClosed; 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/forum_topic_reopened.rs b/crates/teloxide-core/src/types/forum_topic_reopened.rs index 88107186..faae4bd6 100644 --- a/crates/teloxide-core/src/types/forum_topic_reopened.rs +++ b/crates/teloxide-core/src/types/forum_topic_reopened.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; /// This object represents a service message about a forum topic reopened in the /// chat. Currently holds no information. /// -/// [The official docs](https://core.telegram.org/bots/api#forumtopiccreated). +/// [The official docs](https://core.telegram.org/bots/api#forumtopicreopened). #[serde_with_macros::skip_serializing_none] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct ForumTopicReopened; 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..9b9effcc 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. @@ -534,6 +573,7 @@ mod tests { caption: None, parse_mode: None, caption_entities: None, + has_spoiler: false, }); let actual_json = serde_json::to_string(&photo).unwrap(); @@ -553,6 +593,7 @@ mod tests { duration: None, supports_streaming: None, caption_entities: None, + has_spoiler: false, }); let actual_json = serde_json::to_string(&video).unwrap(); @@ -571,6 +612,7 @@ mod tests { height: None, duration: None, caption_entities: None, + has_spoiler: false, }); let actual_json = serde_json::to_string(&video).unwrap(); diff --git a/crates/teloxide-core/src/types/message.rs b/crates/teloxide-core/src/types/message.rs index 00927091..e121ee1f 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. @@ -41,6 +42,9 @@ pub struct Message { pub kind: MessageKind, } +// FIXME: this could be a use-case for serde mixed-tags, some variants need to +// untagged (`MessageCommon` as an example), while other need to be +// tagged (e.g.: Forum*) #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum MessageKind { @@ -58,12 +62,16 @@ pub enum MessageKind { Invoice(MessageInvoice), SuccessfulPayment(MessageSuccessfulPayment), ConnectedWebsite(MessageConnectedWebsite), + WriteAccessAllowed(MessageWriteAccessAllowed), PassportData(MessagePassportData), Dice(MessageDice), ProximityAlertTriggered(MessageProximityAlertTriggered), - ForumTopicCreated(ForumTopicCreated), - ForumTopicClosed(ForumTopicClosed), - ForumTopicReopened(ForumTopicReopened), + ForumTopicCreated(MessageForumTopicCreated), + ForumTopicEdited(MessageForumTopicEdited), + ForumTopicClosed(MessageForumTopicClosed), + ForumTopicReopened(MessageForumTopicReopened), + GeneralForumTopicHidden(MessageGeneralForumTopicHidden), + GeneralForumTopicUnhidden(MessageGeneralForumTopicUnhidden), VideoChatScheduled(MessageVideoChatScheduled), VideoChatStarted(MessageVideoChatStarted), VideoChatEnded(MessageVideoChatEnded), @@ -339,6 +347,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 +427,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 +474,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, @@ -506,12 +526,25 @@ pub struct MessageProximityAlertTriggered { pub proximity_alert_triggered: ProximityAlertTriggered, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageWriteAccessAllowed { + /// Service message: the user allowed the bot added to the attachment menu + /// to write messages. + pub write_access_allowed: WriteAccessAllowed, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct MessageForumTopicCreated { /// Service message: forum topic created. pub forum_topic_created: ForumTopicCreated, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageForumTopicEdited { + /// Service message: forum topic edited. + pub forum_topic_edited: ForumTopicEdited, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct MessageForumTopicClosed { /// Service message: forum topic closed. @@ -524,6 +557,18 @@ pub struct MessageForumTopicReopened { pub forum_topic_reopened: ForumTopicReopened, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageGeneralForumTopicHidden { + /// Service message: the 'General' forum topic hidden. + pub general_forum_topic_hidden: GeneralForumTopicHidden, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct MessageGeneralForumTopicUnhidden { + /// Service message: the 'General' forum topic unhidden. + pub general_forum_topic_unhidden: GeneralForumTopicUnhidden, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct MessageVideoChatScheduled { /// Service message: video chat scheduled @@ -767,6 +812,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 { @@ -1131,6 +1205,8 @@ mod getters { _ => None, } } + + // FIXME: add more getters for other types of messages } } @@ -1584,6 +1660,8 @@ mod tests { message_auto_delete_time: None, photo: None, pinned_message: None, + has_hidden_members: false, + has_aggressive_anti_spam_enabled: false, }; assert!(message.from().unwrap().is_anonymous()); 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/update.rs b/crates/teloxide-core/src/types/update.rs index df8f7cd6..6ec2040f 100644 --- a/crates/teloxide-core/src/types/update.rs +++ b/crates/teloxide-core/src/types/update.rs @@ -348,6 +348,8 @@ mod test { photo: None, pinned_message: None, message_auto_delete_time: None, + has_hidden_members: false, + has_aggressive_anti_spam_enabled: false, }, kind: MessageKind::Common(MessageCommon { from: Some(User { 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; diff --git a/crates/teloxide/tests/command.rs b/crates/teloxide/tests/command.rs index ce8ed389..cc4cd8a1 100644 --- a/crates/teloxide/tests/command.rs +++ b/crates/teloxide/tests/command.rs @@ -260,6 +260,5 @@ fn custom_result() { type Result = (); #[derive(BotCommands, Debug, PartialEq)] - enum DefaultCommands { - } + enum DefaultCommands {} }