Skip to main content

tgbot/types/definitions/
user.rs

1use std::{error::Error, fmt};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    api::{Method, Payload},
7    types::{Audio, Integer, Message, ParseMode, PhotoSize},
8};
9
10/// Represents the date of birth of a user.
11#[serde_with::skip_serializing_none]
12#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
13pub struct Birthdate {
14    /// Day of the user's birth; 1-31
15    pub day: Integer,
16    /// Month of the user's birth; 1-12
17    pub month: Integer,
18    /// Year of the user's birth
19    pub year: Option<Integer>,
20}
21
22impl Birthdate {
23    /// Creates a new `Birthdate`.
24    ///
25    /// # Arguments
26    ///
27    /// * `day` - Day.
28    /// * `month` - Month.
29    pub fn new(day: Integer, month: Integer) -> Self {
30        Self { day, month, year: None }
31    }
32
33    /// Sets a new year.
34    ///
35    /// # Arguments
36    ///
37    /// * `year` - Year.
38    pub fn with_year(mut self, value: Integer) -> Self {
39        self.year = Some(value);
40        self
41    }
42}
43
44/// Contains information about a user that
45/// was shared with the bot using a [`crate::types::KeyboardButtonRequestUsers`] button.
46#[serde_with::skip_serializing_none]
47#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
48pub struct SharedUser {
49    /// Identifier of the shared user.
50    ///
51    /// The bot may not have access to the user and could be unable to use this identifier,
52    /// unless the user is already known to the bot by some other means.
53    pub user_id: Integer,
54    /// First name of the user, if the name was requested by the bot.
55    pub first_name: Option<String>,
56    /// Last name of the user, if the name was requested by the bot.
57    pub last_name: Option<String>,
58    /// Available sizes of the user photo, if the photo was requested by the bot
59    pub photo: Option<Vec<PhotoSize>>,
60    /// Username of the user, if the username was requested by the bot.
61    pub username: Option<String>,
62}
63
64impl SharedUser {
65    /// Creates a new `SharedUser`.
66    ///
67    /// # Arguments
68    ///
69    /// * `user_id` - Identifier of the shared user.
70    pub fn new(user_id: Integer) -> Self {
71        Self {
72            user_id,
73            first_name: None,
74            last_name: None,
75            photo: None,
76            username: None,
77        }
78    }
79
80    /// Sets a new first name.
81    ///
82    /// # Arguments
83    ///
84    /// * `value` - First name.
85    pub fn with_first_name<T>(mut self, value: T) -> Self
86    where
87        T: Into<String>,
88    {
89        self.first_name = Some(value.into());
90        self
91    }
92
93    /// Sets a new last name.
94    ///
95    /// # Arguments
96    ///
97    /// * `value` - Last name.
98    pub fn with_last_name<T>(mut self, value: T) -> Self
99    where
100        T: Into<String>,
101    {
102        self.last_name = Some(value.into());
103        self
104    }
105
106    /// Sets new photo sizes.
107    ///
108    /// # Arguments
109    ///
110    /// * `value` - Available sizes of photo.
111    pub fn with_photo<T>(mut self, value: T) -> Self
112    where
113        T: IntoIterator<Item = PhotoSize>,
114    {
115        self.photo = Some(value.into_iter().collect());
116        self
117    }
118
119    /// Sets a new username.
120    ///
121    /// # Arguments
122    ///
123    /// * `value` - Username.
124    pub fn with_username<T>(mut self, value: T) -> Self
125    where
126        T: Into<String>,
127    {
128        self.username = Some(value.into());
129        self
130    }
131}
132
133/// Represents a user.
134#[serde_with::skip_serializing_none]
135#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
136pub struct User {
137    /// First name of the user.
138    pub first_name: String,
139    /// Unique identifier of the user.
140    pub id: UserPeerId,
141    /// Indicates whether the user is a bot.
142    pub is_bot: bool,
143    /// Indicates whether the user added the bot to the attachment menu.
144    pub added_to_attachment_menu: Option<bool>,
145    /// Indicates whether the user is a Telegram Premium user.
146    pub is_premium: Option<bool>,
147    /// [IETF language tag][1] of the user's language.
148    ///
149    /// [1]: https://en.wikipedia.org/wiki/IETF_language_tag
150    pub language_code: Option<String>,
151    /// Last name of the user.
152    pub last_name: Option<String>,
153    /// Username of the user.
154    pub username: Option<UserUsername>,
155}
156
157impl User {
158    /// Creates a new `User`.
159    ///
160    /// # Arguments
161    ///
162    /// * `id` - Unique identifier of the user.
163    /// * `first_name` - First name of the user.
164    /// * `is_bot` - Indicates whether the user is a bot.
165    pub fn new<A, B>(id: A, first_name: B, is_bot: bool) -> Self
166    where
167        A: Into<UserPeerId>,
168        B: Into<String>,
169    {
170        Self {
171            first_name: first_name.into(),
172            id: id.into(),
173            is_bot,
174            added_to_attachment_menu: None,
175            is_premium: None,
176            language_code: None,
177            last_name: None,
178            username: None,
179        }
180    }
181
182    /// Returns the full name of the user (first name + last name).
183    pub fn get_full_name(&self) -> String {
184        let mut full_name = self.first_name.clone();
185        if let Some(ref last_name) = self.last_name {
186            full_name.push(' ');
187            full_name += last_name;
188        }
189        full_name
190    }
191
192    /// Returns the link to the user (`tg://user?id=xxx`).
193    ///
194    /// These links will work only if they are used inside an inline link.
195    /// For example, they will not work,
196    /// when used in an inline keyboard button or in a message text.
197    pub fn get_link(&self) -> String {
198        format!("tg://user?id={}", self.id.0)
199    }
200
201    /// Returns the mention for the user.
202    ///
203    /// # Arguments
204    ///
205    /// * `parse_mode` - A parse mode for formatting the mention.
206    ///
207    /// These mentions are only guaranteed to work if the user has contacted the bot in the past,
208    /// has sent a callback query to the bot via inline button or is a member
209    /// in the group where he was mentioned.
210    pub fn get_link_mention(&self, parse_mode: ParseMode) -> Result<String, MentionError> {
211        let full_name = parse_mode.escape(self.get_full_name());
212        let user_link = self.get_link();
213        Ok(match parse_mode {
214            ParseMode::Markdown => return Err(MentionError::UnsupportedParseMode(parse_mode)),
215            ParseMode::MarkdownV2 => format!(r#"[{full_name}]({user_link})"#),
216            ParseMode::Html => format!(r#"<a href="{user_link}">{full_name}</a>"#),
217        })
218    }
219
220    /// Sets a new value for the `added_to_attachment_menu` flag.
221    ///
222    /// # Arguments
223    ///
224    /// * `value` - Indicates whether the user added the bot to the attachment menu.
225    pub fn with_added_to_attachment_menu(mut self, value: bool) -> Self {
226        self.added_to_attachment_menu = Some(value);
227        self
228    }
229
230    /// Sets a new value for the `is_premium` flag.
231    ///
232    /// # Arguments
233    ///
234    /// * `value` - Indicates whether the user is a Telegram Premium user.
235    pub fn with_is_premium(mut self, value: bool) -> Self {
236        self.is_premium = Some(value);
237        self
238    }
239
240    /// Sets a new language code.
241    ///
242    /// # Arguments
243    ///
244    /// * `value` - Language code.
245    pub fn with_language_code<T>(mut self, value: T) -> Self
246    where
247        T: Into<String>,
248    {
249        self.language_code = Some(value.into());
250        self
251    }
252
253    /// Sets a new last name.
254    ///
255    /// # Arguments
256    ///
257    /// * `value` - Last name.
258    pub fn with_last_name<T>(mut self, value: T) -> Self
259    where
260        T: Into<String>,
261    {
262        self.last_name = Some(value.into());
263        self
264    }
265
266    /// Sets a new username.
267    ///
268    /// # Arguments
269    ///
270    /// * `value` - Username.
271    pub fn with_username<T>(mut self, value: T) -> Self
272    where
273        T: Into<UserUsername>,
274    {
275        self.username = Some(value.into());
276        self
277    }
278}
279
280/// Represents an error occurred when getting user mention.
281#[derive(Debug)]
282pub enum MentionError {
283    /// Parse mode is not supported
284    UnsupportedParseMode(ParseMode),
285}
286
287impl Error for MentionError {}
288
289impl fmt::Display for MentionError {
290    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
291        match self {
292            MentionError::UnsupportedParseMode(parse_mode) => {
293                write!(out, "can not mention with {parse_mode} parse mode")
294            }
295        }
296    }
297}
298
299/// Represents the audios displayed on a user's profile.
300#[derive(Clone, Debug, Deserialize, Serialize)]
301pub struct UserProfileAudios {
302    /// Requested profile audios.
303    pub audios: Vec<Audio>,
304    /// Total number of profile audios for the target user.
305    pub total_count: Integer,
306}
307
308impl UserProfileAudios {
309    /// Creates a new `UserProfileAudios`.
310    ///
311    /// # Arguments
312    ///
313    /// * `audios` - A list of audios.
314    /// * `total_count` - Total number of audios.
315    pub fn new<T>(audios: T, total_count: Integer) -> Self
316    where
317        T: IntoIterator<Item = Audio>,
318    {
319        Self {
320            audios: audios.into_iter().collect(),
321            total_count,
322        }
323    }
324}
325
326/// Represents a list of profile pictures of a user.
327#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
328pub struct UserProfilePhotos {
329    /// Requested profile pictures (in up to 4 sizes each).
330    pub photos: Vec<Vec<PhotoSize>>,
331    /// Total number of profile pictures the target user has.
332    pub total_count: Integer,
333}
334
335impl UserProfilePhotos {
336    /// Creates a new `UserProfilePhotos`.
337    ///
338    /// # Arguments
339    ///
340    /// * `photos` - A list of photos.
341    /// * `total_count` - Total number of photos.
342    pub fn new<A, B>(photos: A, total_count: Integer) -> Self
343    where
344        A: IntoIterator<Item = B>,
345        B: IntoIterator<Item = PhotoSize>,
346    {
347        Self {
348            photos: photos.into_iter().map(|x| x.into_iter().collect()).collect(),
349            total_count,
350        }
351    }
352}
353
354/// ID of a user.
355#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
356#[serde(from = "Integer", into = "Integer")]
357pub struct UserPeerId(Integer);
358
359impl From<Integer> for UserPeerId {
360    fn from(value: Integer) -> Self {
361        Self(value)
362    }
363}
364
365impl From<UserPeerId> for Integer {
366    fn from(value: UserPeerId) -> Self {
367        value.0
368    }
369}
370
371impl fmt::Display for UserPeerId {
372    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373        self.0.fmt(f)
374    }
375}
376
377impl PartialEq<Integer> for UserPeerId {
378    fn eq(&self, other: &Integer) -> bool {
379        self.0.eq(other)
380    }
381}
382
383/// Describes the rating of a user based on their Telegram Star spendings.
384#[derive(Copy, Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
385pub struct UserRating {
386    /// The rating value required to get the current level.
387    pub current_level_rating: Integer,
388    /// Current level of the user, indicating their reliability when purchasing digital goods and services.
389    ///
390    /// A higher level suggests a more trustworthy customer; a negative level is likely reason for concern.
391    pub level: Integer,
392    /// Numerical value of the user's rating; the higher the rating, the better.
393    pub rating: Integer,
394    /// The rating value required to get to the next level; omitted if the maximum level was reached.
395    pub next_level_rating: Option<Integer>,
396}
397
398/// Username of a user in the format `@username`.
399#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
400#[serde(from = "String", into = "String")]
401pub struct UserUsername(String);
402
403impl From<&str> for UserUsername {
404    fn from(value: &str) -> Self {
405        Self(String::from(value))
406    }
407}
408
409impl From<String> for UserUsername {
410    fn from(value: String) -> Self {
411        Self(value)
412    }
413}
414
415impl From<UserUsername> for String {
416    fn from(value: UserUsername) -> Self {
417        value.0
418    }
419}
420
421impl fmt::Display for UserUsername {
422    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423        self.0.fmt(f)
424    }
425}
426
427impl PartialEq<String> for UserUsername {
428    fn eq(&self, other: &String) -> bool {
429        self.0.eq(other)
430    }
431}
432
433impl PartialEq<str> for UserUsername {
434    fn eq(&self, other: &str) -> bool {
435        self.0.eq(other)
436    }
437}
438
439/// Represents a user ID.
440#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
441#[serde(untagged)]
442pub enum UserId {
443    /// ID of a user.
444    Id(UserPeerId),
445    /// @username of a user.
446    Username(UserUsername),
447}
448
449impl From<&str> for UserId {
450    fn from(username: &str) -> UserId {
451        UserId::Username(String::from(username).into())
452    }
453}
454
455impl From<String> for UserId {
456    fn from(username: String) -> UserId {
457        UserId::Username(username.into())
458    }
459}
460
461impl From<Integer> for UserId {
462    fn from(id: Integer) -> UserId {
463        UserId::Id(id.into())
464    }
465}
466
467impl fmt::Display for UserId {
468    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
469        match self {
470            UserId::Id(chat_id) => write!(out, "{}", chat_id.0),
471            UserId::Username(username) => write!(out, "{}", username.0),
472        }
473    }
474}
475
476impl From<UserPeerId> for UserId {
477    fn from(value: UserPeerId) -> Self {
478        UserId::Id(value)
479    }
480}
481
482impl From<UserUsername> for UserId {
483    fn from(value: UserUsername) -> Self {
484        UserId::Username(value)
485    }
486}
487
488/// Returns the last messages from the personal chat of a given user.
489#[derive(Clone, Copy, Debug, Serialize)]
490pub struct GetUserPersonalChatMessages {
491    user_id: Integer,
492    limit: Integer,
493}
494
495impl GetUserPersonalChatMessages {
496    /// Creates a new `GetUserPersonalChatMessages`.
497    ///
498    /// # Arguments
499    ///
500    /// * `user_id` - Unique identifier of the target user.
501    /// * `limit` - The maximum number of messages to return; 1-20
502    pub fn new(user_id: Integer, limit: Integer) -> Self {
503        Self { user_id, limit }
504    }
505}
506
507impl Method for GetUserPersonalChatMessages {
508    type Response = Vec<Message>;
509
510    fn into_payload(self) -> Payload {
511        Payload::json("getUserPersonalChatMessages", self)
512    }
513}
514
515/// Returns a list of profile audios for a user.
516#[serde_with::skip_serializing_none]
517#[derive(Clone, Copy, Debug, Serialize)]
518pub struct GetUserProfileAudios {
519    user_id: Integer,
520    limit: Option<Integer>,
521    offset: Option<Integer>,
522}
523
524impl GetUserProfileAudios {
525    /// Creates a new `GetUserProfileAudios`.
526    ///
527    /// # Arguments
528    ///
529    /// * `user_id` - Unique identifier of the target user.
530    pub fn new(user_id: Integer) -> Self {
531        Self {
532            user_id,
533            limit: None,
534            offset: None,
535        }
536    }
537
538    /// Sets a new limit.
539    ///
540    /// # Arguments
541    ///
542    /// * `value` - Sequential number of the first audio to be returned.
543    ///
544    /// By default, all audios are returned.
545    pub fn with_limit(mut self, value: Integer) -> Self {
546        self.limit = Some(value);
547        self
548    }
549
550    /// Sets a new offset
551    ///
552    /// # Arguments
553    ///
554    /// * `value` - Limits the number of audios to be retrieved.
555    ///
556    /// Values between 1-100 are accepted. Defaults to 100.
557    pub fn with_offset(mut self, value: Integer) -> Self {
558        self.offset = Some(value);
559        self
560    }
561}
562
563impl Method for GetUserProfileAudios {
564    type Response = UserProfileAudios;
565
566    fn into_payload(self) -> Payload {
567        Payload::json("getUserProfileAudios", self)
568    }
569}
570
571/// Returns a list of profile pictures for a user.
572#[serde_with::skip_serializing_none]
573#[derive(Clone, Copy, Debug, Serialize)]
574pub struct GetUserProfilePhotos {
575    user_id: Integer,
576    limit: Option<Integer>,
577    offset: Option<Integer>,
578}
579
580impl GetUserProfilePhotos {
581    /// Creates a new `GetUserProfilePhotos`.
582    ///
583    /// # Arguments
584    ///
585    /// * `user_id` - Unique identifier of the target user.
586    pub fn new(user_id: Integer) -> Self {
587        GetUserProfilePhotos {
588            user_id,
589            offset: None,
590            limit: None,
591        }
592    }
593
594    /// Sets a new limit.
595    ///
596    /// # Arguments
597    ///
598    /// * `value` - Limit of the number of photos to be retrieved; 1—100; default - 100.
599    pub fn with_limit(mut self, limit: Integer) -> Self {
600        self.limit = Some(limit);
601        self
602    }
603
604    /// Sets a new offset.
605    ///
606    /// # Arguments
607    ///
608    /// * `value` - Sequential number of the first photo to be returned.
609    ///
610    /// By default, all photos are returned.
611    pub fn with_offset(mut self, offset: Integer) -> Self {
612        self.offset = Some(offset);
613        self
614    }
615}
616
617impl Method for GetUserProfilePhotos {
618    type Response = UserProfilePhotos;
619
620    fn into_payload(self) -> Payload {
621        Payload::json("getUserProfilePhotos", self)
622    }
623}
624
625/// Changes the emoji status for a given user
626/// that previously allowed the bot to manage their emoji status
627/// via the Mini App method `requestEmojiStatusAccess`.
628#[serde_with::skip_serializing_none]
629#[derive(Clone, Debug, Serialize)]
630pub struct SetUserEmojiStatus {
631    user_id: Integer,
632    emoji_status_custom_emoji_id: Option<String>,
633    emoji_status_expiration_date: Option<Integer>,
634}
635
636impl SetUserEmojiStatus {
637    /// Creates a new `SetUserEmojiStatus`.
638    ///
639    /// # Arguments
640    ///
641    /// * `user_id` - Unique identifier of the target user
642    pub fn new(user_id: Integer) -> Self {
643        Self {
644            user_id,
645            emoji_status_custom_emoji_id: None,
646            emoji_status_expiration_date: None,
647        }
648    }
649
650    /// Sets a new emoji ID.
651    ///
652    /// # Arguments
653    ///
654    /// * `value` - Custom emoji identifier of the emoji status to set.
655    ///   Pass an empty string to remove the status.
656    pub fn with_emoji_id<T>(mut self, value: T) -> Self
657    where
658        T: Into<String>,
659    {
660        self.emoji_status_custom_emoji_id = Some(value.into());
661        self
662    }
663
664    /// Sets a new expiration date.
665    ///
666    /// # Arguments
667    ///
668    /// * `value` - Expiration date of the emoji status, if any.
669    pub fn with_expiration_date(mut self, value: Integer) -> Self {
670        self.emoji_status_expiration_date = Some(value);
671        self
672    }
673}
674
675impl Method for SetUserEmojiStatus {
676    type Response = bool;
677
678    fn into_payload(self) -> Payload {
679        Payload::json("setUserEmojiStatus", self)
680    }
681}