Skip to main content

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}