mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-11 04:21:12 +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(
|
fn ban_chat_sender_chat(
|
||||||
&self,
|
&self,
|
||||||
chat_id: Recipient,
|
chat_id: Recipient,
|
||||||
sender_chat_id: i64,
|
sender_chat_id: ChatId,
|
||||||
) -> ErasedRequest<'a, BanChatSenderChat, Self::Err>;
|
) -> ErasedRequest<'a, BanChatSenderChat, Self::Err>;
|
||||||
|
|
||||||
fn unban_chat_sender_chat(
|
fn unban_chat_sender_chat(
|
||||||
&self,
|
&self,
|
||||||
chat_id: Recipient,
|
chat_id: Recipient,
|
||||||
sender_chat_id: i64,
|
sender_chat_id: ChatId,
|
||||||
) -> ErasedRequest<'a, UnbanChatSenderChat, Self::Err>;
|
) -> ErasedRequest<'a, UnbanChatSenderChat, Self::Err>;
|
||||||
|
|
||||||
fn set_chat_permissions(
|
fn set_chat_permissions(
|
||||||
|
@ -978,7 +978,7 @@ where
|
||||||
fn ban_chat_sender_chat(
|
fn ban_chat_sender_chat(
|
||||||
&self,
|
&self,
|
||||||
chat_id: Recipient,
|
chat_id: Recipient,
|
||||||
sender_chat_id: i64,
|
sender_chat_id: ChatId,
|
||||||
) -> ErasedRequest<'a, BanChatSenderChat, Self::Err> {
|
) -> ErasedRequest<'a, BanChatSenderChat, Self::Err> {
|
||||||
Requester::ban_chat_sender_chat(self, chat_id, sender_chat_id).erase()
|
Requester::ban_chat_sender_chat(self, chat_id, sender_chat_id).erase()
|
||||||
}
|
}
|
||||||
|
@ -986,7 +986,7 @@ where
|
||||||
fn unban_chat_sender_chat(
|
fn unban_chat_sender_chat(
|
||||||
&self,
|
&self,
|
||||||
chat_id: Recipient,
|
chat_id: Recipient,
|
||||||
sender_chat_id: i64,
|
sender_chat_id: ChatId,
|
||||||
) -> ErasedRequest<'a, UnbanChatSenderChat, Self::Err> {
|
) -> ErasedRequest<'a, UnbanChatSenderChat, Self::Err> {
|
||||||
Requester::unban_chat_sender_chat(self, chat_id, sender_chat_id).erase()
|
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.)
|
/// usernames. (It is just a hashed username.)
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||||
enum ChatIdHash {
|
enum ChatIdHash {
|
||||||
Id(i64),
|
Id(ChatId),
|
||||||
ChannelUsernameHash(u64),
|
ChannelUsernameHash(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatIdHash {
|
impl ChatIdHash {
|
||||||
fn is_channel(&self) -> bool {
|
fn is_channel(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&Self::Id(id) => Recipient::Id(id).is_channel(),
|
&Self::Id(id) => id.is_channel(),
|
||||||
Self::ChannelUsernameHash(_) => true,
|
Self::ChannelUsernameHash(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ use crate::{
|
||||||
prelude::Requester,
|
prelude::Requester,
|
||||||
requests::{JsonRequest, MultipartRequest},
|
requests::{JsonRequest, MultipartRequest},
|
||||||
types::{
|
types::{
|
||||||
BotCommand, ChatPermissions, InlineQueryResult, InputFile, InputMedia, InputSticker,
|
BotCommand, ChatId, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
|
||||||
LabeledPrice, Recipient, UserId,
|
InputSticker, LabeledPrice, Recipient, UserId,
|
||||||
},
|
},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
@ -401,7 +401,7 @@ impl Requester for Bot {
|
||||||
|
|
||||||
type BanChatSenderChat = JsonRequest<payloads::BanChatSenderChat>;
|
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
|
where
|
||||||
C: Into<Recipient>,
|
C: Into<Recipient>,
|
||||||
{
|
{
|
||||||
|
@ -416,7 +416,7 @@ impl Requester for Bot {
|
||||||
fn unban_chat_sender_chat<C>(
|
fn unban_chat_sender_chat<C>(
|
||||||
&self,
|
&self,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
sender_chat_id: i64,
|
sender_chat_id: ChatId,
|
||||||
) -> Self::UnbanChatSenderChat
|
) -> Self::UnbanChatSenderChat
|
||||||
where
|
where
|
||||||
C: Into<Recipient>,
|
C: Into<Recipient>,
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "auto_send")]
|
//! # #[cfg(feature = "auto_send")]
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # let chat_id = 0;
|
//! # let chat_id = teloxide_core::types::ChatId(-1);
|
||||||
//! use teloxide_core::{
|
//! use teloxide_core::{
|
||||||
//! prelude::*,
|
//! prelude::*,
|
||||||
//! types::{DiceEmoji, ParseMode},
|
//! types::{DiceEmoji, ParseMode},
|
||||||
|
|
|
@ -724,17 +724,17 @@ macro_rules! requester_forward {
|
||||||
(@method ban_chat_sender_chat $body:ident $ty:ident) => {
|
(@method ban_chat_sender_chat $body:ident $ty:ident) => {
|
||||||
type BanChatSenderChat = $ty![BanChatSenderChat];
|
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;
|
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) => {
|
(@method unban_chat_sender_chat $body:ident $ty:ident) => {
|
||||||
type UnbanChatSenderChat = $ty![UnbanChatSenderChat];
|
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;
|
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) => {
|
(@method set_chat_permissions $body:ident $ty:ident) => {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// [`schema`]: https://github.com/WaffleLapkin/tg-methods-schema
|
// [`schema`]: https://github.com/WaffleLapkin/tg-methods-schema
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::types::{Recipient, True};
|
use crate::types::{ChatId, Recipient, True};
|
||||||
|
|
||||||
impl_payload! {
|
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.
|
/// 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`)
|
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
|
||||||
pub chat_id: Recipient [into],
|
pub chat_id: Recipient [into],
|
||||||
/// Unique identifier of the target sender chat
|
/// 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
|
// [`schema`]: https://github.com/WaffleLapkin/tg-methods-schema
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::types::{Recipient, True};
|
use crate::types::{ChatId, Recipient, True};
|
||||||
|
|
||||||
impl_payload! {
|
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.
|
/// 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`)
|
/// Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
|
||||||
pub chat_id: Recipient [into],
|
pub chat_id: Recipient [into],
|
||||||
/// Unique identifier of the target sender chat
|
/// 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
|
/// ## Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # async {
|
/// # async {
|
||||||
/// use teloxide_core::{prelude::*, requests::Request, Bot};
|
/// use teloxide_core::{prelude::*, requests::Request, types::ChatId, Bot};
|
||||||
///
|
///
|
||||||
/// let bot = Bot::new("TOKEN");
|
/// 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 {
|
/// for chat_id in chat_ids {
|
||||||
/// req.chat_id = chat_id;
|
/// req.chat_id = chat_id;
|
||||||
/// req.send_ref().await.unwrap();
|
/// req.send_ref().await.unwrap();
|
||||||
|
|
|
@ -6,10 +6,7 @@ use url::Url;
|
||||||
use crate::{
|
use crate::{
|
||||||
payloads::{GetMe, SendMessage, *},
|
payloads::{GetMe, SendMessage, *},
|
||||||
requests::Request,
|
requests::Request,
|
||||||
types::{
|
types::*,
|
||||||
BotCommand, ChatAction, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
|
|
||||||
InputSticker, LabeledPrice, PassportElementError, Recipient, TargetMessage, UserId,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Methods for building requests.
|
/// Methods for building requests.
|
||||||
|
@ -22,27 +19,35 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # async {
|
/// # async {
|
||||||
/// use teloxide_core::{prelude::*, types::ParseMode};
|
/// # let chat_id = ChatId(-1);
|
||||||
|
/// use teloxide_core::{
|
||||||
|
/// prelude::*,
|
||||||
|
/// types::{ChatId, ParseMode},
|
||||||
|
/// };
|
||||||
///
|
///
|
||||||
/// // Bot implements `Requester`
|
/// // Bot implements `Requester`
|
||||||
/// let bot = Bot::new("TOKEN");
|
/// let bot = Bot::new("TOKEN");
|
||||||
///
|
///
|
||||||
/// // Required parameters are supplied to the `Requester` methods:
|
/// // 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
|
/// // Optional parameters can be supplied by calling setters
|
||||||
/// .parse_mode(ParseMode::Html)
|
/// .parse_mode(ParseMode::Html)
|
||||||
/// // To send request to telegram you need to call `.send()` and await the resulting future
|
/// // To send request to telegram you need to call `.send()` and await the resulting future
|
||||||
/// .send()
|
/// .send()
|
||||||
/// .await?;
|
/// .await?;
|
||||||
/// # Ok::<_, teloxide_core::RequestError>(()) };
|
/// # Ok::<_, teloxide_core::RequestError>(())
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Using `Requester` in a generic context:
|
/// 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
|
/// where
|
||||||
/// R: Requester,
|
/// R: Requester,
|
||||||
/// {
|
/// {
|
||||||
|
@ -371,7 +376,11 @@ pub trait Requester {
|
||||||
type BanChatSenderChat: Request<Payload = BanChatSenderChat, Err = Self::Err>;
|
type BanChatSenderChat: Request<Payload = BanChatSenderChat, Err = Self::Err>;
|
||||||
|
|
||||||
/// For Telegram documentation see [`BanChatSenderChat`].
|
/// 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
|
where
|
||||||
C: Into<Recipient>;
|
C: Into<Recipient>;
|
||||||
|
|
||||||
|
@ -381,7 +390,7 @@ pub trait Requester {
|
||||||
fn unban_chat_sender_chat<C>(
|
fn unban_chat_sender_chat<C>(
|
||||||
&self,
|
&self,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
sender_chat_id: i64,
|
sender_chat_id: ChatId,
|
||||||
) -> Self::UnbanChatSenderChat
|
) -> Self::UnbanChatSenderChat
|
||||||
where
|
where
|
||||||
C: Into<Recipient>;
|
C: Into<Recipient>;
|
||||||
|
|
|
@ -88,9 +88,9 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
payloads::{self, setters::*},
|
payloads::{self, setters::*},
|
||||||
types::{
|
types::{
|
||||||
InputFile, InputMedia, InputMediaAnimation, InputMediaAudio, InputMediaDocument,
|
ChatId, InputFile, InputMedia, InputMediaAnimation, InputMediaAudio,
|
||||||
InputMediaPhoto, InputMediaVideo, InputSticker, MessageEntity, MessageEntityKind,
|
InputMediaDocument, InputMediaPhoto, InputMediaVideo, InputSticker, MessageEntity,
|
||||||
ParseMode, UserId,
|
MessageEntityKind, ParseMode, UserId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ mod tests {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn issue_473() {
|
async fn issue_473() {
|
||||||
to_form_ref(
|
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 {
|
MessageEntity {
|
||||||
kind: MessageEntityKind::Url,
|
kind: MessageEntityKind::Url,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
|
@ -115,7 +115,7 @@ mod tests {
|
||||||
const CAPTION: &str = "caption";
|
const CAPTION: &str = "caption";
|
||||||
|
|
||||||
to_form_ref(&payloads::SendMediaGroup::new(
|
to_form_ref(&payloads::SendMediaGroup::new(
|
||||||
0,
|
ChatId(0),
|
||||||
[
|
[
|
||||||
InputMedia::Photo(
|
InputMedia::Photo(
|
||||||
InputMediaPhoto::new(InputFile::file("./media/logo.png"))
|
InputMediaPhoto::new(InputFile::file("./media/logo.png"))
|
||||||
|
@ -163,7 +163,7 @@ mod tests {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_send_animation() {
|
async fn test_send_animation() {
|
||||||
to_form_ref(
|
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())
|
.caption_entities(entities())
|
||||||
.thumb(InputFile::read(
|
.thumb(InputFile::read(
|
||||||
File::open("./media/logo.png").await.unwrap(),
|
File::open("./media/logo.png").await.unwrap(),
|
||||||
|
|
|
@ -220,9 +220,11 @@ mod non_telegram_types {
|
||||||
pub(super) mod until_date;
|
pub(super) mod until_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod chat_id;
|
||||||
mod recipient;
|
mod recipient;
|
||||||
mod user_id;
|
mod user_id;
|
||||||
|
|
||||||
|
pub use chat_id::*;
|
||||||
pub use recipient::*;
|
pub use recipient::*;
|
||||||
pub use user_id::*;
|
pub use user_id::*;
|
||||||
|
|
||||||
|
|
|
@ -56,13 +56,15 @@ pub enum BotCommandScope {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn issue_486() {
|
fn issue_486() {
|
||||||
|
use crate::types::ChatId;
|
||||||
|
|
||||||
serde_json::to_string(&BotCommandScope::Chat {
|
serde_json::to_string(&BotCommandScope::Chat {
|
||||||
chat_id: Recipient::Id(0),
|
chat_id: Recipient::Id(ChatId(0)),
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
serde_json::to_string(&BotCommandScope::ChatAdministrators {
|
serde_json::to_string(&BotCommandScope::ChatAdministrators {
|
||||||
chat_id: Recipient::Id(0),
|
chat_id: Recipient::Id(ChatId(0)),
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
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.
|
/// This object represents a chat.
|
||||||
///
|
///
|
||||||
|
@ -8,12 +8,8 @@ use crate::types::{ChatLocation, ChatPermissions, ChatPhoto, Message, True};
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Chat {
|
pub struct Chat {
|
||||||
/// A unique identifier for this chat. This number may be greater than 32
|
/// A unique identifier for this chat.
|
||||||
/// bits and some programming languages may have difficulty/silent defects
|
pub id: ChatId,
|
||||||
/// 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,
|
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub kind: ChatKind,
|
pub kind: ChatKind,
|
||||||
|
@ -454,11 +450,11 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn channel_de() {
|
fn channel_de() {
|
||||||
let expected = Chat {
|
let expected = Chat {
|
||||||
id: -1,
|
id: ChatId(-1),
|
||||||
kind: ChatKind::Public(ChatPublic {
|
kind: ChatKind::Public(ChatPublic {
|
||||||
title: None,
|
title: None,
|
||||||
kind: PublicChatKind::Channel(PublicChatChannel {
|
kind: PublicChatKind::Channel(PublicChatChannel {
|
||||||
username: Some("channelname".into()),
|
username: Some("channel_name".into()),
|
||||||
linked_chat_id: None,
|
linked_chat_id: None,
|
||||||
}),
|
}),
|
||||||
description: None,
|
description: None,
|
||||||
|
@ -469,7 +465,7 @@ mod tests {
|
||||||
pinned_message: None,
|
pinned_message: None,
|
||||||
message_auto_delete_time: 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);
|
assert_eq!(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +473,7 @@ mod tests {
|
||||||
fn private_chat_de() {
|
fn private_chat_de() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Chat {
|
Chat {
|
||||||
id: 0,
|
id: ChatId(0),
|
||||||
kind: ChatKind::Private(ChatPrivate {
|
kind: ChatKind::Private(ChatPrivate {
|
||||||
type_: (),
|
type_: (),
|
||||||
username: Some("username".into()),
|
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 serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Animation, Audio, Chat, Contact, Dice, Document, Game, InlineKeyboardMarkup, Invoice, Location,
|
Animation, Audio, Chat, ChatId, Contact, Dice, Document, Game, InlineKeyboardMarkup, Invoice,
|
||||||
MessageAutoDeleteTimerChanged, MessageEntity, PassportData, PhotoSize, Poll,
|
Location, MessageAutoDeleteTimerChanged, MessageEntity, PassportData, PhotoSize, Poll,
|
||||||
ProximityAlertTriggered, Sticker, SuccessfulPayment, True, User, Venue, Video, VideoNote,
|
ProximityAlertTriggered, Sticker, SuccessfulPayment, True, User, Venue, Video, VideoNote,
|
||||||
Voice, VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatScheduled, VoiceChatStarted,
|
Voice, VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatScheduled, VoiceChatStarted,
|
||||||
};
|
};
|
||||||
|
@ -187,14 +187,14 @@ pub enum ChatMigration {
|
||||||
/// identifier `chat_id`.
|
/// identifier `chat_id`.
|
||||||
To {
|
To {
|
||||||
#[serde(rename = "migrate_to_chat_id")]
|
#[serde(rename = "migrate_to_chat_id")]
|
||||||
chat_id: i64,
|
chat_id: ChatId,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// The supergroup has been migrated from a group with the specified
|
/// The supergroup has been migrated from a group with the specified
|
||||||
/// identifier `chat_id`.
|
/// identifier `chat_id`.
|
||||||
From {
|
From {
|
||||||
#[serde(rename = "migrate_from_chat_id")]
|
#[serde(rename = "migrate_from_chat_id")]
|
||||||
chat_id: i64,
|
chat_id: ChatId,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,14 +519,15 @@ mod getters {
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
self, message::MessageKind::*, Chat, ChatMigration, Forward, ForwardedFrom, MediaAnimation,
|
self, message::MessageKind::*, Chat, ChatId, ChatMigration, Forward, ForwardedFrom,
|
||||||
MediaAudio, MediaContact, MediaDocument, MediaGame, MediaKind, MediaLocation, MediaPhoto,
|
MediaAnimation, MediaAudio, MediaContact, MediaDocument, MediaGame, MediaKind,
|
||||||
MediaPoll, MediaSticker, MediaText, MediaVenue, MediaVideo, MediaVideoNote, MediaVoice,
|
MediaLocation, MediaPhoto, MediaPoll, MediaSticker, MediaText, MediaVenue, MediaVideo,
|
||||||
Message, MessageChannelChatCreated, MessageCommon, MessageConnectedWebsite,
|
MediaVideoNote, MediaVoice, Message, MessageChannelChatCreated, MessageCommon,
|
||||||
MessageDeleteChatPhoto, MessageDice, MessageEntity, MessageGroupChatCreated,
|
MessageConnectedWebsite, MessageDeleteChatPhoto, MessageDice, MessageEntity,
|
||||||
MessageInvoice, MessageLeftChatMember, MessageNewChatMembers, MessageNewChatPhoto,
|
MessageGroupChatCreated, MessageInvoice, MessageLeftChatMember, MessageNewChatMembers,
|
||||||
MessageNewChatTitle, MessagePassportData, MessagePinned, MessageProximityAlertTriggered,
|
MessageNewChatPhoto, MessageNewChatTitle, MessagePassportData, MessagePinned,
|
||||||
MessageSuccessfulPayment, MessageSupergroupChatCreated, PhotoSize, True, User,
|
MessageProximityAlertTriggered, MessageSuccessfulPayment, MessageSupergroupChatCreated,
|
||||||
|
PhotoSize, True, User,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Getters for [Message] fields from [telegram docs].
|
/// Getters for [Message] fields from [telegram docs].
|
||||||
|
@ -558,7 +559,7 @@ mod getters {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated(since = "0.4.2", note = "use `.chat.id` field instead")]
|
#[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
|
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 {
|
match &self.kind {
|
||||||
Common(MessageCommon {
|
Common(MessageCommon {
|
||||||
media_kind: MediaKind::Migration(ChatMigration::To { chat_id }),
|
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 {
|
match &self.kind {
|
||||||
Common(MessageCommon {
|
Common(MessageCommon {
|
||||||
media_kind: MediaKind::Migration(ChatMigration::From { chat_id }),
|
media_kind: MediaKind::Migration(ChatMigration::From { chat_id }),
|
||||||
|
@ -1069,7 +1070,8 @@ impl Message {
|
||||||
// accessible to the group members.
|
// accessible to the group members.
|
||||||
None => format!(
|
None => format!(
|
||||||
"https://t.me/c/{0}/{1}/",
|
"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
|
self.id
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -1326,7 +1328,7 @@ mod tests {
|
||||||
let message: Message = serde_json::from_str(json).unwrap();
|
let message: Message = serde_json::from_str(json).unwrap();
|
||||||
|
|
||||||
let group = Chat {
|
let group = Chat {
|
||||||
id: -1001160242915,
|
id: ChatId(-1001160242915),
|
||||||
kind: ChatKind::Public(ChatPublic {
|
kind: ChatKind::Public(ChatPublic {
|
||||||
title: Some("a".to_owned()),
|
title: Some("a".to_owned()),
|
||||||
kind: PublicChatKind::Supergroup(PublicChatSupergroup {
|
kind: PublicChatKind::Supergroup(PublicChatSupergroup {
|
||||||
|
@ -1360,8 +1362,8 @@ mod tests {
|
||||||
/// Regression test for <https://github.com/teloxide/teloxide/issues/427>
|
/// Regression test for <https://github.com/teloxide/teloxide/issues/427>
|
||||||
#[test]
|
#[test]
|
||||||
fn issue_427() {
|
fn issue_427() {
|
||||||
let old = -599075523;
|
let old = ChatId(-599075523);
|
||||||
let new = -1001555296434;
|
let new = ChatId(-1001555296434);
|
||||||
|
|
||||||
// Migration to a supergroup
|
// 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}"#;
|
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 derive_more::{Display, From};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::types::ChatId;
|
||||||
|
|
||||||
/// A unique identifier for the target chat or username of the target channel
|
/// A unique identifier for the target chat or username of the target channel
|
||||||
/// (in the format `@channelusername`).
|
/// (in the format `@channelusername`).
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Display, From)]
|
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Display, From)]
|
||||||
|
@ -8,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
||||||
pub enum Recipient {
|
pub enum Recipient {
|
||||||
/// A chat identifier.
|
/// A chat identifier.
|
||||||
#[display(fmt = "{}", _0)]
|
#[display(fmt = "{}", _0)]
|
||||||
Id(i64),
|
Id(ChatId),
|
||||||
|
|
||||||
/// A channel username (in the format @channelusername).
|
/// A channel username (in the format @channelusername).
|
||||||
#[display(fmt = "{}", _0)]
|
#[display(fmt = "{}", _0)]
|
||||||
|
@ -16,39 +18,13 @@ pub enum Recipient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Recipient {
|
impl Recipient {
|
||||||
|
#[allow(unused)]
|
||||||
pub(crate) fn is_channel(&self) -> bool {
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -58,7 +34,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn chat_id_id_serialization() {
|
fn chat_id_id_serialization() {
|
||||||
let expected_json = String::from(r#"123456"#);
|
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)
|
assert_eq!(expected_json, actual_json)
|
||||||
}
|
}
|
||||||
|
@ -71,12 +47,4 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(expected_json, actual_json)
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Chat, ChatKind, ChatPrivate, MediaKind, MediaText, Message, MessageCommon, MessageKind,
|
Chat, ChatId, ChatKind, ChatPrivate, MediaKind, MediaText, Message, MessageCommon,
|
||||||
Update, UpdateKind, User, UserId,
|
MessageKind, Update, UpdateKind, User, UserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
|
@ -335,7 +335,7 @@ mod test {
|
||||||
id: 6557,
|
id: 6557,
|
||||||
date,
|
date,
|
||||||
chat: Chat {
|
chat: Chat {
|
||||||
id: 218_485_655,
|
id: ChatId(218_485_655),
|
||||||
kind: ChatKind::Private(ChatPrivate {
|
kind: ChatKind::Private(ChatPrivate {
|
||||||
type_: (),
|
type_: (),
|
||||||
username: Some(String::from("WaffleLapkin")),
|
username: Some(String::from("WaffleLapkin")),
|
||||||
|
|
Loading…
Reference in a new issue