1use std::{error::Error, fmt};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 api::{Method, Payload},
7 types::{Integer, ParseMode, PhotoSize},
8};
9
10#[serde_with::skip_serializing_none]
12#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
13pub struct Birthdate {
14 pub day: Integer,
16 pub month: Integer,
18 pub year: Option<Integer>,
20}
21
22impl Birthdate {
23 pub fn new(day: Integer, month: Integer) -> Self {
30 Self { day, month, year: None }
31 }
32
33 pub fn with_year(mut self, value: Integer) -> Self {
39 self.year = Some(value);
40 self
41 }
42}
43
44#[serde_with::skip_serializing_none]
47#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
48pub struct SharedUser {
49 pub user_id: Integer,
54 pub first_name: Option<String>,
56 pub last_name: Option<String>,
58 pub photo: Option<Vec<PhotoSize>>,
60 pub username: Option<String>,
62}
63
64impl SharedUser {
65 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 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 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 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 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#[serde_with::skip_serializing_none]
135#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
136pub struct User {
137 pub first_name: String,
139 pub id: UserPeerId,
141 pub is_bot: bool,
143 pub added_to_attachment_menu: Option<bool>,
145 pub is_premium: Option<bool>,
147 pub language_code: Option<String>,
151 pub last_name: Option<String>,
153 pub username: Option<UserUsername>,
155}
156
157impl User {
158 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 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 pub fn get_link(&self) -> String {
198 format!("tg://user?id={}", self.id.0)
199 }
200
201 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 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 pub fn with_is_premium(mut self, value: bool) -> Self {
236 self.is_premium = Some(value);
237 self
238 }
239
240 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 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 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#[derive(Debug)]
282pub enum MentionError {
283 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#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
301pub struct UserProfilePhotos {
302 pub photos: Vec<Vec<PhotoSize>>,
304 pub total_count: Integer,
306}
307
308impl UserProfilePhotos {
309 pub fn new<A, B>(photos: A, total_count: Integer) -> Self
316 where
317 A: IntoIterator<Item = B>,
318 B: IntoIterator<Item = PhotoSize>,
319 {
320 Self {
321 photos: photos.into_iter().map(|x| x.into_iter().collect()).collect(),
322 total_count,
323 }
324 }
325}
326
327#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
329#[serde(from = "Integer", into = "Integer")]
330pub struct UserPeerId(Integer);
331
332impl From<Integer> for UserPeerId {
333 fn from(value: Integer) -> Self {
334 Self(value)
335 }
336}
337
338impl From<UserPeerId> for Integer {
339 fn from(value: UserPeerId) -> Self {
340 value.0
341 }
342}
343
344impl fmt::Display for UserPeerId {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 self.0.fmt(f)
347 }
348}
349
350impl PartialEq<Integer> for UserPeerId {
351 fn eq(&self, other: &Integer) -> bool {
352 self.0.eq(other)
353 }
354}
355
356#[derive(Copy, Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
358pub struct UserRating {
359 pub current_level_rating: Integer,
361 pub level: Integer,
365 pub rating: Integer,
367 pub next_level_rating: Option<Integer>,
369}
370
371#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
373#[serde(from = "String", into = "String")]
374pub struct UserUsername(String);
375
376impl From<&str> for UserUsername {
377 fn from(value: &str) -> Self {
378 Self(String::from(value))
379 }
380}
381
382impl From<String> for UserUsername {
383 fn from(value: String) -> Self {
384 Self(value)
385 }
386}
387
388impl From<UserUsername> for String {
389 fn from(value: UserUsername) -> Self {
390 value.0
391 }
392}
393
394impl fmt::Display for UserUsername {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 self.0.fmt(f)
397 }
398}
399
400impl PartialEq<String> for UserUsername {
401 fn eq(&self, other: &String) -> bool {
402 self.0.eq(other)
403 }
404}
405
406impl PartialEq<str> for UserUsername {
407 fn eq(&self, other: &str) -> bool {
408 self.0.eq(other)
409 }
410}
411
412#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
414#[serde(untagged)]
415pub enum UserId {
416 Id(UserPeerId),
418 Username(UserUsername),
420}
421
422impl From<&str> for UserId {
423 fn from(username: &str) -> UserId {
424 UserId::Username(String::from(username).into())
425 }
426}
427
428impl From<String> for UserId {
429 fn from(username: String) -> UserId {
430 UserId::Username(username.into())
431 }
432}
433
434impl From<Integer> for UserId {
435 fn from(id: Integer) -> UserId {
436 UserId::Id(id.into())
437 }
438}
439
440impl fmt::Display for UserId {
441 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
442 match self {
443 UserId::Id(chat_id) => write!(out, "{}", chat_id.0),
444 UserId::Username(username) => write!(out, "{}", username.0),
445 }
446 }
447}
448
449impl From<UserPeerId> for UserId {
450 fn from(value: UserPeerId) -> Self {
451 UserId::Id(value)
452 }
453}
454
455impl From<UserUsername> for UserId {
456 fn from(value: UserUsername) -> Self {
457 UserId::Username(value)
458 }
459}
460
461#[serde_with::skip_serializing_none]
463#[derive(Clone, Debug, Serialize)]
464pub struct GetUserProfilePhotos {
465 user_id: Integer,
466 limit: Option<Integer>,
467 offset: Option<Integer>,
468}
469
470impl GetUserProfilePhotos {
471 pub fn new(user_id: Integer) -> Self {
477 GetUserProfilePhotos {
478 user_id,
479 offset: None,
480 limit: None,
481 }
482 }
483
484 pub fn with_limit(mut self, limit: Integer) -> Self {
490 self.limit = Some(limit);
491 self
492 }
493
494 pub fn with_offset(mut self, offset: Integer) -> Self {
502 self.offset = Some(offset);
503 self
504 }
505}
506
507impl Method for GetUserProfilePhotos {
508 type Response = UserProfilePhotos;
509
510 fn into_payload(self) -> Payload {
511 Payload::json("getUserProfilePhotos", self)
512 }
513}
514
515#[serde_with::skip_serializing_none]
519#[derive(Clone, Debug, Serialize)]
520pub struct SetUserEmojiStatus {
521 user_id: Integer,
522 emoji_status_custom_emoji_id: Option<String>,
523 emoji_status_expiration_date: Option<Integer>,
524}
525
526impl SetUserEmojiStatus {
527 pub fn new(user_id: Integer) -> Self {
533 Self {
534 user_id,
535 emoji_status_custom_emoji_id: None,
536 emoji_status_expiration_date: None,
537 }
538 }
539
540 pub fn with_emoji_id<T>(mut self, value: T) -> Self
547 where
548 T: Into<String>,
549 {
550 self.emoji_status_custom_emoji_id = Some(value.into());
551 self
552 }
553
554 pub fn with_expiration_date(mut self, value: Integer) -> Self {
560 self.emoji_status_expiration_date = Some(value);
561 self
562 }
563}
564
565impl Method for SetUserEmojiStatus {
566 type Response = bool;
567
568 fn into_payload(self) -> Payload {
569 Payload::json("setUserEmojiStatus", self)
570 }
571}