Merge pull request #1131 from shdwchn10/feature/tba-support/7.1

Add TBA 7.1 support
This commit is contained in:
Сырцев Вадим Игоревич 2024-08-17 18:56:20 +00:00 committed by GitHub
commit 0d63d3a8ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 297 additions and 43 deletions

View file

@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## unreleased
### Added
- Add `filter_boost_added` and `filter_reply_to_story` filters to `MessageFilterExt` trait
## 0.13.0 - 2024-08-16
### Added

View file

@ -11,7 +11,7 @@
<img src="https://img.shields.io/crates/v/teloxide.svg">
</a>
<a href="https://core.telegram.org/bots/api">
<img src="https://img.shields.io/badge/API%20coverage-Up%20to%207.0%20(inclusively)-green.svg">
<img src="https://img.shields.io/badge/API%20coverage-Up%20to%207.1%20(inclusively)-green.svg">
</a>
<a href="https://t.me/teloxide">
<img src="https://img.shields.io/badge/support-t.me%2Fteloxide-blueviolet">

View file

@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## unreleased
### Added
- Support for TBA 7.1 ([#1131](pr1131))
- Updated docs for `can_post_stories`, `can_edit_stories` and `can_delete_stories` admin privileges
- Add `ChatBoostAdded` and `StoryId` structs
- Add `ChatBoostAdded` variant to `MessageKind` enum
- Add `sender_boost_count` and `reply_to_story` fields to `MessageCommon` struct
- Add `chat` and `id` fields to `Story` struct
- Add `unrestrict_boost_count` and `custom_emoji_sticker_set_name` fields to `PublicChatSupergroup` struct
- Add `boost_added` and `reply_to_story` getters to `Message` struct
- Add `unrestrict_boost_count` and `custom_emoji_sticker_set_name` getters to `Chat` struct
[pr1131]: https://github.com/teloxide/teloxide/pull/1131
## 0.10.1 - 2024-08-17
### Fixed

View file

@ -12,7 +12,7 @@
<img src="https://img.shields.io/badge/license-MIT-blue.svg">
</a>
<a href="https://core.telegram.org/bots/api">
<img src="https://img.shields.io/badge/API%20coverage-Up%20to%207.0%20(inclusively)-green.svg">
<img src="https://img.shields.io/badge/API%20coverage-Up%20to%207.1%20(inclusively)-green.svg">
</a>
<a href="https://crates.io/crates/teloxide_core">
<img src="https://img.shields.io/crates/v/teloxide_core.svg">

View file

@ -39,7 +39,7 @@
//! [github]: https://github.com/WaffleLapkin/tg-methods-schema
Schema(
api_version: ApiVersion(ver: "7.0", date: "December 29, 2023"),
api_version: ApiVersion(ver: "7.1", date: "February 16, 2024"),
methods: [
Method(
names: ("getUpdates", "GetUpdates", "get_updates"),
@ -2098,17 +2098,17 @@ Schema(
Param(
name: "can_post_stories",
ty: Option(bool),
descr: Doc(md: "Pass True, if the administrator can post stories in the channel, channels only")
descr: Doc(md: "Pass True, if the administrator can post stories to the chat")
),
Param(
name: "can_edit_stories",
ty: Option(bool),
descr: Doc(md: "Pass True, if the administrator can edit stories posted by other users, channels only")
descr: Doc(md: "Pass True, if the administrator can edit stories posted by other users")
),
Param(
name: "can_delete_stories",
ty: Option(bool),
descr: Doc(md: "Pass True, if the administrator can delete stories posted by other users, channels only")
descr: Doc(md: "Pass True, if the administrator can delete stories posted by other users")
),
Param(
name: "can_manage_video_chats",

View file

@ -1,7 +1,7 @@
//! Core part of the [`teloxide`] library.
//!
//! This library provides tools for making requests to the [Telegram Bot API]
//! (Currently, version `7.0` is supported) with ease. The library is fully
//! (Currently, version `7.1` is supported) with ease. The library is fully
//! asynchronous and built using [`tokio`].
//!
//!```toml

View file

@ -25,11 +25,11 @@ impl_payload! {
pub can_edit_messages: bool,
/// Pass True, if the administrator can delete messages of other users
pub can_delete_messages: bool,
/// Pass True, if the administrator can post stories in the channel, channels only
/// Pass True, if the administrator can post stories to the chat
pub can_post_stories: bool,
/// Pass True, if the administrator can edit stories posted by other users, channels only
/// Pass True, if the administrator can edit stories posted by other users
pub can_edit_stories: bool,
/// Pass True, if the administrator can delete stories posted by other users, channels only
/// Pass True, if the administrator can delete stories posted by other users
pub can_delete_stories: bool,
/// Pass True, if the administrator can manage video chats, supergroups only
pub can_manage_video_chats: bool,

View file

@ -14,6 +14,7 @@ pub use chat::*;
pub use chat_action::*;
pub use chat_administrator_rights::*;
pub use chat_boost::*;
pub use chat_boost_added::*;
pub use chat_boost_removed::*;
pub use chat_boost_source::*;
pub use chat_boost_updated::*;
@ -125,6 +126,7 @@ pub use shipping_query::*;
pub use sticker::*;
pub use sticker_set::*;
pub use story::*;
pub use story_id::*;
pub use successful_payment::*;
pub use switch_inline_query_chosen_chat::*;
pub use target_message::*;
@ -273,6 +275,7 @@ mod web_app_info;
mod webhook_info;
mod write_access_allowed;
mod chat_boost_added;
mod inline_query;
mod inline_query_result;
mod inline_query_result_article;
@ -295,6 +298,7 @@ mod inline_query_result_photo;
mod inline_query_result_venue;
mod inline_query_result_video;
mod inline_query_result_voice;
mod story_id;
mod encrypted_credentials;
mod encrypted_passport_element;

View file

@ -197,6 +197,13 @@ pub struct PublicChatSupergroup {
/// [`GetChat`]: crate::payloads::GetChat
pub can_set_sticker_set: Option<bool>,
/// For supergroups, the name of the group's custom emoji sticker set.
/// Custom emoji from this set can be used by all users and bots in the
/// group. Returned only from [`GetChat`].
///
/// [`GetChat`]: crate::payloads::GetChat
pub custom_emoji_sticker_set_name: Option<String>,
/// A default chat member permissions, for groups and supergroups.
/// Returned only from [`GetChat`].
///
@ -209,6 +216,13 @@ pub struct PublicChatSupergroup {
/// [`GetChat`]: crate::payloads::GetChat
pub slow_mode_delay: Option<Seconds>,
/// For supergroups, the minimum number of boosts that a non-administrator
/// user needs to add in order to ignore slow mode and chat permissions.
/// Returned only from [`GetChat`].
///
/// [`GetChat`]: crate::payloads::GetChat
pub unrestrict_boost_count: Option<u16>,
/// Unique identifier for the linked chat, i.e. the discussion group
/// identifier for a channel and vice versa. Returned only in [`GetChat`].
///
@ -355,6 +369,22 @@ impl Chat {
None
}
/// For supergroups, the name of the group's custom emoji sticker set.
/// Custom emoji from this set can be used by all users and bots in the
/// group. Returned only from [`GetChat`].
///
/// [`GetChat`]: crate::payloads::GetChat
#[must_use]
pub fn custom_emoji_sticker_set_name(&self) -> Option<&str> {
if let ChatKind::Public(this) = &self.kind {
if let PublicChatKind::Supergroup(this) = &this.kind {
return this.custom_emoji_sticker_set_name.as_deref();
}
}
None
}
/// The minimum allowed delay between consecutive messages sent by each
/// unpriviledged user. Returned only from [`GetChat`].
///
@ -370,6 +400,21 @@ impl Chat {
None
}
/// Unique identifier for the linked chat, i.e. the discussion group
/// identifier for a channel and vice versa. Returned only in [`GetChat`].
///
/// [`GetChat`]: crate::payloads::GetChat
#[must_use]
pub fn unrestrict_boost_count(&self) -> Option<u16> {
if let ChatKind::Public(this) = &self.kind {
if let PublicChatKind::Supergroup(this) = &this.kind {
return this.unrestrict_boost_count;
}
}
None
}
/// The location to which the supergroup is connected. Returned only in
/// [`GetChat`].
///

View file

@ -47,16 +47,13 @@ pub struct ChatAdministratorRights {
/// supergroups only
pub can_pin_messages: Option<bool>,
/// `true`, if the administrator can post stories in the channel;
/// channels only
/// `true`, if the administrator can post stories to the chat
pub can_post_stories: Option<bool>,
/// `true`, if the administrator can edit stories posted by other users;
/// channels only
/// `true`, if the administrator can edit stories posted by other users
pub can_edit_stories: Option<bool>,
/// `true`, if the administrator can delete stories posted by other users;
/// channels only
/// `true`, if the administrator can delete stories posted by other users
pub can_delete_stories: Option<bool>,
/// `true`, if the user is allowed to create, rename, close, and reopen

View file

@ -0,0 +1,24 @@
use serde::{Deserialize, Serialize};
/// This object represents a service message about a user boosting a chat.
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ChatBoostAdded {
/// Number of boosts added by the user
pub boost_count: u16,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize() {
let data = r#"
{
"boost_count": 4
}
"#;
serde_json::from_str::<ChatBoostAdded>(data).unwrap();
}
}

View file

@ -80,18 +80,15 @@ pub struct Administrator {
/// `true` if the administrator can delete messages of other users.
pub can_delete_messages: bool,
/// `true` if the administrator can post stories in the channel, channels
/// only.
/// `true` if the administrator can post stories to the chat.
#[serde(default)]
pub can_post_stories: bool,
/// `true` if the administrator can edit stories posted by other users,
/// channels only.
/// `true` if the administrator can edit stories posted by other users.
#[serde(default)]
pub can_edit_stories: bool,
/// `true` if the administrator can delete stories posted by other users,
/// channels only.
/// `true` if the administrator can delete stories posted by other users.
#[serde(default)]
pub can_delete_stories: bool,
@ -447,8 +444,7 @@ impl ChatMemberKind {
}
}
/// Returns `true` if the user can post stories in the channel, channels
/// only.
/// Returns `true` if the administrator can post stories to the chat.
///
/// I.e. returns `true` if the user
/// - is the owner of the chat (even if the chat is not a channel)
@ -467,8 +463,8 @@ impl ChatMemberKind {
}
}
/// Returns `true` if the user can edit stories posted by other users,
/// channels only.
/// Returns `true` if the administrator can edit stories posted by other
/// users.
///
/// I.e. returns `true` if the user
/// - is the owner of the chat (even if the chat is not a channel)
@ -487,8 +483,8 @@ impl ChatMemberKind {
}
}
/// Returns `true` if the user can delete stories posted by other users,
/// channels only.
/// Returns `true` if the administrator can delete stories posted by other
/// users.
///
/// I.e. returns `true` if the user
/// - is the owner of the chat

View file

@ -5,15 +5,15 @@ use serde::{Deserialize, Serialize};
use url::Url;
use crate::types::{
Animation, Audio, BareChatId, Chat, ChatId, ChatShared, Contact, Dice, Document,
ExternalReplyInfo, ForumTopicClosed, ForumTopicCreated, ForumTopicEdited, ForumTopicReopened,
Game, GeneralForumTopicHidden, GeneralForumTopicUnhidden, Giveaway, GiveawayCompleted,
GiveawayCreated, GiveawayWinners, InlineKeyboardMarkup, Invoice, LinkPreviewOptions, Location,
MaybeInaccessibleMessage, MessageAutoDeleteTimerChanged, MessageEntity, MessageEntityRef,
MessageId, MessageOrigin, PassportData, PhotoSize, Poll, ProximityAlertTriggered, Sticker,
Story, SuccessfulPayment, TextQuote, ThreadId, True, User, UsersShared, Venue, Video,
VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled, VideoChatStarted, VideoNote,
Voice, WebAppData, WriteAccessAllowed,
Animation, Audio, BareChatId, Chat, ChatBoostAdded, ChatId, ChatShared, Contact, Dice,
Document, ExternalReplyInfo, ForumTopicClosed, ForumTopicCreated, ForumTopicEdited,
ForumTopicReopened, Game, GeneralForumTopicHidden, GeneralForumTopicUnhidden, Giveaway,
GiveawayCompleted, GiveawayCreated, GiveawayWinners, InlineKeyboardMarkup, Invoice,
LinkPreviewOptions, Location, MaybeInaccessibleMessage, MessageAutoDeleteTimerChanged,
MessageEntity, MessageEntityRef, MessageId, MessageOrigin, PassportData, PhotoSize, Poll,
ProximityAlertTriggered, Sticker, Story, SuccessfulPayment, TextQuote, ThreadId, True, User,
UsersShared, Venue, Video, VideoChatEnded, VideoChatParticipantsInvited, VideoChatScheduled,
VideoChatStarted, VideoNote, Voice, WebAppData, WriteAccessAllowed,
};
/// This object represents a message.
@ -84,6 +84,7 @@ pub enum MessageKind {
PassportData(MessagePassportData),
Dice(MessageDice),
ProximityAlertTriggered(MessageProximityAlertTriggered),
ChatBoostAdded(MessageChatBoostAdded),
ForumTopicCreated(MessageForumTopicCreated),
ForumTopicEdited(MessageForumTopicEdited),
ForumTopicClosed(MessageForumTopicClosed),
@ -127,6 +128,13 @@ pub struct MessageCommon {
/// the message
pub quote: Option<TextQuote>,
/// For replies to a story, the original story
pub reply_to_story: Option<Story>,
/// If the sender of the message boosted the chat, the number of boosts
/// added by the user
pub sender_boost_count: Option<u16>,
/// Date the message was last edited in Unix time.
#[serde(default, with = "crate::types::serde_opt_date_from_unix_timestamp")]
pub edit_date: Option<DateTime<Utc>>,
@ -553,6 +561,13 @@ pub struct MessageProximityAlertTriggered {
pub proximity_alert_triggered: ProximityAlertTriggered,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageChatBoostAdded {
/// Service message. User boosted the chat.
pub boost_added: ChatBoostAdded,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MessageWriteAccessAllowed {
@ -692,12 +707,12 @@ mod getters {
MessageInvoice, MessageLeftChatMember, MessageNewChatMembers, MessageNewChatPhoto,
MessageNewChatTitle, MessageOrigin, MessagePassportData, MessagePinned,
MessageProximityAlertTriggered, MessageSuccessfulPayment, MessageSupergroupChatCreated,
MessageUsersShared, MessageVideoChatParticipantsInvited, PhotoSize, TextQuote, User,
MessageUsersShared, MessageVideoChatParticipantsInvited, PhotoSize, Story, TextQuote, User,
};
use super::{
MessageForumTopicClosed, MessageForumTopicCreated, MessageForumTopicEdited,
MessageForumTopicReopened, MessageGeneralForumTopicHidden,
MessageChatBoostAdded, MessageForumTopicClosed, MessageForumTopicCreated,
MessageForumTopicEdited, MessageForumTopicReopened, MessageGeneralForumTopicHidden,
MessageGeneralForumTopicUnhidden, MessageGiveaway, MessageGiveawayCompleted,
MessageGiveawayCreated, MessageGiveawayWinners, MessageMessageAutoDeleteTimerChanged,
MessageVideoChatEnded, MessageVideoChatScheduled, MessageVideoChatStarted,
@ -746,6 +761,14 @@ mod getters {
}
}
#[must_use]
pub fn reply_to_story(&self) -> Option<&Story> {
match &self.kind {
Common(MessageCommon { reply_to_story, .. }) => reply_to_story.as_ref(),
_ => None,
}
}
#[must_use]
pub fn forward_date(&self) -> Option<DateTime<Utc>> {
self.forward_origin().map(|f| f.date())
@ -1367,6 +1390,14 @@ mod getters {
}
}
#[must_use]
pub fn boost_added(&self) -> Option<&types::ChatBoostAdded> {
match &self.kind {
ChatBoostAdded(MessageChatBoostAdded { boost_added }) => Some(boost_added),
_ => None,
}
}
#[must_use]
pub fn forum_topic_created(&self) -> Option<&types::ForumTopicCreated> {
match &self.kind {
@ -2083,8 +2114,10 @@ mod tests {
username: None,
sticker_set_name: None,
can_set_sticker_set: None,
custom_emoji_sticker_set_name: None,
permissions: None,
slow_mode_delay: None,
unrestrict_boost_count: None,
linked_chat_id: None,
location: None,
join_by_request: None,
@ -2675,4 +2708,30 @@ mod tests {
}
)
}
#[test]
fn chat_boost_added() {
let json = r#"{
"message_id": 28,
"sender_chat": {
"id": -1002236736395,
"title": "Test",
"type": "channel"
},
"chat": {
"id": -1002236736395,
"title": "Test",
"type": "channel"
},
"date": 1721162702,
"boost_added": {
"boost_count": 4
}
}"#;
let message: Message = from_str(json).unwrap();
assert_eq!(
message.boost_added().expect("Failed to get ChatBoostAdded from Message!"),
&ChatBoostAdded { boost_count: 4 }
)
}
}

View file

@ -1,5 +1,81 @@
use serde::{Deserialize, Serialize};
/// TBA 6.8: currently it holds no information
use crate::types::{Chat, ChatKind, StoryId};
/// This object represents a story.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Story {}
pub struct Story {
/// Unique identifier for the story in the chat.
pub id: StoryId,
/// Chat that posted the story.
pub chat: Chat,
}
impl Story {
/// Returns an URL that links to the story with it's id and chat username in
/// the form of `tg://resolve?domain=<…>&story=<…>`.
#[must_use]
pub fn url(&self) -> Option<url::Url> {
let username = match &self.chat.kind {
ChatKind::Public(c) => match &c.kind {
super::PublicChatKind::Channel(c) => c.username.as_ref(),
super::PublicChatKind::Group(_) => None,
super::PublicChatKind::Supergroup(g) => g.username.as_ref(),
},
ChatKind::Private(c) => c.username.as_ref(),
};
username.map(|username| {
reqwest::Url::parse(&format!("tg://resolve?domain={username}&story={}", self.id))
.unwrap()
})
}
}
#[cfg(test)]
mod tests {
use crate::types::{
Chat, ChatFullInfo, ChatId, ChatKind, ChatPublic, PublicChatKind, PublicChatSupergroup,
Story, StoryId,
};
#[test]
fn url_works() {
let story = Story {
chat: Chat {
id: ChatId(-1001389841361),
kind: ChatKind::Public(ChatPublic {
title: Some("GNOME".to_owned()),
kind: PublicChatKind::Supergroup(PublicChatSupergroup {
username: Some("gnome_ru".to_owned()),
active_usernames: None,
is_forum: false,
sticker_set_name: None,
can_set_sticker_set: None,
custom_emoji_sticker_set_name: None,
permissions: None,
slow_mode_delay: None,
unrestrict_boost_count: None,
linked_chat_id: None,
location: None,
join_to_send_messages: None,
join_by_request: None,
}),
description: None,
invite_link: None,
has_protected_content: None,
}),
photo: None,
available_reactions: None,
pinned_message: None,
message_auto_delete_time: None,
has_hidden_members: false,
has_aggressive_anti_spam_enabled: false,
chat_full_info: ChatFullInfo::default(),
},
id: StoryId(420),
};
assert_eq!(story.url().unwrap(), "tg://resolve?domain=gnome_ru&story=420".parse().unwrap());
}
}

View file

@ -0,0 +1,29 @@
use serde::{Deserialize, Serialize};
/// Identifier of a story.
#[derive(Clone, Copy)]
#[derive(Debug, derive_more::Display)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct StoryId(pub u64);
#[cfg(test)]
mod tests {
use super::*;
/// Test that `StoryId` is serialized as the underlying integer
#[test]
fn deser() {
let story_id = S { id: StoryId(17) };
let json = r#"{"id":17}"#;
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
struct S {
id: StoryId,
}
assert_eq!(serde_json::to_string(&story_id).unwrap(), json);
assert_eq!(story_id, serde_json::from_str(json).unwrap());
}
}

View file

@ -548,6 +548,8 @@ mod test {
forward_origin: None,
external_reply: None,
quote: None,
reply_to_story: None,
sender_boost_count: None,
edit_date: None,
media_kind: MediaKind::Text(MediaText {
text: String::from("hello there"),
@ -868,8 +870,10 @@ mod test {
is_forum: false,
sticker_set_name: None,
can_set_sticker_set: None,
custom_emoji_sticker_set_name: None,
permissions: None,
slow_mode_delay: None,
unrestrict_boost_count: None,
linked_chat_id: None,
location: None,
join_to_send_messages: None,

View file

@ -96,6 +96,7 @@ define_message_ext! {
(filter_migration_to, Message::migrate_to_chat_id),
(filter_reply_to_message, Message::reply_to_message),
(filter_forward_origin, Message::forward_origin),
(filter_reply_to_story, Message::reply_to_story),
// Rest variants of a MessageKind
(filter_new_chat_members, Message::new_chat_members),
(filter_left_chat_member, Message::left_chat_member),
@ -114,6 +115,7 @@ define_message_ext! {
(filter_passport_data, Message::passport_data),
(filter_dice, Message::dice),
(filter_proximity_alert_triggered, Message::proximity_alert_triggered),
(filter_boost_added, Message::boost_added),
(filter_forum_topic_created, Message::forum_topic_created),
(filter_forum_topic_edited, Message::forum_topic_edited),
(filter_forum_topic_closed, Message::forum_topic_closed),

View file

@ -1,6 +1,6 @@
//! A full-featured framework that empowers you to easily build [Telegram bots]
//! using [Rust]. It handles all the difficult stuff so you can focus only on
//! your business logic. Currently, version `7.0` of [Telegram Bot API] is
//! your business logic. Currently, version `7.1` of [Telegram Bot API] is
//! supported.
//!
//! For a high-level overview, see [our GitHub repository](https://github.com/teloxide/teloxide).