diff --git a/CHANGELOG.md b/CHANGELOG.md
index be577e57..f4a82ef4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `filter_web_app_data`
- Implement `PostgresStorage`, a persistent dialogue storage based on [PostgreSQL](https://www.postgresql.org/)([PR 996](https://github.com/teloxide/teloxide/pull/996)).
- Implement `GetChatId` for `teloxide_core::types::{Chat, ChatJoinRequest, ChatMemberUpdated}`.
+- Add `MessageExt::filter_story` method for the corresponding `MediaKind::Story` variant ([PR 1087](https://github.com/teloxide/teloxide/pull/1087))
### Fixed
diff --git a/Cargo.lock b/Cargo.lock
index 0ba28d75..41efcc3d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -531,12 +531,6 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
-[[package]]
-name = "finl_unicode"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
-
[[package]]
name = "flume"
version = "0.11.0"
diff --git a/README.md b/README.md
index 9d335b9e..6eda6f18 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 36317098..951ca6b0 100644
--- a/crates/teloxide-core/CHANGELOG.md
+++ b/crates/teloxide-core/CHANGELOG.md
@@ -79,7 +79,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `set_my_name`
- `get_my_name`
- Add the ability to specify custom emoji entities using `HTML` and `MarkdownV2` formatting options for bots that purchased additional usernames on [Fragment](https://fragment.com/)
-
+- Support for TBA 6.8 ([#1087](pr1087))
+ - Add the `MediaKind::Story`
+ - Add new fields
+ - `PollAnswer::voter` to support anonymous poll answers in chats
+ - `emoji_status_expiration_date` to `Chat` as part of the future `ChatFullInfo` type TBA type
+ - Add the `unpin_all_general_forum_topic_messages` method
[pr851]: https://github.com/teloxide/teloxide/pull/851
[pr887]: https://github.com/teloxide/teloxide/pull/887
@@ -87,6 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[pr982]: https://github.com/teloxide/teloxide/pull/982
[pr1040]: https://github.com/teloxide/teloxide/pull/1040
[pr1086]: https://github.com/teloxide/teloxide/pull/1086
+[pr1087]: https://github.com/teloxide/teloxide/pull/1087
### Fixed
diff --git a/crates/teloxide-core/README.md b/crates/teloxide-core/README.md
index 3ae43842..6a382bb3 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 2e876287..cc649e5d 100644
--- a/crates/teloxide-core/schema.ron
+++ b/crates/teloxide-core/schema.ron
@@ -39,7 +39,7 @@
//! [github]: https://github.com/WaffleLapkin/tg-methods-schema
Schema(
- api_version: ApiVersion(ver: "6.7", date: "April 21, 2023"),
+ api_version: ApiVersion(ver: "6.8", date: "August 18, 2023"),
methods: [
Method(
names: ("getUpdates", "GetUpdates", "get_updates"),
@@ -2801,6 +2801,20 @@ Schema(
),
],
),
+ Method(
+ names: ("unpinAllGeneralForumTopicMessages", "UnpinAllGeneralForumTopicMessages", "unpin_all_general_forum_topic_messages"),
+ return_ty: True,
+ doc: Doc(md: "Use this method to clear the list of pinned messages in a General 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#unpinallgeneralforumtopicmessages",
+ 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 supergroup (in the format @supergroupusername)")
+ ),
+ ],
+ ),
Method(
names: ("answerCallbackQuery", "AnswerCallbackQuery", "answer_callback_query"),
return_ty: True,
diff --git a/crates/teloxide-core/src/adaptors/cache_me.rs b/crates/teloxide-core/src/adaptors/cache_me.rs
index 84b4887e..eecac8bc 100644
--- a/crates/teloxide-core/src/adaptors/cache_me.rs
+++ b/crates/teloxide-core/src/adaptors/cache_me.rs
@@ -156,6 +156,7 @@ where
reopen_general_forum_topic,
hide_general_forum_topic,
unhide_general_forum_topic,
+ unpin_all_general_forum_topic_messages,
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 7e4f390c..509cbdaa 100644
--- a/crates/teloxide-core/src/adaptors/erased.rs
+++ b/crates/teloxide-core/src/adaptors/erased.rs
@@ -251,6 +251,7 @@ where
reopen_general_forum_topic,
hide_general_forum_topic,
unhide_general_forum_topic,
+ unpin_all_general_forum_topic_messages,
answer_callback_query,
set_my_commands,
get_my_commands,
@@ -699,6 +700,11 @@ trait ErasableRequester<'a> {
chat_id: Recipient,
) -> ErasedRequest<'a, UnhideGeneralForumTopic, Self::Err>;
+ fn unpin_all_general_forum_topic_messages(
+ &self,
+ chat_id: Recipient,
+ ) -> ErasedRequest<'a, UnpinAllGeneralForumTopicMessages, Self::Err>;
+
fn answer_callback_query(
&self,
callback_query_id: String,
@@ -1500,6 +1506,13 @@ where
Requester::unhide_general_forum_topic(self, chat_id).erase()
}
+ fn unpin_all_general_forum_topic_messages(
+ &self,
+ chat_id: Recipient,
+ ) -> ErasedRequest<'a, UnpinAllGeneralForumTopicMessages, Self::Err> {
+ Requester::unpin_all_general_forum_topic_messages(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 d7540115..216893a4 100644
--- a/crates/teloxide-core/src/adaptors/parse_mode.rs
+++ b/crates/teloxide-core/src/adaptors/parse_mode.rs
@@ -231,12 +231,13 @@ where
close_forum_topic,
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,
- unpin_all_forum_topic_messages,
+ unpin_all_general_forum_topic_messages,
answer_callback_query,
set_my_commands,
get_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 436f6488..28d82051 100644
--- a/crates/teloxide-core/src/adaptors/throttle/requester_impl.rs
+++ b/crates/teloxide-core/src/adaptors/throttle/requester_impl.rs
@@ -139,6 +139,7 @@ where
reopen_general_forum_topic,
hide_general_forum_topic,
unhide_general_forum_topic,
+ unpin_all_general_forum_topic_messages,
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 466674d1..bf4141bc 100644
--- a/crates/teloxide-core/src/adaptors/trace.rs
+++ b/crates/teloxide-core/src/adaptors/trace.rs
@@ -185,6 +185,7 @@ where
reopen_general_forum_topic,
hide_general_forum_topic,
unhide_general_forum_topic,
+ unpin_all_general_forum_topic_messages,
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 35c6231c..6ff8b81d 100644
--- a/crates/teloxide-core/src/bot/api.rs
+++ b/crates/teloxide-core/src/bot/api.rs
@@ -802,6 +802,22 @@ impl Requester for Bot {
)
}
+ type UnpinAllGeneralForumTopicMessages =
+ JsonRequest;
+
+ fn unpin_all_general_forum_topic_messages(
+ &self,
+ chat_id: C,
+ ) -> Self::UnpinAllGeneralForumTopicMessages
+ where
+ C: Into,
+ {
+ Self::UnpinAllGeneralForumTopicMessages::new(
+ self.clone(),
+ payloads::UnpinAllGeneralForumTopicMessages::new(chat_id),
+ )
+ }
+
type AnswerCallbackQuery = JsonRequest;
fn answer_callback_query(&self, callback_query_id: C) -> Self::AnswerCallbackQuery
diff --git a/crates/teloxide-core/src/local_macros.rs b/crates/teloxide-core/src/local_macros.rs
index 9ce59f58..8207bd01 100644
--- a/crates/teloxide-core/src/local_macros.rs
+++ b/crates/teloxide-core/src/local_macros.rs
@@ -1009,6 +1009,14 @@ macro_rules! requester_forward {
$body!(unhide_general_forum_topic this (chat_id: C))
}
};
+ (@method unpin_all_general_forum_topic_messages $body:ident $ty:ident) => {
+ type UnpinAllGeneralForumTopicMessages = $ty![UnpinAllGeneralForumTopicMessages];
+
+ fn unpin_all_general_forum_topic_messages(&self, chat_id: C) -> Self::UnpinAllGeneralForumTopicMessages where C: Into {
+ let this = self;
+ $body!(unpin_all_general_forum_topic_messages 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 97d2e61d..7f3cf308 100644
--- a/crates/teloxide-core/src/payloads.rs
+++ b/crates/teloxide-core/src/payloads.rs
@@ -135,6 +135,7 @@ mod unban_chat_sender_chat;
mod unhide_general_forum_topic;
mod unpin_all_chat_messages;
mod unpin_all_forum_topic_messages;
+mod unpin_all_general_forum_topic_messages;
mod unpin_chat_message;
mod upload_sticker_file;
@@ -276,6 +277,9 @@ pub use unpin_all_chat_messages::{UnpinAllChatMessages, UnpinAllChatMessagesSett
pub use unpin_all_forum_topic_messages::{
UnpinAllForumTopicMessages, UnpinAllForumTopicMessagesSetters,
};
+pub use unpin_all_general_forum_topic_messages::{
+ UnpinAllGeneralForumTopicMessages, UnpinAllGeneralForumTopicMessagesSetters,
+};
pub use unpin_chat_message::{UnpinChatMessage, UnpinChatMessageSetters};
pub use upload_sticker_file::{UploadStickerFile, UploadStickerFileSetters};
// END BLOCK payload_modules
diff --git a/crates/teloxide-core/src/payloads/setters.rs b/crates/teloxide-core/src/payloads/setters.rs
index 6faa7d16..9771e38b 100644
--- a/crates/teloxide-core/src/payloads/setters.rs
+++ b/crates/teloxide-core/src/payloads/setters.rs
@@ -47,6 +47,6 @@ pub use crate::payloads::{
StopMessageLiveLocationInlineSetters as _, StopMessageLiveLocationSetters as _,
StopPollSetters as _, UnbanChatMemberSetters as _, UnbanChatSenderChatSetters as _,
UnhideGeneralForumTopicSetters as _, UnpinAllChatMessagesSetters as _,
- UnpinAllForumTopicMessagesSetters as _, UnpinChatMessageSetters as _,
- UploadStickerFileSetters as _,
+ UnpinAllForumTopicMessagesSetters as _, UnpinAllGeneralForumTopicMessagesSetters as _,
+ UnpinChatMessageSetters as _, UploadStickerFileSetters as _,
};
diff --git a/crates/teloxide-core/src/payloads/unpin_all_general_forum_topic_messages.rs b/crates/teloxide-core/src/payloads/unpin_all_general_forum_topic_messages.rs
new file mode 100644
index 00000000..776b066a
--- /dev/null
+++ b/crates/teloxide-core/src/payloads/unpin_all_general_forum_topic_messages.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 clear the list of pinned messages in a General 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.
+ #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize)]
+ pub UnpinAllGeneralForumTopicMessages (UnpinAllGeneralForumTopicMessagesSetters) => True {
+ required {
+ /// Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername)
+ pub chat_id: Recipient [into],
+ }
+ }
+}
diff --git a/crates/teloxide-core/src/requests/requester.rs b/crates/teloxide-core/src/requests/requester.rs
index 58adb2b6..f178ab8b 100644
--- a/crates/teloxide-core/src/requests/requester.rs
+++ b/crates/teloxide-core/src/requests/requester.rs
@@ -758,6 +758,19 @@ pub trait Requester {
where
C: Into;
+ type UnpinAllGeneralForumTopicMessages: Request<
+ Payload = UnpinAllGeneralForumTopicMessages,
+ Err = Self::Err,
+ >;
+
+ /// For Telegram documentation see [`UnpinAllGeneralForumTopicMessages`].
+ fn unpin_all_general_forum_topic_messages(
+ &self,
+ chat_id: C,
+ ) -> Self::UnpinAllGeneralForumTopicMessages
+ where
+ C: Into;
+
type AnswerCallbackQuery: Request;
/// For Telegram documentation see [`AnswerCallbackQuery`].
@@ -1297,6 +1310,7 @@ macro_rules! forward_all {
reopen_general_forum_topic,
hide_general_forum_topic,
unhide_general_forum_topic,
+ unpin_all_general_forum_topic_messages,
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 26128929..f142825d 100644
--- a/crates/teloxide-core/src/types.rs
+++ b/crates/teloxide-core/src/types.rs
@@ -13,6 +13,7 @@ pub use callback_query::*;
pub use chat::*;
pub use chat_action::*;
pub use chat_administrator_rights::*;
+pub use chat_full_info::*;
pub use chat_invite_link::*;
pub use chat_join_request::*;
pub use chat_location::*;
@@ -105,6 +106,7 @@ pub use shipping_option::*;
pub use shipping_query::*;
pub use sticker::*;
pub use sticker_set::*;
+pub use story::*;
pub use successful_payment::*;
pub use switch_inline_query_chosen_chat::*;
pub use target_message::*;
@@ -141,6 +143,7 @@ mod callback_query;
mod chat;
mod chat_action;
mod chat_administrator_rights;
+mod chat_full_info;
mod chat_invite_link;
mod chat_join_request;
mod chat_location;
@@ -206,6 +209,7 @@ mod shipping_option;
mod shipping_query;
mod sticker;
mod sticker_set;
+mod story;
mod successful_payment;
mod switch_inline_query_chosen_chat;
mod target_message;
diff --git a/crates/teloxide-core/src/types/chat.rs b/crates/teloxide-core/src/types/chat.rs
index 2bd38dd9..6f12745d 100644
--- a/crates/teloxide-core/src/types/chat.rs
+++ b/crates/teloxide-core/src/types/chat.rs
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::types::{
- ChatId, ChatLocation, ChatPermissions, ChatPhoto, Message, Seconds, True, User,
+ ChatFullInfo, ChatId, ChatLocation, ChatPermissions, ChatPhoto, Message, Seconds, True, User,
};
/// This object represents a chat.
@@ -47,6 +47,9 @@ pub struct Chat {
/// [`GetChat`]: crate::payloads::GetChat
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub has_aggressive_anti_spam_enabled: bool,
+
+ #[serde(flatten)]
+ pub chat_full_info: ChatFullInfo,
}
#[serde_with_macros::skip_serializing_none]
@@ -615,6 +618,7 @@ mod tests {
message_auto_delete_time: None,
has_hidden_members: false,
has_aggressive_anti_spam_enabled: false,
+ chat_full_info: ChatFullInfo { emoji_status_expiration_date: None },
};
let actual = from_str(r#"{"id":-1,"type":"channel","username":"channel_name"}"#).unwrap();
assert_eq!(expected, actual);
@@ -639,6 +643,7 @@ mod tests {
message_auto_delete_time: None,
has_hidden_members: false,
has_aggressive_anti_spam_enabled: false,
+ chat_full_info: ChatFullInfo { emoji_status_expiration_date: None }
},
from_str(r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#)
.unwrap()
@@ -663,6 +668,7 @@ mod tests {
message_auto_delete_time: None,
has_hidden_members: false,
has_aggressive_anti_spam_enabled: false,
+ chat_full_info: ChatFullInfo { emoji_status_expiration_date: None },
};
let json = to_string(&chat).unwrap();
diff --git a/crates/teloxide-core/src/types/chat_full_info.rs b/crates/teloxide-core/src/types/chat_full_info.rs
new file mode 100644
index 00000000..9857ce7d
--- /dev/null
+++ b/crates/teloxide-core/src/types/chat_full_info.rs
@@ -0,0 +1,35 @@
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+
+// TODO: in the TBA7.3 the Chat will be splitted into Chat and ChatInfo
+// Currently it's just a container for the some fields of the Chat struct
+#[serde_with_macros::skip_serializing_none]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct ChatFullInfo {
+ /// Expiration date of the emoji status of the chat or the other party in a
+ /// private chat, in Unix time, if any
+ #[serde(default, with = "crate::types::serde_opt_date_from_unix_timestamp")]
+ pub emoji_status_expiration_date: Option>,
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_chat_full_info_de() {
+ assert_eq!(
+ serde_json::from_str::("{}").unwrap(),
+ ChatFullInfo { emoji_status_expiration_date: None }
+ );
+ assert_eq!(
+ serde_json::from_str::(
+ r#"{
+ "emoji_status_expiration_date": 1720708004
+ }"#
+ )
+ .unwrap(),
+ ChatFullInfo { emoji_status_expiration_date: DateTime::from_timestamp(1720708004, 0) }
+ );
+ }
+}
diff --git a/crates/teloxide-core/src/types/message.rs b/crates/teloxide-core/src/types/message.rs
index b80c4bbb..0eb7f353 100644
--- a/crates/teloxide-core/src/types/message.rs
+++ b/crates/teloxide-core/src/types/message.rs
@@ -9,9 +9,9 @@ use crate::types::{
ForumTopicClosed, ForumTopicCreated, ForumTopicEdited, ForumTopicReopened, Game,
GeneralForumTopicHidden, GeneralForumTopicUnhidden, InlineKeyboardMarkup, Invoice, Location,
MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef, MessageId, PassportData,
- PhotoSize, Poll, ProximityAlertTriggered, Sticker, SuccessfulPayment, ThreadId, True, User,
- UserShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled,
- VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed,
+ PhotoSize, Poll, ProximityAlertTriggered, Sticker, Story, SuccessfulPayment, ThreadId, True,
+ User, UserShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited,
+ VideoChatScheduled, VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed,
};
/// This object represents a message.
@@ -366,6 +366,7 @@ pub enum MediaKind {
Photo(MediaPhoto),
Poll(MediaPoll),
Sticker(MediaSticker),
+ Story(MediaStory),
Text(MediaText),
Video(MediaVideo),
VideoNote(MediaVideoNote),
@@ -494,6 +495,13 @@ pub struct MediaSticker {
pub sticker: Sticker,
}
+#[serde_with_macros::skip_serializing_none]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct MediaStory {
+ /// Message is a forwarded story
+ pub story: Story,
+}
+
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MediaText {
@@ -668,14 +676,14 @@ mod getters {
use crate::types::{
self, message::MessageKind::*, Chat, ChatId, ChatMigration, Forward, ForwardedFrom,
MediaAnimation, MediaAudio, MediaContact, MediaDocument, MediaGame, MediaKind,
- MediaLocation, MediaPhoto, MediaPoll, MediaSticker, MediaText, MediaVenue, MediaVideo,
- MediaVideoNote, MediaVoice, Message, MessageChannelChatCreated, MessageChatShared,
- MessageCommon, MessageConnectedWebsite, MessageDeleteChatPhoto, MessageDice, MessageEntity,
- MessageGroupChatCreated, MessageId, MessageInvoice, MessageLeftChatMember,
- MessageNewChatMembers, MessageNewChatPhoto, MessageNewChatTitle, MessagePassportData,
- MessagePinned, MessageProximityAlertTriggered, MessageSuccessfulPayment,
- MessageSupergroupChatCreated, MessageUserShared, MessageVideoChatParticipantsInvited,
- PhotoSize, User,
+ MediaLocation, MediaPhoto, MediaPoll, MediaSticker, MediaStory, MediaText, MediaVenue,
+ MediaVideo, MediaVideoNote, MediaVoice, Message, MessageChannelChatCreated,
+ MessageChatShared, MessageCommon, MessageConnectedWebsite, MessageDeleteChatPhoto,
+ MessageDice, MessageEntity, MessageGroupChatCreated, MessageId, MessageInvoice,
+ MessageLeftChatMember, MessageNewChatMembers, MessageNewChatPhoto, MessageNewChatTitle,
+ MessagePassportData, MessagePinned, MessageProximityAlertTriggered,
+ MessageSuccessfulPayment, MessageSupergroupChatCreated, MessageUserShared,
+ MessageVideoChatParticipantsInvited, PhotoSize, User,
};
use super::{
@@ -899,6 +907,7 @@ mod getters {
| MediaKind::Location(_)
| MediaKind::Poll(_)
| MediaKind::Sticker(_)
+ | MediaKind::Story(_)
| MediaKind::Text(_)
| MediaKind::VideoNote(_)
| MediaKind::Voice(_)
@@ -973,6 +982,17 @@ mod getters {
}
}
+ #[must_use]
+ pub fn story(&self) -> Option<&types::Story> {
+ match &self.kind {
+ Common(MessageCommon {
+ media_kind: MediaKind::Story(MediaStory { story, .. }),
+ ..
+ }) => Some(story),
+ _ => None,
+ }
+ }
+
#[must_use]
pub fn video(&self) -> Option<&types::Video> {
match &self.kind {
@@ -1763,7 +1783,8 @@ mod tests {
has_aggressive_anti_spam_enabled: false,
pinned_message: None,
message_auto_delete_time: None,
- has_hidden_members: false
+ has_hidden_members: false,
+ chat_full_info: ChatFullInfo { emoji_status_expiration_date: None }
},
kind: MessageKind::ChatShared(MessageChatShared {
chat_shared: ChatShared { request_id: 348349, chat_id: ChatId(384939) }
@@ -1996,6 +2017,7 @@ mod tests {
pinned_message: None,
has_hidden_members: false,
has_aggressive_anti_spam_enabled: false,
+ chat_full_info: ChatFullInfo { emoji_status_expiration_date: None },
};
assert!(message.from().unwrap().is_anonymous());
diff --git a/crates/teloxide-core/src/types/poll_answer.rs b/crates/teloxide-core/src/types/poll_answer.rs
index e87e0878..f40b55fb 100644
--- a/crates/teloxide-core/src/types/poll_answer.rs
+++ b/crates/teloxide-core/src/types/poll_answer.rs
@@ -1,17 +1,117 @@
-use crate::types::User;
-use serde::{Deserialize, Serialize};
+use serde::{Deserialize, Deserializer, Serialize};
+
+use crate::types::{Chat, User};
#[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PollAnswer {
/// Unique poll identifier.
pub poll_id: String,
- /// The user, who changed the answer to the poll.
- pub user: User,
+ /// If the voter is anonymous, stores the chat that changed the answer to
+ /// the poll.
+ ///
+ /// If the voter isn't anonymous, stores the user that changed
+ /// the answer to the poll
+ #[serde(deserialize_with = "deserialize_voter", flatten)]
+ pub voter: Voter,
/// 0-based identifiers of answer options, chosen by the user.
///
/// May be empty if the user retracted their vote.
pub option_ids: Vec,
}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
+pub enum Voter {
+ Chat(Chat),
+ User(User),
+}
+
+impl Voter {
+ #[must_use]
+ pub fn chat(&self) -> Option<&Chat> {
+ match self {
+ Self::Chat(chat) => Some(chat),
+ _ => None,
+ }
+ }
+
+ #[must_use]
+ pub fn user(&self) -> Option<&User> {
+ match self {
+ Self::User(user) => Some(user),
+ _ => None,
+ }
+ }
+}
+
+/// These fields `chat` and `user` from the original [`PollAnswer`] should be
+/// exclusive, but in cases when the `voter_chat` is presented the `user` isn't
+/// `None`, but rather actual value for backward compatibility, the field `user`
+/// in such objects will contain the user 136817688 (@Channel_Bot).
+#[derive(Deserialize)]
+struct VoterDe {
+ /// The chat that changed the answer to the poll, if the voter is anonymous
+ pub voter_chat: Option,
+
+ /// The user that changed the answer to the poll, if the voter isn't
+ /// anonymous
+ pub user: Option,
+}
+
+fn deserialize_voter<'d, D: Deserializer<'d>>(d: D) -> Result {
+ let VoterDe { voter_chat, user } = VoterDe::deserialize(d)?;
+ Ok(voter_chat.map(Voter::Chat).or(user.map(Voter::User)).unwrap())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_poll_answer_with_user_de() {
+ let json = r#"{
+ "poll_id":"POLL_ID",
+ "user": {"id":42,"is_bot":false,"first_name":"blah"},
+ "option_ids": []
+ }"#;
+
+ let poll_answer: PollAnswer = serde_json::from_str(json).unwrap();
+ assert!(matches!(poll_answer.voter, Voter::User(_)));
+ }
+
+ #[test]
+ fn test_poll_answer_with_voter_chat_de() {
+ let json = r#"{
+ "poll_id":"POLL_ID",
+ "voter_chat": {
+ "id": -1001160242915,
+ "title": "a",
+ "type": "group"
+ },
+ "option_ids": []
+ }"#;
+
+ let poll_answer: PollAnswer = serde_json::from_str(json).unwrap();
+ assert!(matches!(poll_answer.voter, Voter::Chat(_)));
+ }
+
+ #[test]
+ fn test_poll_answer_with_both_user_and_voter_chat_de() {
+ let json = r#"{
+ "poll_id":"POLL_ID",
+ "voter_chat": {
+ "id": -1001160242915,
+ "title": "a",
+ "type": "group"
+ },
+ "user": {"id":136817688,"is_bot":true,"first_name":"Channel_Bot"},
+ "option_ids": []
+ }"#;
+
+ let poll_answer: PollAnswer = serde_json::from_str(json).unwrap();
+ assert!(matches!(poll_answer.voter, Voter::Chat(_)));
+ }
+}
diff --git a/crates/teloxide-core/src/types/story.rs b/crates/teloxide-core/src/types/story.rs
new file mode 100644
index 00000000..a59e1568
--- /dev/null
+++ b/crates/teloxide-core/src/types/story.rs
@@ -0,0 +1,5 @@
+use serde::{Deserialize, Serialize};
+
+/// TBA 6.8: currently it holds no information
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct Story {}
diff --git a/crates/teloxide-core/src/types/update.rs b/crates/teloxide-core/src/types/update.rs
index caff4c50..adc8056a 100644
--- a/crates/teloxide-core/src/types/update.rs
+++ b/crates/teloxide-core/src/types/update.rs
@@ -136,7 +136,7 @@ impl Update {
InlineQuery(query) => &query.from,
ShippingQuery(query) => &query.from,
PreCheckoutQuery(query) => &query.from,
- PollAnswer(answer) => &answer.user,
+ PollAnswer(answer) => return answer.voter.user(),
MyChatMember(m) | ChatMember(m) => &m.from,
ChatJoinRequest(r) => &r.from,
@@ -198,7 +198,12 @@ impl Update {
UpdateKind::PreCheckoutQuery(query) => i1(once(&query.from)),
UpdateKind::Poll(poll) => i3(poll.mentioned_users()),
- UpdateKind::PollAnswer(answer) => i1(once(&answer.user)),
+ UpdateKind::PollAnswer(answer) => {
+ if let Some(user) = answer.voter.user() {
+ return i1(once(user));
+ }
+ i6(empty())
+ }
UpdateKind::MyChatMember(member) | UpdateKind::ChatMember(member) => {
i4(member.mentioned_users())
@@ -380,8 +385,8 @@ fn empty_error() -> UpdateKind {
#[cfg(test)]
mod test {
use crate::types::{
- Chat, ChatId, ChatKind, ChatPrivate, MediaKind, MediaText, Message, MessageCommon,
- MessageId, MessageKind, Update, UpdateId, UpdateKind, User, UserId,
+ Chat, ChatFullInfo, ChatId, ChatKind, ChatPrivate, MediaKind, MediaText, Message,
+ MessageCommon, MessageId, MessageKind, Update, UpdateId, UpdateKind, User, UserId,
};
use chrono::DateTime;
@@ -437,6 +442,7 @@ mod test {
message_auto_delete_time: None,
has_hidden_members: false,
has_aggressive_anti_spam_enabled: false,
+ chat_full_info: ChatFullInfo { emoji_status_expiration_date: None },
},
kind: MessageKind::Common(MessageCommon {
from: Some(User {
diff --git a/crates/teloxide/src/dispatching/filter_ext.rs b/crates/teloxide/src/dispatching/filter_ext.rs
index c0ab8e04..532f614f 100644
--- a/crates/teloxide/src/dispatching/filter_ext.rs
+++ b/crates/teloxide/src/dispatching/filter_ext.rs
@@ -83,6 +83,7 @@ define_message_ext! {
(filter_photo, Message::photo),
(filter_poll, Message::poll),
(filter_sticker, Message::sticker),
+ (filter_story, Message::story),
(filter_text, Message::text),
(filter_video, Message::video),
(filter_video_note, Message::video_note),