Skip to main content

rustigram_api/methods/
chat_management.rs

1use crate::client::BotClient;
2use crate::error::Result;
3use reqwest::multipart::{Form, Part};
4use rustigram_types::chat::{ChatInviteLink, ChatPermissions};
5use rustigram_types::file::InputFile;
6use rustigram_types::update::UserChatBoosts;
7use rustigram_types::user::ChatId;
8use serde::Serialize;
9use std::future::{Future, IntoFuture};
10use std::pin::Pin;
11
12// ─── Helper macro ─────────────────────────────────────────────────────────────
13
14/// Generates an `IntoFuture` impl that calls `BotClient::post_json`.
15macro_rules! impl_into_future {
16    ($builder:ident, $return_ty:ty, $method:literal) => {
17        impl IntoFuture for $builder {
18            type Output = Result<$return_ty>;
19            type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
20
21            fn into_future(self) -> Self::IntoFuture {
22                Box::pin(async move { self.client.post_json($method, &self.params).await })
23            }
24        }
25    };
26}
27
28// ─── banChatMember ────────────────────────────────────────────────────────────
29
30#[derive(Serialize)]
31struct BanChatMemberParams {
32    chat_id: ChatId,
33    user_id: i64,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    until_date: Option<i64>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    revoke_messages: Option<bool>,
38}
39
40/// Builder for the [`banChatMember`](https://core.telegram.org/bots/api#banchatmember) method.
41pub struct BanChatMember {
42    client: BotClient,
43    params: BanChatMemberParams,
44}
45
46impl BanChatMember {
47    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
48        Self {
49            client,
50            params: BanChatMemberParams {
51                chat_id: chat_id.into(),
52                user_id,
53                until_date: None,
54                revoke_messages: None,
55            },
56        }
57    }
58    /// Bans the user until this Unix timestamp. Omit or set to 0 for a permanent ban.
59    pub fn until_date(mut self, ts: i64) -> Self {
60        self.params.until_date = Some(ts);
61        self
62    }
63    /// Deletes all messages from this user in the chat on ban.
64    pub fn revoke_messages(mut self, v: bool) -> Self {
65        self.params.revoke_messages = Some(v);
66        self
67    }
68}
69
70impl_into_future!(BanChatMember, bool, "banChatMember");
71
72// ─── unbanChatMember ──────────────────────────────────────────────────────────
73
74#[derive(Serialize)]
75struct UnbanChatMemberParams {
76    chat_id: ChatId,
77    user_id: i64,
78    #[serde(skip_serializing_if = "Option::is_none")]
79    only_if_banned: Option<bool>,
80}
81
82/// Builder for the [`unbanChatMember`](https://core.telegram.org/bots/api#unbanchatmember) method.
83pub struct UnbanChatMember {
84    client: BotClient,
85    params: UnbanChatMemberParams,
86}
87
88impl UnbanChatMember {
89    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
90        Self {
91            client,
92            params: UnbanChatMemberParams {
93                chat_id: chat_id.into(),
94                user_id,
95                only_if_banned: None,
96            },
97        }
98    }
99    /// Only unbans the user if they are currently banned (ignores non-banned users).
100    pub fn only_if_banned(mut self, v: bool) -> Self {
101        self.params.only_if_banned = Some(v);
102        self
103    }
104}
105
106impl_into_future!(UnbanChatMember, bool, "unbanChatMember");
107
108// ─── restrictChatMember ───────────────────────────────────────────────────────
109
110#[derive(Serialize)]
111struct RestrictChatMemberParams {
112    chat_id: ChatId,
113    user_id: i64,
114    permissions: ChatPermissions,
115    #[serde(skip_serializing_if = "Option::is_none")]
116    use_independent_chat_permissions: Option<bool>,
117    #[serde(skip_serializing_if = "Option::is_none")]
118    until_date: Option<i64>,
119}
120
121/// Builder for the [`restrictChatMember`](https://core.telegram.org/bots/api#restrictchatmember) method.
122pub struct RestrictChatMember {
123    client: BotClient,
124    params: RestrictChatMemberParams,
125}
126
127impl RestrictChatMember {
128    pub(crate) fn new(
129        client: BotClient,
130        chat_id: impl Into<ChatId>,
131        user_id: i64,
132        permissions: ChatPermissions,
133    ) -> Self {
134        Self {
135            client,
136            params: RestrictChatMemberParams {
137                chat_id: chat_id.into(),
138                user_id,
139                permissions,
140                use_independent_chat_permissions: None,
141                until_date: None,
142            },
143        }
144    }
145    /// Restricts the user until this Unix timestamp. Omit or set to 0 for a permanent restriction.
146    pub fn until_date(mut self, ts: i64) -> Self {
147        self.params.until_date = Some(ts);
148        self
149    }
150    /// Sets whether to apply permissions independently (supergroups only).
151    pub fn use_independent_chat_permissions(mut self, v: bool) -> Self {
152        self.params.use_independent_chat_permissions = Some(v);
153        self
154    }
155}
156
157impl_into_future!(RestrictChatMember, bool, "restrictChatMember");
158
159// ─── promoteChatMember ────────────────────────────────────────────────────────
160
161#[derive(Serialize)]
162/// Parameters for a `promoteChatMember` request.
163pub struct PromoteChatMemberParams {
164    chat_id: ChatId,
165    user_id: i64,
166    /// `true` to make the admin anonymous.
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub is_anonymous: Option<bool>,
169    /// Allows the admin to manage the chat.
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub can_manage_chat: Option<bool>,
172    /// Allows the admin to delete messages of other users.
173    #[serde(skip_serializing_if = "Option::is_none")]
174    pub can_delete_messages: Option<bool>,
175    /// Allows the admin to manage video chats.
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub can_manage_video_chats: Option<bool>,
178    /// Allows the admin to restrict, ban, or unban chat members.
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub can_restrict_members: Option<bool>,
181    /// Allows the admin to add new administrators.
182    #[serde(skip_serializing_if = "Option::is_none")]
183    pub can_promote_members: Option<bool>,
184    /// Allows the admin to change the chat title, photo, and other settings.
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub can_change_info: Option<bool>,
187    /// Allows the admin to invite new users to the chat.
188    #[serde(skip_serializing_if = "Option::is_none")]
189    pub can_invite_users: Option<bool>,
190    /// Allows the admin to post messages in channels.
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub can_post_messages: Option<bool>,
193    /// Allows the admin to edit messages in channels.
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub can_edit_messages: Option<bool>,
196    /// Allows the admin to pin messages.
197    #[serde(skip_serializing_if = "Option::is_none")]
198    pub can_pin_messages: Option<bool>,
199    /// Allows the admin to manage forum topics.
200    #[serde(skip_serializing_if = "Option::is_none")]
201    pub can_manage_topics: Option<bool>,
202    /// Allows the admin to post stories.
203    #[serde(skip_serializing_if = "Option::is_none")]
204    pub can_post_stories: Option<bool>,
205    /// Allows the admin to edit stories posted by others.
206    #[serde(skip_serializing_if = "Option::is_none")]
207    pub can_edit_stories: Option<bool>,
208    /// Allows the admin to delete stories.
209    #[serde(skip_serializing_if = "Option::is_none")]
210    pub can_delete_stories: Option<bool>,
211    /// Allows the admin to manage direct messages.
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub can_manage_direct_messages: Option<bool>,
214    /// Allows the admin to manage tags.
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub can_manage_tags: Option<bool>,
217}
218
219/// Builder for the [`promoteChatMember`](https://core.telegram.org/bots/api#promotechatmember) method.
220pub struct PromoteChatMember {
221    client: BotClient,
222    params: PromoteChatMemberParams,
223}
224
225impl PromoteChatMember {
226    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
227        Self {
228            client,
229            params: PromoteChatMemberParams {
230                chat_id: chat_id.into(),
231                user_id,
232                is_anonymous: None,
233                can_manage_chat: None,
234                can_delete_messages: None,
235                can_manage_video_chats: None,
236                can_restrict_members: None,
237                can_promote_members: None,
238                can_change_info: None,
239                can_invite_users: None,
240                can_post_messages: None,
241                can_edit_messages: None,
242                can_pin_messages: None,
243                can_manage_topics: None,
244                can_post_stories: None,
245                can_edit_stories: None,
246                can_delete_stories: None,
247                can_manage_direct_messages: None,
248                can_manage_tags: None,
249            },
250        }
251    }
252    /// Allows the admin to manage the chat.
253    pub fn can_manage_chat(mut self, v: bool) -> Self {
254        self.params.can_manage_chat = Some(v);
255        self
256    }
257    /// Allows the admin to delete messages of other users.
258    pub fn can_delete_messages(mut self, v: bool) -> Self {
259        self.params.can_delete_messages = Some(v);
260        self
261    }
262    /// Allows the admin to manage video chats.
263    pub fn can_manage_video_chats(mut self, v: bool) -> Self {
264        self.params.can_manage_video_chats = Some(v);
265        self
266    }
267    /// Allows the admin to restrict, ban, or unban chat members.
268    pub fn can_restrict_members(mut self, v: bool) -> Self {
269        self.params.can_restrict_members = Some(v);
270        self
271    }
272    /// Allows the admin to add new administrators with a subset of their own privileges or demote administrators that they have promoted, directly or indirectly (promoted by administrators that were appointed by the user).
273    pub fn can_promote_members(mut self, v: bool) -> Self {
274        self.params.can_promote_members = Some(v);
275        self
276    }
277    /// Allows the admin to change the chat title, photo, and other settings.
278    pub fn can_change_info(mut self, v: bool) -> Self {
279        self.params.can_change_info = Some(v);
280        self
281    }
282    /// Allows the admin to invite new users to the chat.
283    pub fn can_invite_users(mut self, v: bool) -> Self {
284        self.params.can_invite_users = Some(v);
285        self
286    }
287    /// Allows the admin to pin messages.
288    pub fn can_pin_messages(mut self, v: bool) -> Self {
289        self.params.can_pin_messages = Some(v);
290        self
291    }
292    /// Allows the admin to manage forum topics.
293    pub fn can_manage_topics(mut self, v: bool) -> Self {
294        self.params.can_manage_topics = Some(v);
295        self
296    }
297    /// Allows the admin to post stories.
298    pub fn can_post_stories(mut self, v: bool) -> Self {
299        self.params.can_post_stories = Some(v);
300        self
301    }
302    /// Allows the admin to manage direct messages.
303    pub fn can_manage_direct_messages(mut self, v: bool) -> Self {
304        self.params.can_manage_direct_messages = Some(v);
305        self
306    }
307    /// Allows the admin to manage tags.
308    pub fn can_manage_tags(mut self, v: bool) -> Self {
309        self.params.can_manage_tags = Some(v);
310        self
311    }
312}
313
314impl_into_future!(PromoteChatMember, bool, "promoteChatMember");
315
316// ─── createChatInviteLink ─────────────────────────────────────────────────────
317
318#[derive(Serialize)]
319struct CreateChatInviteLinkParams {
320    chat_id: ChatId,
321    #[serde(skip_serializing_if = "Option::is_none")]
322    name: Option<String>,
323    #[serde(skip_serializing_if = "Option::is_none")]
324    expire_date: Option<i64>,
325    #[serde(skip_serializing_if = "Option::is_none")]
326    member_limit: Option<u32>,
327    #[serde(skip_serializing_if = "Option::is_none")]
328    creates_join_request: Option<bool>,
329}
330
331/// Builder for the [`createChatInviteLink`](https://core.telegram.org/bots/api#createchatinvitelink) method.
332pub struct CreateChatInviteLink {
333    client: BotClient,
334    params: CreateChatInviteLinkParams,
335}
336
337impl CreateChatInviteLink {
338    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
339        Self {
340            client,
341            params: CreateChatInviteLinkParams {
342                chat_id: chat_id.into(),
343                name: None,
344                expire_date: None,
345                member_limit: None,
346                creates_join_request: None,
347            },
348        }
349    }
350    /// Sets the name of the invite link (up to 32 characters).
351    pub fn name(mut self, n: impl Into<String>) -> Self {
352        self.params.name = Some(n.into());
353        self
354    }
355    /// Sets the Unix timestamp when the invite link expires.
356    pub fn expire_date(mut self, ts: i64) -> Self {
357        self.params.expire_date = Some(ts);
358        self
359    }
360    /// Limits how many users can join via this link.
361    pub fn member_limit(mut self, n: u32) -> Self {
362        self.params.member_limit = Some(n);
363        self
364    }
365    /// Makes the link require admin approval for each join request.
366    pub fn creates_join_request(mut self, v: bool) -> Self {
367        self.params.creates_join_request = Some(v);
368        self
369    }
370}
371
372impl_into_future!(CreateChatInviteLink, ChatInviteLink, "createChatInviteLink");
373
374// ─── pinChatMessage ───────────────────────────────────────────────────────────
375
376#[derive(Serialize)]
377struct PinChatMessageParams {
378    chat_id: ChatId,
379    message_id: i64,
380    #[serde(skip_serializing_if = "Option::is_none")]
381    disable_notification: Option<bool>,
382}
383
384/// Builder for the [`pinChatMessage`](https://core.telegram.org/bots/api#pinchatmessage) method.
385pub struct PinChatMessage {
386    client: BotClient,
387    params: PinChatMessageParams,
388}
389
390impl PinChatMessage {
391    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, message_id: i64) -> Self {
392        Self {
393            client,
394            params: PinChatMessageParams {
395                chat_id: chat_id.into(),
396                message_id,
397                disable_notification: None,
398            },
399        }
400    }
401    /// Pins the message without notifying members.
402    pub fn disable_notification(mut self, v: bool) -> Self {
403        self.params.disable_notification = Some(v);
404        self
405    }
406}
407
408impl_into_future!(PinChatMessage, bool, "pinChatMessage");
409
410// ─── unpinChatMessage ─────────────────────────────────────────────────────────
411
412#[derive(Serialize)]
413struct UnpinChatMessageParams {
414    chat_id: ChatId,
415    #[serde(skip_serializing_if = "Option::is_none")]
416    message_id: Option<i64>,
417}
418
419/// Builder for the [`unpinChatMessage`](https://core.telegram.org/bots/api#unpinchatmessage) method.
420pub struct UnpinChatMessage {
421    client: BotClient,
422    params: UnpinChatMessageParams,
423}
424
425impl UnpinChatMessage {
426    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
427        Self {
428            client,
429            params: UnpinChatMessageParams {
430                chat_id: chat_id.into(),
431                message_id: None,
432            },
433        }
434    }
435    /// Unpins a specific message. Omit to unpin the most recent pinned message.
436    pub fn message_id(mut self, id: i64) -> Self {
437        self.params.message_id = Some(id);
438        self
439    }
440}
441
442impl_into_future!(UnpinChatMessage, bool, "unpinChatMessage");
443
444// ─── setChatAdministratorCustomTitle ─────────────────────────────────────────
445
446#[derive(Serialize)]
447struct SetChatAdministratorCustomTitleParams {
448    chat_id: ChatId,
449    user_id: i64,
450    custom_title: String,
451}
452
453/// Builder for the [`setChatAdministratorCustomTitle`](https://core.telegram.org/bots/api#setchatadministratorcustomtitle) method.
454pub struct SetChatAdministratorCustomTitle {
455    client: BotClient,
456    params: SetChatAdministratorCustomTitleParams,
457}
458
459impl SetChatAdministratorCustomTitle {
460    pub(crate) fn new(
461        client: BotClient,
462        chat_id: impl Into<ChatId>,
463        user_id: i64,
464        custom_title: impl Into<String>,
465    ) -> Self {
466        Self {
467            client,
468            params: SetChatAdministratorCustomTitleParams {
469                chat_id: chat_id.into(),
470                user_id,
471                custom_title: custom_title.into(),
472            },
473        }
474    }
475}
476
477impl_into_future!(
478    SetChatAdministratorCustomTitle,
479    bool,
480    "setChatAdministratorCustomTitle"
481);
482
483// ─── setChatMemberTag ─────────────────────────────────────────────────────────
484
485#[derive(Serialize)]
486struct SetChatMemberTagParams {
487    chat_id: ChatId,
488    user_id: i64,
489    #[serde(skip_serializing_if = "Option::is_none")]
490    tag: Option<String>,
491}
492
493/// Builder for the [`setChatMemberTag`](https://core.telegram.org/bots/api#setchatmembertag) method.
494///
495/// Bot API 9.5 — requires the `can_manage_tags` administrator right.
496pub struct SetChatMemberTag {
497    client: BotClient,
498    params: SetChatMemberTagParams,
499}
500
501impl SetChatMemberTag {
502    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
503        Self {
504            client,
505            params: SetChatMemberTagParams {
506                chat_id: chat_id.into(),
507                user_id,
508                tag: None,
509            },
510        }
511    }
512    /// Sets the tag for the member (0–16 characters, no emoji). Omit to remove the tag.
513    pub fn tag(mut self, t: impl Into<String>) -> Self {
514        self.params.tag = Some(t.into());
515        self
516    }
517}
518
519impl_into_future!(SetChatMemberTag, bool, "setChatMemberTag");
520
521// ─── setChatPermissions ───────────────────────────────────────────────────────
522
523#[derive(Serialize)]
524struct SetChatPermissionsParams {
525    chat_id: ChatId,
526    permissions: ChatPermissions,
527    #[serde(skip_serializing_if = "Option::is_none")]
528    use_independent_chat_permissions: Option<bool>,
529}
530
531/// Builder for the [`setChatPermissions`](https://core.telegram.org/bots/api#setchatpermissions) method.
532pub struct SetChatPermissions {
533    client: BotClient,
534    params: SetChatPermissionsParams,
535}
536
537impl SetChatPermissions {
538    pub(crate) fn new(
539        client: BotClient,
540        chat_id: impl Into<ChatId>,
541        permissions: ChatPermissions,
542    ) -> Self {
543        Self {
544            client,
545            params: SetChatPermissionsParams {
546                chat_id: chat_id.into(),
547                permissions,
548                use_independent_chat_permissions: None,
549            },
550        }
551    }
552    /// Sets whether permissions are applied independently (supergroups only).
553    pub fn use_independent_chat_permissions(mut self, v: bool) -> Self {
554        self.params.use_independent_chat_permissions = Some(v);
555        self
556    }
557}
558
559impl_into_future!(SetChatPermissions, bool, "setChatPermissions");
560
561// ─── exportChatInviteLink ─────────────────────────────────────────────────────
562
563#[derive(Serialize)]
564struct ExportChatInviteLinkParams {
565    chat_id: ChatId,
566}
567
568/// Builder for the [`exportChatInviteLink`](https://core.telegram.org/bots/api#exportchatinvitelink) method.
569///
570/// Generates a new primary invite link, revoking any previously generated primary link.
571pub struct ExportChatInviteLink {
572    client: BotClient,
573    params: ExportChatInviteLinkParams,
574}
575
576impl ExportChatInviteLink {
577    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
578        Self {
579            client,
580            params: ExportChatInviteLinkParams {
581                chat_id: chat_id.into(),
582            },
583        }
584    }
585}
586
587impl_into_future!(ExportChatInviteLink, String, "exportChatInviteLink");
588
589// ─── editChatInviteLink ───────────────────────────────────────────────────────
590
591#[derive(Serialize)]
592struct EditChatInviteLinkParams {
593    chat_id: ChatId,
594    invite_link: String,
595    #[serde(skip_serializing_if = "Option::is_none")]
596    name: Option<String>,
597    #[serde(skip_serializing_if = "Option::is_none")]
598    expire_date: Option<i64>,
599    #[serde(skip_serializing_if = "Option::is_none")]
600    member_limit: Option<u32>,
601    #[serde(skip_serializing_if = "Option::is_none")]
602    creates_join_request: Option<bool>,
603}
604
605/// Builder for the [`editChatInviteLink`](https://core.telegram.org/bots/api#editchatinvitelink) method.
606pub struct EditChatInviteLink {
607    client: BotClient,
608    params: EditChatInviteLinkParams,
609}
610
611impl EditChatInviteLink {
612    pub(crate) fn new(
613        client: BotClient,
614        chat_id: impl Into<ChatId>,
615        invite_link: impl Into<String>,
616    ) -> Self {
617        Self {
618            client,
619            params: EditChatInviteLinkParams {
620                chat_id: chat_id.into(),
621                invite_link: invite_link.into(),
622                name: None,
623                expire_date: None,
624                member_limit: None,
625                creates_join_request: None,
626            },
627        }
628    }
629    /// Sets the name of the invite link (0–32 characters).
630    pub fn name(mut self, n: impl Into<String>) -> Self {
631        self.params.name = Some(n.into());
632        self
633    }
634    /// Sets the Unix timestamp when the invite link expires.
635    pub fn expire_date(mut self, ts: i64) -> Self {
636        self.params.expire_date = Some(ts);
637        self
638    }
639    /// Limits how many users can join via this link (1–99999).
640    pub fn member_limit(mut self, n: u32) -> Self {
641        self.params.member_limit = Some(n);
642        self
643    }
644    /// Makes the link require admin approval for each join request.
645    pub fn creates_join_request(mut self, v: bool) -> Self {
646        self.params.creates_join_request = Some(v);
647        self
648    }
649}
650
651impl_into_future!(EditChatInviteLink, ChatInviteLink, "editChatInviteLink");
652
653// ─── revokeChatInviteLink ─────────────────────────────────────────────────────
654
655#[derive(Serialize)]
656struct RevokeChatInviteLinkParams {
657    chat_id: ChatId,
658    invite_link: String,
659}
660
661/// Builder for the [`revokeChatInviteLink`](https://core.telegram.org/bots/api#revokechatinvitelink) method.
662pub struct RevokeChatInviteLink {
663    client: BotClient,
664    params: RevokeChatInviteLinkParams,
665}
666
667impl RevokeChatInviteLink {
668    pub(crate) fn new(
669        client: BotClient,
670        chat_id: impl Into<ChatId>,
671        invite_link: impl Into<String>,
672    ) -> Self {
673        Self {
674            client,
675            params: RevokeChatInviteLinkParams {
676                chat_id: chat_id.into(),
677                invite_link: invite_link.into(),
678            },
679        }
680    }
681}
682
683impl_into_future!(RevokeChatInviteLink, ChatInviteLink, "revokeChatInviteLink");
684
685// ─── createChatSubscriptionInviteLink ────────────────────────────────────────
686
687#[derive(Serialize)]
688struct CreateChatSubscriptionInviteLinkParams {
689    chat_id: ChatId,
690    subscription_period: u32,
691    subscription_price: u32,
692    #[serde(skip_serializing_if = "Option::is_none")]
693    name: Option<String>,
694}
695
696/// Builder for the [`createChatSubscriptionInviteLink`](https://core.telegram.org/bots/api#createchatsubscriptioninvitelink) method.
697///
698/// Creates a subscription invite link for a channel. The subscription period must currently
699/// always be `2592000` (30 days) and the price must be between 1–10000 Telegram Stars.
700pub struct CreateChatSubscriptionInviteLink {
701    client: BotClient,
702    params: CreateChatSubscriptionInviteLinkParams,
703}
704
705impl CreateChatSubscriptionInviteLink {
706    pub(crate) fn new(
707        client: BotClient,
708        chat_id: impl Into<ChatId>,
709        subscription_period: u32,
710        subscription_price: u32,
711    ) -> Self {
712        Self {
713            client,
714            params: CreateChatSubscriptionInviteLinkParams {
715                chat_id: chat_id.into(),
716                subscription_period,
717                subscription_price,
718                name: None,
719            },
720        }
721    }
722    /// Sets the name of the invite link (0–32 characters).
723    pub fn name(mut self, n: impl Into<String>) -> Self {
724        self.params.name = Some(n.into());
725        self
726    }
727}
728
729impl_into_future!(
730    CreateChatSubscriptionInviteLink,
731    ChatInviteLink,
732    "createChatSubscriptionInviteLink"
733);
734
735// ─── editChatSubscriptionInviteLink ──────────────────────────────────────────
736
737#[derive(Serialize)]
738struct EditChatSubscriptionInviteLinkParams {
739    chat_id: ChatId,
740    invite_link: String,
741    #[serde(skip_serializing_if = "Option::is_none")]
742    name: Option<String>,
743}
744
745/// Builder for the [`editChatSubscriptionInviteLink`](https://core.telegram.org/bots/api#editchatsubscriptioninvitelink) method.
746pub struct EditChatSubscriptionInviteLink {
747    client: BotClient,
748    params: EditChatSubscriptionInviteLinkParams,
749}
750
751impl EditChatSubscriptionInviteLink {
752    pub(crate) fn new(
753        client: BotClient,
754        chat_id: impl Into<ChatId>,
755        invite_link: impl Into<String>,
756    ) -> Self {
757        Self {
758            client,
759            params: EditChatSubscriptionInviteLinkParams {
760                chat_id: chat_id.into(),
761                invite_link: invite_link.into(),
762                name: None,
763            },
764        }
765    }
766    /// Sets the name of the invite link (0–32 characters).
767    pub fn name(mut self, n: impl Into<String>) -> Self {
768        self.params.name = Some(n.into());
769        self
770    }
771}
772
773impl_into_future!(
774    EditChatSubscriptionInviteLink,
775    ChatInviteLink,
776    "editChatSubscriptionInviteLink"
777);
778
779// ─── approveChatJoinRequest ───────────────────────────────────────────────────
780
781#[derive(Serialize)]
782struct ApproveChatJoinRequestParams {
783    chat_id: ChatId,
784    user_id: i64,
785}
786
787/// Builder for the [`approveChatJoinRequest`](https://core.telegram.org/bots/api#approvechatjoinrequest) method.
788pub struct ApproveChatJoinRequest {
789    client: BotClient,
790    params: ApproveChatJoinRequestParams,
791}
792
793impl ApproveChatJoinRequest {
794    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
795        Self {
796            client,
797            params: ApproveChatJoinRequestParams {
798                chat_id: chat_id.into(),
799                user_id,
800            },
801        }
802    }
803}
804
805impl_into_future!(ApproveChatJoinRequest, bool, "approveChatJoinRequest");
806
807// ─── declineChatJoinRequest ───────────────────────────────────────────────────
808
809#[derive(Serialize)]
810struct DeclineChatJoinRequestParams {
811    chat_id: ChatId,
812    user_id: i64,
813}
814
815/// Builder for the [`declineChatJoinRequest`](https://core.telegram.org/bots/api#declinechatjoinrequest) method.
816pub struct DeclineChatJoinRequest {
817    client: BotClient,
818    params: DeclineChatJoinRequestParams,
819}
820
821impl DeclineChatJoinRequest {
822    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
823        Self {
824            client,
825            params: DeclineChatJoinRequestParams {
826                chat_id: chat_id.into(),
827                user_id,
828            },
829        }
830    }
831}
832
833impl_into_future!(DeclineChatJoinRequest, bool, "declineChatJoinRequest");
834
835// ─── banChatSenderChat ────────────────────────────────────────────────────────
836
837#[derive(Serialize)]
838struct BanChatSenderChatParams {
839    chat_id: ChatId,
840    sender_chat_id: i64,
841}
842
843/// Builder for the [`banChatSenderChat`](https://core.telegram.org/bots/api#banchatsenderchat) method.
844///
845/// Bans a channel chat in a supergroup or channel. The owner of the banned chat
846/// will not be able to send messages on behalf of any of their channels until unbanned.
847pub struct BanChatSenderChat {
848    client: BotClient,
849    params: BanChatSenderChatParams,
850}
851
852impl BanChatSenderChat {
853    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, sender_chat_id: i64) -> Self {
854        Self {
855            client,
856            params: BanChatSenderChatParams {
857                chat_id: chat_id.into(),
858                sender_chat_id,
859            },
860        }
861    }
862}
863
864impl_into_future!(BanChatSenderChat, bool, "banChatSenderChat");
865
866// ─── unbanChatSenderChat ──────────────────────────────────────────────────────
867
868#[derive(Serialize)]
869struct UnbanChatSenderChatParams {
870    chat_id: ChatId,
871    sender_chat_id: i64,
872}
873
874/// Builder for the [`unbanChatSenderChat`](https://core.telegram.org/bots/api#unbanchatsenderchat) method.
875pub struct UnbanChatSenderChat {
876    client: BotClient,
877    params: UnbanChatSenderChatParams,
878}
879
880impl UnbanChatSenderChat {
881    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, sender_chat_id: i64) -> Self {
882        Self {
883            client,
884            params: UnbanChatSenderChatParams {
885                chat_id: chat_id.into(),
886                sender_chat_id,
887            },
888        }
889    }
890}
891
892impl_into_future!(UnbanChatSenderChat, bool, "unbanChatSenderChat");
893
894// ─── unpinAllChatMessages ─────────────────────────────────────────────────────
895
896#[derive(Serialize)]
897struct UnpinAllChatMessagesParams {
898    chat_id: ChatId,
899}
900
901/// Builder for the [`unpinAllChatMessages`](https://core.telegram.org/bots/api#unpinallchatmessages) method.
902///
903/// Clears the entire list of pinned messages in a chat.
904pub struct UnpinAllChatMessages {
905    client: BotClient,
906    params: UnpinAllChatMessagesParams,
907}
908
909impl UnpinAllChatMessages {
910    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
911        Self {
912            client,
913            params: UnpinAllChatMessagesParams {
914                chat_id: chat_id.into(),
915            },
916        }
917    }
918}
919
920impl_into_future!(UnpinAllChatMessages, bool, "unpinAllChatMessages");
921
922// ─── setChatPhoto ─────────────────────────────────────────────────────────────
923
924/// Builder for the [`setChatPhoto`](https://core.telegram.org/bots/api#setchatphoto) method.
925///
926/// Sets a new profile photo for the chat. Must be uploaded via multipart/form-data.
927pub struct SetChatPhoto {
928    client: BotClient,
929    chat_id: ChatId,
930    photo: InputFile,
931}
932
933impl SetChatPhoto {
934    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, photo: InputFile) -> Self {
935        Self {
936            client,
937            chat_id: chat_id.into(),
938            photo,
939        }
940    }
941}
942
943impl IntoFuture for SetChatPhoto {
944    type Output = Result<bool>;
945    type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
946
947    fn into_future(self) -> Self::IntoFuture {
948        Box::pin(async move {
949            match self.photo {
950                InputFile::Bytes {
951                    filename,
952                    data,
953                    mime_type,
954                } => {
955                    let part = Part::bytes(data)
956                        .file_name(filename)
957                        .mime_str(&mime_type)
958                        .map_err(|e| crate::error::Error::Decode(e.to_string()))?;
959                    let form = Form::new()
960                        .text("chat_id", self.chat_id.to_string())
961                        .part("photo", part);
962                    self.client.post_multipart("setChatPhoto", form).await
963                }
964                other => {
965                    let body = serde_json::json!({
966                        "chat_id": self.chat_id,
967                        "photo": other.as_str(),
968                    });
969                    self.client.post_json("setChatPhoto", &body).await
970                }
971            }
972        })
973    }
974}
975
976// ─── deleteChatPhoto ──────────────────────────────────────────────────────────
977
978#[derive(Serialize)]
979struct DeleteChatPhotoParams {
980    chat_id: ChatId,
981}
982
983/// Builder for the [`deleteChatPhoto`](https://core.telegram.org/bots/api#deletechatphoto) method.
984pub struct DeleteChatPhoto {
985    client: BotClient,
986    params: DeleteChatPhotoParams,
987}
988
989impl DeleteChatPhoto {
990    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
991        Self {
992            client,
993            params: DeleteChatPhotoParams {
994                chat_id: chat_id.into(),
995            },
996        }
997    }
998}
999
1000impl_into_future!(DeleteChatPhoto, bool, "deleteChatPhoto");
1001
1002// ─── setChatTitle ─────────────────────────────────────────────────────────────
1003
1004#[derive(Serialize)]
1005struct SetChatTitleParams {
1006    chat_id: ChatId,
1007    title: String,
1008}
1009
1010/// Builder for the [`setChatTitle`](https://core.telegram.org/bots/api#setchattitle) method.
1011pub struct SetChatTitle {
1012    client: BotClient,
1013    params: SetChatTitleParams,
1014}
1015
1016impl SetChatTitle {
1017    pub(crate) fn new(
1018        client: BotClient,
1019        chat_id: impl Into<ChatId>,
1020        title: impl Into<String>,
1021    ) -> Self {
1022        Self {
1023            client,
1024            params: SetChatTitleParams {
1025                chat_id: chat_id.into(),
1026                title: title.into(),
1027            },
1028        }
1029    }
1030}
1031
1032impl_into_future!(SetChatTitle, bool, "setChatTitle");
1033
1034// ─── setChatDescription ───────────────────────────────────────────────────────
1035
1036#[derive(Serialize)]
1037struct SetChatDescriptionParams {
1038    chat_id: ChatId,
1039    #[serde(skip_serializing_if = "Option::is_none")]
1040    description: Option<String>,
1041}
1042
1043/// Builder for the [`setChatDescription`](https://core.telegram.org/bots/api#setchatdescription) method.
1044///
1045/// Pass an empty string or omit `description` to remove the current description.
1046pub struct SetChatDescription {
1047    client: BotClient,
1048    params: SetChatDescriptionParams,
1049}
1050
1051impl SetChatDescription {
1052    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
1053        Self {
1054            client,
1055            params: SetChatDescriptionParams {
1056                chat_id: chat_id.into(),
1057                description: None,
1058            },
1059        }
1060    }
1061    /// Sets the new description (0–255 characters). Omit to clear the description.
1062    pub fn description(mut self, d: impl Into<String>) -> Self {
1063        self.params.description = Some(d.into());
1064        self
1065    }
1066}
1067
1068impl_into_future!(SetChatDescription, bool, "setChatDescription");
1069
1070// ─── setChatStickerSet ────────────────────────────────────────────────────────
1071
1072#[derive(Serialize)]
1073struct SetChatStickerSetParams {
1074    chat_id: ChatId,
1075    sticker_set_name: String,
1076}
1077
1078/// Builder for the [`setChatStickerSet`](https://core.telegram.org/bots/api#setchatstickerset) method.
1079pub struct SetChatStickerSet {
1080    client: BotClient,
1081    params: SetChatStickerSetParams,
1082}
1083
1084impl SetChatStickerSet {
1085    pub(crate) fn new(
1086        client: BotClient,
1087        chat_id: impl Into<ChatId>,
1088        sticker_set_name: impl Into<String>,
1089    ) -> Self {
1090        Self {
1091            client,
1092            params: SetChatStickerSetParams {
1093                chat_id: chat_id.into(),
1094                sticker_set_name: sticker_set_name.into(),
1095            },
1096        }
1097    }
1098}
1099
1100impl_into_future!(SetChatStickerSet, bool, "setChatStickerSet");
1101
1102// ─── deleteChatStickerSet ─────────────────────────────────────────────────────
1103
1104#[derive(Serialize)]
1105struct DeleteChatStickerSetParams {
1106    chat_id: ChatId,
1107}
1108
1109/// Builder for the [`deleteChatStickerSet`](https://core.telegram.org/bots/api#deletechatstickerset) method.
1110pub struct DeleteChatStickerSet {
1111    client: BotClient,
1112    params: DeleteChatStickerSetParams,
1113}
1114
1115impl DeleteChatStickerSet {
1116    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
1117        Self {
1118            client,
1119            params: DeleteChatStickerSetParams {
1120                chat_id: chat_id.into(),
1121            },
1122        }
1123    }
1124}
1125
1126impl_into_future!(DeleteChatStickerSet, bool, "deleteChatStickerSet");
1127
1128// ─── leaveChat ────────────────────────────────────────────────────────────────
1129
1130#[derive(Serialize)]
1131struct LeaveChatParams {
1132    chat_id: ChatId,
1133}
1134
1135/// Builder for the [`leaveChat`](https://core.telegram.org/bots/api#leavechat) method.
1136pub struct LeaveChat {
1137    client: BotClient,
1138    params: LeaveChatParams,
1139}
1140
1141impl LeaveChat {
1142    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
1143        Self {
1144            client,
1145            params: LeaveChatParams {
1146                chat_id: chat_id.into(),
1147            },
1148        }
1149    }
1150}
1151
1152impl_into_future!(LeaveChat, bool, "leaveChat");
1153
1154// ─── getUserChatBoosts ────────────────────────────────────────────────────────
1155
1156#[derive(Serialize)]
1157struct GetUserChatBoostsParams {
1158    chat_id: ChatId,
1159    user_id: i64,
1160}
1161
1162/// Builder for the [`getUserChatBoosts`](https://core.telegram.org/bots/api#getuserchatboosts) method.
1163///
1164/// Returns the list of boosts added to a chat by a specific user.
1165/// Requires administrator rights in the chat.
1166pub struct GetUserChatBoosts {
1167    client: BotClient,
1168    params: GetUserChatBoostsParams,
1169}
1170
1171impl GetUserChatBoosts {
1172    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
1173        Self {
1174            client,
1175            params: GetUserChatBoostsParams {
1176                chat_id: chat_id.into(),
1177                user_id,
1178            },
1179        }
1180    }
1181}
1182
1183impl_into_future!(GetUserChatBoosts, UserChatBoosts, "getUserChatBoosts");
1184
1185// ─── answerChatJoinRequestQuery ───────────────────────────────────────────────
1186
1187/// Outcome of a chat join request query.
1188#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1189#[serde(rename_all = "snake_case")]
1190pub enum JoinRequestResult {
1191    /// Approve the user's request and let them join.
1192    Approve,
1193    /// Decline the user's request.
1194    Decline,
1195    /// Leave the decision to other administrators.
1196    Queue,
1197}
1198
1199#[derive(Serialize)]
1200struct AnswerChatJoinRequestQueryParams {
1201    chat_join_request_query_id: String,
1202    result: JoinRequestResult,
1203}
1204
1205/// Builder for the [`answerChatJoinRequestQuery`](https://core.telegram.org/bots/api#answerchatjoinrequestquery) method.
1206pub struct AnswerChatJoinRequestQuery {
1207    client: BotClient,
1208    params: AnswerChatJoinRequestQueryParams,
1209}
1210
1211impl AnswerChatJoinRequestQuery {
1212    pub(crate) fn new(
1213        client: BotClient,
1214        chat_join_request_query_id: impl Into<String>,
1215        result: JoinRequestResult,
1216    ) -> Self {
1217        Self {
1218            client,
1219            params: AnswerChatJoinRequestQueryParams {
1220                chat_join_request_query_id: chat_join_request_query_id.into(),
1221                result,
1222            },
1223        }
1224    }
1225}
1226
1227impl_into_future!(
1228    AnswerChatJoinRequestQuery,
1229    bool,
1230    "answerChatJoinRequestQuery"
1231);
1232
1233// ─── sendChatJoinRequestWebApp ────────────────────────────────────────────────
1234
1235#[derive(Serialize)]
1236struct SendChatJoinRequestWebAppParams {
1237    chat_join_request_query_id: String,
1238    web_app_url: String,
1239}
1240
1241/// Builder for the [`sendChatJoinRequestWebApp`](https://core.telegram.org/bots/api#sendchatjoinrequestwebapp) method.
1242///
1243/// Shows a Mini App to the user before the join decision is made.
1244pub struct SendChatJoinRequestWebApp {
1245    client: BotClient,
1246    params: SendChatJoinRequestWebAppParams,
1247}
1248
1249impl SendChatJoinRequestWebApp {
1250    pub(crate) fn new(
1251        client: BotClient,
1252        chat_join_request_query_id: impl Into<String>,
1253        web_app_url: impl Into<String>,
1254    ) -> Self {
1255        Self {
1256            client,
1257            params: SendChatJoinRequestWebAppParams {
1258                chat_join_request_query_id: chat_join_request_query_id.into(),
1259                web_app_url: web_app_url.into(),
1260            },
1261        }
1262    }
1263}
1264
1265impl_into_future!(SendChatJoinRequestWebApp, bool, "sendChatJoinRequestWebApp");