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#[cfg(test)]
11mod tests;
12
13#[serde_with::skip_serializing_none]
15#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
16pub struct Birthdate {
17 pub day: Integer,
19 pub month: Integer,
21 pub year: Option<Integer>,
23}
24
25impl Birthdate {
26 pub fn new(day: Integer, month: Integer) -> Self {
33 Self { day, month, year: None }
34 }
35
36 pub fn with_year(mut self, value: Integer) -> Self {
42 self.year = Some(value);
43 self
44 }
45}
46
47#[serde_with::skip_serializing_none]
50#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
51pub struct SharedUser {
52 pub user_id: Integer,
57 pub first_name: Option<String>,
59 pub last_name: Option<String>,
61 pub photo: Option<Vec<PhotoSize>>,
63 pub username: Option<String>,
65}
66
67impl SharedUser {
68 pub fn new(user_id: Integer) -> Self {
74 Self {
75 user_id,
76 first_name: None,
77 last_name: None,
78 photo: None,
79 username: None,
80 }
81 }
82
83 pub fn with_first_name<T>(mut self, value: T) -> Self
89 where
90 T: Into<String>,
91 {
92 self.first_name = Some(value.into());
93 self
94 }
95
96 pub fn with_last_name<T>(mut self, value: T) -> Self
102 where
103 T: Into<String>,
104 {
105 self.last_name = Some(value.into());
106 self
107 }
108
109 pub fn with_photo<T>(mut self, value: T) -> Self
115 where
116 T: IntoIterator<Item = PhotoSize>,
117 {
118 self.photo = Some(value.into_iter().collect());
119 self
120 }
121
122 pub fn with_username<T>(mut self, value: T) -> Self
128 where
129 T: Into<String>,
130 {
131 self.username = Some(value.into());
132 self
133 }
134}
135
136#[serde_with::skip_serializing_none]
138#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
139pub struct User {
140 pub first_name: String,
142 pub id: UserPeerId,
144 pub is_bot: bool,
146 pub added_to_attachment_menu: Option<bool>,
148 pub is_premium: Option<bool>,
150 pub language_code: Option<String>,
154 pub last_name: Option<String>,
156 pub username: Option<UserUsername>,
158}
159
160impl User {
161 pub fn new<A, B>(id: A, first_name: B, is_bot: bool) -> Self
169 where
170 A: Into<UserPeerId>,
171 B: Into<String>,
172 {
173 Self {
174 first_name: first_name.into(),
175 id: id.into(),
176 is_bot,
177 added_to_attachment_menu: None,
178 is_premium: None,
179 language_code: None,
180 last_name: None,
181 username: None,
182 }
183 }
184
185 pub fn get_full_name(&self) -> String {
187 let mut full_name = self.first_name.clone();
188 if let Some(ref last_name) = self.last_name {
189 full_name.push(' ');
190 full_name += last_name;
191 }
192 full_name
193 }
194
195 pub fn get_link(&self) -> String {
201 format!("tg://user?id={}", self.id.0)
202 }
203
204 pub fn get_link_mention(&self, parse_mode: ParseMode) -> Result<String, MentionError> {
214 let full_name = parse_mode.escape(self.get_full_name());
215 let user_link = self.get_link();
216 Ok(match parse_mode {
217 ParseMode::Markdown => return Err(MentionError::UnsupportedParseMode(parse_mode)),
218 ParseMode::MarkdownV2 => format!(r#"[{}]({})"#, full_name, user_link),
219 ParseMode::Html => format!(r#"<a href="{}">{}</a>"#, user_link, full_name),
220 })
221 }
222
223 pub fn with_added_to_attachment_menu(mut self, value: bool) -> Self {
229 self.added_to_attachment_menu = Some(value);
230 self
231 }
232
233 pub fn with_is_premium(mut self, value: bool) -> Self {
239 self.is_premium = Some(value);
240 self
241 }
242
243 pub fn with_language_code<T>(mut self, value: T) -> Self
249 where
250 T: Into<String>,
251 {
252 self.language_code = Some(value.into());
253 self
254 }
255
256 pub fn with_last_name<T>(mut self, value: T) -> Self
262 where
263 T: Into<String>,
264 {
265 self.last_name = Some(value.into());
266 self
267 }
268
269 pub fn with_username<T>(mut self, value: T) -> Self
275 where
276 T: Into<UserUsername>,
277 {
278 self.username = Some(value.into());
279 self
280 }
281}
282
283#[derive(Debug)]
285pub enum MentionError {
286 UnsupportedParseMode(ParseMode),
288}
289
290impl Error for MentionError {}
291
292impl fmt::Display for MentionError {
293 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
294 match self {
295 MentionError::UnsupportedParseMode(parse_mode) => {
296 write!(out, "can not mention with {} parse mode", parse_mode)
297 }
298 }
299 }
300}
301
302#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
304pub struct UserProfilePhotos {
305 pub photos: Vec<Vec<PhotoSize>>,
307 pub total_count: Integer,
309}
310
311impl UserProfilePhotos {
312 pub fn new<A, B>(photos: A, total_count: Integer) -> Self
319 where
320 A: IntoIterator<Item = B>,
321 B: IntoIterator<Item = PhotoSize>,
322 {
323 Self {
324 photos: photos.into_iter().map(|x| x.into_iter().collect()).collect(),
325 total_count,
326 }
327 }
328}
329
330#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
332#[serde(from = "Integer", into = "Integer")]
333pub struct UserPeerId(Integer);
334
335impl From<Integer> for UserPeerId {
336 fn from(value: Integer) -> Self {
337 Self(value)
338 }
339}
340
341impl From<UserPeerId> for Integer {
342 fn from(value: UserPeerId) -> Self {
343 value.0
344 }
345}
346
347impl fmt::Display for UserPeerId {
348 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349 self.0.fmt(f)
350 }
351}
352
353impl PartialEq<Integer> for UserPeerId {
354 fn eq(&self, other: &Integer) -> bool {
355 self.0.eq(other)
356 }
357}
358
359#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
361#[serde(from = "String", into = "String")]
362pub struct UserUsername(String);
363
364impl From<&str> for UserUsername {
365 fn from(value: &str) -> Self {
366 Self(String::from(value))
367 }
368}
369
370impl From<String> for UserUsername {
371 fn from(value: String) -> Self {
372 Self(value)
373 }
374}
375
376impl From<UserUsername> for String {
377 fn from(value: UserUsername) -> Self {
378 value.0
379 }
380}
381
382impl fmt::Display for UserUsername {
383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384 self.0.fmt(f)
385 }
386}
387
388impl PartialEq<String> for UserUsername {
389 fn eq(&self, other: &String) -> bool {
390 self.0.eq(other)
391 }
392}
393
394impl PartialEq<str> for UserUsername {
395 fn eq(&self, other: &str) -> bool {
396 self.0.eq(other)
397 }
398}
399
400#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
402#[serde(untagged)]
403pub enum UserId {
404 Id(UserPeerId),
406 Username(UserUsername),
408}
409
410impl From<&str> for UserId {
411 fn from(username: &str) -> UserId {
412 UserId::Username(String::from(username).into())
413 }
414}
415
416impl From<String> for UserId {
417 fn from(username: String) -> UserId {
418 UserId::Username(username.into())
419 }
420}
421
422impl From<Integer> for UserId {
423 fn from(id: Integer) -> UserId {
424 UserId::Id(id.into())
425 }
426}
427
428impl fmt::Display for UserId {
429 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
430 match self {
431 UserId::Id(chat_id) => write!(out, "{}", chat_id.0),
432 UserId::Username(username) => write!(out, "{}", username.0),
433 }
434 }
435}
436
437impl From<UserPeerId> for UserId {
438 fn from(value: UserPeerId) -> Self {
439 UserId::Id(value)
440 }
441}
442
443impl From<UserUsername> for UserId {
444 fn from(value: UserUsername) -> Self {
445 UserId::Username(value)
446 }
447}
448
449#[serde_with::skip_serializing_none]
451#[derive(Clone, Debug, Serialize)]
452pub struct GetUserProfilePhotos {
453 user_id: Integer,
454 limit: Option<Integer>,
455 offset: Option<Integer>,
456}
457
458impl GetUserProfilePhotos {
459 pub fn new(user_id: Integer) -> Self {
465 GetUserProfilePhotos {
466 user_id,
467 offset: None,
468 limit: None,
469 }
470 }
471
472 pub fn with_limit(mut self, limit: Integer) -> Self {
478 self.limit = Some(limit);
479 self
480 }
481
482 pub fn with_offset(mut self, offset: Integer) -> Self {
490 self.offset = Some(offset);
491 self
492 }
493}
494
495impl Method for GetUserProfilePhotos {
496 type Response = UserProfilePhotos;
497
498 fn into_payload(self) -> Payload {
499 Payload::json("getUserProfilePhotos", self)
500 }
501}
502
503#[serde_with::skip_serializing_none]
507#[derive(Clone, Debug, Serialize)]
508pub struct SetUserEmojiStatus {
509 user_id: Integer,
510 emoji_status_custom_emoji_id: Option<String>,
511 emoji_status_expiration_date: Option<Integer>,
512}
513
514impl SetUserEmojiStatus {
515 pub fn new(user_id: Integer) -> Self {
521 Self {
522 user_id,
523 emoji_status_custom_emoji_id: None,
524 emoji_status_expiration_date: None,
525 }
526 }
527
528 pub fn with_emoji_id<T>(mut self, value: T) -> Self
535 where
536 T: Into<String>,
537 {
538 self.emoji_status_custom_emoji_id = Some(value.into());
539 self
540 }
541
542 pub fn with_expiration_date(mut self, value: Integer) -> Self {
548 self.emoji_status_expiration_date = Some(value);
549 self
550 }
551}
552
553impl Method for SetUserEmojiStatus {
554 type Response = bool;
555
556 fn into_payload(self) -> Payload {
557 Payload::json("setUserEmojiStatus", self)
558 }
559}