Skip to main content

rustigram_api/methods/
editing.rs

1use std::future::{Future, IntoFuture};
2use std::pin::Pin;
3
4use serde::Serialize;
5
6use rustigram_types::checklist::InputChecklist;
7use rustigram_types::file::InputMedia;
8use rustigram_types::keyboard::InlineKeyboardMarkup;
9use rustigram_types::message::{LinkPreviewOptions, Message, MessageEntity, ParseMode};
10use rustigram_types::rich_message::InputRichMessage;
11use rustigram_types::user::ChatId;
12
13use crate::client::BotClient;
14use crate::error::Result;
15
16// ─── Helper macro ─────────────────────────────────────────────────────────────
17
18/// Generates an `IntoFuture` impl that calls `BotClient::post_json`.
19macro_rules! impl_into_future {
20    ($builder:ident, $return_ty:ty, $method:literal) => {
21        impl IntoFuture for $builder {
22            type Output = Result<$return_ty>;
23            type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
24
25            fn into_future(self) -> Self::IntoFuture {
26                Box::pin(async move { self.client.post_json($method, &self.params).await })
27            }
28        }
29    };
30}
31
32/// Target identifier for inline message edits.
33#[derive(Serialize)]
34#[serde(untagged)]
35/// Identifies the target message — either a chat message or an inline message.
36pub enum EditTarget {
37    /// Targets a regular chat message.
38    Chat {
39        /// The chat containing the message.
40        chat_id: ChatId,
41        /// Identifier of the message to edit.
42        message_id: i64,
43    },
44    /// Targets an inline message sent via inline mode.
45    Inline {
46        /// Identifier of the inline message.
47        inline_message_id: String,
48    },
49}
50
51// ─── editMessageText ──────────────────────────────────────────────────────────
52
53#[derive(Serialize)]
54struct EditMessageTextParams {
55    #[serde(flatten)]
56    target: EditTarget,
57    /// New text of the message; required if `rich_message` isn't specified.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    text: Option<String>,
60    /// New rich content of the message; required if `text` isn't specified.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    rich_message: Option<InputRichMessage>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    business_connection_id: Option<String>,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    parse_mode: Option<ParseMode>,
67    #[serde(skip_serializing_if = "Option::is_none")]
68    entities: Option<Vec<MessageEntity>>,
69    #[serde(skip_serializing_if = "Option::is_none")]
70    link_preview_options: Option<LinkPreviewOptions>,
71    #[serde(skip_serializing_if = "Option::is_none")]
72    reply_markup: Option<InlineKeyboardMarkup>,
73}
74
75/// Builder for the [`editMessageText`](https://core.telegram.org/bots/api#editmessagetext) method.
76pub struct EditMessageText {
77    client: BotClient,
78    params: EditMessageTextParams,
79}
80
81impl EditMessageText {
82    pub(crate) fn in_chat(
83        client: BotClient,
84        chat_id: impl Into<ChatId>,
85        message_id: i64,
86        text: impl Into<String>,
87    ) -> Self {
88        Self {
89            client,
90            params: EditMessageTextParams {
91                target: EditTarget::Chat {
92                    chat_id: chat_id.into(),
93                    message_id,
94                },
95                text: Some(text.into()),
96                rich_message: None,
97                business_connection_id: None,
98                parse_mode: None,
99                entities: None,
100                link_preview_options: None,
101                reply_markup: None,
102            },
103        }
104    }
105    pub(crate) fn inline(
106        client: BotClient,
107        inline_message_id: impl Into<String>,
108        text: impl Into<String>,
109    ) -> Self {
110        Self {
111            client,
112            params: EditMessageTextParams {
113                target: EditTarget::Inline {
114                    inline_message_id: inline_message_id.into(),
115                },
116                text: Some(text.into()),
117                rich_message: None,
118                business_connection_id: None,
119                parse_mode: None,
120                entities: None,
121                link_preview_options: None,
122                reply_markup: None,
123            },
124        }
125    }
126    /// Targets a chat message for editing with a rich message.
127    pub(crate) fn in_chat_rich(
128        client: BotClient,
129        chat_id: impl Into<ChatId>,
130        message_id: i64,
131        rich_message: InputRichMessage,
132    ) -> Self {
133        Self {
134            client,
135            params: EditMessageTextParams {
136                target: EditTarget::Chat {
137                    chat_id: chat_id.into(),
138                    message_id,
139                },
140                text: None,
141                rich_message: Some(rich_message),
142                business_connection_id: None,
143                parse_mode: None,
144                entities: None,
145                link_preview_options: None,
146                reply_markup: None,
147            },
148        }
149    }
150    /// Targets an inline message for editing with a rich message.
151    pub(crate) fn inline_rich(
152        client: BotClient,
153        inline_message_id: impl Into<String>,
154        rich_message: InputRichMessage,
155    ) -> Self {
156        Self {
157            client,
158            params: EditMessageTextParams {
159                target: EditTarget::Inline {
160                    inline_message_id: inline_message_id.into(),
161                },
162                text: None,
163                rich_message: Some(rich_message),
164                business_connection_id: None,
165                parse_mode: None,
166                entities: None,
167                link_preview_options: None,
168                reply_markup: None,
169            },
170        }
171    }
172    /// Sets the text parse mode (`MarkdownV2`, `HTML`, or `Markdown`).
173    pub fn parse_mode(mut self, m: ParseMode) -> Self {
174        self.params.parse_mode = Some(m);
175        self
176    }
177    /// Sets custom message entities instead of using a parse mode.
178    pub fn entities(mut self, e: Vec<MessageEntity>) -> Self {
179        self.params.entities = Some(e);
180        self
181    }
182    /// Configures link preview options for the edited message.
183    pub fn link_preview_options(mut self, o: LinkPreviewOptions) -> Self {
184        self.params.link_preview_options = Some(o);
185        self
186    }
187    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
188    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
189        self.params.reply_markup = Some(m);
190        self
191    }
192    /// Business connection ID for acting on behalf of a business account.
193    pub fn business_connection_id(mut self, v: impl Into<String>) -> Self {
194        self.params.business_connection_id = Some(v.into());
195        self
196    }
197}
198
199impl_into_future!(EditMessageText, Message, "editMessageText");
200
201// ─── editMessageCaption ───────────────────────────────────────────────────────
202
203#[derive(Serialize)]
204struct EditMessageCaptionParams {
205    #[serde(flatten)]
206    target: EditTarget,
207    #[serde(skip_serializing_if = "Option::is_none")]
208    business_connection_id: Option<String>,
209    #[serde(skip_serializing_if = "Option::is_none")]
210    caption: Option<String>,
211    #[serde(skip_serializing_if = "Option::is_none")]
212    parse_mode: Option<ParseMode>,
213    #[serde(skip_serializing_if = "Option::is_none")]
214    caption_entities: Option<Vec<MessageEntity>>,
215    #[serde(skip_serializing_if = "Option::is_none")]
216    show_caption_above_media: Option<bool>,
217    #[serde(skip_serializing_if = "Option::is_none")]
218    reply_markup: Option<InlineKeyboardMarkup>,
219}
220
221/// Builder for the [`editMessageCaption`](https://core.telegram.org/bots/api#editmessagecaption) method.
222pub struct EditMessageCaption {
223    client: BotClient,
224    params: EditMessageCaptionParams,
225}
226
227impl EditMessageCaption {
228    pub(crate) fn in_chat(client: BotClient, chat_id: impl Into<ChatId>, message_id: i64) -> Self {
229        Self {
230            client,
231            params: EditMessageCaptionParams {
232                target: EditTarget::Chat {
233                    chat_id: chat_id.into(),
234                    message_id,
235                },
236                business_connection_id: None,
237                caption: None,
238                parse_mode: None,
239                caption_entities: None,
240                show_caption_above_media: None,
241                reply_markup: None,
242            },
243        }
244    }
245    pub(crate) fn inline(client: BotClient, inline_message_id: impl Into<String>) -> Self {
246        Self {
247            client,
248            params: EditMessageCaptionParams {
249                target: EditTarget::Inline {
250                    inline_message_id: inline_message_id.into(),
251                },
252                business_connection_id: None,
253                caption: None,
254                parse_mode: None,
255                caption_entities: None,
256                show_caption_above_media: None,
257                reply_markup: None,
258            },
259        }
260    }
261    /// Sets the new caption text (0–1024 characters).
262    pub fn caption(mut self, c: impl Into<String>) -> Self {
263        self.params.caption = Some(c.into());
264        self
265    }
266    /// Sets the caption parse mode (`MarkdownV2`, `HTML`, or `Markdown`).
267    pub fn parse_mode(mut self, m: ParseMode) -> Self {
268        self.params.parse_mode = Some(m);
269        self
270    }
271    /// Shows the caption above the media instead of below it.
272    pub fn show_caption_above_media(mut self, v: bool) -> Self {
273        self.params.show_caption_above_media = Some(v);
274        self
275    }
276    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
277    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
278        self.params.reply_markup = Some(m);
279        self
280    }
281    /// Business connection ID for acting on behalf of a business account.
282    pub fn business_connection_id(mut self, v: impl Into<String>) -> Self {
283        self.params.business_connection_id = Some(v.into());
284        self
285    }
286    /// Special entities in the caption, in place of `parse_mode`.
287    pub fn caption_entities(mut self, v: Vec<MessageEntity>) -> Self {
288        self.params.caption_entities = Some(v);
289        self
290    }
291}
292
293impl_into_future!(EditMessageCaption, Message, "editMessageCaption");
294
295// ─── editMessageMedia ─────────────────────────────────────────────────────────
296
297#[derive(Serialize)]
298struct EditMessageMediaParams {
299    #[serde(flatten)]
300    target: EditTarget,
301    /// The new media content.
302    /// Pass the result of `serde_json::to_value(&your_input_media)`.
303    media: InputMedia,
304    #[serde(skip_serializing_if = "Option::is_none")]
305    business_connection_id: Option<String>,
306    #[serde(skip_serializing_if = "Option::is_none")]
307    reply_markup: Option<InlineKeyboardMarkup>,
308}
309
310/// Builder for the [`editMessageMedia`](https://core.telegram.org/bots/api#editmessagemedia) method.
311///
312/// Edits the media content of a message (animation, audio, document, photo, or video).
313///
314pub struct EditMessageMedia {
315    client: BotClient,
316    params: EditMessageMediaParams,
317}
318
319impl EditMessageMedia {
320    pub(crate) fn in_chat(
321        client: BotClient,
322        chat_id: impl Into<ChatId>,
323        message_id: i64,
324        media: InputMedia,
325    ) -> Self {
326        Self {
327            client,
328            params: EditMessageMediaParams {
329                target: EditTarget::Chat {
330                    chat_id: chat_id.into(),
331                    message_id,
332                },
333                media,
334                business_connection_id: None,
335                reply_markup: None,
336            },
337        }
338    }
339    pub(crate) fn inline(
340        client: BotClient,
341        inline_message_id: impl Into<String>,
342        media: InputMedia,
343    ) -> Self {
344        Self {
345            client,
346            params: EditMessageMediaParams {
347                target: EditTarget::Inline {
348                    inline_message_id: inline_message_id.into(),
349                },
350                media,
351                business_connection_id: None,
352                reply_markup: None,
353            },
354        }
355    }
356    /// Business connection ID for editing a message sent on behalf of a business account.
357    pub fn business_connection_id(mut self, id: impl Into<String>) -> Self {
358        self.params.business_connection_id = Some(id.into());
359        self
360    }
361    /// Attaches a new inline keyboard to the message.
362    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
363        self.params.reply_markup = Some(m);
364        self
365    }
366}
367
368impl_into_future!(EditMessageMedia, Message, "editMessageMedia");
369
370// ─── editMessageReplyMarkup ───────────────────────────────────────────────────
371
372#[derive(Serialize)]
373struct EditMessageReplyMarkupParams {
374    #[serde(flatten)]
375    target: EditTarget,
376    #[serde(skip_serializing_if = "Option::is_none")]
377    business_connection_id: Option<String>,
378    #[serde(skip_serializing_if = "Option::is_none")]
379    reply_markup: Option<InlineKeyboardMarkup>,
380}
381
382/// Builder for the [`editMessageReplyMarkup`](https://core.telegram.org/bots/api#editmessagereplymarkup) method.
383pub struct EditMessageReplyMarkup {
384    client: BotClient,
385    params: EditMessageReplyMarkupParams,
386}
387
388impl EditMessageReplyMarkup {
389    pub(crate) fn in_chat(client: BotClient, chat_id: impl Into<ChatId>, message_id: i64) -> Self {
390        Self {
391            client,
392            params: EditMessageReplyMarkupParams {
393                target: EditTarget::Chat {
394                    chat_id: chat_id.into(),
395                    message_id,
396                },
397                business_connection_id: None,
398                reply_markup: None,
399            },
400        }
401    }
402    pub(crate) fn inline(client: BotClient, inline_message_id: impl Into<String>) -> Self {
403        Self {
404            client,
405            params: EditMessageReplyMarkupParams {
406                target: EditTarget::Inline {
407                    inline_message_id: inline_message_id.into(),
408                },
409                business_connection_id: None,
410                reply_markup: None,
411            },
412        }
413    }
414    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
415    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
416        self.params.reply_markup = Some(m);
417        self
418    }
419    /// Removes the inline keyboard from the message.
420    pub fn remove_markup(mut self) -> Self {
421        self.params.reply_markup = None;
422        self
423    }
424    /// Business connection ID for acting on behalf of a business account.
425    pub fn business_connection_id(mut self, v: impl Into<String>) -> Self {
426        self.params.business_connection_id = Some(v.into());
427        self
428    }
429}
430
431impl_into_future!(EditMessageReplyMarkup, Message, "editMessageReplyMarkup");
432
433// ─── editEphemeralMessageText ─────────────────────────────────────────────────
434
435#[derive(Serialize)]
436struct EditEphemeralMessageTextParams {
437    chat_id: ChatId,
438    receiver_user_id: i64,
439    ephemeral_message_id: i64,
440    text: String,
441    #[serde(skip_serializing_if = "Option::is_none")]
442    parse_mode: Option<ParseMode>,
443    #[serde(skip_serializing_if = "Option::is_none")]
444    entities: Option<Vec<MessageEntity>>,
445    #[serde(skip_serializing_if = "Option::is_none")]
446    reply_markup: Option<InlineKeyboardMarkup>,
447    #[serde(skip_serializing_if = "Option::is_none")]
448    link_preview_options: Option<LinkPreviewOptions>,
449}
450
451/// Builder for the [`editEphemeralMessageText`](https://core.telegram.org/bots/api#editephemeralmessagetext) method.
452///
453/// Note that it is not guaranteed that the user will receive the message edit
454/// event, especially if they are offline.
455pub struct EditEphemeralMessageText {
456    client: BotClient,
457    params: EditEphemeralMessageTextParams,
458}
459
460impl EditEphemeralMessageText {
461    pub(crate) fn new(
462        client: BotClient,
463        chat_id: impl Into<ChatId>,
464        receiver_user_id: i64,
465        ephemeral_message_id: i64,
466        text: impl Into<String>,
467    ) -> Self {
468        Self {
469            client,
470            params: EditEphemeralMessageTextParams {
471                chat_id: chat_id.into(),
472                receiver_user_id,
473                ephemeral_message_id,
474                text: text.into(),
475                parse_mode: None,
476                entities: None,
477                reply_markup: None,
478                link_preview_options: None,
479            },
480        }
481    }
482    /// Sets the parse mode for the message text.
483    pub fn parse_mode(mut self, m: ParseMode) -> Self {
484        self.params.parse_mode = Some(m);
485        self
486    }
487    /// Special entities in the message text, in place of `parse_mode`.
488    pub fn entities(mut self, e: Vec<MessageEntity>) -> Self {
489        self.params.entities = Some(e);
490        self
491    }
492    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
493    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
494        self.params.reply_markup = Some(m);
495        self
496    }
497    /// Configures link preview generation options.
498    pub fn link_preview_options(mut self, v: LinkPreviewOptions) -> Self {
499        self.params.link_preview_options = Some(v);
500        self
501    }
502}
503
504impl_into_future!(EditEphemeralMessageText, bool, "editEphemeralMessageText");
505
506// ─── editEphemeralMessageCaption ──────────────────────────────────────────────
507
508#[derive(Serialize)]
509struct EditEphemeralMessageCaptionParams {
510    chat_id: ChatId,
511    receiver_user_id: i64,
512    ephemeral_message_id: i64,
513    #[serde(skip_serializing_if = "Option::is_none")]
514    caption: Option<String>,
515    #[serde(skip_serializing_if = "Option::is_none")]
516    parse_mode: Option<ParseMode>,
517    #[serde(skip_serializing_if = "Option::is_none")]
518    caption_entities: Option<Vec<MessageEntity>>,
519    #[serde(skip_serializing_if = "Option::is_none")]
520    reply_markup: Option<InlineKeyboardMarkup>,
521}
522
523/// Builder for the [`editEphemeralMessageCaption`](https://core.telegram.org/bots/api#editephemeralmessagecaption) method.
524///
525/// Note that it is not guaranteed that the user will receive the message edit
526/// event, especially if they are offline.
527pub struct EditEphemeralMessageCaption {
528    client: BotClient,
529    params: EditEphemeralMessageCaptionParams,
530}
531
532impl EditEphemeralMessageCaption {
533    pub(crate) fn new(
534        client: BotClient,
535        chat_id: impl Into<ChatId>,
536        receiver_user_id: i64,
537        ephemeral_message_id: i64,
538    ) -> Self {
539        Self {
540            client,
541            params: EditEphemeralMessageCaptionParams {
542                chat_id: chat_id.into(),
543                receiver_user_id,
544                ephemeral_message_id,
545                caption: None,
546                parse_mode: None,
547                caption_entities: None,
548                reply_markup: None,
549            },
550        }
551    }
552    /// Sets the new caption text (0–1024 characters).
553    pub fn caption(mut self, c: impl Into<String>) -> Self {
554        self.params.caption = Some(c.into());
555        self
556    }
557    /// Sets the caption parse mode.
558    pub fn parse_mode(mut self, m: ParseMode) -> Self {
559        self.params.parse_mode = Some(m);
560        self
561    }
562    /// Special entities in the caption, in place of `parse_mode`.
563    pub fn caption_entities(mut self, e: Vec<MessageEntity>) -> Self {
564        self.params.caption_entities = Some(e);
565        self
566    }
567    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
568    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
569        self.params.reply_markup = Some(m);
570        self
571    }
572}
573
574impl_into_future!(
575    EditEphemeralMessageCaption,
576    bool,
577    "editEphemeralMessageCaption"
578);
579
580#[derive(Serialize)]
581struct EditEphemeralMessageMediaParams {
582    chat_id: ChatId,
583    receiver_user_id: i64,
584    ephemeral_message_id: i64,
585    media: InputMedia,
586    #[serde(skip_serializing_if = "Option::is_none")]
587    reply_markup: Option<InlineKeyboardMarkup>,
588}
589
590/// Builder for the [`editEphemeralMessageMedia`](https://core.telegram.org/bots/api#editephemeralmessagemedia) method.
591///
592/// Note that it is not guaranteed that the user will receive the message edit
593/// event, especially if they are offline.
594pub struct EditEphemeralMessageMedia {
595    client: BotClient,
596    params: EditEphemeralMessageMediaParams,
597}
598
599impl EditEphemeralMessageMedia {
600    pub(crate) fn new(
601        client: BotClient,
602        chat_id: impl Into<ChatId>,
603        receiver_user_id: i64,
604        ephemeral_message_id: i64,
605        media: InputMedia,
606    ) -> Self {
607        Self {
608            client,
609            params: EditEphemeralMessageMediaParams {
610                chat_id: chat_id.into(),
611                receiver_user_id,
612                ephemeral_message_id,
613                media,
614                reply_markup: None,
615            },
616        }
617    }
618    /// Attaches a reply markup (inline keyboard).
619    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
620        self.params.reply_markup = Some(m);
621        self
622    }
623}
624
625impl_into_future!(EditEphemeralMessageMedia, bool, "editEphemeralMessageMedia");
626
627// ─── editEphemeralMessageReplyMarkup ──────────────────────────────────────────
628
629#[derive(Serialize)]
630struct EditEphemeralMessageReplyMarkupParams {
631    chat_id: ChatId,
632    receiver_user_id: i64,
633    ephemeral_message_id: i64,
634    #[serde(skip_serializing_if = "Option::is_none")]
635    reply_markup: Option<InlineKeyboardMarkup>,
636}
637
638/// Builder for the [`editEphemeralMessageReplyMarkup`](https://core.telegram.org/bots/api#editephemeralmessagereplymarkup) method.
639///
640/// Note that it is not guaranteed that the user will receive the message edit
641/// event, especially if they are offline.
642pub struct EditEphemeralMessageReplyMarkup {
643    client: BotClient,
644    params: EditEphemeralMessageReplyMarkupParams,
645}
646
647impl EditEphemeralMessageReplyMarkup {
648    pub(crate) fn new(
649        client: BotClient,
650        chat_id: impl Into<ChatId>,
651        receiver_user_id: i64,
652        ephemeral_message_id: i64,
653    ) -> Self {
654        Self {
655            client,
656            params: EditEphemeralMessageReplyMarkupParams {
657                chat_id: chat_id.into(),
658                receiver_user_id,
659                ephemeral_message_id,
660                reply_markup: None,
661            },
662        }
663    }
664    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
665    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
666        self.params.reply_markup = Some(m);
667        self
668    }
669    /// Removes the inline keyboard from the message.
670    pub fn remove_markup(mut self) -> Self {
671        self.params.reply_markup = None;
672        self
673    }
674}
675
676impl_into_future!(
677    EditEphemeralMessageReplyMarkup,
678    bool,
679    "editEphemeralMessageReplyMarkup"
680);
681
682// ─── editMessageChecklist ─────────────────────────────────────────────────────
683
684#[derive(Serialize)]
685struct EditMessageChecklistParams {
686    business_connection_id: String,
687    chat_id: i64,
688    message_id: i64,
689    checklist: InputChecklist,
690    #[serde(skip_serializing_if = "Option::is_none")]
691    reply_markup: Option<InlineKeyboardMarkup>,
692}
693
694/// Builder for the [`editMessageChecklist`](https://core.telegram.org/bots/api#editmessagechecklist) method.
695///
696/// Business bots only — edits a checklist message sent on behalf of a connected
697/// business account. Requires the `can_reply` business bot right.
698pub struct EditMessageChecklist {
699    client: BotClient,
700    params: EditMessageChecklistParams,
701}
702
703impl EditMessageChecklist {
704    pub(crate) fn new(
705        client: BotClient,
706        business_connection_id: impl Into<String>,
707        chat_id: i64,
708        message_id: i64,
709        checklist: InputChecklist,
710    ) -> Self {
711        Self {
712            client,
713            params: EditMessageChecklistParams {
714                business_connection_id: business_connection_id.into(),
715                chat_id,
716                message_id,
717                checklist,
718                reply_markup: None,
719            },
720        }
721    }
722    /// Attaches a new inline keyboard to the message.
723    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
724        self.params.reply_markup = Some(m);
725        self
726    }
727}
728
729impl_into_future!(EditMessageChecklist, Message, "editMessageChecklist");
730
731// ─── approveSuggestedPost ─────────────────────────────────────────────────────
732
733#[derive(Serialize)]
734struct ApproveSuggestedPostParams {
735    chat_id: i64,
736    message_id: i64,
737    #[serde(skip_serializing_if = "Option::is_none")]
738    send_date: Option<i64>,
739}
740
741/// Builder for the [`approveSuggestedPost`](https://core.telegram.org/bots/api#approvesuggestedpost) method.
742///
743/// Approves a suggested post in a direct messages chat.
744/// Requires the `can_post_messages` administrator right in the corresponding channel.
745pub struct ApproveSuggestedPost {
746    client: BotClient,
747    params: ApproveSuggestedPostParams,
748}
749
750impl ApproveSuggestedPost {
751    pub(crate) fn new(client: BotClient, chat_id: i64, message_id: i64) -> Self {
752        Self {
753            client,
754            params: ApproveSuggestedPostParams {
755                chat_id,
756                message_id,
757                send_date: None,
758            },
759        }
760    }
761    /// Unix timestamp when the post will be published (not more than 30 days in the future).
762    ///
763    /// Omit if the send date was already specified when the post was suggested.
764    pub fn send_date(mut self, ts: i64) -> Self {
765        self.params.send_date = Some(ts);
766        self
767    }
768}
769
770impl_into_future!(ApproveSuggestedPost, bool, "approveSuggestedPost");
771
772// ─── declineSuggestedPost ─────────────────────────────────────────────────────
773
774#[derive(Serialize)]
775struct DeclineSuggestedPostParams {
776    chat_id: i64,
777    message_id: i64,
778    #[serde(skip_serializing_if = "Option::is_none")]
779    comment: Option<String>,
780}
781
782/// Builder for the [`declineSuggestedPost`](https://core.telegram.org/bots/api#declinesuggestedpost) method.
783///
784/// Declines a suggested post in a direct messages chat.
785/// Requires the `can_manage_direct_messages` administrator right in the corresponding channel.
786pub struct DeclineSuggestedPost {
787    client: BotClient,
788    params: DeclineSuggestedPostParams,
789}
790
791impl DeclineSuggestedPost {
792    pub(crate) fn new(client: BotClient, chat_id: i64, message_id: i64) -> Self {
793        Self {
794            client,
795            params: DeclineSuggestedPostParams {
796                chat_id,
797                message_id,
798                comment: None,
799            },
800        }
801    }
802    /// Optional comment for the creator of the suggested post (0–128 characters).
803    pub fn comment(mut self, c: impl Into<String>) -> Self {
804        self.params.comment = Some(c.into());
805        self
806    }
807}
808
809impl_into_future!(DeclineSuggestedPost, bool, "declineSuggestedPost");
810
811// ─── editMessageLiveLocation ──────────────────────────────────────────────────
812
813#[derive(Serialize)]
814struct EditMessageLiveLocationParams {
815    #[serde(flatten)]
816    target: EditTarget,
817    latitude: f64,
818    longitude: f64,
819    #[serde(skip_serializing_if = "Option::is_none")]
820    live_period: Option<u32>,
821    #[serde(skip_serializing_if = "Option::is_none")]
822    horizontal_accuracy: Option<f64>,
823    #[serde(skip_serializing_if = "Option::is_none")]
824    heading: Option<u16>,
825    #[serde(skip_serializing_if = "Option::is_none")]
826    proximity_alert_radius: Option<u32>,
827    #[serde(skip_serializing_if = "Option::is_none")]
828    reply_markup: Option<InlineKeyboardMarkup>,
829    #[serde(skip_serializing_if = "Option::is_none")]
830    business_connection_id: Option<String>,
831}
832
833/// Builder for the [`editMessageLiveLocation`](https://core.telegram.org/bots/api#editmessagelivelocation) method.
834pub struct EditMessageLiveLocation {
835    client: BotClient,
836    params: EditMessageLiveLocationParams,
837}
838
839impl EditMessageLiveLocation {
840    pub(crate) fn in_chat(
841        client: BotClient,
842        chat_id: impl Into<ChatId>,
843        message_id: i64,
844        latitude: f64,
845        longitude: f64,
846    ) -> Self {
847        Self {
848            client,
849            params: EditMessageLiveLocationParams {
850                target: EditTarget::Chat {
851                    chat_id: chat_id.into(),
852                    message_id,
853                },
854                latitude,
855                longitude,
856                live_period: None,
857                horizontal_accuracy: None,
858                heading: None,
859                proximity_alert_radius: None,
860                reply_markup: None,
861                business_connection_id: None,
862            },
863        }
864    }
865    pub(crate) fn inline(
866        client: BotClient,
867        inline_message_id: impl Into<String>,
868        latitude: f64,
869        longitude: f64,
870    ) -> Self {
871        Self {
872            client,
873            params: EditMessageLiveLocationParams {
874                target: EditTarget::Inline {
875                    inline_message_id: inline_message_id.into(),
876                },
877                latitude,
878                longitude,
879                live_period: None,
880                horizontal_accuracy: None,
881                heading: None,
882                proximity_alert_radius: None,
883                reply_markup: None,
884                business_connection_id: None,
885            },
886        }
887    }
888    /// Sets how long the location stays live, in seconds (60–86400).
889    pub fn live_period(mut self, v: u32) -> Self {
890        self.params.live_period = Some(v);
891        self
892    }
893    /// Sets the direction of movement in degrees (1–360).
894    pub fn heading(mut self, v: u16) -> Self {
895        self.params.heading = Some(v);
896        self
897    }
898    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
899    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
900        self.params.reply_markup = Some(m);
901        self
902    }
903    /// Business connection ID for acting on behalf of a business account.
904    pub fn business_connection_id(mut self, v: impl Into<String>) -> Self {
905        self.params.business_connection_id = Some(v.into());
906        self
907    }
908    /// Radius of uncertainty for the location, in metres (0–1500).
909    pub fn horizontal_accuracy(mut self, v: f64) -> Self {
910        self.params.horizontal_accuracy = Some(v);
911        self
912    }
913    /// Distance for proximity alerts about the approaching member, in metres.
914    pub fn proximity_alert_radius(mut self, v: u32) -> Self {
915        self.params.proximity_alert_radius = Some(v);
916        self
917    }
918}
919
920impl_into_future!(EditMessageLiveLocation, Message, "editMessageLiveLocation");
921
922// ─── stopMessageLiveLocation ──────────────────────────────────────────────────
923
924#[derive(Serialize)]
925struct StopMessageLiveLocationParams {
926    #[serde(flatten)]
927    target: EditTarget,
928    #[serde(skip_serializing_if = "Option::is_none")]
929    reply_markup: Option<InlineKeyboardMarkup>,
930    #[serde(skip_serializing_if = "Option::is_none")]
931    business_connection_id: Option<String>,
932}
933
934/// Builder for the [`stopMessageLiveLocation`](https://core.telegram.org/bots/api#stopmessagelivelocation) method.
935pub struct StopMessageLiveLocation {
936    client: BotClient,
937    params: StopMessageLiveLocationParams,
938}
939
940impl StopMessageLiveLocation {
941    pub(crate) fn in_chat(client: BotClient, chat_id: impl Into<ChatId>, message_id: i64) -> Self {
942        Self {
943            client,
944            params: StopMessageLiveLocationParams {
945                target: EditTarget::Chat {
946                    chat_id: chat_id.into(),
947                    message_id,
948                },
949                reply_markup: None,
950                business_connection_id: None,
951            },
952        }
953    }
954    pub(crate) fn inline(client: BotClient, inline_message_id: impl Into<String>) -> Self {
955        Self {
956            client,
957            params: StopMessageLiveLocationParams {
958                target: EditTarget::Inline {
959                    inline_message_id: inline_message_id.into(),
960                },
961                reply_markup: None,
962                business_connection_id: None,
963            },
964        }
965    }
966    /// Attaches a reply markup (inline keyboard, reply keyboard, etc.).
967    pub fn reply_markup(mut self, m: InlineKeyboardMarkup) -> Self {
968        self.params.reply_markup = Some(m);
969        self
970    }
971    /// Business connection ID for acting on behalf of a business account.
972    pub fn business_connection_id(mut self, v: impl Into<String>) -> Self {
973        self.params.business_connection_id = Some(v.into());
974        self
975    }
976}
977
978impl_into_future!(StopMessageLiveLocation, Message, "stopMessageLiveLocation");