1#![allow(clippy::large_enum_variant)]
2use serde::{de::MapAccess, Deserialize, Serialize, Serializer};
3use serde_json::Value;
4
5use crate::types::{
6 CallbackQuery, Chat, ChatJoinRequest, ChatMemberUpdated, ChosenInlineResult, InlineQuery,
7 Message, Poll, PollAnswer, PreCheckoutQuery, ShippingQuery, User,
8};
9
10#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
16pub struct Update {
17 #[serde(rename = "update_id")]
25 pub id: i32,
26
27 #[serde(flatten)]
28 pub kind: UpdateKind,
29}
30
31impl Update {
32 #[must_use]
40 pub fn from(&self) -> Option<&User> {
41 use UpdateKind::*;
42
43 let from = match &self.kind {
44 Message(m) | EditedMessage(m) | ChannelPost(m) | EditedChannelPost(m) => m.from()?,
45
46 CallbackQuery(query) => &query.from,
47 ChosenInlineResult(chosen) => &chosen.from,
48 InlineQuery(query) => &query.from,
49 ShippingQuery(query) => &query.from,
50 PreCheckoutQuery(query) => &query.from,
51 PollAnswer(answer) => &answer.user,
52
53 MyChatMember(m) | ChatMember(m) => &m.from,
54 ChatJoinRequest(r) => &r.from,
55
56 Poll(_) | Error(_) => return None,
57 };
58
59 Some(from)
60 }
61
62 pub fn mentioned_users(&self) -> impl Iterator<Item = &User> {
70 use either::Either::{Left, Right};
71 use std::iter::{empty, once};
72
73 let i0 = Left;
74 let i1 = |x| Right(Left(x));
75 let i2 = |x| Right(Right(Left(x)));
76 let i3 = |x| Right(Right(Right(Left(x))));
77 let i4 = |x| Right(Right(Right(Right(Left(x)))));
78 let i5 = |x| Right(Right(Right(Right(Right(Left(x))))));
79 let i6 = |x| Right(Right(Right(Right(Right(Right(x))))));
80
81 match &self.kind {
82 UpdateKind::Message(message)
83 | UpdateKind::EditedMessage(message)
84 | UpdateKind::ChannelPost(message)
85 | UpdateKind::EditedChannelPost(message) => i0(message.mentioned_users()),
86
87 UpdateKind::InlineQuery(query) => i1(once(&query.from)),
88 UpdateKind::ChosenInlineResult(query) => i1(once(&query.from)),
89 UpdateKind::CallbackQuery(query) => i2(query.mentioned_users()),
90 UpdateKind::ShippingQuery(query) => i1(once(&query.from)),
91 UpdateKind::PreCheckoutQuery(query) => i1(once(&query.from)),
92 UpdateKind::Poll(poll) => i3(poll.mentioned_users()),
93
94 UpdateKind::PollAnswer(answer) => i1(once(&answer.user)),
95
96 UpdateKind::MyChatMember(member) | UpdateKind::ChatMember(member) => {
97 i4(member.mentioned_users())
98 }
99 UpdateKind::ChatJoinRequest(request) => i5(request.mentioned_users()),
100 UpdateKind::Error(_) => i6(empty()),
101 }
102 }
103
104 #[must_use]
106 pub fn chat(&self) -> Option<&Chat> {
107 use UpdateKind::*;
108
109 let chat = match &self.kind {
110 Message(m) | EditedMessage(m) | ChannelPost(m) | EditedChannelPost(m) => &m.chat,
111 CallbackQuery(q) => &q.message.as_ref()?.chat,
112 ChatMember(m) => &m.chat,
113 MyChatMember(m) => &m.chat,
114 ChatJoinRequest(c) => &c.chat,
115
116 InlineQuery(_)
117 | ChosenInlineResult(_)
118 | ShippingQuery(_)
119 | PreCheckoutQuery(_)
120 | Poll(_)
121 | PollAnswer(_)
122 | Error(_) => return None,
123 };
124
125 Some(chat)
126 }
127
128 #[deprecated(note = "renamed to `from`", since = "0.10.0")]
129 pub fn user(&self) -> Option<&User> {
130 self.from()
131 }
132}
133
134#[derive(Clone, Debug, PartialEq)]
135pub enum UpdateKind {
136 Message(Message),
144
145 EditedMessage(Message),
147
148 ChannelPost(Message),
150
151 EditedChannelPost(Message),
153
154 InlineQuery(InlineQuery),
158
159 ChosenInlineResult(ChosenInlineResult),
166
167 CallbackQuery(CallbackQuery),
169
170 ShippingQuery(ShippingQuery),
172
173 PreCheckoutQuery(PreCheckoutQuery),
176
177 Poll(Poll),
180
181 PollAnswer(PollAnswer),
184
185 MyChatMember(ChatMemberUpdated),
189
190 ChatMember(ChatMemberUpdated),
197
198 ChatJoinRequest(ChatJoinRequest),
202
203 Error(Value),
211}
212
213impl<'de> Deserialize<'de> for UpdateKind {
214 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
215 where
216 D: serde::Deserializer<'de>,
217 {
218 struct Visitor;
219
220 impl<'de> serde::de::Visitor<'de> for Visitor {
221 type Value = UpdateKind;
222
223 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
224 formatter.write_str("a map")
225 }
226
227 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
228 where
229 A: MapAccess<'de>,
230 {
231 let mut tmp = None;
232
233 let key = map.next_key::<&str>().or_else(|_| {
236 map.next_key::<String>().map(|k| {
237 tmp = k;
238 tmp.as_deref()
239 })
240 });
241
242 let this = key
243 .ok()
244 .flatten()
245 .and_then(|key| match key {
246 "message" => map.next_value::<Message>().ok().map(UpdateKind::Message),
247 "edited_message" => map
248 .next_value::<Message>()
249 .ok()
250 .map(UpdateKind::EditedMessage),
251 "channel_post" => map
252 .next_value::<Message>()
253 .ok()
254 .map(UpdateKind::ChannelPost),
255 "edited_channel_post" => map
256 .next_value::<Message>()
257 .ok()
258 .map(UpdateKind::EditedChannelPost),
259 "inline_query" => map
260 .next_value::<InlineQuery>()
261 .ok()
262 .map(UpdateKind::InlineQuery),
263 "chosen_inline_result" => map
264 .next_value::<ChosenInlineResult>()
265 .ok()
266 .map(UpdateKind::ChosenInlineResult),
267 "callback_query" => map
268 .next_value::<CallbackQuery>()
269 .ok()
270 .map(UpdateKind::CallbackQuery),
271 "shipping_query" => map
272 .next_value::<ShippingQuery>()
273 .ok()
274 .map(UpdateKind::ShippingQuery),
275 "pre_checkout_query" => map
276 .next_value::<PreCheckoutQuery>()
277 .ok()
278 .map(UpdateKind::PreCheckoutQuery),
279 "poll" => map.next_value::<Poll>().ok().map(UpdateKind::Poll),
280 "poll_answer" => map
281 .next_value::<PollAnswer>()
282 .ok()
283 .map(UpdateKind::PollAnswer),
284 "my_chat_member" => map
285 .next_value::<ChatMemberUpdated>()
286 .ok()
287 .map(UpdateKind::MyChatMember),
288 "chat_member" => map
289 .next_value::<ChatMemberUpdated>()
290 .ok()
291 .map(UpdateKind::ChatMember),
292 "chat_join_request" => map
293 .next_value::<ChatJoinRequest>()
294 .ok()
295 .map(UpdateKind::ChatJoinRequest),
296 _ => Some(empty_error()),
297 })
298 .unwrap_or_else(empty_error);
299
300 Ok(this)
301 }
302 }
303
304 deserializer.deserialize_any(Visitor)
305 }
306}
307
308impl Serialize for UpdateKind {
309 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
310 where
311 S: Serializer,
312 {
313 let name = "UpdateKind";
314 match self {
315 UpdateKind::Message(v) => s.serialize_newtype_variant(name, 0, "message", v),
316 UpdateKind::EditedMessage(v) => {
317 s.serialize_newtype_variant(name, 1, "edited_message", v)
318 }
319 UpdateKind::ChannelPost(v) => s.serialize_newtype_variant(name, 2, "channel_post", v),
320 UpdateKind::EditedChannelPost(v) => {
321 s.serialize_newtype_variant(name, 3, "edited_channel_post", v)
322 }
323 UpdateKind::InlineQuery(v) => s.serialize_newtype_variant(name, 4, "inline_query", v),
324 UpdateKind::ChosenInlineResult(v) => {
325 s.serialize_newtype_variant(name, 5, "chosen_inline_result", v)
326 }
327 UpdateKind::CallbackQuery(v) => {
328 s.serialize_newtype_variant(name, 6, "callback_query", v)
329 }
330 UpdateKind::ShippingQuery(v) => {
331 s.serialize_newtype_variant(name, 7, "shipping_query", v)
332 }
333 UpdateKind::PreCheckoutQuery(v) => {
334 s.serialize_newtype_variant(name, 8, "pre_checkout_query", v)
335 }
336 UpdateKind::Poll(v) => s.serialize_newtype_variant(name, 9, "poll", v),
337 UpdateKind::PollAnswer(v) => s.serialize_newtype_variant(name, 10, "poll_answer", v),
338 UpdateKind::MyChatMember(v) => {
339 s.serialize_newtype_variant(name, 11, "my_chat_member", v)
340 }
341 UpdateKind::ChatMember(v) => s.serialize_newtype_variant(name, 12, "chat_member", v),
342 UpdateKind::ChatJoinRequest(v) => {
343 s.serialize_newtype_variant(name, 13, "chat_join_request", v)
344 }
345 UpdateKind::Error(v) => v.serialize(s),
346 }
347 }
348}
349
350fn empty_error() -> UpdateKind {
351 UpdateKind::Error(Value::Object(<_>::default()))
352}
353
354#[cfg(test)]
355mod test {
356 use crate::types::{
357 Chat, ChatId, ChatKind, ChatPrivate, MediaKind, MediaText, Message, MessageCommon,
358 MessageId, MessageKind, Update, UpdateKind, User, UserId,
359 };
360
361 use chrono::{DateTime, NaiveDateTime, Utc};
362
363 #[test]
365 fn message() {
366 let timestamp = 1_569_518_342;
367 let date = DateTime::from_utc(
368 NaiveDateTime::from_timestamp_opt(timestamp, 0).unwrap(),
369 Utc,
370 );
371
372 let json = r#"{
373 "update_id":892252934,
374 "message":{
375 "message_id":6557,
376 "from":{
377 "id":218485655,
378 "is_bot": false,
379 "first_name":"Waffle",
380 "username":"WaffleLapkin",
381 "language_code":"en"
382 },
383 "chat":{
384 "id":218485655,
385 "first_name":"Waffle",
386 "username":"WaffleLapkin",
387 "type":"private"
388 },
389 "date":1569518342,
390 "text":"hello there"
391 }
392 }"#;
393
394 let expected = Update {
395 id: 892_252_934,
396 kind: UpdateKind::Message(Message {
397 via_bot: None,
398 id: MessageId(6557),
399 thread_id: None,
400 date,
401 chat: Chat {
402 id: ChatId(218_485_655),
403 kind: ChatKind::Private(ChatPrivate {
404 username: Some(String::from("WaffleLapkin")),
405 first_name: Some(String::from("Waffle")),
406 last_name: None,
407 bio: None,
408 has_private_forwards: None,
409 has_restricted_voice_and_video_messages: None,
410 emoji_status_custom_emoji_id: None,
411 }),
412 photo: None,
413 pinned_message: None,
414 message_auto_delete_time: None,
415 has_hidden_members: false,
416 has_aggressive_anti_spam_enabled: false,
417 },
418 kind: MessageKind::Common(MessageCommon {
419 from: Some(User {
420 id: UserId(218_485_655),
421 is_bot: false,
422 first_name: String::from("Waffle"),
423 last_name: None,
424 username: Some(String::from("WaffleLapkin")),
425 language_code: Some(String::from("en")),
426 is_premium: false,
427 added_to_attachment_menu: false,
428 }),
429 reply_to_message: None,
430 forward: None,
431 edit_date: None,
432 media_kind: MediaKind::Text(MediaText {
433 text: String::from("hello there"),
434 entities: vec![],
435 }),
436 reply_markup: None,
437 sender_chat: None,
438 author_signature: None,
439 is_topic_message: false,
440 is_automatic_forward: false,
441 has_protected_content: false,
442 }),
443 }),
444 };
445
446 let actual = serde_json::from_str::<Update>(json).unwrap();
447 assert_eq!(expected, actual);
448 }
449
450 #[test]
451 fn de_private_chat_text_message() {
452 let text = r#"
453 {
454 "message": {
455 "chat": {
456 "first_name": "Hirrolot",
457 "id": 408258968,
458 "type": "private",
459 "username": "hirrolot"
460 },
461 "date": 1581448857,
462 "from": {
463 "first_name": "Hirrolot",
464 "id": 408258968,
465 "is_bot": false,
466 "language_code": "en",
467 "username": "hirrolot"
468 },
469 "message_id": 154,
470 "text": "4"
471 },
472 "update_id": 306197398
473 }
474"#;
475
476 let Update { kind, .. } = serde_json::from_str::<Update>(text).unwrap();
477 match kind {
478 UpdateKind::Message(_) => {}
479 _ => panic!("Expected `Message`"),
480 }
481 }
482
483 #[test]
484 fn pinned_message_works() {
485 let json = r#"{
486 "message": {
487 "chat": {
488 "id": -1001276785818,
489 "title": "teloxide dev",
490 "type": "supergroup",
491 "username": "teloxide_dev"
492 },
493 "date": 1582134655,
494 "from": {
495 "first_name": "Hirrolot",
496 "id": 408258968,
497 "is_bot": false,
498 "username": "hirrolot"
499 },
500 "message_id": 20225,
501 "pinned_message": {
502 "chat": {
503 "id": -1001276785818,
504 "title": "teloxide dev",
505 "type": "supergroup",
506 "username": "teloxide_dev"
507 },
508 "date": 1582134643,
509 "from": {
510 "first_name": "Hirrolot",
511 "id": 408258968,
512 "is_bot": false,
513 "username": "hirrolot"
514 },
515 "message_id": 20224,
516 "text": "Faster than a bullet"
517 }
518 },
519 "update_id": 845402291
520}"#;
521
522 let Update { kind, .. } = serde_json::from_str(json).unwrap();
523 match kind {
524 UpdateKind::Message(_) => {}
525 _ => panic!("Expected `Message`"),
526 }
527 }
528
529 #[test]
530 fn dice_works() {
531 let json = r#"
532 {
533 "message": {
534 "chat": {
535 "id": -1001276785818,
536 "title": "bla bla bla chat",
537 "type": "supergroup",
538 "username": "teloxide_dev"
539 },
540 "date": 1596014550,
541 "dice": {
542 "emoji": "🎲",
543 "value": 2
544 },
545 "from": {
546 "first_name": "Hirrolot",
547 "id": 408258968,
548 "is_bot": false,
549 "language_code": "en",
550 "username": "hirrolot"
551 },
552 "message_id": 35410
553 },
554 "update_id": 573255266
555}
556 "#;
557
558 let Update { kind, .. } = serde_json::from_str(json).unwrap();
559 match kind {
560 UpdateKind::Message(_) => {}
561 _ => panic!("Expected `Message`"),
562 }
563 }
564
565 #[test]
566 fn new_update_kind_error() {
567 let json = r#"{
568 "new_update_kind": {"some_field_idk": 1},
569 "update_id": 1
570 }"#;
571
572 let Update { kind, .. } = serde_json::from_str(json).unwrap();
573
574 match kind {
575 UpdateKind::Error(_) => {}
577 _ => panic!("Expected error"),
578 }
579 }
580
581 #[test]
582 fn issue_523() {
583 let json = r#"{
584 "update_id":0,
585 "my_chat_member": {
586 "chat":{"id":0,"first_name":"FN","last_name":"LN","username":"UN","type":"private"},
587 "from":{"id":0,"is_bot":false,"first_name":"FN","last_name":"LN","username":"UN"},
588 "date":1644677726,
589 "old_chat_member":{"user":{"id":1,"is_bot":true,"first_name":"bot","username":"unBot"},"status":"member"},
590 "new_chat_member":{"user":{"id":1,"is_bot":true,"first_name":"bot","username":"unBot"},"status":"kicked","until_date":0}
591 }
592 }"#;
593
594 let Update { kind, .. } = serde_json::from_str(json).unwrap();
595
596 match kind {
597 UpdateKind::MyChatMember(_) => {}
598 _ => panic!("Expected `MyChatMember`"),
599 }
600 }
601}