tgbot/types/bot/
mod.rs

1use std::{error::Error, fmt};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    api::{Method, Payload},
7    types::{ChatAdministratorRights, ChatId, Integer},
8};
9
10#[cfg(test)]
11mod tests;
12
13/// Represents information about a bot returned in [`GetBot`].
14#[serde_with::skip_serializing_none]
15#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
16pub struct Bot {
17    /// The first name of the bot.
18    pub first_name: String,
19    /// The unique identifier for the bot.
20    pub id: Integer,
21    /// The username of the bot.
22    pub username: String,
23    /// Whether the bot can be connected to a Telegram Business account to receive its messages.
24    pub can_connect_to_business: bool,
25    /// Indicates whether the bot can be invited to groups.
26    pub can_join_groups: bool,
27    /// Indicates whether privacy mode is disabled, allowing the bot to read all group messages.
28    pub can_read_all_group_messages: bool,
29    /// Indicates whether the bot has a main Web App.
30    pub has_main_web_app: bool,
31    /// The last name of the bot.
32    pub last_name: Option<String>,
33    /// Indicates whether the bot supports inline queries.
34    pub supports_inline_queries: bool,
35}
36
37impl Bot {
38    /// Creates a new `Bot`.
39    ///
40    /// # Arguments
41    ///
42    /// * `id` - The unique identifier for the bot.
43    /// * `username` - The username of the bot.
44    /// * `first_name` - The first name of the bot.
45    pub fn new<A, B>(id: Integer, username: A, first_name: B) -> Self
46    where
47        A: Into<String>,
48        B: Into<String>,
49    {
50        Self {
51            first_name: first_name.into(),
52            id,
53            username: username.into(),
54            can_connect_to_business: false,
55            can_join_groups: false,
56            can_read_all_group_messages: false,
57            has_main_web_app: false,
58            last_name: None,
59            supports_inline_queries: false,
60        }
61    }
62
63    /// Sets a new value for the `can_connect_to_business` flag.
64    ///
65    /// # Arguments
66    ///
67    /// * `value` - Whether the bot can be connected to a Telegram Business account.
68    pub fn with_can_connect_to_business(mut self, value: bool) -> Self {
69        self.can_connect_to_business = value;
70        self
71    }
72
73    /// Sets a new value for the `can_join_groups` flag.
74    ///
75    /// # Arguments
76    ///
77    /// * `value` - Indicates whether the bot can be invited to groups.
78    pub fn with_can_join_groups(mut self, value: bool) -> Self {
79        self.can_join_groups = value;
80        self
81    }
82
83    /// Sets a new value for the `can_read_all_group_messages` flag.
84    ///
85    /// # Arguments
86    ///
87    /// * `value` - Indicates whether privacy mode is disabled.
88    pub fn with_can_read_all_group_messages(mut self, value: bool) -> Self {
89        self.can_read_all_group_messages = value;
90        self
91    }
92
93    /// Sets a new value for the `has_main_web_app` flag.
94    ///
95    /// # Arguments
96    ///
97    /// * `value` - Indicates whether the bot has a main Web App.
98    pub fn with_has_main_web_app(mut self, value: bool) -> Self {
99        self.has_main_web_app = value;
100        self
101    }
102
103    /// Sets a new value for the last name of the bot.
104    ///
105    /// # Arguments
106    ///
107    /// * `value` - The last name of the bot.
108    pub fn with_last_name<T>(mut self, value: T) -> Self
109    where
110        T: Into<String>,
111    {
112        self.last_name = Some(value.into());
113        self
114    }
115
116    /// Sets a new value for the `supports_inline_queries` flag.
117    ///
118    /// # Arguments
119    ///
120    /// * `value` - Indicates whether the bot supports inline queries.
121    pub fn with_supports_inline_queries(mut self, value: bool) -> Self {
122        self.supports_inline_queries = value;
123        self
124    }
125}
126
127/// Represents a command of a bot.
128#[derive(Clone, Debug, Deserialize, Serialize)]
129pub struct BotCommand {
130    #[serde(rename = "command")]
131    name: String,
132    description: String,
133}
134
135impl BotCommand {
136    const MIN_NAME_LEN: usize = 1;
137    const MAX_NAME_LEN: usize = 32;
138    const MIN_DESCRIPTION_LEN: usize = 3;
139    const MAX_DESCRIPTION_LEN: usize = 256;
140
141    /// Creates a new `BotCommand`.
142    ///
143    /// # Arguments
144    ///
145    /// * `name` - The name of the command; 1-32 characters;
146    ///   can contain only lowercase English letters, digits and underscores.
147    /// * `description` - The description of the command; 3-256 characters.
148    pub fn new<C, D>(name: C, description: D) -> Result<Self, BotCommandError>
149    where
150        C: Into<String>,
151        D: Into<String>,
152    {
153        let name = name.into();
154        let description = description.into();
155        let name_len = name.len();
156        let description_len = description.len();
157        if !(Self::MIN_NAME_LEN..=Self::MAX_NAME_LEN).contains(&name_len) {
158            Err(BotCommandError::BadNameLen(name_len))
159        } else if !(Self::MIN_DESCRIPTION_LEN..=Self::MAX_DESCRIPTION_LEN).contains(&description_len) {
160            Err(BotCommandError::BadDescriptionLen(description_len))
161        } else {
162            Ok(Self { name, description })
163        }
164    }
165
166    /// Returns the name of the command.
167    pub fn name(&self) -> &str {
168        &self.name
169    }
170
171    /// Sets a new name for the command.
172    ///
173    /// # Arguments
174    ///
175    /// * `value` - The new name.
176    pub fn with_name<T>(mut self, value: T) -> Self
177    where
178        T: Into<String>,
179    {
180        self.name = value.into();
181        self
182    }
183
184    /// Returns the description of the command.
185    pub fn description(&self) -> &str {
186        &self.description
187    }
188
189    /// Sets a new description for the command.
190    ///
191    /// # Arguments
192    ///
193    /// * `value` - The new description.
194    pub fn with_description<T>(mut self, value: T) -> Self
195    where
196        T: Into<String>,
197    {
198        self.description = value.into();
199        self
200    }
201}
202
203/// Represents an error that can occur when creating a new [`BotCommand`].
204#[derive(Debug)]
205pub enum BotCommandError {
206    /// The provided name has an invalid length.
207    BadNameLen(usize),
208    /// The provided description has an invalid length.
209    BadDescriptionLen(usize),
210}
211
212impl Error for BotCommandError {}
213
214impl fmt::Display for BotCommandError {
215    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
216        use self::BotCommandError::*;
217        match self {
218            BadNameLen(len) => write!(
219                out,
220                "command name can have a length of {} up to {} characters, got {}",
221                BotCommand::MIN_NAME_LEN,
222                BotCommand::MAX_NAME_LEN,
223                len
224            ),
225            BadDescriptionLen(len) => write!(
226                out,
227                "command description can have a length of {} up to {} characters, got {}",
228                BotCommand::MIN_DESCRIPTION_LEN,
229                BotCommand::MAX_DESCRIPTION_LEN,
230                len
231            ),
232        }
233    }
234}
235
236/// Represents a scope to which bot commands are applied.
237#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
238#[serde(tag = "type")]
239#[serde(rename_all = "snake_case")]
240pub enum BotCommandScope {
241    /// All group and supergroup chat administrators.
242    AllChatAdministrators,
243    /// All group and supergroup chats.
244    AllGroupChats,
245    /// All private chats.
246    AllPrivateChats,
247    /// A specific chat.
248    Chat {
249        /// Unique identifier of the target chat.
250        chat_id: ChatId,
251    },
252    /// All administrators of a specific group or supergroup chat.
253    ChatAdministrators {
254        /// Unique identifier of the target chat.
255        chat_id: ChatId,
256    },
257    /// A specific member of a group or supergroup chat.
258    ChatMember {
259        /// Unique identifier of the target chat.
260        chat_id: ChatId,
261        /// Unique identifier of the target user.
262        user_id: Integer,
263    },
264    /// Default scope.
265    ///
266    /// Default commands are used if no commands with a narrower scope are specified for a user.
267    Default,
268}
269
270impl BotCommandScope {
271    /// Creates a new `BotCommandScope` covering a specific chat.
272    ///
273    /// # Arguments
274    ///
275    /// * `value` - Chat ID.
276    pub fn chat<T>(value: T) -> Self
277    where
278        T: Into<ChatId>,
279    {
280        Self::Chat { chat_id: value.into() }
281    }
282
283    /// Creates a new `BotCommandScope` covering all administrators
284    /// of a specific group or supergroup chat.
285    ///
286    /// # Arguments
287    ///
288    /// * `value` - Chat ID.
289    pub fn chat_administrators<T>(value: T) -> Self
290    where
291        T: Into<ChatId>,
292    {
293        Self::ChatAdministrators { chat_id: value.into() }
294    }
295
296    /// Creates a new `BotCommandScope` covering a specific member of a group or supergroup chat.
297    ///
298    /// # Arguments
299    ///
300    /// * `chat_id` - Chat ID.
301    /// * `user_id` - User ID.
302    pub fn chat_member<A>(chat_id: A, user_id: Integer) -> Self
303    where
304        A: Into<ChatId>,
305    {
306        Self::ChatMember {
307            chat_id: chat_id.into(),
308            user_id,
309        }
310    }
311}
312
313/// Represents a description of a bot.
314#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
315pub struct BotDescription {
316    /// The description of the bot.
317    pub description: String,
318}
319
320impl BotDescription {
321    /// Creates a new `BotDescription`.
322    ///
323    /// # Arguments
324    ///
325    /// * `value` - The description of the bot.
326    pub fn new<T>(value: T) -> Self
327    where
328        T: Into<String>,
329    {
330        Self {
331            description: value.into(),
332        }
333    }
334}
335
336/// Represents a name of a bot.
337#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
338pub struct BotName {
339    /// The name of the bot.
340    pub name: String,
341}
342
343impl BotName {
344    /// Creates a new `BotName`.
345    ///
346    /// # Arguments
347    ///
348    /// * `value` - The name of the bot.
349    pub fn new<T>(value: T) -> Self
350    where
351        T: Into<String>,
352    {
353        Self { name: value.into() }
354    }
355}
356
357/// Represents a short description of a bot.
358#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
359pub struct BotShortDescription {
360    /// The short description of the bot.
361    pub short_description: String,
362}
363
364impl BotShortDescription {
365    /// Creates a new `BotShortDescription`.
366    ///
367    /// # Arguments
368    ///
369    /// * `value` - The short description of the bot.
370    pub fn new<T>(value: T) -> Self
371    where
372        T: Into<String>,
373    {
374        Self {
375            short_description: value.into(),
376        }
377    }
378}
379
380/// Closes a bot instance before moving it from one local server to another.
381///
382/// You need to delete the webhook before calling this method to ensure
383/// that the bot isn't launched again after server restart.
384///
385/// The method will return error 429 in the first 10 minutes after the bot is launched.
386#[derive(Clone, Copy, Debug)]
387pub struct Close;
388
389impl Method for Close {
390    type Response = bool;
391
392    fn into_payload(self) -> Payload {
393        Payload::empty("close")
394    }
395}
396
397/// Deletes a list of a bot commands of a given scope and user language.
398///
399/// After deletion, higher level commands will be shown to affected users.
400#[serde_with::skip_serializing_none]
401#[derive(Clone, Debug, Default, Serialize)]
402pub struct DeleteBotCommands {
403    language_code: Option<String>,
404    scope: Option<BotCommandScope>,
405}
406
407impl DeleteBotCommands {
408    /// Sets a new language code.
409    ///
410    /// # Arguments
411    ///
412    /// * `value` - Two-letter ISO 639-1 language code or an empty string.
413    pub fn with_language_code<T>(mut self, value: T) -> Self
414    where
415        T: Into<String>,
416    {
417        self.language_code = Some(value.into());
418        self
419    }
420
421    /// Sets a new scope of users.
422    ///
423    /// # Arguments
424    ///
425    /// * `value` - Scope; default - [`BotCommandScope::Default`].
426    pub fn with_scope(mut self, value: BotCommandScope) -> Self {
427        self.scope = Some(value);
428        self
429    }
430}
431
432impl Method for DeleteBotCommands {
433    type Response = bool;
434
435    fn into_payload(self) -> Payload {
436        Payload::json("deleteMyCommands", self)
437    }
438}
439
440/// Returns a basic information about a bot.
441#[derive(Clone, Copy, Debug)]
442pub struct GetBot;
443
444impl Method for GetBot {
445    type Response = Bot;
446
447    fn into_payload(self) -> Payload {
448        Payload::empty("getMe")
449    }
450}
451
452/// Returns the current list of bot commands.
453#[serde_with::skip_serializing_none]
454#[derive(Clone, Debug, Default, Serialize)]
455pub struct GetBotCommands {
456    language_code: Option<String>,
457    scope: Option<BotCommandScope>,
458}
459
460impl GetBotCommands {
461    /// Sets a new language code.
462    ///
463    /// # Arguments
464    ///
465    /// * `value` - Two-letter ISO 639-1 language code or an empty string.
466    pub fn with_language_code<T>(mut self, value: T) -> Self
467    where
468        T: Into<String>,
469    {
470        self.language_code = Some(value.into());
471        self
472    }
473
474    /// Sets a new scope.
475    ///
476    /// # Arguments
477    ///
478    /// * `value` - Scope of users; default - [`BotCommandScope::Default`].
479    pub fn with_scope(mut self, value: BotCommandScope) -> Self {
480        self.scope = Some(value);
481        self
482    }
483}
484
485impl Method for GetBotCommands {
486    type Response = Vec<BotCommand>;
487
488    fn into_payload(self) -> Payload {
489        Payload::json("getMyCommands", self)
490    }
491}
492
493/// Returns the current default administrator rights of a bot.
494#[serde_with::skip_serializing_none]
495#[derive(Clone, Copy, Debug, Default, Serialize)]
496pub struct GetBotDefaultAdministratorRights {
497    for_channels: Option<bool>,
498}
499
500impl GetBotDefaultAdministratorRights {
501    /// Sets a new value of a `for_channels` flag.
502    ///
503    /// # Arguments
504    ///
505    /// * `value` - For channels - `true`; for groups and supergroups - `false`.
506    pub fn with_for_channels(mut self, value: bool) -> Self {
507        self.for_channels = Some(value);
508        self
509    }
510}
511
512impl Method for GetBotDefaultAdministratorRights {
513    type Response = ChatAdministratorRights;
514
515    fn into_payload(self) -> Payload {
516        Payload::json("getMyDefaultAdministratorRights", self)
517    }
518}
519
520/// Returns the current description of a bot for a given user language.
521#[serde_with::skip_serializing_none]
522#[derive(Clone, Debug, Default, Serialize)]
523pub struct GetBotDescription {
524    language_code: Option<String>,
525}
526
527impl GetBotDescription {
528    /// Sets a new language code.
529    ///
530    /// # Arguments
531    ///
532    /// * `value` - Two-letter ISO 639-1 language code or an empty string.
533    pub fn with_language_code<T>(mut self, value: T) -> Self
534    where
535        T: Into<String>,
536    {
537        self.language_code = Some(value.into());
538        self
539    }
540}
541
542impl Method for GetBotDescription {
543    type Response = BotDescription;
544
545    fn into_payload(self) -> Payload {
546        Payload::json("getMyDescription", self)
547    }
548}
549
550/// Returns the current name of a bot for a given user language.
551#[serde_with::skip_serializing_none]
552#[derive(Clone, Debug, Default, Serialize)]
553pub struct GetBotName {
554    language_code: Option<String>,
555}
556
557impl GetBotName {
558    /// Sets a new language code.
559    ///
560    /// # Arguments
561    ///
562    /// * `value` - Two-letter ISO 639-1 language code or an empty string.
563    pub fn with_language_code<T>(mut self, value: T) -> Self
564    where
565        T: Into<String>,
566    {
567        self.language_code = Some(value.into());
568        self
569    }
570}
571
572impl Method for GetBotName {
573    type Response = BotName;
574
575    fn into_payload(self) -> Payload {
576        Payload::json("getMyName", self)
577    }
578}
579
580/// Returns the current short description of a bot for a given user language.
581#[serde_with::skip_serializing_none]
582#[derive(Clone, Debug, Default, Serialize)]
583pub struct GetBotShortDescription {
584    language_code: Option<String>,
585}
586
587impl GetBotShortDescription {
588    /// Sets a new language code.
589    ///
590    /// # Arguments
591    ///
592    /// * `value` - Two-letter ISO 639-1 language code or an empty string.
593    pub fn with_language_code<T>(mut self, value: T) -> Self
594    where
595        T: Into<String>,
596    {
597        self.language_code = Some(value.into());
598        self
599    }
600}
601
602impl Method for GetBotShortDescription {
603    type Response = BotShortDescription;
604
605    fn into_payload(self) -> Payload {
606        Payload::json("getMyShortDescription", self)
607    }
608}
609
610/// Logs out from the Cloud Bot API.
611///
612/// You must log out a bot before running it locally,
613/// otherwise there is no guarantee that the bot will receive updates.
614///
615/// After a successful call, you can immediately log in on a local server,
616/// but will not be able to log in back to the Cloud Bot API server for 10 minutes.
617#[derive(Clone, Copy, Debug)]
618pub struct LogOut;
619
620impl Method for LogOut {
621    type Response = bool;
622
623    fn into_payload(self) -> Payload {
624        Payload::empty("logOut")
625    }
626}
627
628/// Changes a list of commands of a bot.
629#[serde_with::skip_serializing_none]
630#[derive(Clone, Debug, Serialize)]
631pub struct SetBotCommands {
632    commands: Vec<BotCommand>,
633    language_code: Option<String>,
634    scope: Option<BotCommandScope>,
635}
636
637impl SetBotCommands {
638    /// Creates a new `SetBotCommands`.
639    ///
640    /// # Arguments
641    ///
642    /// * `commands` - Commands to set.
643    pub fn new(commands: impl IntoIterator<Item = BotCommand>) -> Self {
644        Self {
645            commands: commands.into_iter().collect(),
646            language_code: None,
647            scope: None,
648        }
649    }
650
651    /// Sets a new language code.
652    ///
653    /// # Arguments
654    ///
655    /// * `value` - Two-letter ISO 639-1 language code;
656    ///   if empty, commands will be applied to all users from the given scope,
657    ///   for whose language there are no dedicated commands.
658    pub fn with_language_code<T>(mut self, value: T) -> Self
659    where
660        T: Into<String>,
661    {
662        self.language_code = Some(value.into());
663        self
664    }
665
666    /// Sets a new scope.
667    ///
668    /// # Arguments
669    ///
670    /// * `value` - Scope of users for which the commands are relevant;
671    ///   default - [`BotCommandScope::Default`].
672    pub fn with_scope(mut self, value: BotCommandScope) -> Self {
673        self.scope = Some(value);
674        self
675    }
676}
677
678impl Method for SetBotCommands {
679    type Response = bool;
680
681    fn into_payload(self) -> Payload {
682        Payload::json("setMyCommands", self)
683    }
684}
685
686/// Changes default administrator rights requested by a bot
687/// when it's added as an administrator to groups or channels.
688///
689/// These rights will be suggested to users,
690/// but they are free to modify the list before adding the bot.
691#[serde_with::skip_serializing_none]
692#[derive(Clone, Copy, Debug, Default, Serialize)]
693pub struct SetBotDefaultAdministratorRights {
694    for_channels: Option<bool>,
695    rights: Option<ChatAdministratorRights>,
696}
697
698impl SetBotDefaultAdministratorRights {
699    /// Sets a new value of a `for_channels` flag.
700    ///
701    /// # Arguments
702    ///
703    /// * `value` - For channels - `true`; for groups and supergroups - `false`.
704    pub fn with_for_channels(mut self, value: bool) -> Self {
705        self.for_channels = Some(value);
706        self
707    }
708
709    /// Sets new default administrator rights
710    ///
711    /// # Arguments
712    ///
713    /// * `value` - Default administrator rights;
714    ///   if not specified, the default administrator rights will be cleared.
715    pub fn with_rights(mut self, value: ChatAdministratorRights) -> Self {
716        self.rights = Some(value);
717        self
718    }
719}
720
721impl Method for SetBotDefaultAdministratorRights {
722    type Response = bool;
723
724    fn into_payload(self) -> Payload {
725        Payload::json("setMyDefaultAdministratorRights", self)
726    }
727}
728
729/// Changes the description of a bot, which is shown in a chat with the bot if the chat is empty.
730#[serde_with::skip_serializing_none]
731#[derive(Clone, Debug, Default, Serialize)]
732pub struct SetBotDescription {
733    description: Option<String>,
734    language_code: Option<String>,
735}
736
737impl SetBotDescription {
738    /// Sets a new description.
739    ///
740    /// # Arguments
741    ///
742    /// * `value` - Description of the bot; 0-512 characters;
743    ///   pass an empty string to remove the dedicated description
744    ///   of the given language.
745    pub fn with_description<T>(mut self, value: T) -> Self
746    where
747        T: Into<String>,
748    {
749        self.description = Some(value.into());
750        self
751    }
752
753    /// Sets a new language code.
754    ///
755    /// # Arguments
756    ///
757    /// * `value` - Two-letter ISO 639-1 language code;
758    ///   if empty, the description will be applied to all users
759    ///   for whose language there is no dedicated description.
760    pub fn with_language_code<T>(mut self, value: T) -> Self
761    where
762        T: Into<String>,
763    {
764        self.language_code = Some(value.into());
765        self
766    }
767}
768
769impl Method for SetBotDescription {
770    type Response = bool;
771
772    fn into_payload(self) -> Payload {
773        Payload::json("setMyDescription", self)
774    }
775}
776
777/// Changes the name of a bot.
778#[serde_with::skip_serializing_none]
779#[derive(Clone, Debug, Default, Serialize)]
780pub struct SetBotName {
781    language_code: Option<String>,
782    name: Option<String>,
783}
784
785impl SetBotName {
786    /// Sets a new language code.
787    ///
788    /// # Arguments
789    ///
790    /// * `value` - Two-letter ISO 639-1 language code;
791    ///   if empty, the name will be shown to all users
792    ///   for whose language there is no dedicated name.
793    pub fn with_language_code<T>(mut self, value: T) -> Self
794    where
795        T: Into<String>,
796    {
797        self.language_code = Some(value.into());
798        self
799    }
800
801    /// Sets a new name of a bot.
802    ///
803    /// # Arguments
804    ///
805    /// * `value` - New name of the bot; 0-64 characters;
806    ///   pass an empty string to remove the dedicated name
807    ///   of the given language.
808    pub fn with_name<T>(mut self, value: T) -> Self
809    where
810        T: Into<String>,
811    {
812        self.name = Some(value.into());
813        self
814    }
815}
816
817impl Method for SetBotName {
818    type Response = bool;
819
820    fn into_payload(self) -> Payload {
821        Payload::json("setMyName", self)
822    }
823}
824
825/// Changes the short description of a bot, which is shown on the bot profile page
826/// and is sent together with the link when users share the bot.
827#[serde_with::skip_serializing_none]
828#[derive(Clone, Debug, Default, Serialize)]
829pub struct SetBotShortDescription {
830    language_code: Option<String>,
831    short_description: Option<String>,
832}
833
834impl SetBotShortDescription {
835    /// Sets a new language code.
836    ///
837    /// # Arguments
838    ///
839    /// * `value` - Two-letter ISO 639-1 language code;
840    ///   if empty, the short description will be applied
841    ///   to all users for whose language there is no dedicated short description.
842    pub fn with_language_code<T>(mut self, value: T) -> Self
843    where
844        T: Into<String>,
845    {
846        self.language_code = Some(value.into());
847        self
848    }
849
850    /// Sets a new short description.
851    ///
852    /// # Arguments
853    ///
854    /// * `value` - Short description of a bot; 0-120 characters;
855    ///   pass an empty string to remove the dedicated short description
856    ///   of the given language.
857    pub fn with_short_description<T>(mut self, value: T) -> Self
858    where
859        T: Into<String>,
860    {
861        self.short_description = Some(value.into());
862        self
863    }
864}
865
866impl Method for SetBotShortDescription {
867    type Response = bool;
868
869    fn into_payload(self) -> Payload {
870        Payload::json("setMyShortDescription", self)
871    }
872}