tgbot/types/definitions/poll.rs
1use std::{error::Error, fmt};
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5use crate::{
6 api::{Form, Method, Payload},
7 types::{
8 Animation,
9 Audio,
10 Chat,
11 ChatId,
12 Document,
13 InlineKeyboardMarkup,
14 InputMedia,
15 InputMediaData,
16 InputMediaError,
17 Integer,
18 Link,
19 LivePhoto,
20 Location,
21 Message,
22 ParseMode,
23 PhotoSize,
24 ReplyMarkup,
25 ReplyMarkupError,
26 ReplyParameters,
27 ReplyParametersError,
28 Sticker,
29 Text,
30 TextEntities,
31 TextEntity,
32 TextEntityError,
33 User,
34 Venue,
35 Video,
36 },
37};
38
39/// Represents a poll.
40#[derive(Clone, Debug, derive_more::From, Deserialize, Serialize)]
41#[serde(tag = "type")]
42#[serde(rename_all = "snake_case")]
43pub enum Poll {
44 /// A regular poll.
45 Regular(RegularPoll),
46 /// A quiz.
47 Quiz(Quiz),
48}
49
50/// Represents a type of a poll.
51#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
52#[serde(rename_all = "lowercase")]
53pub enum PollType {
54 /// A quiz.
55 Quiz,
56 /// A regular poll.
57 Regular,
58}
59
60impl fmt::Display for PollType {
61 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
62 match self {
63 Self::Quiz => write!(out, "quiz"),
64 Self::Regular => write!(out, "regular"),
65 }
66 }
67}
68
69#[serde_with::skip_serializing_none]
70#[derive(Deserialize, Serialize)]
71struct RawQuestion {
72 question: String,
73 question_entities: Option<TextEntities>,
74}
75
76impl RawQuestion {
77 fn deserialize_value<'de, D>(deserializer: D) -> Result<Text, D::Error>
78 where
79 D: Deserializer<'de>,
80 {
81 let value = Self::deserialize(deserializer)?;
82 Ok(Text {
83 data: value.question,
84 entities: value.question_entities,
85 })
86 }
87
88 fn serialize_value<S>(value: &Text, serializer: S) -> Result<S::Ok, S::Error>
89 where
90 S: Serializer,
91 {
92 Self {
93 question: value.data.clone(),
94 question_entities: value.entities.clone(),
95 }
96 .serialize(serializer)
97 }
98}
99
100/// Represents a regular poll.
101#[serde_with::skip_serializing_none]
102#[derive(Clone, Debug, Deserialize, Serialize)]
103pub struct RegularPoll {
104 /// Indicates whether the poll allows multiple answers.
105 pub allows_multiple_answers: bool,
106 /// Whether the poll allows to change the chosen answer options.
107 pub allows_revoting: bool,
108 /// Unique identifier of the poll.
109 pub id: String,
110 /// Indicates whether the poll is anonymous.
111 pub is_anonymous: bool,
112 /// Indicates whether the poll is closed.
113 pub is_closed: bool,
114 /// Indicates whether voting is limited to users
115 /// who have been members of the chat where
116 /// the poll was originally sent for more than 24 hours.
117 pub members_only: bool,
118 /// List of options.
119 pub options: Vec<PollOption>,
120 /// Question; 1-255 characters.
121 #[serde(
122 flatten,
123 deserialize_with = "RawQuestion::deserialize_value",
124 serialize_with = "RawQuestion::serialize_value"
125 )]
126 pub question: Text,
127 /// Total number of users that voted in the poll.
128 pub total_voter_count: Integer,
129 /// Point in time (Unix timestamp) when the poll will be automatically closed.
130 pub close_date: Option<Integer>,
131 /// A list of two-letter ISO 3166-1 alpha-2 country codes
132 /// indicating the countries from which users can vote in the poll.
133 ///
134 /// The country code “FT” is used for users with anonymous numbers.
135 /// If omitted, then users from any country can participate in the poll.
136 pub country_codes: Option<Vec<String>>,
137 /// Description of the poll.
138 ///
139 /// For a poll inside the message object only.
140 #[serde(
141 flatten,
142 deserialize_with = "PollDescription::deserialize_value",
143 serialize_with = "PollDescription::serialize_value"
144 )]
145 pub description: Option<Text>,
146 /// Media added to the poll description; for polls inside the Message object only.
147 pub media: Option<PollMedia>,
148 /// Amount of time in seconds the poll will be active after creation.
149 pub open_period: Option<Integer>,
150}
151
152impl RegularPoll {
153 /// Creates a new `RegularPoll`.
154 ///
155 /// # Arguments
156 ///
157 /// * `id` - Unique identifier.
158 /// * `question` - Question; 1-255 characters.
159 pub fn new<A, B>(id: A, question: B) -> Self
160 where
161 A: Into<String>,
162 B: Into<Text>,
163 {
164 Self {
165 allows_multiple_answers: false,
166 allows_revoting: false,
167 id: id.into(),
168 is_anonymous: false,
169 is_closed: false,
170 members_only: false,
171 options: vec![],
172 question: question.into(),
173 total_voter_count: 0,
174 close_date: None,
175 country_codes: None,
176 description: None,
177 media: None,
178 open_period: None,
179 }
180 }
181
182 /// Sets a new value for the `allows_multiple_answers` flag.
183 ///
184 /// # Arguments
185 ///
186 /// * `value` - Indicates whether the poll allows multiple answers.
187 pub fn with_allows_multiple_answers(mut self, value: bool) -> Self {
188 self.allows_multiple_answers = value;
189 self
190 }
191
192 /// Sets a new value for the `allows_revoting` flag.
193 ///
194 /// # Arguments
195 ///
196 /// * `value` - Whether the poll allows to change the chosen answer options.
197 pub fn with_allows_revoting(mut self, value: bool) -> Self {
198 self.allows_revoting = value;
199 self
200 }
201
202 /// Sets a new close date.
203 ///
204 /// # Arguments
205 ///
206 /// * `value` - Point in time (Unix timestamp) when the poll will be automatically closed.
207 pub fn with_close_date(mut self, value: Integer) -> Self {
208 self.close_date = Some(value);
209 self
210 }
211
212 /// Sets a new list of country codes.
213 ///
214 /// # Arguments
215 ///
216 /// * `value` - ISO-3166-1 alpha-2 country codes.
217 pub fn with_country_codes<A, B>(mut self, value: A) -> Self
218 where
219 A: IntoIterator<Item = B>,
220 B: Into<String>,
221 {
222 self.country_codes = Some(value.into_iter().map(Into::into).collect());
223 self
224 }
225
226 /// Sets a new description.
227 ///
228 /// # Arguments
229 ///
230 /// * `value` - Description of the poll.
231 pub fn with_description<T>(mut self, value: T) -> Self
232 where
233 T: Into<Text>,
234 {
235 self.description = Some(value.into());
236 self
237 }
238
239 /// Sets a new value for the `is_anonymous` flag.
240 ///
241 /// # Arguments
242 ///
243 /// * `value` - Indicates whether the quiz is anonymous.
244 pub fn with_is_anonymous(mut self, value: bool) -> Self {
245 self.is_anonymous = value;
246 self
247 }
248
249 /// Sets a new value for the `is_closed` flag.
250 ///
251 /// # Arguments
252 ///
253 /// * `value` - Indicates whether the quiz is closed.
254 pub fn with_is_closed(mut self, value: bool) -> Self {
255 self.is_closed = value;
256 self
257 }
258
259 /// Sets a new media.
260 ///
261 /// # Arguments
262 ///
263 /// * `value` - Media added to the poll description.
264 pub fn with_media(mut self, value: PollMedia) -> Self {
265 self.media = Some(value);
266 self
267 }
268
269 /// Sets a new value for the `members_only` flag.
270 ///
271 /// # Arguments
272 ///
273 /// * `value` - Whether voting is limited to the chat members.
274 pub fn with_members_only(mut self, value: bool) -> Self {
275 self.members_only = value;
276 self
277 }
278
279 /// Sets a new open period.
280 ///
281 /// # Arguments
282 ///
283 /// * `value` - Amount of time in seconds the poll will be active after creation.
284 pub fn with_open_period(mut self, value: Integer) -> Self {
285 self.open_period = Some(value);
286 self
287 }
288
289 /// Sets a new list of options.
290 ///
291 /// # Arguments
292 ///
293 /// * `value` - The list of options.
294 pub fn with_options<T>(mut self, value: T) -> Self
295 where
296 T: IntoIterator<Item = PollOption>,
297 {
298 self.options = value.into_iter().collect();
299 self
300 }
301
302 /// Sets a new correct total voter count.
303 ///
304 /// # Arguments
305 ///
306 /// * `value` - Total number of users that answered to the quiz.
307 pub fn with_total_voter_count(mut self, value: Integer) -> Self {
308 self.total_voter_count = value;
309 self
310 }
311}
312
313/// Represents a quiz.
314#[serde_with::skip_serializing_none]
315#[derive(Clone, Debug, Deserialize, Serialize)]
316pub struct Quiz {
317 /// Whether the poll allows to change the chosen answer options.
318 pub allows_revoting: bool,
319 /// Unique identifier of the quiz.
320 pub id: String,
321 /// Indicates whether the quiz is anonymous.
322 pub is_anonymous: bool,
323 /// Indicates whether the quiz is closed.
324 pub is_closed: bool,
325 /// Indicates whether voting is limited to users
326 /// who have been members of the chat where
327 /// the poll was originally sent for more than 24 hours.
328 pub members_only: bool,
329 /// List of options.
330 pub options: Vec<PollOption>,
331 /// Question; 1-255 characters.
332 #[serde(
333 flatten,
334 deserialize_with = "RawQuestion::deserialize_value",
335 serialize_with = "RawQuestion::serialize_value"
336 )]
337 pub question: Text,
338 /// Total number of users that answered to the quiz.
339 pub total_voter_count: Integer,
340 /// Point in time (Unix timestamp) when the quiz will be automatically closed.
341 pub close_date: Option<Integer>,
342 /// Array of 0-based identifiers of the correct answer options.
343 ///
344 /// Available only for polls in quiz mode which are closed
345 /// or were sent (not forwarded) by the bot or to the private chat with the bot.
346 pub correct_option_ids: Option<Vec<Integer>>,
347 /// A list of two-letter ISO 3166-1 alpha-2 country codes
348 /// indicating the countries from which users can vote in the poll.
349 ///
350 /// The country code “FT” is used for users with anonymous numbers.
351 /// If omitted, then users from any country can participate in the poll.
352 pub country_codes: Option<Vec<String>>,
353 /// Description of the quiz.
354 ///
355 /// For a quiz inside the message object only.
356 #[serde(
357 flatten,
358 deserialize_with = "PollDescription::deserialize_value",
359 serialize_with = "PollDescription::serialize_value"
360 )]
361 pub description: Option<Text>,
362 /// Text that is shown when a user chooses an incorrect answer or
363 /// taps on the lamp icon; 0-200 characters.
364 #[serde(
365 flatten,
366 deserialize_with = "QuizExplanation::deserialize_value",
367 serialize_with = "QuizExplanation::serialize_value"
368 )]
369 pub explanation: Option<Text>,
370 /// Media added to the quiz explanation.
371 pub explanation_media: Option<PollMedia>,
372 /// Amount of time in seconds the quiz will be active after creation.
373 pub open_period: Option<Integer>,
374}
375
376impl Quiz {
377 /// Creates a new `Quiz`.
378 ///
379 /// # Arguments
380 ///
381 /// * `id` - Unique identifier.
382 /// * `question` - Question; 1-255 characters.
383 pub fn new<A, B>(id: A, question: B) -> Self
384 where
385 A: Into<String>,
386 B: Into<Text>,
387 {
388 Self {
389 allows_revoting: false,
390 id: id.into(),
391 is_anonymous: false,
392 is_closed: false,
393 members_only: true,
394 options: vec![],
395 question: question.into(),
396 total_voter_count: 0,
397 close_date: None,
398 correct_option_ids: None,
399 country_codes: None,
400 description: None,
401 explanation: None,
402 explanation_media: None,
403 open_period: None,
404 }
405 }
406
407 /// Sets a new value for the `allows_revoting` flag.
408 ///
409 /// # Arguments
410 ///
411 /// * `value` - Whether the poll allows to change the chosen answer options.
412 pub fn with_allows_revoting(mut self, value: bool) -> Self {
413 self.allows_revoting = value;
414 self
415 }
416
417 /// Sets a new close date.
418 ///
419 /// # Arguments
420 ///
421 /// * `value` - Point in time (Unix timestamp) when the quiz will be automatically closed.
422 pub fn with_close_date(mut self, value: Integer) -> Self {
423 self.close_date = Some(value);
424 self
425 }
426
427 /// Sets a new list of correct option IDs.
428 ///
429 /// # Arguments
430 ///
431 /// * `value` - 0-based identifiers of the correct answer options.
432 pub fn with_correct_option_ids<T>(mut self, value: T) -> Self
433 where
434 T: IntoIterator<Item = Integer>,
435 {
436 self.correct_option_ids = Some(value.into_iter().collect());
437 self
438 }
439
440 /// Sets a new list of country codes.
441 ///
442 /// # Arguments
443 ///
444 /// * `value` - ISO-3166-1 alpha-2 country codes.
445 pub fn with_country_codes<A, B>(mut self, value: A) -> Self
446 where
447 A: IntoIterator<Item = B>,
448 B: Into<String>,
449 {
450 self.country_codes = Some(value.into_iter().map(Into::into).collect());
451 self
452 }
453
454 /// Sets a new description.
455 ///
456 /// # Arguments
457 ///
458 /// * `value` - Description of the quiz.
459 pub fn with_description<T>(mut self, value: T) -> Self
460 where
461 T: Into<Text>,
462 {
463 self.description = Some(value.into());
464 self
465 }
466
467 /// Sets a new explanation.
468 ///
469 /// # Arguments
470 ///
471 /// * `value` - Text that is shown when a user chooses
472 /// an incorrect answer or
473 /// taps on the lamp icon; 0-200 characters.
474 pub fn with_explanation<T>(mut self, value: T) -> Self
475 where
476 T: Into<Text>,
477 {
478 self.explanation = Some(value.into());
479 self
480 }
481
482 /// Sets a new explanation media.
483 ///
484 /// # Arguments
485 ///
486 /// * `value` - Media added to the quiz explanation.
487 pub fn with_explanation_media(mut self, value: PollMedia) -> Self {
488 self.explanation_media = Some(value);
489 self
490 }
491
492 /// Sets a new value for the `is_anonymous` flag.
493 ///
494 /// # Arguments
495 ///
496 /// * `value` - Indicates whether the quiz is anonymous.
497 pub fn with_is_anonymous(mut self, value: bool) -> Self {
498 self.is_anonymous = value;
499 self
500 }
501
502 /// Sets a new value for the `is_closed` flag.
503 ///
504 /// # Arguments
505 ///
506 /// * `value` - Indicates whether the quiz is closed.
507 pub fn with_is_closed(mut self, value: bool) -> Self {
508 self.is_closed = value;
509 self
510 }
511
512 /// Sets a new value for the `members_only` flag.
513 ///
514 /// # Arguments
515 ///
516 /// * `value` - Whether voting is limited to the chat members.
517 pub fn with_members_only(mut self, value: bool) -> Self {
518 self.members_only = value;
519 self
520 }
521
522 /// Sets a new open period.
523 ///
524 /// # Arguments
525 ///
526 /// * `value` - Amount of time in seconds the quiz will be active after creation.
527 pub fn with_open_period(mut self, value: Integer) -> Self {
528 self.open_period = Some(value);
529 self
530 }
531
532 /// Sets a new list of options.
533 ///
534 /// # Arguments
535 ///
536 /// * `value` - The list of options.
537 pub fn with_options<T>(mut self, value: T) -> Self
538 where
539 T: IntoIterator<Item = PollOption>,
540 {
541 self.options = value.into_iter().collect();
542 self
543 }
544
545 /// Sets a new correct total voter count.
546 ///
547 /// # Arguments
548 ///
549 /// * `value` - Total number of users that answered to the quiz.
550 pub fn with_total_voter_count(mut self, value: Integer) -> Self {
551 self.total_voter_count = value;
552 self
553 }
554}
555
556#[serde_with::skip_serializing_none]
557#[derive(Deserialize, Serialize)]
558struct PollDescription {
559 description: String,
560 description_entities: Option<TextEntities>,
561}
562
563impl PollDescription {
564 fn deserialize_value<'de, D>(deserializer: D) -> Result<Option<Text>, D::Error>
565 where
566 D: Deserializer<'de>,
567 {
568 Option::<PollDescription>::deserialize(deserializer).map(|x| {
569 x.map(|value| Text {
570 data: value.description,
571 entities: value.description_entities,
572 })
573 })
574 }
575
576 fn serialize_value<S>(value: &Option<Text>, serializer: S) -> Result<S::Ok, S::Error>
577 where
578 S: Serializer,
579 {
580 let value = value.clone().map(|value| PollDescription {
581 description: value.data,
582 description_entities: value.entities,
583 });
584 value.serialize(serializer)
585 }
586}
587
588#[serde_with::skip_serializing_none]
589#[derive(Deserialize, Serialize)]
590struct QuizExplanation {
591 explanation: String,
592 explanation_entities: Option<TextEntities>,
593}
594
595impl QuizExplanation {
596 fn deserialize_value<'de, D>(deserializer: D) -> Result<Option<Text>, D::Error>
597 where
598 D: Deserializer<'de>,
599 {
600 Option::<QuizExplanation>::deserialize(deserializer).map(|x| {
601 x.map(|value| Text {
602 data: value.explanation,
603 entities: value.explanation_entities,
604 })
605 })
606 }
607
608 fn serialize_value<S>(value: &Option<Text>, serializer: S) -> Result<S::Ok, S::Error>
609 where
610 S: Serializer,
611 {
612 let value = value.clone().map(|value| QuizExplanation {
613 explanation: value.data,
614 explanation_entities: value.entities,
615 });
616 value.serialize(serializer)
617 }
618}
619
620/// Represents the content of a poll description or a quiz explanation.
621#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
622#[serde(rename_all = "snake_case")]
623pub enum PollMedia {
624 /// Media is an animation.
625 Animation(Animation),
626 /// Media is an audio file.
627 Audio(Audio),
628 /// Media is a general file.
629 Document(Document),
630 /// The HTTP link.
631 Link(Link),
632 /// Media is a live photo.
633 LivePhoto(LivePhoto),
634 /// Media is a shared location.
635 Location(Location),
636 /// Media is a photo.
637 Photo(Vec<PhotoSize>),
638 /// Media is a sticker.
639 Sticker(Sticker),
640 /// Media is a venue.
641 Venue(Venue),
642 /// Media is a video.
643 Video(Video),
644}
645
646#[serde_with::skip_serializing_none]
647#[derive(Deserialize, Serialize)]
648struct RawPollOptionText {
649 text: String,
650 text_entities: Option<TextEntities>,
651}
652
653impl RawPollOptionText {
654 fn deserialize_value<'de, D>(deserializer: D) -> Result<Text, D::Error>
655 where
656 D: Deserializer<'de>,
657 {
658 let value = Self::deserialize(deserializer)?;
659 Ok(Text {
660 data: value.text,
661 entities: value.text_entities,
662 })
663 }
664
665 fn serialize_value<S>(value: &Text, serializer: S) -> Result<S::Ok, S::Error>
666 where
667 S: Serializer,
668 {
669 Self {
670 text: value.data.clone(),
671 text_entities: value.entities.clone(),
672 }
673 .serialize(serializer)
674 }
675}
676
677/// Represents an answer option in a poll.
678#[serde_with::skip_serializing_none]
679#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
680pub struct PollOption {
681 /// Unique identifier of the option, persistent on option addition and deletion.
682 pub persistent_id: String,
683 /// Option text; 1-100 characters.
684 #[serde(
685 flatten,
686 deserialize_with = "RawPollOptionText::deserialize_value",
687 serialize_with = "RawPollOptionText::serialize_value"
688 )]
689 pub text: Text,
690 /// Number of users that voted for this option.
691 pub voter_count: Integer,
692 /// Chat that added the option.
693 ///
694 /// Omitted if the option wasn't added by a chat after poll creation.
695 pub added_by_chat: Option<Chat>,
696 /// User who added the option.
697 ///
698 /// Omitted if the option wasn't added by a user after poll creation.
699 pub added_by_user: Option<User>,
700 /// Point in time (Unix timestamp) when the option was added.
701 ///
702 /// Omitted if the option existed in the original poll.
703 pub addition_date: Option<Integer>,
704 /// Media added to the poll option.
705 pub media: Option<PollMedia>,
706}
707
708impl PollOption {
709 /// Creates a new `PollOption`.
710 ///
711 /// # Arguments
712 ///
713 /// * `persistent_id` - Unique identifier of the option.
714 /// * `text` - Option text; 1-100 characters.
715 /// * `voter_count` - Number of users that voted for this option.
716 pub fn new<A, B>(persistent_id: A, text: B, voter_count: Integer) -> Self
717 where
718 A: Into<String>,
719 B: Into<Text>,
720 {
721 Self {
722 persistent_id: persistent_id.into(),
723 text: text.into(),
724 voter_count,
725 added_by_chat: None,
726 added_by_user: None,
727 addition_date: None,
728 media: None,
729 }
730 }
731
732 /// Sets a new chat.
733 ///
734 /// # Arguments
735 ///
736 /// * `value` - Chat that added the option.
737 pub fn with_added_by_chat<T>(mut self, value: T) -> Self
738 where
739 T: Into<Chat>,
740 {
741 self.added_by_chat = Some(value.into());
742 self
743 }
744
745 /// Sets a new user.
746 ///
747 /// # Arguments
748 ///
749 /// * `value` - User who added the option.
750 pub fn with_added_by_user(mut self, value: User) -> Self {
751 self.added_by_user = Some(value);
752 self
753 }
754
755 /// Sets a new addition date.
756 ///
757 /// # Arguments
758 ///
759 /// * `value` - Point in time when the option was added.
760 pub fn with_addition_date(mut self, value: Integer) -> Self {
761 self.addition_date = Some(value);
762 self
763 }
764
765 /// Sets a new media.
766 ///
767 /// # Arguments
768 ///
769 /// * `value` - Media added to the option.
770 pub fn with_media(mut self, value: PollMedia) -> Self {
771 self.media = Some(value);
772 self
773 }
774}
775
776/// Represents an answer of a user in a non-anonymous poll.
777#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
778pub struct PollAnswer {
779 /// 0-based identifiers of answer options, chosen by the user.
780 ///
781 /// May be empty if the user retracted their vote.
782 pub option_ids: Vec<Integer>,
783 /// Persistent identifiers of the chosen answer options.
784 ///
785 /// May be empty if the vote was retracted.
786 pub option_persistent_ids: Vec<String>,
787 /// Unique poll identifier.
788 pub poll_id: String,
789 /// The chat or the user that changed answer to the poll.
790 #[serde(flatten)]
791 pub voter: PollAnswerVoter,
792}
793
794impl PollAnswer {
795 /// Creates a new `PollAnswer`.
796 ///
797 /// # Arguments
798 ///
799 /// * `option_ids` - 0-based identifiers of answer options, chosen by the user.
800 /// * `poll_id` - Unique poll identifier.
801 /// * `voter` - The chat or the user that changed answer to the poll.
802 pub fn new<A, B, C>(option_ids: A, poll_id: B, voter: C) -> Self
803 where
804 A: IntoIterator<Item = Integer>,
805 B: Into<String>,
806 C: Into<PollAnswerVoter>,
807 {
808 Self {
809 option_ids: option_ids.into_iter().collect(),
810 option_persistent_ids: vec![],
811 poll_id: poll_id.into(),
812 voter: voter.into(),
813 }
814 }
815}
816
817/// Represents the chat or the user that changed answer to the poll.
818#[derive(Clone, Debug, derive_more::From, Deserialize, PartialEq, Serialize)]
819#[serde(rename_all = "snake_case")]
820pub enum PollAnswerVoter {
821 /// The chat that changed the answer to the poll, if the voter is anonymous.
822 Chat(Chat),
823 /// The user that changed the answer to the poll, if the voter isn't anonymous.
824 User(User),
825}
826
827/// Contains information about one answer option in a poll to send.
828#[derive(Debug)]
829pub struct InputPollOption {
830 data: InputPollOptionData,
831 media_form: Option<Form>,
832}
833
834impl InputPollOption {
835 /// Creates a new `InputPollOption`.
836 ///
837 /// # Arguments
838 ///
839 /// * `text` - Option text; 1-100 characters.
840 pub fn new<T>(text: T) -> Self
841 where
842 T: Into<String>,
843 {
844 Self {
845 data: InputPollOptionData {
846 text: text.into(),
847 text_parse_mode: None,
848 text_entities: None,
849 media: None,
850 },
851 media_form: None,
852 }
853 }
854
855 /// Sets a new list of text entities.
856 ///
857 /// # Arguments
858 ///
859 /// * `value` - A list of special entities that appear in the poll option text.
860 ///
861 /// Text parse mode will be set to [`None`] when this method is called.
862 pub fn with_entities<T>(mut self, value: T) -> Self
863 where
864 T: IntoIterator<Item = TextEntity>,
865 {
866 self.data.text_entities = Some(value.into_iter().collect());
867 self.data.text_parse_mode = None;
868 self
869 }
870
871 /// Sets a new media.
872 ///
873 /// # Arguments
874 ///
875 /// * `value` - Media added to the poll option.
876 pub fn with_media(mut self, value: InputMedia) -> Self {
877 let (form, data) = value.into_parts();
878 self.data.media = Some(data);
879 self.media_form = Some(form);
880 self
881 }
882
883 /// Sets a new text parse mode.
884 ///
885 /// # Arguments
886 ///
887 /// * `value` - Mode for parsing entities in the text.
888 ///
889 /// Currently, only custom emoji entities are allowed.
890 /// Text entities will be set to [`None`] when this method is called.
891 pub fn with_parse_mode(mut self, value: ParseMode) -> Self {
892 self.data.text_parse_mode = Some(value);
893 self.data.text_entities = None;
894 self
895 }
896}
897
898impl<T> From<T> for InputPollOption
899where
900 T: Into<Text>,
901{
902 fn from(value: T) -> Self {
903 let value = value.into();
904 Self {
905 data: InputPollOptionData {
906 text: value.data,
907 text_entities: value.entities,
908 text_parse_mode: None,
909 media: None,
910 },
911 media_form: None,
912 }
913 }
914}
915
916#[serde_with::skip_serializing_none]
917#[derive(Debug, Serialize)]
918struct InputPollOptionData {
919 text: String,
920 text_parse_mode: Option<ParseMode>,
921 text_entities: Option<TextEntities>,
922 media: Option<InputMediaData>,
923}
924
925#[derive(Debug)]
926struct PollParameters {
927 form: Form,
928 allow_adding_options: bool,
929 is_anonymous: bool,
930}
931
932impl PollParameters {
933 fn new<A, B>(chat_id: ChatId, question: String, poll_type: PollType, options: A) -> Result<Self, PollError>
934 where
935 A: IntoIterator<Item = B>,
936 B: Into<InputPollOption>,
937 {
938 let mut form = Form::from([
939 ("chat_id", chat_id.into()),
940 ("question", question.into()),
941 ("type", poll_type.into()),
942 ]);
943 let mut options_data = Vec::with_capacity(20);
944 for (idx, option) in options.into_iter().map(Into::into).enumerate() {
945 if let Some(option_form) = option.media_form {
946 form.extend(option_form.with_suffix(format!("{idx}")))
947 }
948 options_data.push(option.data);
949 }
950 form.insert_field(
951 "options",
952 serde_json::to_string(&options_data).map_err(PollError::SerializeOptions)?,
953 );
954 Ok(Self {
955 form,
956 allow_adding_options: false,
957 is_anonymous: false,
958 })
959 }
960
961 fn set_allow_adding_options(&mut self, value: bool) {
962 self.form.insert_field("allow_adding_options", value);
963 self.allow_adding_options = value;
964 if value && self.is_anonymous {
965 self.form.remove_field("is_anonymous");
966 self.is_anonymous = false;
967 }
968 }
969
970 fn set_description_entities<T>(&mut self, value: T) -> Result<(), TextEntityError>
971 where
972 T: IntoIterator<Item = TextEntity>,
973 {
974 let value: TextEntities = value.into_iter().collect();
975 self.form.insert_field("description_entities", value.serialize()?);
976 self.form.remove_field("description_parse_mode");
977 Ok(())
978 }
979
980 fn set_description_parse_mode(&mut self, value: ParseMode) {
981 self.form.insert_field("description_parse_mode", value);
982 self.form.remove_field("description_entities");
983 }
984
985 fn set_is_anonymous(&mut self, value: bool) {
986 self.is_anonymous = value;
987 self.form.insert_field("is_anonymous", value);
988 if value && self.allow_adding_options {
989 self.allow_adding_options = false;
990 self.form.remove_field("allow_adding_options")
991 }
992 }
993}
994
995/// Sends a quiz.
996///
997/// On success, the sent [`Message`] is returned.
998#[derive(Debug)]
999pub struct SendQuiz {
1000 inner: PollParameters,
1001}
1002
1003impl SendQuiz {
1004 /// Creates a new `SendQuiz`.
1005 ///
1006 /// # Arguments
1007 ///
1008 /// * `chat_id` - Unique identifier of the target chat.
1009 /// * `question` - Question; 1-300 characters.
1010 /// * `correct_option_ids` - 0-based identifiers of the correct answer options.
1011 /// * `options` - Answer options; 1-12.
1012 pub fn new<A, B, C, D, DI>(chat_id: A, question: B, correct_option_ids: C, options: D) -> Result<Self, PollError>
1013 where
1014 A: Into<ChatId>,
1015 B: Into<String>,
1016 C: IntoIterator<Item = Integer>,
1017 D: IntoIterator<Item = DI>,
1018 DI: Into<InputPollOption>,
1019 {
1020 let mut parameters = PollParameters::new(chat_id.into(), question.into(), PollType::Quiz, options)?;
1021 let correct_option_ids: Vec<Integer> = correct_option_ids.into_iter().collect();
1022 let correct_option_ids_data =
1023 serde_json::to_string(&correct_option_ids).map_err(PollError::SerializeCorrectOptionIds)?;
1024 parameters
1025 .form
1026 .insert_field("correct_option_ids", correct_option_ids_data);
1027 Ok(Self { inner: parameters })
1028 }
1029
1030 /// Sets a new value for the `allow_adding_options` flag.
1031 ///
1032 /// # Arguments
1033 ///
1034 /// * `value` - Whether answer options can be added to the poll after creation.
1035 ///
1036 /// `is_anonymous` will be set to [`None`] when it is set to `true` and the value is `true`.
1037 pub fn with_allow_adding_options(mut self, value: bool) -> Self {
1038 self.inner.set_allow_adding_options(value);
1039 self
1040 }
1041
1042 /// Sets a new value for the `allow_paid_broadcast` flag.
1043 ///
1044 /// # Arguments
1045 ///
1046 /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
1047 /// for a fee of 0.1 Telegram Stars per message.
1048 /// The relevant Stars will be withdrawn from the bot's balance.
1049 pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
1050 self.inner.form.insert_field("allow_paid_broadcast", value);
1051 self
1052 }
1053
1054 /// Sets a new value for the `allows_multiple_answers` flag.
1055 ///
1056 /// # Arguments
1057 ///
1058 /// * `value` - Indicates whether the poll allows multiple answers; default - `false`.
1059 pub fn with_allows_multiple_answers(mut self, value: bool) -> Self {
1060 self.inner.form.insert_field("allows_multiple_answers", value);
1061 self
1062 }
1063
1064 /// Sets a new value for the `allows_revoting` flag.
1065 ///
1066 /// # Arguments
1067 ///
1068 /// * `value` - Whether if the poll allows to change chosen answer options,
1069 /// defaults to false.
1070 pub fn with_allows_revoting(mut self, value: bool) -> Self {
1071 self.inner.form.insert_field("allows_revoting", value);
1072 self
1073 }
1074
1075 /// Sets a new business connection ID.
1076 ///
1077 /// # Arguments
1078 ///
1079 /// * `value` - Unique identifier of the business connection.
1080 pub fn with_business_connection_id<T>(mut self, value: T) -> Self
1081 where
1082 T: Into<String>,
1083 {
1084 self.inner.form.insert_field("business_connection_id", value.into());
1085 self
1086 }
1087
1088 /// Sets a new close date.
1089 ///
1090 /// # Arguments
1091 ///
1092 /// * `value` - Point in time (Unix timestamp) when the quiz will be automatically closed.
1093 ///
1094 /// Must be at least 5 and no more than 600 seconds in the future.
1095 /// Can't be used together with [`Self::with_open_period`] (open period will be set to [`None`]).
1096 pub fn with_close_date(mut self, value: Integer) -> Self {
1097 self.inner.form.insert_field("close_date", value);
1098 self.inner.form.remove_field("open_period");
1099 self
1100 }
1101
1102 /// Sets a new list of country codes.
1103 ///
1104 /// # Arguments
1105 ///
1106 /// * `value` - The list of 0-12 two-letter ISO 3166-1 alpha-2 country codes
1107 /// indicating the countries from which users can vote in the poll;
1108 /// for channel chats only.
1109 ///
1110 /// Use “FT” as a country code to allow users with anonymous numbers to vote.
1111 ///
1112 /// If omitted or empty, then users from any country can participate in the poll.
1113 pub fn with_country_codes<A, B>(mut self, value: A) -> Result<Self, PollError>
1114 where
1115 A: IntoIterator<Item = B>,
1116 B: Into<String>,
1117 {
1118 let value: Vec<String> = value.into_iter().map(Into::into).collect();
1119 self.inner.form.insert_field(
1120 "country_codes",
1121 serde_json::to_string(&value).map_err(PollError::SerializeCountryCodes)?,
1122 );
1123 Ok(self)
1124 }
1125
1126 /// Sets a new description.
1127 ///
1128 /// # Arguments
1129 ///
1130 /// * `value` - Description; 0-1024 characters after entities parsing.
1131 pub fn with_description<T>(mut self, value: T) -> Self
1132 where
1133 T: Into<String>,
1134 {
1135 self.inner.form.insert_field("description", value.into());
1136 self
1137 }
1138
1139 /// Sets a new list of description entities.
1140 ///
1141 /// # Arguments
1142 ///
1143 /// * `value` - A list of special entities that appear in the description.
1144 ///
1145 /// Parse mode will be set to [`None`].
1146 pub fn with_description_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
1147 where
1148 T: IntoIterator<Item = TextEntity>,
1149 {
1150 self.inner.set_description_entities(value)?;
1151 Ok(self)
1152 }
1153
1154 /// Sets a new description parse mode.
1155 ///
1156 /// # Arguments
1157 ///
1158 /// * `value` - Mode for parsing entities in the description.
1159 ///
1160 /// Entities will be set to [`None`].
1161 pub fn with_description_parse_mode(mut self, value: ParseMode) -> Self {
1162 self.inner.set_description_parse_mode(value);
1163 self
1164 }
1165
1166 /// Sets a new value for the `disable_notification` flag.
1167 ///
1168 /// # Arguments
1169 ///
1170 /// * `value` - Indicates whether to send the message silently or not;
1171 /// a user will receive a notification without sound.
1172 pub fn with_disable_notification(mut self, value: bool) -> Self {
1173 self.inner.form.insert_field("disable_notification", value);
1174 self
1175 }
1176
1177 /// Sets a new explanation.
1178 ///
1179 /// # Arguments
1180 ///
1181 /// * `value` - Text that is shown when a user chooses
1182 /// an incorrect answer or taps on the lamp icon;
1183 /// 0-200 characters with at most 2 line feeds after entities parsing.
1184 pub fn with_explanation<T>(mut self, value: T) -> Self
1185 where
1186 T: Into<String>,
1187 {
1188 self.inner.form.insert_field("explanation", value.into());
1189 self
1190 }
1191
1192 /// Sets a new explanation media.
1193 ///
1194 /// # Arguments
1195 ///
1196 /// * `value` - Media added to the quiz explanation.
1197 pub fn with_explanation_media(mut self, value: InputMedia) -> Result<Self, InputMediaError> {
1198 self.inner.form.extend(value.try_into_form("explanation_media")?);
1199 Ok(self)
1200 }
1201
1202 /// Sets a new list of explanation entities.
1203 ///
1204 /// # Arguments
1205 ///
1206 /// * `value` - List of special entities that appear in the quiz explanation.
1207 ///
1208 /// Explanation parse mode will be removed when this method is called.
1209 pub fn with_explanation_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
1210 where
1211 T: IntoIterator<Item = TextEntity>,
1212 {
1213 let value: TextEntities = value.into_iter().collect();
1214 self.inner.form.insert_field("explanation_entities", value.serialize()?);
1215 self.inner.form.remove_field("explanation_parse_mode");
1216 Ok(self)
1217 }
1218
1219 /// Sets a new explanation parse mode.
1220 ///
1221 /// # Arguments
1222 ///
1223 /// * `value` - Mode for parsing entities in the explanation.
1224 ///
1225 /// Explanation entities will be removed when this method is called.
1226 pub fn with_explanation_parse_mode(mut self, value: ParseMode) -> Self {
1227 self.inner.form.insert_field("explanation_parse_mode", value);
1228 self.inner.form.remove_field("explanation_entities");
1229 self
1230 }
1231
1232 /// Sets a new value for the `hide_results_until_closes` flag.
1233 ///
1234 /// # Arguments
1235 ///
1236 /// * `value` - Whether the poll results must be shown only after the poll closes.
1237 pub fn with_hide_results_until_closes(mut self, value: bool) -> Self {
1238 self.inner.form.insert_field("hide_results_until_closes", value);
1239 self
1240 }
1241
1242 /// Sets a new value for the `is_anonymous` flag.
1243 ///
1244 /// # Arguments
1245 ///
1246 /// * `value` - Indicates whether the quiz needs to be anonymous; default - `true`.
1247 ///
1248 /// `allow_adding_options` will be set to [`None`] if the `value` is `true`.
1249 pub fn with_is_anonymous(mut self, value: bool) -> Self {
1250 self.inner.set_is_anonymous(value);
1251 self
1252 }
1253
1254 /// Sets a new value for the `is_closed` flag.
1255 ///
1256 /// # Arguments
1257 ///
1258 /// * `value` - Indicates whether the quiz needs to be immediately closed.
1259 pub fn with_is_closed(mut self, value: bool) -> Self {
1260 self.inner.form.insert_field("is_closed", value);
1261 self
1262 }
1263
1264 /// Sets a new value for the `members_only` flag.
1265 ///
1266 /// # Arguments
1267 ///
1268 /// * `value` - Whether voting is limited to users
1269 /// who have been members of the chat where the poll
1270 /// is being sent for more than 24 hours; for channel chats only
1271 pub fn with_members_only(mut self, value: bool) -> Self {
1272 self.inner.form.insert_field("members_only", value);
1273 self
1274 }
1275
1276 /// Sets a new message effect ID.
1277 ///
1278 /// # Arguments
1279 ///
1280 /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
1281 pub fn with_message_effect_id<T>(mut self, value: T) -> Self
1282 where
1283 T: Into<String>,
1284 {
1285 self.inner.form.insert_field("message_effect_id", value.into());
1286 self
1287 }
1288
1289 /// Sets a new message thread ID.
1290 ///
1291 /// # Arguments
1292 ///
1293 /// * `value` - Unique identifier of the target message thread;
1294 /// for forum supergroups and private chats of bots with forum topic mode enabled only.
1295 pub fn with_message_thread_id(mut self, value: Integer) -> Self {
1296 self.inner.form.insert_field("message_thread_id", value);
1297 self
1298 }
1299
1300 /// Sets a new open period.
1301 ///
1302 /// # Arguments
1303 ///
1304 /// * `value` - Amount of time in seconds the quiz will be active after creation; 5-600.
1305 ///
1306 /// Can't be used together with [`Self::with_close_date`] (close date will be set to [`None`]).
1307 pub fn with_open_period(mut self, value: Integer) -> Self {
1308 self.inner.form.insert_field("open_period", value);
1309 self.inner.form.remove_field("close_date");
1310 self
1311 }
1312
1313 /// Sets a new value for the `protect_content` flag.
1314 ///
1315 /// # Arguments
1316 ///
1317 /// * `value` - Indicates whether to protect the contents
1318 /// of the sent message from forwarding and saving.
1319 pub fn with_protect_content(mut self, value: bool) -> Self {
1320 self.inner.form.insert_field("protect_content", value);
1321 self
1322 }
1323
1324 /// Sets a new list of question entities.
1325 ///
1326 /// # Arguments
1327 ///
1328 /// * `value` - A list of special entities that appear in the poll question.
1329 ///
1330 /// Question parse mode will be removed when this method is called.
1331 pub fn with_question_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
1332 where
1333 T: IntoIterator<Item = TextEntity>,
1334 {
1335 let value: TextEntities = value.into_iter().collect();
1336 self.inner.form.insert_field("question_entities", value.serialize()?);
1337 self.inner.form.remove_field("question_parse_mode");
1338 Ok(self)
1339 }
1340
1341 /// Sets a new question parse mode.
1342 ///
1343 /// # Arguments
1344 ///
1345 /// * `value` - Mode for parsing entities in the question.
1346 ///
1347 /// Question entities will be removed when this method is called.
1348 pub fn with_question_parse_mode(mut self, value: ParseMode) -> Self {
1349 self.inner.form.insert_field("question_parse_mode", value);
1350 self.inner.form.remove_field("question_entities");
1351 self
1352 }
1353
1354 /// Sets a new reply markup.
1355 ///
1356 /// # Arguments
1357 ///
1358 /// * `value` - Reply markup.
1359 pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
1360 where
1361 T: Into<ReplyMarkup>,
1362 {
1363 self.inner.form.insert_field("reply_markup", value.into().serialize()?);
1364 Ok(self)
1365 }
1366
1367 /// Sets new reply parameters.
1368 ///
1369 /// # Arguments
1370 ///
1371 /// * `value` - Description of the message to reply to.
1372 pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
1373 self.inner.form.insert_field("reply_parameters", value.serialize()?);
1374 Ok(self)
1375 }
1376
1377 /// Sets a new value for the `shuffle_options` flag.
1378 ///
1379 /// # Arguments
1380 ///
1381 /// * `value` - Whether the poll options must be shown in random order.
1382 pub fn with_shuffle_options(mut self, value: bool) -> Self {
1383 self.inner.form.insert_field("shuffle_options", value);
1384 self
1385 }
1386}
1387
1388impl Method for SendQuiz {
1389 type Response = Message;
1390
1391 fn into_payload(self) -> Payload {
1392 Payload::form("sendPoll", self.inner.form)
1393 }
1394}
1395
1396/// Sends a native poll.
1397///
1398/// On success, the sent [`Message`] is returned.
1399#[derive(Debug)]
1400pub struct SendPoll {
1401 inner: PollParameters,
1402}
1403
1404impl SendPoll {
1405 /// Creates a new `SendPoll`.
1406 ///
1407 /// # Arguments
1408 ///
1409 /// * `chat_id` - Unique identifier of the target chat.
1410 /// * `question` - Question; 1-300 characters.
1411 /// * `options` - Answer options; 1-12.
1412 pub fn new<A, B, C, D>(chat_id: A, question: B, options: C) -> Result<Self, PollError>
1413 where
1414 A: Into<ChatId>,
1415 B: Into<String>,
1416 C: IntoIterator<Item = D>,
1417 D: Into<InputPollOption>,
1418 {
1419 Ok(Self {
1420 inner: PollParameters::new(chat_id.into(), question.into(), PollType::Regular, options)?,
1421 })
1422 }
1423
1424 /// Sets a new value for the `allow_adding_options` flag.
1425 ///
1426 /// # Arguments
1427 ///
1428 /// * `value` - Whether answer options can be added to the poll after creation.
1429 ///
1430 /// `is_anonymous` will be set to [`None`] when it is set to `true` and the value is `true`.
1431 pub fn with_allow_adding_options(mut self, value: bool) -> Self {
1432 self.inner.set_allow_adding_options(value);
1433 self
1434 }
1435
1436 /// Sets a new value for the `allow_paid_broadcast` flag.
1437 ///
1438 /// # Arguments
1439 ///
1440 /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
1441 /// for a fee of 0.1 Telegram Stars per message.
1442 /// The relevant Stars will be withdrawn from the bot's balance.
1443 pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
1444 self.inner.form.insert_field("allow_paid_broadcast", value);
1445 self
1446 }
1447
1448 /// Sets a new value for the `allows_multiple_answers` flag.
1449 ///
1450 /// # Arguments
1451 ///
1452 /// * `value` - Indicates whether the poll allows multiple answers; default - `false`.
1453 pub fn with_allows_multiple_answers(mut self, value: bool) -> Self {
1454 self.inner.form.insert_field("allows_multiple_answers", value);
1455 self
1456 }
1457
1458 /// Sets a new value for the `allows_revoting` flag.
1459 ///
1460 /// # Arguments
1461 ///
1462 /// * `value` - Whether if the poll allows to change chosen answer options,
1463 /// defaults to True.
1464 pub fn with_allows_revoting(mut self, value: bool) -> Self {
1465 self.inner.form.insert_field("allows_revoting", value);
1466 self
1467 }
1468
1469 /// Sets a new business connection ID.
1470 ///
1471 /// # Arguments
1472 ///
1473 /// * `value` - Unique identifier of the business connection on behalf.
1474 pub fn with_business_connection_id<T>(mut self, value: T) -> Self
1475 where
1476 T: Into<String>,
1477 {
1478 self.inner.form.insert_field("business_connection_id", value.into());
1479 self
1480 }
1481
1482 /// Sets a new close date.
1483 ///
1484 /// # Arguments
1485 ///
1486 /// * `value` - Point in time (Unix timestamp) when the poll will be automatically closed.
1487 ///
1488 /// Must be at least 5 and no more than 600 seconds in the future.
1489 /// Can't be used together with [`Self::with_open_period`] (open period will be set to [`None`])
1490 pub fn with_close_date(mut self, value: Integer) -> Self {
1491 self.inner.form.insert_field("close_date", value);
1492 self.inner.form.remove_field("open_period");
1493 self
1494 }
1495
1496 /// Sets a new list of country codes.
1497 ///
1498 /// # Arguments
1499 ///
1500 /// * `value` - The list of 0-12 two-letter ISO 3166-1 alpha-2 country codes
1501 /// indicating the countries from which users can vote in the poll;
1502 /// for channel chats only.
1503 ///
1504 /// Use “FT” as a country code to allow users with anonymous numbers to vote.
1505 ///
1506 /// If omitted or empty, then users from any country can participate in the poll.
1507 pub fn with_country_codes<A, B>(mut self, value: A) -> Result<Self, PollError>
1508 where
1509 A: IntoIterator<Item = B>,
1510 B: Into<String>,
1511 {
1512 let value: Vec<String> = value.into_iter().map(Into::into).collect();
1513 self.inner.form.insert_field(
1514 "country_codes",
1515 serde_json::to_string(&value).map_err(PollError::SerializeCountryCodes)?,
1516 );
1517 Ok(self)
1518 }
1519
1520 /// Sets a new description.
1521 ///
1522 /// # Arguments
1523 ///
1524 /// * `value` - Description; 0-1024 characters after entities parsing.
1525 pub fn with_description<T>(mut self, value: T) -> Self
1526 where
1527 T: Into<String>,
1528 {
1529 self.inner.form.insert_field("description", value.into());
1530 self
1531 }
1532
1533 /// Sets a new list of description entities.
1534 ///
1535 /// # Arguments
1536 ///
1537 /// * `value` - A list of special entities that appear in the description.
1538 ///
1539 /// Parse mode will be set to [`None`].
1540 pub fn with_description_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
1541 where
1542 T: IntoIterator<Item = TextEntity>,
1543 {
1544 self.inner.set_description_entities(value)?;
1545 Ok(self)
1546 }
1547
1548 /// Sets a new description parse mode.
1549 ///
1550 /// # Arguments
1551 ///
1552 /// * `value` - Mode for parsing entities in the description.
1553 ///
1554 /// Entities will be set to [`None`].
1555 pub fn with_description_parse_mode(mut self, value: ParseMode) -> Self {
1556 self.inner.set_description_parse_mode(value);
1557 self
1558 }
1559
1560 /// Sets a new value for the `disable_notification` flag.
1561 ///
1562 /// # Arguments
1563 ///
1564 /// * `value` - Indicates whether to send the message silently or not;
1565 /// a user will receive a notification without sound.
1566 pub fn with_disable_notification(mut self, value: bool) -> Self {
1567 self.inner.form.insert_field("disable_notification", value);
1568 self
1569 }
1570
1571 /// Sets a new value for the `hide_results_until_closes` flag.
1572 ///
1573 /// # Arguments
1574 ///
1575 /// * `value` - Whether the poll results must be shown only after the poll closes.
1576 pub fn with_hide_results_until_closes(mut self, value: bool) -> Self {
1577 self.inner.form.insert_field("hide_results_until_closes", value);
1578 self
1579 }
1580
1581 /// Sets a new value for the `is_anonymous` flag.
1582 ///
1583 /// # Arguments
1584 ///
1585 /// * `value` - Indicates whether the poll needs to be anonymous; default - `true`.
1586 ///
1587 /// `allow_adding_options` will be set to [`None`] if the `value` is `true`.
1588 pub fn with_is_anonymous(mut self, value: bool) -> Self {
1589 self.inner.set_is_anonymous(value);
1590 self
1591 }
1592
1593 /// Sets a new value for the `is_closed` flag.
1594 ///
1595 /// # Arguments
1596 ///
1597 /// * `value` - Indicates whether the poll needs to be immediately closed.
1598 pub fn with_is_closed(mut self, value: bool) -> Self {
1599 self.inner.form.insert_field("is_closed", value);
1600 self
1601 }
1602
1603 /// Sets a new media.
1604 ///
1605 /// # Arguments
1606 ///
1607 /// * `value` - Media added to the poll description.
1608 pub fn with_media(mut self, value: InputMedia) -> Result<Self, InputMediaError> {
1609 self.inner.form.extend(value.try_into_form("media")?);
1610 Ok(self)
1611 }
1612
1613 /// Sets a new value for the `members_only` flag.
1614 ///
1615 /// # Arguments
1616 ///
1617 /// * `value` - Whether voting is limited to users
1618 /// who have been members of the chat where the poll
1619 /// is being sent for more than 24 hours; for channel chats only
1620 pub fn with_members_only(mut self, value: bool) -> Self {
1621 self.inner.form.insert_field("members_only", value);
1622 self
1623 }
1624
1625 /// Sets a new message effect ID.
1626 ///
1627 /// # Arguments
1628 ///
1629 /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
1630 pub fn with_message_effect_id<T>(mut self, value: T) -> Self
1631 where
1632 T: Into<String>,
1633 {
1634 self.inner.form.insert_field("message_effect_id", value.into());
1635 self
1636 }
1637
1638 /// Sets a new message thread ID.
1639 ///
1640 /// # Arguments
1641 ///
1642 /// * `value` - Unique identifier of the target message thread;
1643 /// for forum supergroups and private chats of bots with forum topic mode enabled only.
1644 pub fn with_message_thread_id(mut self, value: Integer) -> Self {
1645 self.inner.form.insert_field("message_thread_id", value);
1646 self
1647 }
1648
1649 /// Sets a new open period.
1650 ///
1651 /// # Arguments
1652 ///
1653 /// * `value` - Amount of time in seconds the poll will be active after creation; 5-600.
1654 ///
1655 /// Can't be used together with `close_date` (`close_date` will be set to [`None`]).
1656 pub fn with_open_period(mut self, value: Integer) -> Self {
1657 self.inner.form.insert_field("open_period", value);
1658 self.inner.form.remove_field("close_date");
1659 self
1660 }
1661
1662 /// Sets a new value for the `protect_content` flag.
1663 ///
1664 /// # Arguments
1665 ///
1666 /// * `value` - Indicates whether to protect the contents
1667 /// of the sent message from forwarding and saving.
1668 pub fn with_protect_content(mut self, value: bool) -> Self {
1669 self.inner.form.insert_field("protect_content", value);
1670 self
1671 }
1672
1673 /// Sets a new list of question entities.
1674 ///
1675 /// # Arguments
1676 ///
1677 /// * `value` - A list of special entities that appear in the poll question.
1678 ///
1679 /// Question parse mode will be set to [`None`] when this method is called.
1680 pub fn with_question_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
1681 where
1682 T: IntoIterator<Item = TextEntity>,
1683 {
1684 let value: TextEntities = value.into_iter().collect();
1685 self.inner.form.insert_field("question_entities", value.serialize()?);
1686 self.inner.form.remove_field("question_parse_mode");
1687 Ok(self)
1688 }
1689
1690 /// Sets a new question parse mode.
1691 ///
1692 /// # Arguments
1693 ///
1694 /// * `value` - Mode for parsing entities in the question.
1695 ///
1696 /// Question entities will be set to [`None`] when this method is called.
1697 pub fn with_question_parse_mode(mut self, value: ParseMode) -> Self {
1698 self.inner.form.insert_field("question_parse_mode", value);
1699 self.inner.form.remove_field("question_entities");
1700 self
1701 }
1702
1703 /// Sets a new reply markup.
1704 ///
1705 /// # Arguments
1706 ///
1707 /// * `value` - Reply markup.
1708 pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
1709 where
1710 T: Into<ReplyMarkup>,
1711 {
1712 self.inner.form.insert_field("reply_markup", value.into().serialize()?);
1713 Ok(self)
1714 }
1715
1716 /// Sets new reply parameters.
1717 ///
1718 /// # Arguments
1719 ///
1720 /// * `value` - Description of the message to reply to.
1721 pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
1722 self.inner.form.insert_field("reply_parameters", value.serialize()?);
1723 Ok(self)
1724 }
1725
1726 /// Sets a new value for the `shuffle_options` flag.
1727 ///
1728 /// # Arguments
1729 ///
1730 /// * `value` - Whether the poll options must be shown in random order.
1731 pub fn with_shuffle_options(mut self, value: bool) -> Self {
1732 self.inner.form.insert_field("shuffle_options", value);
1733 self
1734 }
1735}
1736
1737impl Method for SendPoll {
1738 type Response = Message;
1739
1740 fn into_payload(self) -> Payload {
1741 Payload::form("sendPoll", self.inner.form)
1742 }
1743}
1744
1745/// Stops a poll which was sent by the bot.
1746///
1747/// On success, the stopped [`Poll`] with the final results is returned.
1748#[serde_with::skip_serializing_none]
1749#[derive(Clone, Debug, Serialize)]
1750pub struct StopPoll {
1751 chat_id: ChatId,
1752 message_id: Integer,
1753 business_connection_id: Option<String>,
1754 reply_markup: Option<InlineKeyboardMarkup>,
1755}
1756
1757/// Stops a quiz which was sent by the bot.
1758///
1759/// On success, the stopped [`Quiz`] with the final results is returned.
1760pub type StopQuiz = StopPoll;
1761
1762impl StopPoll {
1763 /// Creates a new `StopPoll`.
1764 ///
1765 /// # Arguments
1766 ///
1767 /// * `chat_id` - Unique identifier of the target chat.
1768 /// * `message_id` - Identifier of the original message with the poll.
1769 pub fn new<T>(chat_id: T, message_id: Integer) -> Self
1770 where
1771 T: Into<ChatId>,
1772 {
1773 Self {
1774 chat_id: chat_id.into(),
1775 message_id,
1776 business_connection_id: None,
1777 reply_markup: None,
1778 }
1779 }
1780
1781 /// Sets a new business connection ID.
1782 ///
1783 /// # Arguments
1784 ///
1785 /// * `value` - Unique identifier of the business connection on behalf of which the message to be edited was sent.
1786 pub fn with_business_connection_id<T>(mut self, value: T) -> Self
1787 where
1788 T: Into<String>,
1789 {
1790 self.business_connection_id = Some(value.into());
1791 self
1792 }
1793
1794 /// Sets a new reply markup.
1795 ///
1796 /// # Arguments
1797 ///
1798 /// * `value` - Reply markup.
1799 pub fn with_reply_markup<T>(mut self, value: T) -> Self
1800 where
1801 T: Into<InlineKeyboardMarkup>,
1802 {
1803 self.reply_markup = Some(value.into());
1804 self
1805 }
1806}
1807
1808impl Method for StopPoll {
1809 type Response = Poll;
1810
1811 fn into_payload(self) -> Payload {
1812 Payload::json("stopPoll", self)
1813 }
1814}
1815
1816/// A poll error.
1817#[derive(Debug)]
1818pub enum PollError {
1819 /// Failed to serialize correct option IDs.
1820 SerializeCorrectOptionIds(serde_json::Error),
1821 /// Failed to serialize country codes.
1822 SerializeCountryCodes(serde_json::Error),
1823 /// Failed to serialize options.
1824 SerializeOptions(serde_json::Error),
1825}
1826
1827impl Error for PollError {
1828 fn source(&self) -> Option<&(dyn Error + 'static)> {
1829 Some(match self {
1830 Self::SerializeCorrectOptionIds(err) => err,
1831 Self::SerializeCountryCodes(err) => err,
1832 Self::SerializeOptions(err) => err,
1833 })
1834 }
1835}
1836
1837impl fmt::Display for PollError {
1838 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
1839 match self {
1840 Self::SerializeCorrectOptionIds(err) => write!(out, "can not serialize correct option ids: {}", err),
1841 Self::SerializeCountryCodes(err) => write!(out, "can not serialize country codes: {}", err),
1842 Self::SerializeOptions(err) => write!(out, "can not serialize options: {}", err),
1843 }
1844 }
1845}