Skip to main content

teloxide_ng/sugar/
request.rs

1//! Additions to multiple [`payloads`].
2//!
3//! [`payloads`]: teloxide_core_ng::payloads
4
5use teloxide_core_ng::{payloads::*, types::*};
6
7macro_rules! impl_request_reply_ext {
8    ($(($t:ty, $trait:path)),*) => {
9        $(
10            impl<T> RequestReplyExt<$t> for T
11            where
12                T: $trait
13            {
14                fn reply_to<M>(self, message_id: M) -> Self
15                where
16                    M: Into<MessageId>,
17                    Self: Sized,
18                {
19                    self.reply_parameters(ReplyParameters::new(message_id.into()))
20                }
21            }
22        )*
23    };
24}
25
26macro_rules! impl_request_link_preview_ext {
27    ($(($t:ty, $trait:path)),*) => {
28        $(
29            impl<T> RequestLinkPreviewExt<$t> for T
30            where
31                T: $trait
32            {
33                fn disable_link_preview(self, is_disabled: bool) -> Self
34                where
35                    Self: Sized
36                {
37                    let link_preview_options = LinkPreviewOptions {
38                        is_disabled,
39                        url: None,
40                        prefer_small_media: false,
41                        prefer_large_media: false,
42                        show_above_text: false,
43                    };
44                    self.link_preview_options(link_preview_options)
45                }
46            }
47        )*
48    };
49}
50
51/// `.reply_to(msg)` syntax sugar for requests.
52pub trait RequestReplyExt<P> {
53    /// Replaces `.reply_parameters(ReplyParameters::new(msg.id))`
54    /// with `.reply_to(msg.id)` or `.reply_to(msg)`
55    fn reply_to<M>(self, message_id: M) -> Self
56    where
57        M: Into<MessageId>,
58        Self: Sized;
59}
60
61/// `.disable_link_preview(is_disabled)` syntax sugar for requests.
62pub trait RequestLinkPreviewExt<P> {
63    /// Replaces
64    /// `.link_preview_options(LinkPreviewOptions {
65    ///     is_disabled: true,
66    ///     url: None,
67    ///     prefer_small_media: false,
68    ///     prefer_large_media: false,
69    ///     show_above_text: false
70    /// };)`
71    ///
72    /// with `.disable_link_preview(true)`.
73    fn disable_link_preview(self, is_disabled: bool) -> Self
74    where
75        Self: Sized;
76}
77
78// NOTE: struct in (struct, trait) is mandatory, as well as the blank <P>
79// generic in Request*Ext traits.
80// Or you will get `error[E0119]: conflicting implementations of trait`.
81// This is a Rust issue. See:
82// https://github.com/rust-lang/rust/issues/20400
83// https://github.com/rust-lang/rfcs/pull/1672
84
85impl_request_reply_ext! {
86    (SendDice, SendDiceSetters),
87    (SendInvoice, SendInvoiceSetters),
88    (SendPoll, SendPollSetters),
89    (SendContact, SendContactSetters),
90    (SendGame, SendGameSetters),
91    (SendVenue, SendVenueSetters),
92    (SendLocation, SendLocationSetters),
93    (CopyMessage, CopyMessageSetters),
94    (SendMessage, SendMessageSetters),
95    (SendSticker, SendStickerSetters),
96    (SendMediaGroup, SendMediaGroupSetters),
97    (SendAnimation, SendAnimationSetters),
98    (SendVideoNote, SendVideoNoteSetters),
99    (SendVideo, SendVideoSetters),
100    (SendDocument, SendDocumentSetters),
101    (SendAudio, SendAudioSetters),
102    (SendVoice, SendVoiceSetters),
103    (SendPhoto, SendPhotoSetters)
104}
105
106impl_request_link_preview_ext! {
107    (SendMessage, SendMessageSetters),
108    (EditMessageText, EditMessageTextSetters)
109}
110
111#[cfg(test)]
112mod tests {
113    use std::ops::Deref;
114
115    use super::*;
116    use teloxide_core_ng::{Bot, prelude::*};
117
118    #[test]
119    fn test_reply_to() {
120        let bot = Bot::new("TOKEN");
121
122        let real_reply_req = bot
123            .send_message(ChatId(1234), "test")
124            .reply_parameters(ReplyParameters::new(MessageId(1)));
125        let sugar_reply_req = bot.send_message(ChatId(1234), "test").reply_to(MessageId(1));
126
127        assert_eq!(real_reply_req.deref(), sugar_reply_req.deref())
128    }
129
130    #[test]
131    fn test_reply_to_multipart() {
132        let bot = Bot::new("TOKEN");
133        let document = InputFile::memory("hello world!");
134
135        let real_reply_req = bot
136            .send_document(ChatId(1234), document.clone())
137            .reply_parameters(ReplyParameters::new(MessageId(1)));
138        let sugar_reply_req = bot.send_document(ChatId(1234), document).reply_to(MessageId(1));
139
140        assert_eq!(
141            real_reply_req.deref().reply_parameters,
142            sugar_reply_req.deref().reply_parameters
143        )
144    }
145
146    #[test]
147    #[cfg(feature = "trace-adaptor")]
148    fn test_reply_to_adaptors() {
149        use teloxide_core_ng::{adaptors::trace::Settings, requests::HasPayload};
150
151        let bot = Bot::new("TOKEN").trace(Settings::empty()).parse_mode(ParseMode::Html);
152
153        let real_reply_req = bot
154            .send_message(ChatId(1234), "test")
155            .reply_parameters(ReplyParameters::new(MessageId(1)));
156        let sugar_reply_req = bot.send_message(ChatId(1234), "test").reply_to(MessageId(1));
157
158        assert_eq!(
159            real_reply_req.payload_ref().payload_ref().reply_parameters,
160            sugar_reply_req.payload_ref().payload_ref().reply_parameters
161        )
162    }
163
164    #[test]
165    fn test_disable_link_preview() {
166        let link_preview_options = LinkPreviewOptions {
167            is_disabled: true,
168            url: None,
169            prefer_small_media: false,
170            prefer_large_media: false,
171            show_above_text: false,
172        };
173        let bot = Bot::new("TOKEN");
174
175        let real_link_req =
176            bot.send_message(ChatId(1234), "test").link_preview_options(link_preview_options);
177        let sugar_link_req = bot.send_message(ChatId(1234), "test").disable_link_preview(true);
178
179        assert_eq!(real_link_req.deref(), sugar_link_req.deref())
180    }
181
182    #[test]
183    #[cfg(feature = "trace-adaptor")]
184    fn test_disable_link_preview_adaptors() {
185        use teloxide_core_ng::{adaptors::trace::Settings, requests::HasPayload};
186
187        let link_preview_options = LinkPreviewOptions {
188            is_disabled: true,
189            url: None,
190            prefer_small_media: false,
191            prefer_large_media: false,
192            show_above_text: false,
193        };
194        let bot = Bot::new("TOKEN").trace(Settings::empty()).parse_mode(ParseMode::Html);
195
196        let real_link_req =
197            bot.send_message(ChatId(1234), "test").link_preview_options(link_preview_options);
198        let sugar_link_req = bot.send_message(ChatId(1234), "test").disable_link_preview(true);
199
200        assert_eq!(
201            real_link_req.payload_ref().payload_ref().reply_parameters,
202            sugar_link_req.payload_ref().payload_ref().reply_parameters
203        )
204    }
205}