mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-23 06:51:01 +01:00
Make chat id typed (add ChatId
)
Note that this is different from the previous `ChatId` (that was renamed to `Recipient`), since it can't hold @channelusername. Reason: same as w/ `UserId`
This commit is contained in:
parent
41e09159a6
commit
f2378935b7
17 changed files with 171 additions and 115 deletions
|
@ -386,13 +386,13 @@ trait ErasableRequester<'a> {
|
|||
fn ban_chat_sender_chat(
|
||||
&self,
|
||||
chat_id: Recipient,
|
||||
sender_chat_id: i64,
|
||||
sender_chat_id: ChatId,
|
||||
) -> ErasedRequest<'a, BanChatSenderChat, Self::Err>;
|
||||
|
||||
fn unban_chat_sender_chat(
|
||||
&self,
|
||||
chat_id: Recipient,
|
||||
sender_chat_id: i64,
|
||||
sender_chat_id: ChatId,
|
||||
) -> ErasedRequest<'a, UnbanChatSenderChat, Self::Err>;
|
||||
|
||||
fn set_chat_permissions(
|
||||
|
@ -978,7 +978,7 @@ where
|
|||
fn ban_chat_sender_chat(
|
||||
&self,
|
||||
chat_id: Recipient,
|
||||
sender_chat_id: i64,
|
||||
sender_chat_id: ChatId,
|
||||
) -> ErasedRequest<'a, BanChatSenderChat, Self::Err> {
|
||||
Requester::ban_chat_sender_chat(self, chat_id, sender_chat_id).erase()
|
||||
}
|
||||
|
@ -986,7 +986,7 @@ where
|
|||
fn unban_chat_sender_chat(
|
||||
&self,
|
||||
chat_id: Recipient,
|
||||
sender_chat_id: i64,
|
||||
sender_chat_id: ChatId,
|
||||
) -> ErasedRequest<'a, UnbanChatSenderChat, Self::Err> {
|
||||
Requester::unban_chat_sender_chat(self, chat_id, sender_chat_id).erase()
|
||||
}
|
||||
|
|
|
@ -638,14 +638,14 @@ download_forward! {
|
|||
/// usernames. (It is just a hashed username.)
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
enum ChatIdHash {
|
||||
Id(i64),
|
||||
Id(ChatId),
|
||||
ChannelUsernameHash(u64),
|
||||
}
|
||||
|
||||
impl ChatIdHash {
|
||||
fn is_channel(&self) -> bool {
|
||||
match self {
|
||||
&Self::Id(id) => Recipient::Id(id).is_channel(),
|
||||
&Self::Id(id) => id.is_channel(),
|
||||
Self::ChannelUsernameHash(_) => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ use crate::{
|
|||
prelude::Requester,
|
||||
requests::{JsonRequest, MultipartRequest},
|
||||
types::{
|
||||
BotCommand, ChatPermissions, InlineQueryResult, InputFile, InputMedia, InputSticker,
|
||||
LabeledPrice, Recipient, UserId,
|
||||
BotCommand, ChatId, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
|
||||
InputSticker, LabeledPrice, Recipient, UserId,
|
||||
},
|
||||
Bot,
|
||||
};
|
||||
|
@ -401,7 +401,7 @@ impl Requester for Bot {
|
|||
|
||||
type BanChatSenderChat = JsonRequest<payloads::BanChatSenderChat>;
|
||||
|
||||
fn ban_chat_sender_chat<C>(&self, chat_id: C, sender_chat_id: i64) -> Self::BanChatSenderChat
|
||||
fn ban_chat_sender_chat<C>(&self, chat_id: C, sender_chat_id: ChatId) -> Self::BanChatSenderChat
|
||||
where
|
||||
C: Into<Recipient>,
|
||||
{
|
||||
|
@ -416,7 +416,7 @@ impl Requester for Bot {
|
|||
fn unban_chat_sender_chat<C>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
sender_chat_id: i64,
|
||||
sender_chat_id: ChatId,
|
||||
) -> Self::UnbanChatSenderChat
|
||||
where
|
||||
C: Into<Recipient>,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
//! ```
|
||||
//! # #[cfg(feature = "auto_send")]
|
||||
//! # async {
|
||||
//! # let chat_id = 0;
|
||||
//! # let chat_id = teloxide_core::types::ChatId(-1);
|
||||
//! use teloxide_core::{
|
||||
//! prelude::*,
|
||||
//! types::{DiceEmoji, ParseMode},
|
||||
|
|
|
@ -724,17 +724,17 @@ macro_rules! requester_forward {
|
|||
(@method ban_chat_sender_chat $body:ident $ty:ident) => {
|
||||
type BanChatSenderChat = $ty![BanChatSenderChat];
|
||||
|
||||
fn ban_chat_sender_chat<C>(&self, chat_id: C, sender_chat_id: i64) -> Self::BanChatSenderChat where C: Into<Recipient> {
|
||||
fn ban_chat_sender_chat<C>(&self, chat_id: C, sender_chat_id: ChatId) -> Self::BanChatSenderChat where C: Into<Recipient> {
|
||||
let this = self;
|
||||
$body!(ban_chat_sender_chat this (chat_id: C, sender_chat_id: i64))
|
||||
$body!(ban_chat_sender_chat this (chat_id: C, sender_chat_id: ChatId))
|
||||
}
|
||||
};
|
||||
(@method unban_chat_sender_chat $body:ident $ty:ident) => {
|
||||
type UnbanChatSenderChat = $ty![UnbanChatSenderChat];
|
||||
|
||||
fn unban_chat_sender_chat<C>(&self, chat_id: C, sender_chat_id: i64) -> Self::UnbanChatSenderChat where C: Into<Recipient> {
|
||||
fn unban_chat_sender_chat<C>(&self, chat_id: C, sender_chat_id: ChatId) -> Self::UnbanChatSenderChat where C: Into<Recipient> {
|
||||
let this = self;
|
||||
$body!(unban_chat_sender_chat this (chat_id: C, sender_chat_id: i64))
|
||||
$body!(unban_chat_sender_chat this (chat_id: C, sender_chat_id: ChatId))
|
||||
}
|
||||
};
|
||||
(@method set_chat_permissions $body:ident $ty:ident) => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// [`schema`]: https://github.com/WaffleLapkin/tg-methods-schema
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::types::{Recipient, True};
|
||||
use crate::types::{ChatId, Recipient, True};
|
||||
|
||||
impl_payload! {
|
||||
/// Use this method to ban a channel chat in a supergroup or a channel. The owner of the chat will not be able to send messages and join live streams on behalf of the chat, unless it is unbanned first. The bot must be an administrator in the supergroup or channel for this to work and must have the appropriate administrator rights.
|
||||
|
@ -18,7 +18,7 @@ impl_payload! {
|
|||
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
|
||||
pub chat_id: Recipient [into],
|
||||
/// Unique identifier of the target sender chat
|
||||
pub sender_chat_id: i64,
|
||||
pub sender_chat_id: ChatId,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// [`schema`]: https://github.com/WaffleLapkin/tg-methods-schema
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::types::{Recipient, True};
|
||||
use crate::types::{ChatId, Recipient, True};
|
||||
|
||||
impl_payload! {
|
||||
/// Use this method to unban a previously banned channel chat in a supergroup or channel. The bot must be an administrator for this to work and must have the appropriate administrator rights.
|
||||
|
@ -18,7 +18,7 @@ impl_payload! {
|
|||
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
|
||||
pub chat_id: Recipient [into],
|
||||
/// Unique identifier of the target sender chat
|
||||
pub sender_chat_id: i64,
|
||||
pub sender_chat_id: ChatId,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,12 +75,12 @@ pub trait Request: HasPayload {
|
|||
/// ## Examples
|
||||
/// ```
|
||||
/// # async {
|
||||
/// use teloxide_core::{prelude::*, requests::Request, Bot};
|
||||
/// use teloxide_core::{prelude::*, requests::Request, types::ChatId, Bot};
|
||||
///
|
||||
/// let bot = Bot::new("TOKEN");
|
||||
/// # let chat_ids = vec![1i64, 2, 3, 4].into_iter().map(Into::into);
|
||||
/// # let chat_ids = vec![1i64, 2, 3, 4].into_iter().map(ChatId).map(Into::into).collect::<Vec<_>>();
|
||||
///
|
||||
/// let mut req = bot.send_message(0, "Hi there!");
|
||||
/// let mut req = bot.send_message(ChatId(0xAAAAAAAA), "Hi there!");
|
||||
/// for chat_id in chat_ids {
|
||||
/// req.chat_id = chat_id;
|
||||
/// req.send_ref().await.unwrap();
|
||||
|
|
|
@ -6,10 +6,7 @@ use url::Url;
|
|||
use crate::{
|
||||
payloads::{GetMe, SendMessage, *},
|
||||
requests::Request,
|
||||
types::{
|
||||
BotCommand, ChatAction, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
|
||||
InputSticker, LabeledPrice, PassportElementError, Recipient, TargetMessage, UserId,
|
||||
},
|
||||
types::*,
|
||||
};
|
||||
|
||||
/// Methods for building requests.
|
||||
|
@ -22,27 +19,35 @@ use crate::{
|
|||
///
|
||||
/// ```
|
||||
/// # async {
|
||||
/// use teloxide_core::{prelude::*, types::ParseMode};
|
||||
/// # let chat_id = ChatId(-1);
|
||||
/// use teloxide_core::{
|
||||
/// prelude::*,
|
||||
/// types::{ChatId, ParseMode},
|
||||
/// };
|
||||
///
|
||||
/// // Bot implements `Requester`
|
||||
/// let bot = Bot::new("TOKEN");
|
||||
///
|
||||
/// // Required parameters are supplied to the `Requester` methods:
|
||||
/// bot.send_message(0, "<b>Text</b>")
|
||||
/// bot.send_message(chat_id, "<b>Text</b>")
|
||||
/// // Optional parameters can be supplied by calling setters
|
||||
/// .parse_mode(ParseMode::Html)
|
||||
/// // To send request to telegram you need to call `.send()` and await the resulting future
|
||||
/// .send()
|
||||
/// .await?;
|
||||
/// # Ok::<_, teloxide_core::RequestError>(()) };
|
||||
/// # Ok::<_, teloxide_core::RequestError>(())
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// Using `Requester` in a generic context:
|
||||
///
|
||||
/// ```
|
||||
/// use teloxide_core::{prelude::*, types::Message};
|
||||
/// use teloxide_core::{
|
||||
/// prelude::*,
|
||||
/// types::{ChatId, Message},
|
||||
/// };
|
||||
///
|
||||
/// async fn send_hi<R>(bot: R, chat: i64) -> Message
|
||||
/// async fn send_hi<R>(bot: R, chat: ChatId) -> Message
|
||||
/// where
|
||||
/// R: Requester,
|
||||
/// {
|
||||
|
@ -371,7 +376,11 @@ pub trait Requester {
|
|||
type BanChatSenderChat: Request<Payload = BanChatSenderChat, Err = Self::Err>;
|
||||
|
||||
/// For Telegram documentation see [`BanChatSenderChat`].
|
||||
fn ban_chat_sender_chat<C>(&self, chat_id: C, sender_chat_id: i64) -> Self::BanChatSenderChat
|
||||
fn ban_chat_sender_chat<C>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
sender_chat_id: ChatId,
|
||||
) -> Self::BanChatSenderChat
|
||||
where
|
||||
C: Into<Recipient>;
|
||||
|
||||
|
@ -381,7 +390,7 @@ pub trait Requester {
|
|||
fn unban_chat_sender_chat<C>(
|
||||
&self,
|
||||
chat_id: C,
|
||||
sender_chat_id: i64,
|
||||
sender_chat_id: ChatId,
|
||||
) -> Self::UnbanChatSenderChat
|
||||
where
|
||||
C: Into<Recipient>;
|
||||
|
|
|
@ -88,9 +88,9 @@ mod tests {
|
|||
use crate::{
|
||||
payloads::{self, setters::*},
|
||||
types::{
|
||||
InputFile, InputMedia, InputMediaAnimation, InputMediaAudio, InputMediaDocument,
|
||||
InputMediaPhoto, InputMediaVideo, InputSticker, MessageEntity, MessageEntityKind,
|
||||
ParseMode, UserId,
|
||||
ChatId, InputFile, InputMedia, InputMediaAnimation, InputMediaAudio,
|
||||
InputMediaDocument, InputMediaPhoto, InputMediaVideo, InputSticker, MessageEntity,
|
||||
MessageEntityKind, ParseMode, UserId,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -98,7 +98,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn issue_473() {
|
||||
to_form_ref(
|
||||
&payloads::SendPhoto::new(0, InputFile::file_id("0")).caption_entities([
|
||||
&payloads::SendPhoto::new(ChatId(0), InputFile::file_id("0")).caption_entities([
|
||||
MessageEntity {
|
||||
kind: MessageEntityKind::Url,
|
||||
offset: 0,
|
||||
|
@ -115,7 +115,7 @@ mod tests {
|
|||
const CAPTION: &str = "caption";
|
||||
|
||||
to_form_ref(&payloads::SendMediaGroup::new(
|
||||
0,
|
||||
ChatId(0),
|
||||
[
|
||||
InputMedia::Photo(
|
||||
InputMediaPhoto::new(InputFile::file("./media/logo.png"))
|
||||
|
@ -163,7 +163,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_send_animation() {
|
||||
to_form_ref(
|
||||
&payloads::SendAnimation::new(0, InputFile::file("./media/logo.png"))
|
||||
&payloads::SendAnimation::new(ChatId(0), InputFile::file("./media/logo.png"))
|
||||
.caption_entities(entities())
|
||||
.thumb(InputFile::read(
|
||||
File::open("./media/logo.png").await.unwrap(),
|
||||
|
|
|
@ -220,9 +220,11 @@ mod non_telegram_types {
|
|||
pub(super) mod until_date;
|
||||
}
|
||||
|
||||
mod chat_id;
|
||||
mod recipient;
|
||||
mod user_id;
|
||||
|
||||
pub use chat_id::*;
|
||||
pub use recipient::*;
|
||||
pub use user_id::*;
|
||||
|
||||
|
|
|
@ -56,13 +56,15 @@ pub enum BotCommandScope {
|
|||
|
||||
#[test]
|
||||
fn issue_486() {
|
||||
use crate::types::ChatId;
|
||||
|
||||
serde_json::to_string(&BotCommandScope::Chat {
|
||||
chat_id: Recipient::Id(0),
|
||||
chat_id: Recipient::Id(ChatId(0)),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
serde_json::to_string(&BotCommandScope::ChatAdministrators {
|
||||
chat_id: Recipient::Id(0),
|
||||
chat_id: Recipient::Id(ChatId(0)),
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{ChatLocation, ChatPermissions, ChatPhoto, Message, True};
|
||||
use crate::types::{ChatId, ChatLocation, ChatPermissions, ChatPhoto, Message, True};
|
||||
|
||||
/// This object represents a chat.
|
||||
///
|
||||
|
@ -8,12 +8,8 @@ use crate::types::{ChatLocation, ChatPermissions, ChatPhoto, Message, True};
|
|||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Chat {
|
||||
/// A unique identifier for this chat. This number may be greater than 32
|
||||
/// bits and some programming languages may have difficulty/silent defects
|
||||
/// in interpreting it. But it is smaller than 52 bits, so a signed 64 bit
|
||||
/// integer or double-precision float type are safe for storing this
|
||||
/// identifier.
|
||||
pub id: i64,
|
||||
/// A unique identifier for this chat.
|
||||
pub id: ChatId,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub kind: ChatKind,
|
||||
|
@ -454,11 +450,11 @@ mod tests {
|
|||
#[test]
|
||||
fn channel_de() {
|
||||
let expected = Chat {
|
||||
id: -1,
|
||||
id: ChatId(-1),
|
||||
kind: ChatKind::Public(ChatPublic {
|
||||
title: None,
|
||||
kind: PublicChatKind::Channel(PublicChatChannel {
|
||||
username: Some("channelname".into()),
|
||||
username: Some("channel_name".into()),
|
||||
linked_chat_id: None,
|
||||
}),
|
||||
description: None,
|
||||
|
@ -469,7 +465,7 @@ mod tests {
|
|||
pinned_message: None,
|
||||
message_auto_delete_time: None,
|
||||
};
|
||||
let actual = from_str(r#"{"id":-1,"type":"channel","username":"channelname"}"#).unwrap();
|
||||
let actual = from_str(r#"{"id":-1,"type":"channel","username":"channel_name"}"#).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
|
@ -477,7 +473,7 @@ mod tests {
|
|||
fn private_chat_de() {
|
||||
assert_eq!(
|
||||
Chat {
|
||||
id: 0,
|
||||
id: ChatId(0),
|
||||
kind: ChatKind::Private(ChatPrivate {
|
||||
type_: (),
|
||||
username: Some("username".into()),
|
||||
|
|
|
@ -1 +1,78 @@
|
|||
use derive_more::Display;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::UserId;
|
||||
|
||||
/// Identifier of a chat.
|
||||
///
|
||||
/// Note that "a chat" here means any of group, supergroup, channel or user PM.
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Serialize, Deserialize,
|
||||
)]
|
||||
#[serde(transparent)]
|
||||
pub struct ChatId(pub i64);
|
||||
|
||||
impl ChatId {
|
||||
pub(crate) fn is_channel(self) -> bool {
|
||||
matches!(self.unmark(), UnmarkedChatId::Channel(_))
|
||||
}
|
||||
|
||||
pub(crate) fn unmark(self) -> UnmarkedChatId {
|
||||
use UnmarkedChatId::*;
|
||||
|
||||
// https://github.com/mtcute/mtcute/blob/6933ecc3f82dd2e9100f52b0afec128af564713b/packages/core/src/utils/peer-utils.ts#L4
|
||||
const MIN_MARKED_CHANNEL_ID: i64 = -1997852516352;
|
||||
const MAX_MARKED_CHANNEL_ID: i64 = -1000000000000;
|
||||
const MIN_MARKED_CHAT_ID: i64 = MAX_MARKED_CHANNEL_ID + 1;
|
||||
const MAX_MARKED_CHAT_ID: i64 = MIN_USER_ID - 1;
|
||||
const MIN_USER_ID: i64 = 0;
|
||||
const MAX_USER_ID: i64 = (1 << 40) - 1;
|
||||
|
||||
match self.0 {
|
||||
id @ MIN_MARKED_CHAT_ID..=MAX_MARKED_CHAT_ID => Group(-id as _),
|
||||
id @ MIN_MARKED_CHANNEL_ID..=MAX_MARKED_CHANNEL_ID => {
|
||||
Channel((MAX_MARKED_CHANNEL_ID - id) as _)
|
||||
}
|
||||
id @ MIN_USER_ID..=MAX_USER_ID => User(UserId(id as _)),
|
||||
id => panic!("malformed chat id: {}", id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum UnmarkedChatId {
|
||||
User(UserId),
|
||||
Group(u64),
|
||||
Channel(u64),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{ChatId, UnmarkedChatId, UserId};
|
||||
|
||||
/// Test that `ChatId` is serialized as the underlying integer
|
||||
#[test]
|
||||
fn deser() {
|
||||
let chat_id = S {
|
||||
chat_id: ChatId(0xAA),
|
||||
};
|
||||
let json = r#"{"chat_id":170}"#;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
struct S {
|
||||
chat_id: ChatId,
|
||||
}
|
||||
|
||||
assert_eq!(serde_json::to_string(&chat_id).unwrap(), json);
|
||||
assert_eq!(chat_id, serde_json::from_str(json).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_id_unmark() {
|
||||
assert!(matches!(
|
||||
ChatId(5298363099).unmark(),
|
||||
UnmarkedChatId::User(UserId(5298363099))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ use chrono::{DateTime, Utc};
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{
|
||||
Animation, Audio, Chat, Contact, Dice, Document, Game, InlineKeyboardMarkup, Invoice, Location,
|
||||
MessageAutoDeleteTimerChanged, MessageEntity, PassportData, PhotoSize, Poll,
|
||||
Animation, Audio, Chat, ChatId, Contact, Dice, Document, Game, InlineKeyboardMarkup, Invoice,
|
||||
Location, MessageAutoDeleteTimerChanged, MessageEntity, PassportData, PhotoSize, Poll,
|
||||
ProximityAlertTriggered, Sticker, SuccessfulPayment, True, User, Venue, Video, VideoNote,
|
||||
Voice, VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatScheduled, VoiceChatStarted,
|
||||
};
|
||||
|
@ -187,14 +187,14 @@ pub enum ChatMigration {
|
|||
/// identifier `chat_id`.
|
||||
To {
|
||||
#[serde(rename = "migrate_to_chat_id")]
|
||||
chat_id: i64,
|
||||
chat_id: ChatId,
|
||||
},
|
||||
|
||||
/// The supergroup has been migrated from a group with the specified
|
||||
/// identifier `chat_id`.
|
||||
From {
|
||||
#[serde(rename = "migrate_from_chat_id")]
|
||||
chat_id: i64,
|
||||
chat_id: ChatId,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -519,14 +519,15 @@ mod getters {
|
|||
use std::ops::Deref;
|
||||
|
||||
use crate::types::{
|
||||
self, message::MessageKind::*, Chat, ChatMigration, Forward, ForwardedFrom, MediaAnimation,
|
||||
MediaAudio, MediaContact, MediaDocument, MediaGame, MediaKind, MediaLocation, MediaPhoto,
|
||||
MediaPoll, MediaSticker, MediaText, MediaVenue, MediaVideo, MediaVideoNote, MediaVoice,
|
||||
Message, MessageChannelChatCreated, MessageCommon, MessageConnectedWebsite,
|
||||
MessageDeleteChatPhoto, MessageDice, MessageEntity, MessageGroupChatCreated,
|
||||
MessageInvoice, MessageLeftChatMember, MessageNewChatMembers, MessageNewChatPhoto,
|
||||
MessageNewChatTitle, MessagePassportData, MessagePinned, MessageProximityAlertTriggered,
|
||||
MessageSuccessfulPayment, MessageSupergroupChatCreated, PhotoSize, True, User,
|
||||
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, MessageCommon,
|
||||
MessageConnectedWebsite, MessageDeleteChatPhoto, MessageDice, MessageEntity,
|
||||
MessageGroupChatCreated, MessageInvoice, MessageLeftChatMember, MessageNewChatMembers,
|
||||
MessageNewChatPhoto, MessageNewChatTitle, MessagePassportData, MessagePinned,
|
||||
MessageProximityAlertTriggered, MessageSuccessfulPayment, MessageSupergroupChatCreated,
|
||||
PhotoSize, True, User,
|
||||
};
|
||||
|
||||
/// Getters for [Message] fields from [telegram docs].
|
||||
|
@ -558,7 +559,7 @@ mod getters {
|
|||
}
|
||||
|
||||
#[deprecated(since = "0.4.2", note = "use `.chat.id` field instead")]
|
||||
pub fn chat_id(&self) -> i64 {
|
||||
pub fn chat_id(&self) -> ChatId {
|
||||
self.chat.id
|
||||
}
|
||||
|
||||
|
@ -931,7 +932,7 @@ mod getters {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn migrate_to_chat_id(&self) -> Option<i64> {
|
||||
pub fn migrate_to_chat_id(&self) -> Option<ChatId> {
|
||||
match &self.kind {
|
||||
Common(MessageCommon {
|
||||
media_kind: MediaKind::Migration(ChatMigration::To { chat_id }),
|
||||
|
@ -941,7 +942,7 @@ mod getters {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn migrate_from_chat_id(&self) -> Option<i64> {
|
||||
pub fn migrate_from_chat_id(&self) -> Option<ChatId> {
|
||||
match &self.kind {
|
||||
Common(MessageCommon {
|
||||
media_kind: MediaKind::Migration(ChatMigration::From { chat_id }),
|
||||
|
@ -1069,7 +1070,8 @@ impl Message {
|
|||
// accessible to the group members.
|
||||
None => format!(
|
||||
"https://t.me/c/{0}/{1}/",
|
||||
(-self.chat.id) - 1000000000000,
|
||||
// FIXME: this may be wrong for private channels
|
||||
(-self.chat.id.0) - 1000000000000,
|
||||
self.id
|
||||
),
|
||||
};
|
||||
|
@ -1326,7 +1328,7 @@ mod tests {
|
|||
let message: Message = serde_json::from_str(json).unwrap();
|
||||
|
||||
let group = Chat {
|
||||
id: -1001160242915,
|
||||
id: ChatId(-1001160242915),
|
||||
kind: ChatKind::Public(ChatPublic {
|
||||
title: Some("a".to_owned()),
|
||||
kind: PublicChatKind::Supergroup(PublicChatSupergroup {
|
||||
|
@ -1360,8 +1362,8 @@ mod tests {
|
|||
/// Regression test for <https://github.com/teloxide/teloxide/issues/427>
|
||||
#[test]
|
||||
fn issue_427() {
|
||||
let old = -599075523;
|
||||
let new = -1001555296434;
|
||||
let old = ChatId(-599075523);
|
||||
let new = ChatId(-1001555296434);
|
||||
|
||||
// Migration to a supergroup
|
||||
let json = r#"{"chat":{"all_members_are_administrators":false,"id":-599075523,"title":"test","type":"group"},"date":1629404938,"from":{"first_name":"nullptr","id":729497414,"is_bot":false,"language_code":"en","username":"hex0x0000"},"message_id":16,"migrate_to_chat_id":-1001555296434}"#;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use derive_more::{Display, From};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::ChatId;
|
||||
|
||||
/// A unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`).
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Display, From)]
|
||||
|
@ -8,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||
pub enum Recipient {
|
||||
/// A chat identifier.
|
||||
#[display(fmt = "{}", _0)]
|
||||
Id(i64),
|
||||
Id(ChatId),
|
||||
|
||||
/// A channel username (in the format @channelusername).
|
||||
#[display(fmt = "{}", _0)]
|
||||
|
@ -16,39 +18,13 @@ pub enum Recipient {
|
|||
}
|
||||
|
||||
impl Recipient {
|
||||
#[allow(unused)]
|
||||
pub(crate) fn is_channel(&self) -> bool {
|
||||
matches!(self.unmark(), None | Some(UnmarkedChatId::Channel(_)))
|
||||
match self {
|
||||
Recipient::Id(id) => id.is_channel(),
|
||||
Recipient::ChannelUsername(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unmark(&self) -> Option<UnmarkedChatId> {
|
||||
use UnmarkedChatId::*;
|
||||
|
||||
// https://github.com/mtcute/mtcute/blob/6933ecc3f82dd2e9100f52b0afec128af564713b/packages/core/src/utils/peer-utils.ts#L4
|
||||
const MIN_MARKED_CHANNEL_ID: i64 = -1997852516352;
|
||||
const MAX_MARKED_CHANNEL_ID: i64 = -1000000000000;
|
||||
const MIN_MARKED_CHAT_ID: i64 = MAX_MARKED_CHANNEL_ID + 1;
|
||||
const MAX_MARKED_CHAT_ID: i64 = MIN_USER_ID - 1;
|
||||
const MIN_USER_ID: i64 = 0;
|
||||
const MAX_USER_ID: i64 = (1 << 40) - 1;
|
||||
|
||||
let res = match self {
|
||||
&Self::Id(id @ MIN_MARKED_CHAT_ID..=MAX_MARKED_CHAT_ID) => Chat(-id as _),
|
||||
&Self::Id(id @ MIN_MARKED_CHANNEL_ID..=MAX_MARKED_CHANNEL_ID) => {
|
||||
Channel((MAX_MARKED_CHANNEL_ID - id) as _)
|
||||
}
|
||||
&Self::Id(id @ MIN_USER_ID..=MAX_USER_ID) => User(id as _),
|
||||
&Self::Id(id) => panic!("malformed chat id: {}", id),
|
||||
Self::ChannelUsername(_) => return None,
|
||||
};
|
||||
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum UnmarkedChatId {
|
||||
User(u64),
|
||||
Chat(u64),
|
||||
Channel(u64),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -58,7 +34,7 @@ mod tests {
|
|||
#[test]
|
||||
fn chat_id_id_serialization() {
|
||||
let expected_json = String::from(r#"123456"#);
|
||||
let actual_json = serde_json::to_string(&Recipient::Id(123_456)).unwrap();
|
||||
let actual_json = serde_json::to_string(&Recipient::Id(ChatId(123_456))).unwrap();
|
||||
|
||||
assert_eq!(expected_json, actual_json)
|
||||
}
|
||||
|
@ -71,12 +47,4 @@ mod tests {
|
|||
|
||||
assert_eq!(expected_json, actual_json)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_id_unmark() {
|
||||
assert!(matches!(
|
||||
Recipient::Id(5298363099).unmark(),
|
||||
Some(UnmarkedChatId::User(5298363099))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,8 +294,8 @@ impl Serialize for UpdateKind {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::types::{
|
||||
Chat, ChatKind, ChatPrivate, MediaKind, MediaText, Message, MessageCommon, MessageKind,
|
||||
Update, UpdateKind, User, UserId,
|
||||
Chat, ChatId, ChatKind, ChatPrivate, MediaKind, MediaText, Message, MessageCommon,
|
||||
MessageKind, Update, UpdateKind, User, UserId,
|
||||
};
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
|
@ -335,7 +335,7 @@ mod test {
|
|||
id: 6557,
|
||||
date,
|
||||
chat: Chat {
|
||||
id: 218_485_655,
|
||||
id: ChatId(218_485_655),
|
||||
kind: ChatKind::Private(ChatPrivate {
|
||||
type_: (),
|
||||
username: Some(String::from("WaffleLapkin")),
|
||||
|
|
Loading…
Reference in a new issue