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(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
358#[serde(from = "String", into = "String")]
359pub struct UserUsername(String);
360
361impl From<&str> for UserUsername {
362 fn from(value: &str) -> Self {
363 Self(String::from(value))
364 }
365}
366
367impl From<String> for UserUsername {
368 fn from(value: String) -> Self {
369 Self(value)
370 }
371}
372
373impl From<UserUsername> for String {
374 fn from(value: UserUsername) -> Self {
375 value.0
376 }
377}
378
379impl fmt::Display for UserUsername {
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 self.0.fmt(f)
382 }
383}
384
385impl PartialEq<String> for UserUsername {
386 fn eq(&self, other: &String) -> bool {
387 self.0.eq(other)
388 }
389}
390
391impl PartialEq<str> for UserUsername {
392 fn eq(&self, other: &str) -> bool {
393 self.0.eq(other)
394 }
395}
396
397#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
399#[serde(untagged)]
400pub enum UserId {
401 Id(UserPeerId),
403 Username(UserUsername),
405}
406
407impl From<&str> for UserId {
408 fn from(username: &str) -> UserId {
409 UserId::Username(String::from(username).into())
410 }
411}
412
413impl From<String> for UserId {
414 fn from(username: String) -> UserId {
415 UserId::Username(username.into())
416 }
417}
418
419impl From<Integer> for UserId {
420 fn from(id: Integer) -> UserId {
421 UserId::Id(id.into())
422 }
423}
424
425impl fmt::Display for UserId {
426 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
427 match self {
428 UserId::Id(chat_id) => write!(out, "{}", chat_id.0),
429 UserId::Username(username) => write!(out, "{}", username.0),
430 }
431 }
432}
433
434impl From<UserPeerId> for UserId {
435 fn from(value: UserPeerId) -> Self {
436 UserId::Id(value)
437 }
438}
439
440impl From<UserUsername> for UserId {
441 fn from(value: UserUsername) -> Self {
442 UserId::Username(value)
443 }
444}
445
446#[serde_with::skip_serializing_none]
448#[derive(Clone, Debug, Serialize)]
449pub struct GetUserProfilePhotos {
450 user_id: Integer,
451 limit: Option<Integer>,
452 offset: Option<Integer>,
453}
454
455impl GetUserProfilePhotos {
456 pub fn new(user_id: Integer) -> Self {
462 GetUserProfilePhotos {
463 user_id,
464 offset: None,
465 limit: None,
466 }
467 }
468
469 pub fn with_limit(mut self, limit: Integer) -> Self {
475 self.limit = Some(limit);
476 self
477 }
478
479 pub fn with_offset(mut self, offset: Integer) -> Self {
487 self.offset = Some(offset);
488 self
489 }
490}
491
492impl Method for GetUserProfilePhotos {
493 type Response = UserProfilePhotos;
494
495 fn into_payload(self) -> Payload {
496 Payload::json("getUserProfilePhotos", self)
497 }
498}
499
500#[serde_with::skip_serializing_none]
504#[derive(Clone, Debug, Serialize)]
505pub struct SetUserEmojiStatus {
506 user_id: Integer,
507 emoji_status_custom_emoji_id: Option<String>,
508 emoji_status_expiration_date: Option<Integer>,
509}
510
511impl SetUserEmojiStatus {
512 pub fn new(user_id: Integer) -> Self {
518 Self {
519 user_id,
520 emoji_status_custom_emoji_id: None,
521 emoji_status_expiration_date: None,
522 }
523 }
524
525 pub fn with_emoji_id<T>(mut self, value: T) -> Self
532 where
533 T: Into<String>,
534 {
535 self.emoji_status_custom_emoji_id = Some(value.into());
536 self
537 }
538
539 pub fn with_expiration_date(mut self, value: Integer) -> Self {
545 self.emoji_status_expiration_date = Some(value);
546 self
547 }
548}
549
550impl Method for SetUserEmojiStatus {
551 type Response = bool;
552
553 fn into_payload(self) -> Payload {
554 Payload::json("setUserEmojiStatus", self)
555 }
556}