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    /// Hides the administrator in the chat member list.
313    pub fn is_anonymous(mut self, v: bool) -> Self {
314        self.params.is_anonymous = Some(v);
315        self
316    }
317    /// Sets `can_post_messages`.
318    pub fn can_post_messages(mut self, v: bool) -> Self {
319        self.params.can_post_messages = Some(v);
320        self
321    }
322    /// Sets `can_edit_messages`.
323    pub fn can_edit_messages(mut self, v: bool) -> Self {
324        self.params.can_edit_messages = Some(v);
325        self
326    }
327    /// Sets `can_edit_stories`.
328    pub fn can_edit_stories(mut self, v: bool) -> Self {
329        self.params.can_edit_stories = Some(v);
330        self
331    }
332    /// Sets `can_delete_stories`.
333    pub fn can_delete_stories(mut self, v: bool) -> Self {
334        self.params.can_delete_stories = Some(v);
335        self
336    }
337}
338
339impl_into_future!(PromoteChatMember, bool, "promoteChatMember");
340
341// ─── createChatInviteLink ─────────────────────────────────────────────────────
342
343#[derive(Serialize)]
344struct CreateChatInviteLinkParams {
345    chat_id: ChatId,
346    #[serde(skip_serializing_if = "Option::is_none")]
347    name: Option<String>,
348    #[serde(skip_serializing_if = "Option::is_none")]
349    expire_date: Option<i64>,
350    #[serde(skip_serializing_if = "Option::is_none")]
351    member_limit: Option<u32>,
352    #[serde(skip_serializing_if = "Option::is_none")]
353    creates_join_request: Option<bool>,
354}
355
356/// Builder for the [`createChatInviteLink`](https://core.telegram.org/bots/api#createchatinvitelink) method.
357pub struct CreateChatInviteLink {
358    client: BotClient,
359    params: CreateChatInviteLinkParams,
360}
361
362impl CreateChatInviteLink {
363    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
364        Self {
365            client,
366            params: CreateChatInviteLinkParams {
367                chat_id: chat_id.into(),
368                name: None,
369                expire_date: None,
370                member_limit: None,
371                creates_join_request: None,
372            },
373        }
374    }
375    /// Sets the name of the invite link (up to 32 characters).
376    pub fn name(mut self, n: impl Into<String>) -> Self {
377        self.params.name = Some(n.into());
378        self
379    }
380    /// Sets the Unix timestamp when the invite link expires.
381    pub fn expire_date(mut self, ts: i64) -> Self {
382        self.params.expire_date = Some(ts);
383        self
384    }
385    /// Limits how many users can join via this link.
386    pub fn member_limit(mut self, n: u32) -> Self {
387        self.params.member_limit = Some(n);
388        self
389    }
390    /// Makes the link require admin approval for each join request.
391    pub fn creates_join_request(mut self, v: bool) -> Self {
392        self.params.creates_join_request = Some(v);
393        self
394    }
395}
396
397impl_into_future!(CreateChatInviteLink, ChatInviteLink, "createChatInviteLink");
398
399// ─── pinChatMessage ───────────────────────────────────────────────────────────
400
401#[derive(Serialize)]
402struct PinChatMessageParams {
403    chat_id: ChatId,
404    message_id: i64,
405    #[serde(skip_serializing_if = "Option::is_none")]
406    disable_notification: Option<bool>,
407    #[serde(skip_serializing_if = "Option::is_none")]
408    business_connection_id: Option<String>,
409}
410
411/// Builder for the [`pinChatMessage`](https://core.telegram.org/bots/api#pinchatmessage) method.
412pub struct PinChatMessage {
413    client: BotClient,
414    params: PinChatMessageParams,
415}
416
417impl PinChatMessage {
418    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, message_id: i64) -> Self {
419        Self {
420            client,
421            params: PinChatMessageParams {
422                chat_id: chat_id.into(),
423                message_id,
424                disable_notification: None,
425                business_connection_id: None,
426            },
427        }
428    }
429    /// Pins the message without notifying members.
430    pub fn disable_notification(mut self, v: bool) -> Self {
431        self.params.disable_notification = Some(v);
432        self
433    }
434    /// Business connection ID for acting on behalf of a business account.
435    pub fn business_connection_id(mut self, v: impl Into<String>) -> Self {
436        self.params.business_connection_id = Some(v.into());
437        self
438    }
439}
440
441impl_into_future!(PinChatMessage, bool, "pinChatMessage");
442
443// ─── unpinChatMessage ─────────────────────────────────────────────────────────
444
445#[derive(Serialize)]
446struct UnpinChatMessageParams {
447    chat_id: ChatId,
448    #[serde(skip_serializing_if = "Option::is_none")]
449    message_id: Option<i64>,
450    #[serde(skip_serializing_if = "Option::is_none")]
451    business_connection_id: Option<String>,
452}
453
454/// Builder for the [`unpinChatMessage`](https://core.telegram.org/bots/api#unpinchatmessage) method.
455pub struct UnpinChatMessage {
456    client: BotClient,
457    params: UnpinChatMessageParams,
458}
459
460impl UnpinChatMessage {
461    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
462        Self {
463            client,
464            params: UnpinChatMessageParams {
465                chat_id: chat_id.into(),
466                message_id: None,
467                business_connection_id: None,
468            },
469        }
470    }
471    /// Unpins a specific message. Omit to unpin the most recent pinned message.
472    pub fn message_id(mut self, id: i64) -> Self {
473        self.params.message_id = Some(id);
474        self
475    }
476    /// Business connection ID for acting on behalf of a business account.
477    pub fn business_connection_id(mut self, v: impl Into<String>) -> Self {
478        self.params.business_connection_id = Some(v.into());
479        self
480    }
481}
482
483impl_into_future!(UnpinChatMessage, bool, "unpinChatMessage");
484
485// ─── setChatAdministratorCustomTitle ─────────────────────────────────────────
486
487#[derive(Serialize)]
488struct SetChatAdministratorCustomTitleParams {
489    chat_id: ChatId,
490    user_id: i64,
491    custom_title: String,
492}
493
494/// Builder for the [`setChatAdministratorCustomTitle`](https://core.telegram.org/bots/api#setchatadministratorcustomtitle) method.
495pub struct SetChatAdministratorCustomTitle {
496    client: BotClient,
497    params: SetChatAdministratorCustomTitleParams,
498}
499
500impl SetChatAdministratorCustomTitle {
501    pub(crate) fn new(
502        client: BotClient,
503        chat_id: impl Into<ChatId>,
504        user_id: i64,
505        custom_title: impl Into<String>,
506    ) -> Self {
507        Self {
508            client,
509            params: SetChatAdministratorCustomTitleParams {
510                chat_id: chat_id.into(),
511                user_id,
512                custom_title: custom_title.into(),
513            },
514        }
515    }
516}
517
518impl_into_future!(
519    SetChatAdministratorCustomTitle,
520    bool,
521    "setChatAdministratorCustomTitle"
522);
523
524// ─── setChatMemberTag ─────────────────────────────────────────────────────────
525
526#[derive(Serialize)]
527struct SetChatMemberTagParams {
528    chat_id: ChatId,
529    user_id: i64,
530    #[serde(skip_serializing_if = "Option::is_none")]
531    tag: Option<String>,
532}
533
534/// Builder for the [`setChatMemberTag`](https://core.telegram.org/bots/api#setchatmembertag) method.
535///
536/// Bot API 9.5 — requires the `can_manage_tags` administrator right.
537pub struct SetChatMemberTag {
538    client: BotClient,
539    params: SetChatMemberTagParams,
540}
541
542impl SetChatMemberTag {
543    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
544        Self {
545            client,
546            params: SetChatMemberTagParams {
547                chat_id: chat_id.into(),
548                user_id,
549                tag: None,
550            },
551        }
552    }
553    /// Sets the tag for the member (0–16 characters, no emoji). Omit to remove the tag.
554    pub fn tag(mut self, t: impl Into<String>) -> Self {
555        self.params.tag = Some(t.into());
556        self
557    }
558}
559
560impl_into_future!(SetChatMemberTag, bool, "setChatMemberTag");
561
562// ─── setChatPermissions ───────────────────────────────────────────────────────
563
564#[derive(Serialize)]
565struct SetChatPermissionsParams {
566    chat_id: ChatId,
567    permissions: ChatPermissions,
568    #[serde(skip_serializing_if = "Option::is_none")]
569    use_independent_chat_permissions: Option<bool>,
570}
571
572/// Builder for the [`setChatPermissions`](https://core.telegram.org/bots/api#setchatpermissions) method.
573pub struct SetChatPermissions {
574    client: BotClient,
575    params: SetChatPermissionsParams,
576}
577
578impl SetChatPermissions {
579    pub(crate) fn new(
580        client: BotClient,
581        chat_id: impl Into<ChatId>,
582        permissions: ChatPermissions,
583    ) -> Self {
584        Self {
585            client,
586            params: SetChatPermissionsParams {
587                chat_id: chat_id.into(),
588                permissions,
589                use_independent_chat_permissions: None,
590            },
591        }
592    }
593    /// Sets whether permissions are applied independently (supergroups only).
594    pub fn use_independent_chat_permissions(mut self, v: bool) -> Self {
595        self.params.use_independent_chat_permissions = Some(v);
596        self
597    }
598}
599
600impl_into_future!(SetChatPermissions, bool, "setChatPermissions");
601
602// ─── exportChatInviteLink ─────────────────────────────────────────────────────
603
604#[derive(Serialize)]
605struct ExportChatInviteLinkParams {
606    chat_id: ChatId,
607}
608
609/// Builder for the [`exportChatInviteLink`](https://core.telegram.org/bots/api#exportchatinvitelink) method.
610///
611/// Generates a new primary invite link, revoking any previously generated primary link.
612pub struct ExportChatInviteLink {
613    client: BotClient,
614    params: ExportChatInviteLinkParams,
615}
616
617impl ExportChatInviteLink {
618    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
619        Self {
620            client,
621            params: ExportChatInviteLinkParams {
622                chat_id: chat_id.into(),
623            },
624        }
625    }
626}
627
628impl_into_future!(ExportChatInviteLink, String, "exportChatInviteLink");
629
630// ─── editChatInviteLink ───────────────────────────────────────────────────────
631
632#[derive(Serialize)]
633struct EditChatInviteLinkParams {
634    chat_id: ChatId,
635    invite_link: String,
636    #[serde(skip_serializing_if = "Option::is_none")]
637    name: Option<String>,
638    #[serde(skip_serializing_if = "Option::is_none")]
639    expire_date: Option<i64>,
640    #[serde(skip_serializing_if = "Option::is_none")]
641    member_limit: Option<u32>,
642    #[serde(skip_serializing_if = "Option::is_none")]
643    creates_join_request: Option<bool>,
644}
645
646/// Builder for the [`editChatInviteLink`](https://core.telegram.org/bots/api#editchatinvitelink) method.
647pub struct EditChatInviteLink {
648    client: BotClient,
649    params: EditChatInviteLinkParams,
650}
651
652impl EditChatInviteLink {
653    pub(crate) fn new(
654        client: BotClient,
655        chat_id: impl Into<ChatId>,
656        invite_link: impl Into<String>,
657    ) -> Self {
658        Self {
659            client,
660            params: EditChatInviteLinkParams {
661                chat_id: chat_id.into(),
662                invite_link: invite_link.into(),
663                name: None,
664                expire_date: None,
665                member_limit: None,
666                creates_join_request: None,
667            },
668        }
669    }
670    /// Sets the name of the invite link (0–32 characters).
671    pub fn name(mut self, n: impl Into<String>) -> Self {
672        self.params.name = Some(n.into());
673        self
674    }
675    /// Sets the Unix timestamp when the invite link expires.
676    pub fn expire_date(mut self, ts: i64) -> Self {
677        self.params.expire_date = Some(ts);
678        self
679    }
680    /// Limits how many users can join via this link (1–99999).
681    pub fn member_limit(mut self, n: u32) -> Self {
682        self.params.member_limit = Some(n);
683        self
684    }
685    /// Makes the link require admin approval for each join request.
686    pub fn creates_join_request(mut self, v: bool) -> Self {
687        self.params.creates_join_request = Some(v);
688        self
689    }
690}
691
692impl_into_future!(EditChatInviteLink, ChatInviteLink, "editChatInviteLink");
693
694// ─── revokeChatInviteLink ─────────────────────────────────────────────────────
695
696#[derive(Serialize)]
697struct RevokeChatInviteLinkParams {
698    chat_id: ChatId,
699    invite_link: String,
700}
701
702/// Builder for the [`revokeChatInviteLink`](https://core.telegram.org/bots/api#revokechatinvitelink) method.
703pub struct RevokeChatInviteLink {
704    client: BotClient,
705    params: RevokeChatInviteLinkParams,
706}
707
708impl RevokeChatInviteLink {
709    pub(crate) fn new(
710        client: BotClient,
711        chat_id: impl Into<ChatId>,
712        invite_link: impl Into<String>,
713    ) -> Self {
714        Self {
715            client,
716            params: RevokeChatInviteLinkParams {
717                chat_id: chat_id.into(),
718                invite_link: invite_link.into(),
719            },
720        }
721    }
722}
723
724impl_into_future!(RevokeChatInviteLink, ChatInviteLink, "revokeChatInviteLink");
725
726// ─── createChatSubscriptionInviteLink ────────────────────────────────────────
727
728#[derive(Serialize)]
729struct CreateChatSubscriptionInviteLinkParams {
730    chat_id: ChatId,
731    subscription_period: u32,
732    subscription_price: u32,
733    #[serde(skip_serializing_if = "Option::is_none")]
734    name: Option<String>,
735}
736
737/// Builder for the [`createChatSubscriptionInviteLink`](https://core.telegram.org/bots/api#createchatsubscriptioninvitelink) method.
738///
739/// Creates a subscription invite link for a channel. The subscription period must currently
740/// always be `2592000` (30 days) and the price must be between 1–10000 Telegram Stars.
741pub struct CreateChatSubscriptionInviteLink {
742    client: BotClient,
743    params: CreateChatSubscriptionInviteLinkParams,
744}
745
746impl CreateChatSubscriptionInviteLink {
747    pub(crate) fn new(
748        client: BotClient,
749        chat_id: impl Into<ChatId>,
750        subscription_period: u32,
751        subscription_price: u32,
752    ) -> Self {
753        Self {
754            client,
755            params: CreateChatSubscriptionInviteLinkParams {
756                chat_id: chat_id.into(),
757                subscription_period,
758                subscription_price,
759                name: None,
760            },
761        }
762    }
763    /// Sets the name of the invite link (0–32 characters).
764    pub fn name(mut self, n: impl Into<String>) -> Self {
765        self.params.name = Some(n.into());
766        self
767    }
768}
769
770impl_into_future!(
771    CreateChatSubscriptionInviteLink,
772    ChatInviteLink,
773    "createChatSubscriptionInviteLink"
774);
775
776// ─── editChatSubscriptionInviteLink ──────────────────────────────────────────
777
778#[derive(Serialize)]
779struct EditChatSubscriptionInviteLinkParams {
780    chat_id: ChatId,
781    invite_link: String,
782    #[serde(skip_serializing_if = "Option::is_none")]
783    name: Option<String>,
784}
785
786/// Builder for the [`editChatSubscriptionInviteLink`](https://core.telegram.org/bots/api#editchatsubscriptioninvitelink) method.
787pub struct EditChatSubscriptionInviteLink {
788    client: BotClient,
789    params: EditChatSubscriptionInviteLinkParams,
790}
791
792impl EditChatSubscriptionInviteLink {
793    pub(crate) fn new(
794        client: BotClient,
795        chat_id: impl Into<ChatId>,
796        invite_link: impl Into<String>,
797    ) -> Self {
798        Self {
799            client,
800            params: EditChatSubscriptionInviteLinkParams {
801                chat_id: chat_id.into(),
802                invite_link: invite_link.into(),
803                name: None,
804            },
805        }
806    }
807    /// Sets the name of the invite link (0–32 characters).
808    pub fn name(mut self, n: impl Into<String>) -> Self {
809        self.params.name = Some(n.into());
810        self
811    }
812}
813
814impl_into_future!(
815    EditChatSubscriptionInviteLink,
816    ChatInviteLink,
817    "editChatSubscriptionInviteLink"
818);
819
820// ─── approveChatJoinRequest ───────────────────────────────────────────────────
821
822#[derive(Serialize)]
823struct ApproveChatJoinRequestParams {
824    chat_id: ChatId,
825    user_id: i64,
826}
827
828/// Builder for the [`approveChatJoinRequest`](https://core.telegram.org/bots/api#approvechatjoinrequest) method.
829pub struct ApproveChatJoinRequest {
830    client: BotClient,
831    params: ApproveChatJoinRequestParams,
832}
833
834impl ApproveChatJoinRequest {
835    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
836        Self {
837            client,
838            params: ApproveChatJoinRequestParams {
839                chat_id: chat_id.into(),
840                user_id,
841            },
842        }
843    }
844}
845
846impl_into_future!(ApproveChatJoinRequest, bool, "approveChatJoinRequest");
847
848// ─── declineChatJoinRequest ───────────────────────────────────────────────────
849
850#[derive(Serialize)]
851struct DeclineChatJoinRequestParams {
852    chat_id: ChatId,
853    user_id: i64,
854}
855
856/// Builder for the [`declineChatJoinRequest`](https://core.telegram.org/bots/api#declinechatjoinrequest) method.
857pub struct DeclineChatJoinRequest {
858    client: BotClient,
859    params: DeclineChatJoinRequestParams,
860}
861
862impl DeclineChatJoinRequest {
863    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
864        Self {
865            client,
866            params: DeclineChatJoinRequestParams {
867                chat_id: chat_id.into(),
868                user_id,
869            },
870        }
871    }
872}
873
874impl_into_future!(DeclineChatJoinRequest, bool, "declineChatJoinRequest");
875
876// ─── banChatSenderChat ────────────────────────────────────────────────────────
877
878#[derive(Serialize)]
879struct BanChatSenderChatParams {
880    chat_id: ChatId,
881    sender_chat_id: i64,
882}
883
884/// Builder for the [`banChatSenderChat`](https://core.telegram.org/bots/api#banchatsenderchat) method.
885///
886/// Bans a channel chat in a supergroup or channel. The owner of the banned chat
887/// will not be able to send messages on behalf of any of their channels until unbanned.
888pub struct BanChatSenderChat {
889    client: BotClient,
890    params: BanChatSenderChatParams,
891}
892
893impl BanChatSenderChat {
894    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, sender_chat_id: i64) -> Self {
895        Self {
896            client,
897            params: BanChatSenderChatParams {
898                chat_id: chat_id.into(),
899                sender_chat_id,
900            },
901        }
902    }
903}
904
905impl_into_future!(BanChatSenderChat, bool, "banChatSenderChat");
906
907// ─── unbanChatSenderChat ──────────────────────────────────────────────────────
908
909#[derive(Serialize)]
910struct UnbanChatSenderChatParams {
911    chat_id: ChatId,
912    sender_chat_id: i64,
913}
914
915/// Builder for the [`unbanChatSenderChat`](https://core.telegram.org/bots/api#unbanchatsenderchat) method.
916pub struct UnbanChatSenderChat {
917    client: BotClient,
918    params: UnbanChatSenderChatParams,
919}
920
921impl UnbanChatSenderChat {
922    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, sender_chat_id: i64) -> Self {
923        Self {
924            client,
925            params: UnbanChatSenderChatParams {
926                chat_id: chat_id.into(),
927                sender_chat_id,
928            },
929        }
930    }
931}
932
933impl_into_future!(UnbanChatSenderChat, bool, "unbanChatSenderChat");
934
935// ─── unpinAllChatMessages ─────────────────────────────────────────────────────
936
937#[derive(Serialize)]
938struct UnpinAllChatMessagesParams {
939    chat_id: ChatId,
940}
941
942/// Builder for the [`unpinAllChatMessages`](https://core.telegram.org/bots/api#unpinallchatmessages) method.
943///
944/// Clears the entire list of pinned messages in a chat.
945pub struct UnpinAllChatMessages {
946    client: BotClient,
947    params: UnpinAllChatMessagesParams,
948}
949
950impl UnpinAllChatMessages {
951    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
952        Self {
953            client,
954            params: UnpinAllChatMessagesParams {
955                chat_id: chat_id.into(),
956            },
957        }
958    }
959}
960
961impl_into_future!(UnpinAllChatMessages, bool, "unpinAllChatMessages");
962
963// ─── setChatPhoto ─────────────────────────────────────────────────────────────
964
965/// Builder for the [`setChatPhoto`](https://core.telegram.org/bots/api#setchatphoto) method.
966///
967/// Sets a new profile photo for the chat. Must be uploaded via multipart/form-data.
968pub struct SetChatPhoto {
969    client: BotClient,
970    chat_id: ChatId,
971    photo: InputFile,
972}
973
974impl SetChatPhoto {
975    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, photo: InputFile) -> Self {
976        Self {
977            client,
978            chat_id: chat_id.into(),
979            photo,
980        }
981    }
982}
983
984impl IntoFuture for SetChatPhoto {
985    type Output = Result<bool>;
986    type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
987
988    fn into_future(self) -> Self::IntoFuture {
989        Box::pin(async move {
990            match self.photo {
991                InputFile::Bytes {
992                    filename,
993                    data,
994                    mime_type,
995                } => {
996                    let part = Part::bytes(data)
997                        .file_name(filename)
998                        .mime_str(&mime_type)
999                        .map_err(|e| crate::error::Error::Decode(e.to_string()))?;
1000                    let form = Form::new()
1001                        .text("chat_id", self.chat_id.to_string())
1002                        .part("photo", part);
1003                    self.client.post_multipart("setChatPhoto", form).await
1004                }
1005                other => {
1006                    let body = serde_json::json!({
1007                        "chat_id": self.chat_id,
1008                        "photo": other.as_str(),
1009                    });
1010                    self.client.post_json("setChatPhoto", &body).await
1011                }
1012            }
1013        })
1014    }
1015}
1016
1017// ─── deleteChatPhoto ──────────────────────────────────────────────────────────
1018
1019#[derive(Serialize)]
1020struct DeleteChatPhotoParams {
1021    chat_id: ChatId,
1022}
1023
1024/// Builder for the [`deleteChatPhoto`](https://core.telegram.org/bots/api#deletechatphoto) method.
1025pub struct DeleteChatPhoto {
1026    client: BotClient,
1027    params: DeleteChatPhotoParams,
1028}
1029
1030impl DeleteChatPhoto {
1031    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
1032        Self {
1033            client,
1034            params: DeleteChatPhotoParams {
1035                chat_id: chat_id.into(),
1036            },
1037        }
1038    }
1039}
1040
1041impl_into_future!(DeleteChatPhoto, bool, "deleteChatPhoto");
1042
1043// ─── setChatTitle ─────────────────────────────────────────────────────────────
1044
1045#[derive(Serialize)]
1046struct SetChatTitleParams {
1047    chat_id: ChatId,
1048    title: String,
1049}
1050
1051/// Builder for the [`setChatTitle`](https://core.telegram.org/bots/api#setchattitle) method.
1052pub struct SetChatTitle {
1053    client: BotClient,
1054    params: SetChatTitleParams,
1055}
1056
1057impl SetChatTitle {
1058    pub(crate) fn new(
1059        client: BotClient,
1060        chat_id: impl Into<ChatId>,
1061        title: impl Into<String>,
1062    ) -> Self {
1063        Self {
1064            client,
1065            params: SetChatTitleParams {
1066                chat_id: chat_id.into(),
1067                title: title.into(),
1068            },
1069        }
1070    }
1071}
1072
1073impl_into_future!(SetChatTitle, bool, "setChatTitle");
1074
1075// ─── setChatDescription ───────────────────────────────────────────────────────
1076
1077#[derive(Serialize)]
1078struct SetChatDescriptionParams {
1079    chat_id: ChatId,
1080    #[serde(skip_serializing_if = "Option::is_none")]
1081    description: Option<String>,
1082}
1083
1084/// Builder for the [`setChatDescription`](https://core.telegram.org/bots/api#setchatdescription) method.
1085///
1086/// Pass an empty string or omit `description` to remove the current description.
1087pub struct SetChatDescription {
1088    client: BotClient,
1089    params: SetChatDescriptionParams,
1090}
1091
1092impl SetChatDescription {
1093    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
1094        Self {
1095            client,
1096            params: SetChatDescriptionParams {
1097                chat_id: chat_id.into(),
1098                description: None,
1099            },
1100        }
1101    }
1102    /// Sets the new description (0–255 characters). Omit to clear the description.
1103    pub fn description(mut self, d: impl Into<String>) -> Self {
1104        self.params.description = Some(d.into());
1105        self
1106    }
1107}
1108
1109impl_into_future!(SetChatDescription, bool, "setChatDescription");
1110
1111// ─── setChatStickerSet ────────────────────────────────────────────────────────
1112
1113#[derive(Serialize)]
1114struct SetChatStickerSetParams {
1115    chat_id: ChatId,
1116    sticker_set_name: String,
1117}
1118
1119/// Builder for the [`setChatStickerSet`](https://core.telegram.org/bots/api#setchatstickerset) method.
1120pub struct SetChatStickerSet {
1121    client: BotClient,
1122    params: SetChatStickerSetParams,
1123}
1124
1125impl SetChatStickerSet {
1126    pub(crate) fn new(
1127        client: BotClient,
1128        chat_id: impl Into<ChatId>,
1129        sticker_set_name: impl Into<String>,
1130    ) -> Self {
1131        Self {
1132            client,
1133            params: SetChatStickerSetParams {
1134                chat_id: chat_id.into(),
1135                sticker_set_name: sticker_set_name.into(),
1136            },
1137        }
1138    }
1139}
1140
1141impl_into_future!(SetChatStickerSet, bool, "setChatStickerSet");
1142
1143// ─── deleteChatStickerSet ─────────────────────────────────────────────────────
1144
1145#[derive(Serialize)]
1146struct DeleteChatStickerSetParams {
1147    chat_id: ChatId,
1148}
1149
1150/// Builder for the [`deleteChatStickerSet`](https://core.telegram.org/bots/api#deletechatstickerset) method.
1151pub struct DeleteChatStickerSet {
1152    client: BotClient,
1153    params: DeleteChatStickerSetParams,
1154}
1155
1156impl DeleteChatStickerSet {
1157    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
1158        Self {
1159            client,
1160            params: DeleteChatStickerSetParams {
1161                chat_id: chat_id.into(),
1162            },
1163        }
1164    }
1165}
1166
1167impl_into_future!(DeleteChatStickerSet, bool, "deleteChatStickerSet");
1168
1169// ─── leaveChat ────────────────────────────────────────────────────────────────
1170
1171#[derive(Serialize)]
1172struct LeaveChatParams {
1173    chat_id: ChatId,
1174}
1175
1176/// Builder for the [`leaveChat`](https://core.telegram.org/bots/api#leavechat) method.
1177pub struct LeaveChat {
1178    client: BotClient,
1179    params: LeaveChatParams,
1180}
1181
1182impl LeaveChat {
1183    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>) -> Self {
1184        Self {
1185            client,
1186            params: LeaveChatParams {
1187                chat_id: chat_id.into(),
1188            },
1189        }
1190    }
1191}
1192
1193impl_into_future!(LeaveChat, bool, "leaveChat");
1194
1195// ─── getUserChatBoosts ────────────────────────────────────────────────────────
1196
1197#[derive(Serialize)]
1198struct GetUserChatBoostsParams {
1199    chat_id: ChatId,
1200    user_id: i64,
1201}
1202
1203/// Builder for the [`getUserChatBoosts`](https://core.telegram.org/bots/api#getuserchatboosts) method.
1204///
1205/// Returns the list of boosts added to a chat by a specific user.
1206/// Requires administrator rights in the chat.
1207pub struct GetUserChatBoosts {
1208    client: BotClient,
1209    params: GetUserChatBoostsParams,
1210}
1211
1212impl GetUserChatBoosts {
1213    pub(crate) fn new(client: BotClient, chat_id: impl Into<ChatId>, user_id: i64) -> Self {
1214        Self {
1215            client,
1216            params: GetUserChatBoostsParams {
1217                chat_id: chat_id.into(),
1218                user_id,
1219            },
1220        }
1221    }
1222}
1223
1224impl_into_future!(GetUserChatBoosts, UserChatBoosts, "getUserChatBoosts");
1225
1226// ─── answerChatJoinRequestQuery ───────────────────────────────────────────────
1227
1228/// Outcome of a chat join request query.
1229#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
1230#[serde(rename_all = "snake_case")]
1231pub enum JoinRequestResult {
1232    /// Approve the user's request and let them join.
1233    Approve,
1234    /// Decline the user's request.
1235    Decline,
1236    /// Leave the decision to other administrators.
1237    Queue,
1238}
1239
1240#[derive(Serialize)]
1241struct AnswerChatJoinRequestQueryParams {
1242    chat_join_request_query_id: String,
1243    result: JoinRequestResult,
1244}
1245
1246/// Builder for the [`answerChatJoinRequestQuery`](https://core.telegram.org/bots/api#answerchatjoinrequestquery) method.
1247pub struct AnswerChatJoinRequestQuery {
1248    client: BotClient,
1249    params: AnswerChatJoinRequestQueryParams,
1250}
1251
1252impl AnswerChatJoinRequestQuery {
1253    pub(crate) fn new(
1254        client: BotClient,
1255        chat_join_request_query_id: impl Into<String>,
1256        result: JoinRequestResult,
1257    ) -> Self {
1258        Self {
1259            client,
1260            params: AnswerChatJoinRequestQueryParams {
1261                chat_join_request_query_id: chat_join_request_query_id.into(),
1262                result,
1263            },
1264        }
1265    }
1266}
1267
1268impl_into_future!(
1269    AnswerChatJoinRequestQuery,
1270    bool,
1271    "answerChatJoinRequestQuery"
1272);
1273
1274// ─── sendChatJoinRequestWebApp ────────────────────────────────────────────────
1275
1276#[derive(Serialize)]
1277struct SendChatJoinRequestWebAppParams {
1278    chat_join_request_query_id: String,
1279    web_app_url: String,
1280}
1281
1282/// Builder for the [`sendChatJoinRequestWebApp`](https://core.telegram.org/bots/api#sendchatjoinrequestwebapp) method.
1283///
1284/// Shows a Mini App to the user before the join decision is made.
1285pub struct SendChatJoinRequestWebApp {
1286    client: BotClient,
1287    params: SendChatJoinRequestWebAppParams,
1288}
1289
1290impl SendChatJoinRequestWebApp {
1291    pub(crate) fn new(
1292        client: BotClient,
1293        chat_join_request_query_id: impl Into<String>,
1294        web_app_url: impl Into<String>,
1295    ) -> Self {
1296        Self {
1297            client,
1298            params: SendChatJoinRequestWebAppParams {
1299                chat_join_request_query_id: chat_join_request_query_id.into(),
1300                web_app_url: web_app_url.into(),
1301            },
1302        }
1303    }
1304}
1305
1306impl_into_future!(SendChatJoinRequestWebApp, bool, "sendChatJoinRequestWebApp");