mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-25 01:25:12 +01:00
Merge pull request #80 from teloxide/private_url
Add `Chat` getters, misssing field and improve `Message::url`
This commit is contained in:
commit
893bd50870
4 changed files with 219 additions and 28 deletions
|
@ -10,13 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
|
||||
- `impl Clone` for {`CacheMe`, `DefaultParseMode`, `Throttle`} ([#75][pr75])
|
||||
- Getters for fields nested in `Chat` ([#80][pr80])
|
||||
- API errors: `ApiError::NotEnoughRightsToManagePins`, `ApiError::BotKickedFromSupergroup` ([#84][pr84])
|
||||
|
||||
[pr75]: https://github.com/teloxide/teloxide-core/pull/75
|
||||
[pr80]: https://github.com/teloxide/teloxide-core/pull/80
|
||||
[pr84]: https://github.com/teloxide/teloxide-core/pull/84
|
||||
|
||||
### Changed
|
||||
|
||||
- `Message::url` now returns links to messages in private groups too ([#80][pr80])
|
||||
- Refactor `ChatMember` methods ([#74][pr74])
|
||||
- impl `Deref<Target = ChatMemberKind>` to make `ChatMemberKind`'s methods callible directly on `ChatMember`
|
||||
- Add `ChatMemberKind::is_{creator,administrator,member,restricted,left,kicked}` which check `kind` along with `is_privileged` and `is_in_chat` which combine some of the above.
|
||||
|
@ -26,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Fixed
|
||||
|
||||
- Type of `PublicChatSupergroup::slow_mode_delay` field: `Option<i32>`=> `Option<u32>` ([#80][pr80])
|
||||
- Add missing `Chat::message_auto_delete_time` field ([#80][pr80])
|
||||
- Output types of `LeaveChat` `PinChatMessage`, `SetChatDescription`, `SetChatPhoto` `SetChatTitle`, `UnpinAllChatMessages` and `UnpinChatMessage`: `String` => `True` ([#79][pr79])
|
||||
- `SendChatAction` output type `Message` => `True` ([#75][pr75])
|
||||
- `GetChatAdministrators` output type `ChatMember` => `Vec<ChatMember>` ([#73][pr73])
|
||||
|
|
|
@ -28,6 +28,12 @@ pub struct Chat {
|
|||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub pinned_message: Option<Box<Message>>,
|
||||
|
||||
/// The time after which all messages sent to the chat will be automatically
|
||||
/// deleted; in seconds. Returned only in [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub message_auto_delete_time: Option<u32>,
|
||||
}
|
||||
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
|
@ -153,7 +159,7 @@ pub struct PublicChatSupergroup {
|
|||
/// unpriviledged user. Returned only from [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub slow_mode_delay: Option<i32>,
|
||||
pub slow_mode_delay: Option<u32>,
|
||||
|
||||
/// Unique identifier for the linked chat, i.e. the discussion group
|
||||
/// identifier for a channel and vice versa. Returned only in [`GetChat`].
|
||||
|
@ -199,6 +205,7 @@ impl Chat {
|
|||
pub fn is_private(&self) -> bool {
|
||||
matches!(self.kind, ChatKind::Private(_))
|
||||
}
|
||||
|
||||
pub fn is_group(&self) -> bool {
|
||||
matches!(
|
||||
self.kind,
|
||||
|
@ -208,6 +215,7 @@ impl Chat {
|
|||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_supergroup(&self) -> bool {
|
||||
matches!(
|
||||
self.kind,
|
||||
|
@ -217,6 +225,7 @@ impl Chat {
|
|||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_channel(&self) -> bool {
|
||||
matches!(
|
||||
self.kind,
|
||||
|
@ -232,6 +241,174 @@ impl Chat {
|
|||
}
|
||||
}
|
||||
|
||||
/// Getters
|
||||
impl Chat {
|
||||
/// A title, for supergroups, channels and group chats.
|
||||
pub fn title(&self) -> Option<&str> {
|
||||
match &self.kind {
|
||||
ChatKind::Public(this) => this.title.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A username, for private chats, supergroups and channels if available.
|
||||
pub fn username(&self) -> Option<&str> {
|
||||
match &self.kind {
|
||||
ChatKind::Public(this) => match &this.kind {
|
||||
PublicChatKind::Channel(PublicChatChannel { username, .. })
|
||||
| PublicChatKind::Supergroup(PublicChatSupergroup { username, .. }) => {
|
||||
username.as_deref()
|
||||
}
|
||||
PublicChatKind::Group(_) => None,
|
||||
},
|
||||
ChatKind::Private(this) => this.username.as_deref(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
pub fn linked_chat_id(&self) -> Option<i64> {
|
||||
match &self.kind {
|
||||
ChatKind::Public(this) => match &this.kind {
|
||||
PublicChatKind::Channel(PublicChatChannel { linked_chat_id, .. })
|
||||
| PublicChatKind::Supergroup(PublicChatSupergroup { linked_chat_id, .. }) => {
|
||||
*linked_chat_id
|
||||
}
|
||||
PublicChatKind::Group(_) => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A default chat member permissions, for groups and supergroups. Returned
|
||||
/// only from [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn permissions(&self) -> Option<ChatPermissions> {
|
||||
if let ChatKind::Public(this) = &self.kind {
|
||||
if let PublicChatKind::Group(PublicChatGroup { permissions })
|
||||
| PublicChatKind::Supergroup(PublicChatSupergroup { permissions, .. }) = &this.kind
|
||||
{
|
||||
return *permissions;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// For supergroups, name of group sticker set. Returned only from
|
||||
/// [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn sticker_set_name(&self) -> Option<&str> {
|
||||
if let ChatKind::Public(this) = &self.kind {
|
||||
if let PublicChatKind::Supergroup(this) = &this.kind {
|
||||
return this.sticker_set_name.as_deref();
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// `true`, if the bot can change the group sticker set. Returned only
|
||||
/// from [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn can_set_sticker_set(&self) -> Option<bool> {
|
||||
if let ChatKind::Public(this) = &self.kind {
|
||||
if let PublicChatKind::Supergroup(this) = &this.kind {
|
||||
return this.can_set_sticker_set;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// The minimum allowed delay between consecutive messages sent by each
|
||||
/// unpriviledged user. Returned only from [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn slow_mode_delay(&self) -> Option<u32> {
|
||||
if let ChatKind::Public(this) = &self.kind {
|
||||
if let PublicChatKind::Supergroup(this) = &this.kind {
|
||||
return this.slow_mode_delay;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// The location to which the supergroup is connected. Returned only in
|
||||
/// [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn location(&self) -> Option<&ChatLocation> {
|
||||
if let ChatKind::Public(this) = &self.kind {
|
||||
if let PublicChatKind::Supergroup(this) = &this.kind {
|
||||
return this.location.as_ref();
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// A description, for groups, supergroups and channel chats. Returned
|
||||
/// only in [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn description(&self) -> Option<&str> {
|
||||
match &self.kind {
|
||||
ChatKind::Public(this) => this.description.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A chat invite link, for groups, supergroups and channel chats. Each
|
||||
/// administrator in a chat generates their own invite links, so the
|
||||
/// bot must first generate the link using
|
||||
/// [`ExportChatInviteLink`]. Returned only in
|
||||
/// [`GetChat`].
|
||||
///
|
||||
/// [`ExportChatInviteLink`]:
|
||||
/// crate::payloads::ExportChatInviteLink
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn invite_link(&self) -> Option<&str> {
|
||||
match &self.kind {
|
||||
ChatKind::Public(this) => this.invite_link.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A first name of the other party in a private chat.
|
||||
pub fn first_name(&self) -> Option<&str> {
|
||||
match &self.kind {
|
||||
ChatKind::Private(this) => this.first_name.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A last name of the other party in a private chat.
|
||||
pub fn last_name(&self) -> Option<&str> {
|
||||
match &self.kind {
|
||||
ChatKind::Private(this) => this.last_name.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Bio of the other party in a private chat. Returned only in [`GetChat`].
|
||||
///
|
||||
/// [`GetChat`]: crate::payloads::GetChat
|
||||
pub fn bio(&self) -> Option<&str> {
|
||||
match &self.kind {
|
||||
ChatKind::Private(this) => this.bio.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::from_str;
|
||||
|
@ -253,6 +430,7 @@ mod tests {
|
|||
}),
|
||||
photo: None,
|
||||
pinned_message: None,
|
||||
message_auto_delete_time: None,
|
||||
};
|
||||
let actual = from_str(r#"{"id":-1,"type":"channel","username":"channelname"}"#).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
|
@ -272,6 +450,7 @@ mod tests {
|
|||
}),
|
||||
photo: None,
|
||||
pinned_message: None,
|
||||
message_auto_delete_time: None,
|
||||
},
|
||||
from_str(r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#)
|
||||
.unwrap()
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{
|
||||
chat::{ChatKind, PublicChatKind},
|
||||
Animation, Audio, Chat, ChatPublic, Contact, Dice, Document, Game, InlineKeyboardMarkup,
|
||||
Invoice, Location, MessageAutoDeleteTimerChanged, MessageEntity, PassportData, PhotoSize, Poll,
|
||||
ProximityAlertTriggered, PublicChatChannel, PublicChatSupergroup, Sticker, SuccessfulPayment,
|
||||
True, User, Venue, Video, VideoNote, Voice, VoiceChatEnded, VoiceChatParticipantsInvited,
|
||||
VoiceChatStarted,
|
||||
Animation, Audio, Chat, Contact, Dice, Document, Game, InlineKeyboardMarkup, Invoice, Location,
|
||||
MessageAutoDeleteTimerChanged, MessageEntity, PassportData, PhotoSize, Poll,
|
||||
ProximityAlertTriggered, Sticker, SuccessfulPayment, True, User, Venue, Video, VideoNote,
|
||||
Voice, VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatStarted,
|
||||
};
|
||||
|
||||
/// This object represents a message.
|
||||
|
@ -982,29 +980,37 @@ mod getters {
|
|||
}
|
||||
|
||||
impl Message {
|
||||
/// Produces a direct link to the message.
|
||||
///
|
||||
/// Note that for private groups the link will only be accesible for group
|
||||
/// members.
|
||||
///
|
||||
/// Returns `None` for private chats (i.e.: DMs).
|
||||
pub fn url(&self) -> Option<reqwest::Url> {
|
||||
match &self.chat.kind {
|
||||
ChatKind::Public(ChatPublic {
|
||||
kind:
|
||||
PublicChatKind::Channel(PublicChatChannel {
|
||||
username: Some(username),
|
||||
..
|
||||
}),
|
||||
..
|
||||
})
|
||||
| ChatKind::Public(ChatPublic {
|
||||
kind:
|
||||
PublicChatKind::Supergroup(PublicChatSupergroup {
|
||||
username: Some(username),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) => Some(
|
||||
reqwest::Url::parse(format!("https://t.me/{0}/{1}/", username, self.id).as_str())
|
||||
.unwrap(),
|
||||
),
|
||||
_ => None,
|
||||
if self.chat.is_private() {
|
||||
// For private chats (i.e.: DMs) we can't produce "normal" t.me link.
|
||||
//
|
||||
// There are "tg://openmessage?user_id={0}&message_id={1}" links, which are
|
||||
// supposed to open any chat, including private messages, but they
|
||||
// are only supported by some telegram clients (e.g. Plus Messenger,
|
||||
// Telegram for Androud 4.9+).
|
||||
return None;
|
||||
}
|
||||
|
||||
let url = match self.chat.username() {
|
||||
// If it's public group (i.e. not DM, not private group), we can produce
|
||||
// "normal" t.me link (accesible to everyone).
|
||||
Some(username) => format!("https://t.me/{0}/{1}/", username, self.id),
|
||||
// For private groups we produce "private" t.me/c links. These are only
|
||||
// accesible to the group members.
|
||||
None => format!("https://t.me/c/{0}/{1}/", self.chat.id, self.id),
|
||||
};
|
||||
|
||||
// UNWRAP:
|
||||
//
|
||||
// The `url` produced by formatting is correct since username is
|
||||
// /[a-zA-Z0-9_]{5,32}/ and chat/message ids are integers.
|
||||
Some(reqwest::Url::parse(&url).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@ mod test {
|
|||
}),
|
||||
photo: None,
|
||||
pinned_message: None,
|
||||
message_auto_delete_time: None,
|
||||
},
|
||||
kind: MessageKind::Common(MessageCommon {
|
||||
from: Some(User {
|
||||
|
|
Loading…
Add table
Reference in a new issue