tgbot/types/definitions/file/
photo.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    api::{Form, Method, Payload},
5    types::{
6        ChatId,
7        InputFile,
8        Integer,
9        Message,
10        ParseMode,
11        ReplyMarkup,
12        ReplyMarkupError,
13        ReplyParameters,
14        ReplyParametersError,
15        SuggestedPostParameters,
16        SuggestedPostParametersError,
17        TextEntities,
18        TextEntity,
19        TextEntityError,
20    },
21};
22
23/// Represents a size of a photo or a file / sticker thumbnail.
24#[serde_with::skip_serializing_none]
25#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
26pub struct PhotoSize {
27    /// Identifier of the file.
28    ///
29    /// Can be used to download or reuse the file.
30    pub file_id: String,
31    /// Unique identifier of the file.
32    ///
33    /// It is supposed to be the same over time and for different bots.
34    /// Can't be used to download or reuse the file.
35    pub file_unique_id: String,
36    /// Height of the photo.
37    pub height: Integer,
38    /// Width of the photo.
39    pub width: Integer,
40    /// File size in bytes.
41    pub file_size: Option<Integer>,
42}
43
44impl PhotoSize {
45    /// Creates a new `PhotoSize`.
46    ///
47    /// # Arguments
48    ///
49    /// * `file_id` - Identifier of the file.
50    /// * `file_unique_id` - Unique identifier of the file.
51    /// * `height` - Height of the photo.
52    /// * `width` - Width of the photo.
53    pub fn new<A, B>(file_id: A, file_unique_id: B, height: Integer, width: Integer) -> Self
54    where
55        A: Into<String>,
56        B: Into<String>,
57    {
58        Self {
59            file_id: file_id.into(),
60            file_unique_id: file_unique_id.into(),
61            height,
62            width,
63            file_size: None,
64        }
65    }
66
67    /// Sets a new size of the file.
68    ///
69    /// # Arguments
70    ///
71    /// * `value` - The size of the file in bytes.
72    pub fn with_file_size(mut self, value: Integer) -> Self {
73        self.file_size = Some(value);
74        self
75    }
76}
77
78/// Sends a photo.
79#[derive(Debug)]
80pub struct SendPhoto {
81    form: Form,
82}
83
84impl SendPhoto {
85    /// Creates a new `SendPhoto`.
86    ///
87    /// # Arguments
88    ///
89    /// * `chat_id` - Unique identifier of the target chat.
90    /// * `photo` - Photo to send.
91    pub fn new<A, B>(chat_id: A, photo: B) -> Self
92    where
93        A: Into<ChatId>,
94        B: Into<InputFile>,
95    {
96        Self {
97            form: Form::from([("chat_id", chat_id.into().into()), ("photo", photo.into().into())]),
98        }
99    }
100
101    /// Sets a new value for the `allow_paid_broadcast` flag.
102    ///
103    /// # Arguments
104    ///
105    /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
106    ///   for a fee of 0.1 Telegram Stars per message.
107    ///   The relevant Stars will be withdrawn from the bot's balance.
108    pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
109        self.form.insert_field("allow_paid_broadcast", value);
110        self
111    }
112
113    /// Sets a new business connection ID.
114    ///
115    /// # Arguments
116    ///
117    /// * `value` - Unique identifier of the business connection.
118    pub fn with_business_connection_id<T>(mut self, value: T) -> Self
119    where
120        T: Into<String>,
121    {
122        self.form.insert_field("business_connection_id", value.into());
123        self
124    }
125
126    /// Sets a new caption.
127    ///
128    /// # Arguments
129    ///
130    /// * `value` - Caption; 0-1024 characters.
131    ///
132    /// May also be used when resending documents by `file_id`.
133    pub fn with_caption<T>(mut self, value: T) -> Self
134    where
135        T: Into<String>,
136    {
137        self.form.insert_field("caption", value.into());
138        self
139    }
140
141    /// Sets a new list of caption entities.
142    ///
143    /// # Arguments
144    ///
145    /// * `value` - The list of special entities that appear in the caption.
146    ///
147    /// Caption parse mode will be set to [`None`] when this method is called.
148    pub fn with_caption_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
149    where
150        T: IntoIterator<Item = TextEntity>,
151    {
152        let value: TextEntities = value.into_iter().collect();
153        self.form.insert_field("caption_entities", value.serialize()?);
154        self.form.remove_field("parse_mode");
155        Ok(self)
156    }
157
158    /// Sets a new caption parse mode.
159    ///
160    /// # Arguments
161    ///
162    /// * `value` - Parse mode.
163    ///
164    /// Caption entities will be set to [`None`] when this method is called.
165    pub fn with_caption_parse_mode(mut self, value: ParseMode) -> Self {
166        self.form.insert_field("parse_mode", value);
167        self.form.remove_field("caption_entities");
168        self
169    }
170
171    /// Sets a new direct messages topic ID
172    ///
173    /// * `value` - Identifier of the direct messages topic to which the message will be sent.
174    ///
175    /// Required if the message is sent to a direct messages chat.
176    pub fn with_direct_messages_topic_id(mut self, value: Integer) -> Self {
177        self.form.insert_field("direct_messages_topic_id", value);
178        self
179    }
180
181    /// Sets a new value for the `disable_notification` flag.
182    ///
183    /// # Arguments
184    ///
185    /// * `value` - Indicates whether to send the message silently or not;
186    ///   a user will receive a notification without sound.
187    pub fn with_disable_notification(mut self, value: bool) -> Self {
188        self.form.insert_field("disable_notification", value.to_string());
189        self
190    }
191
192    /// Sets a new value for the `has_spoiler` flag.
193    ///
194    /// # Arguments
195    ///
196    /// * `value` - Indicates whether to cover with a spoiler animation.
197    pub fn with_has_spoiler(mut self, value: bool) -> Self {
198        self.form.insert_field("has_spoiler", value);
199        self
200    }
201
202    /// Sets a new message effect ID.
203    ///
204    /// # Arguments
205    ///
206    /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
207    pub fn with_message_effect_id<T>(mut self, value: T) -> Self
208    where
209        T: Into<String>,
210    {
211        self.form.insert_field("message_effect_id", value.into());
212        self
213    }
214
215    /// Sets a new message thread ID.
216    ///
217    /// # Arguments
218    ///
219    /// * `value` - Unique identifier of the target message thread;
220    ///   supergroups only.
221    pub fn with_message_thread_id(mut self, value: Integer) -> Self {
222        self.form.insert_field("message_thread_id", value);
223        self
224    }
225
226    /// Sets a new value for the `protect_content` flag.
227    ///
228    /// # Arguments
229    ///
230    /// * `value` - Indicates whether to protect the contents
231    ///   of the sent message from forwarding and saving.
232    pub fn with_protect_content(mut self, value: bool) -> Self {
233        self.form.insert_field("protect_content", value.to_string());
234        self
235    }
236
237    /// Sets a new reply markup.
238    ///
239    /// # Arguments
240    ///
241    /// * `value` - Reply markup.
242    pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
243    where
244        T: Into<ReplyMarkup>,
245    {
246        let value = value.into();
247        self.form.insert_field("reply_markup", value.serialize()?);
248        Ok(self)
249    }
250
251    /// Sets new reply parameters.
252    ///
253    /// # Arguments
254    ///
255    /// * `value` - Description of the message to reply to.
256    pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
257        self.form.insert_field("reply_parameters", value.serialize()?);
258        Ok(self)
259    }
260
261    /// Sets a new value for the `show_caption_above_media` flag.
262    ///
263    /// # Arguments
264    ///
265    /// `value` - Whether the caption must be shown above the message media.
266    pub fn with_show_caption_above_media(mut self, value: bool) -> Self {
267        self.form.insert_field("show_caption_above_media", value);
268        self
269    }
270
271    /// Sets a new suggested post parameters.
272    ///
273    /// # Arguments
274    ///
275    /// * `value` - An object containing the parameters of the suggested post to send.
276    ///
277    /// For direct messages chats only.
278    ///
279    /// If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
280    pub fn with_suggested_post_parameters(
281        mut self,
282        value: &SuggestedPostParameters,
283    ) -> Result<Self, SuggestedPostParametersError> {
284        let value = serde_json::to_string(value).map_err(SuggestedPostParametersError::Serialize)?;
285        self.form.insert_field("suggested_post_parameters", value);
286        Ok(self)
287    }
288}
289
290impl Method for SendPhoto {
291    type Response = Message;
292
293    fn into_payload(self) -> Payload {
294        Payload::form("sendPhoto", self.form)
295    }
296}