tgbot/types/definitions/
poll.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2
3use crate::{
4    api::{Method, Payload},
5    types::{
6        Chat,
7        ChatId,
8        InlineKeyboardMarkup,
9        Integer,
10        Message,
11        ParseMode,
12        ReplyMarkup,
13        ReplyParameters,
14        Text,
15        TextEntities,
16        TextEntity,
17        User,
18    },
19};
20
21/// Represents a poll.
22#[derive(Clone, Debug, derive_more::From, Deserialize, PartialEq, PartialOrd, Serialize)]
23#[serde(tag = "type")]
24#[serde(rename_all = "snake_case")]
25pub enum Poll {
26    /// A regular poll.
27    Regular(RegularPoll),
28    /// A quiz.
29    Quiz(Quiz),
30}
31
32/// Represents a type of a poll.
33#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
34#[serde(rename_all = "lowercase")]
35pub enum PollType {
36    /// A quiz.
37    Quiz,
38    /// A regular poll.
39    Regular,
40}
41
42#[serde_with::skip_serializing_none]
43#[derive(Deserialize, Serialize)]
44struct RawQuestion {
45    question: String,
46    question_entities: Option<TextEntities>,
47}
48
49impl RawQuestion {
50    fn deserialize_value<'de, D>(deserializer: D) -> Result<Text, D::Error>
51    where
52        D: Deserializer<'de>,
53    {
54        let value = Self::deserialize(deserializer)?;
55        Ok(Text {
56            data: value.question,
57            entities: value.question_entities,
58        })
59    }
60
61    fn serialize_value<S>(value: &Text, serializer: S) -> Result<S::Ok, S::Error>
62    where
63        S: Serializer,
64    {
65        Self {
66            question: value.data.clone(),
67            question_entities: value.entities.clone(),
68        }
69        .serialize(serializer)
70    }
71}
72
73/// Represents a regular poll.
74#[serde_with::skip_serializing_none]
75#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
76pub struct RegularPoll {
77    /// Indicates whether the poll allows multiple answers.
78    pub allows_multiple_answers: bool,
79    /// Unique identifier of the poll.
80    pub id: String,
81    /// Indicates whether the poll is anonymous.
82    pub is_anonymous: bool,
83    /// Indicates whether the poll is closed.
84    pub is_closed: bool,
85    /// List of options.
86    pub options: Vec<PollOption>,
87    /// Question; 1-255 characters.
88    #[serde(
89        flatten,
90        deserialize_with = "RawQuestion::deserialize_value",
91        serialize_with = "RawQuestion::serialize_value"
92    )]
93    pub question: Text,
94    /// Total number of users that voted in the poll.
95    pub total_voter_count: Integer,
96    /// Point in time (Unix timestamp) when the poll will be automatically closed.
97    pub close_date: Option<Integer>,
98    /// Amount of time in seconds the poll will be active after creation.
99    pub open_period: Option<Integer>,
100}
101
102impl RegularPoll {
103    /// Creates a new `RegularPoll`.
104    ///
105    /// # Arguments
106    ///
107    /// * `id` - Unique identifier.
108    /// * `question` - Question; 1-255 characters.
109    pub fn new<A, B>(id: A, question: B) -> Self
110    where
111        A: Into<String>,
112        B: Into<Text>,
113    {
114        Self {
115            allows_multiple_answers: false,
116            id: id.into(),
117            is_anonymous: false,
118            is_closed: false,
119            options: vec![],
120            question: question.into(),
121            total_voter_count: 0,
122            close_date: None,
123            open_period: None,
124        }
125    }
126
127    /// Sets a new value for the `allows_multiple_answers` flag.
128    ///
129    /// # Arguments
130    ///
131    /// * `value` - Indicates whether the poll allows multiple answers.
132    pub fn with_allows_multiple_answers(mut self, value: bool) -> Self {
133        self.allows_multiple_answers = value;
134        self
135    }
136
137    /// Sets a new close date.
138    ///
139    /// # Arguments
140    ///
141    /// * `value` - Point in time (Unix timestamp) when the poll will be automatically closed.
142    pub fn with_close_date(mut self, value: Integer) -> Self {
143        self.close_date = Some(value);
144        self
145    }
146
147    /// Sets a new value for the `is_anonymous` flag.
148    ///
149    /// # Arguments
150    ///
151    /// * `value` - Indicates whether the quiz is anonymous.
152    pub fn with_is_anonymous(mut self, value: bool) -> Self {
153        self.is_anonymous = value;
154        self
155    }
156
157    /// Sets a new value for the `is_closed` flag.
158    ///
159    /// # Arguments
160    ///
161    /// * `value` - Indicates whether the quiz is closed.
162    pub fn with_is_closed(mut self, value: bool) -> Self {
163        self.is_closed = value;
164        self
165    }
166
167    /// Sets a new open period.
168    ///
169    /// # Arguments
170    ///
171    /// * `value` - Amount of time in seconds the poll will be active after creation.
172    pub fn with_open_period(mut self, value: Integer) -> Self {
173        self.open_period = Some(value);
174        self
175    }
176
177    /// Sets a new list of options.
178    ///
179    /// # Arguments
180    ///
181    /// * `value` - The list of options.
182    pub fn with_options<T>(mut self, value: T) -> Self
183    where
184        T: IntoIterator<Item = PollOption>,
185    {
186        self.options = value.into_iter().collect();
187        self
188    }
189
190    /// Sets a new correct total voter count.
191    ///
192    /// # Arguments
193    ///
194    /// * `value` - Total number of users that answered to the quiz.
195    pub fn with_total_voter_count(mut self, value: Integer) -> Self {
196        self.total_voter_count = value;
197        self
198    }
199}
200
201/// Represents a quiz.
202#[serde_with::skip_serializing_none]
203#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
204pub struct Quiz {
205    /// 0-based identifier of the correct answer option.
206    ///
207    /// Available only for a closed quiz,
208    /// or was sent (not forwarded) by the bot or
209    /// to the private chat with the bot.
210    pub correct_option_id: Integer,
211    /// Unique identifier of the quiz.
212    pub id: String,
213    /// Indicates whether the quiz is anonymous.
214    pub is_anonymous: bool,
215    /// Indicates whether the quiz is closed.
216    pub is_closed: bool,
217    /// List of options.
218    pub options: Vec<PollOption>,
219    /// Question; 1-255 characters.
220    #[serde(
221        flatten,
222        deserialize_with = "RawQuestion::deserialize_value",
223        serialize_with = "RawQuestion::serialize_value"
224    )]
225    pub question: Text,
226    /// Total number of users that answered to the quiz.
227    pub total_voter_count: Integer,
228    /// Point in time (Unix timestamp) when the quiz will be automatically closed.
229    pub close_date: Option<Integer>,
230    /// Text that is shown when a user chooses an incorrect answer or
231    /// taps on the lamp icon; 0-200 characters.
232    #[serde(
233        flatten,
234        deserialize_with = "QuizExplanation::deserialize_value",
235        serialize_with = "QuizExplanation::serialize_value"
236    )]
237    pub explanation: Option<Text>,
238    /// Amount of time in seconds the quiz will be active after creation.
239    pub open_period: Option<Integer>,
240}
241
242impl Quiz {
243    /// Creates a new `Quiz`.
244    ///
245    /// # Arguments
246    ///
247    /// * `id` - Unique identifier.
248    /// * `question` - Question; 1-255 characters.
249    pub fn new<A, B>(id: A, question: B) -> Self
250    where
251        A: Into<String>,
252        B: Into<Text>,
253    {
254        Self {
255            correct_option_id: 0,
256            id: id.into(),
257            is_anonymous: false,
258            is_closed: false,
259            options: vec![],
260            question: question.into(),
261            total_voter_count: 0,
262            close_date: None,
263            explanation: None,
264            open_period: None,
265        }
266    }
267
268    /// Sets a new close date.
269    ///
270    /// # Arguments
271    ///
272    /// * `value` - Point in time (Unix timestamp) when the quiz will be automatically closed.
273    pub fn with_close_date(mut self, value: Integer) -> Self {
274        self.close_date = Some(value);
275        self
276    }
277
278    /// Sets a new correct option ID.
279    ///
280    /// # Arguments
281    ///
282    /// * `value` - 0-based identifier of the correct answer option.
283    pub fn with_correct_option_id(mut self, value: Integer) -> Self {
284        self.correct_option_id = value;
285        self
286    }
287
288    /// Sets a new explanation.
289    ///
290    /// # Arguments
291    ///
292    /// * `value` - Text that is shown when a user chooses
293    ///   an incorrect answer or
294    ///   taps on the lamp icon; 0-200 characters.
295    pub fn with_explanation<T>(mut self, value: T) -> Self
296    where
297        T: Into<Text>,
298    {
299        self.explanation = Some(value.into());
300        self
301    }
302
303    /// Sets a new value for the `is_anonymous` flag.
304    ///
305    /// # Arguments
306    ///
307    /// * `value` - Indicates whether the quiz is anonymous.
308    pub fn with_is_anonymous(mut self, value: bool) -> Self {
309        self.is_anonymous = value;
310        self
311    }
312
313    /// Sets a new value for the `is_closed` flag.
314    ///
315    /// # Arguments
316    ///
317    /// * `value` - Indicates whether the quiz is closed.
318    pub fn with_is_closed(mut self, value: bool) -> Self {
319        self.is_closed = value;
320        self
321    }
322
323    /// Sets a new open period.
324    ///
325    /// # Arguments
326    ///
327    /// * `value` - Amount of time in seconds the quiz will be active after creation.
328    pub fn with_open_period(mut self, value: Integer) -> Self {
329        self.open_period = Some(value);
330        self
331    }
332
333    /// Sets a new list of options.
334    ///
335    /// # Arguments
336    ///
337    /// * `value` - The list of options.
338    pub fn with_options<T>(mut self, value: T) -> Self
339    where
340        T: IntoIterator<Item = PollOption>,
341    {
342        self.options = value.into_iter().collect();
343        self
344    }
345
346    /// Sets a new correct total voter count.
347    ///
348    /// # Arguments
349    ///
350    /// * `value` - Total number of users that answered to the quiz.
351    pub fn with_total_voter_count(mut self, value: Integer) -> Self {
352        self.total_voter_count = value;
353        self
354    }
355}
356
357#[serde_with::skip_serializing_none]
358#[derive(Deserialize, Serialize)]
359struct QuizExplanation {
360    explanation: String,
361    explanation_entities: Option<TextEntities>,
362}
363
364impl QuizExplanation {
365    fn deserialize_value<'de, D>(deserializer: D) -> Result<Option<Text>, D::Error>
366    where
367        D: Deserializer<'de>,
368    {
369        Option::<QuizExplanation>::deserialize(deserializer).map(|x| {
370            x.map(|value| Text {
371                data: value.explanation,
372                entities: value.explanation_entities,
373            })
374        })
375    }
376
377    fn serialize_value<S>(value: &Option<Text>, serializer: S) -> Result<S::Ok, S::Error>
378    where
379        S: Serializer,
380    {
381        let value = value.clone().map(|value| QuizExplanation {
382            explanation: value.data,
383            explanation_entities: value.entities,
384        });
385        value.serialize(serializer)
386    }
387}
388
389#[serde_with::skip_serializing_none]
390#[derive(Deserialize, Serialize)]
391struct RawPollOptionText {
392    text: String,
393    text_entities: Option<TextEntities>,
394}
395
396impl RawPollOptionText {
397    fn deserialize_value<'de, D>(deserializer: D) -> Result<Text, D::Error>
398    where
399        D: Deserializer<'de>,
400    {
401        let value = Self::deserialize(deserializer)?;
402        Ok(Text {
403            data: value.text,
404            entities: value.text_entities,
405        })
406    }
407
408    fn serialize_value<S>(value: &Text, serializer: S) -> Result<S::Ok, S::Error>
409    where
410        S: Serializer,
411    {
412        Self {
413            text: value.data.clone(),
414            text_entities: value.entities.clone(),
415        }
416        .serialize(serializer)
417    }
418}
419
420/// Represents an answer option in a poll.
421#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
422pub struct PollOption {
423    /// Option text; 1-100 characters.
424    #[serde(
425        flatten,
426        deserialize_with = "RawPollOptionText::deserialize_value",
427        serialize_with = "RawPollOptionText::serialize_value"
428    )]
429    pub text: Text,
430    /// Number of users that voted for this option.
431    pub voter_count: Integer,
432}
433
434impl PollOption {
435    /// Creates a new `PollOption`.
436    ///
437    /// # Arguments
438    ///
439    /// * `text` - Option text; 1-100 characters.
440    /// * `voter_count` - Number of users that voted for this option.
441    pub fn new<T>(text: T, voter_count: Integer) -> Self
442    where
443        T: Into<Text>,
444    {
445        Self {
446            text: text.into(),
447            voter_count,
448        }
449    }
450}
451
452/// Represents an answer of a user in a non-anonymous poll.
453#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
454pub struct PollAnswer {
455    /// 0-based identifiers of answer options, chosen by the user.
456    ///
457    /// May be empty if the user retracted their vote.
458    pub option_ids: Vec<Integer>,
459    /// Unique poll identifier.
460    pub poll_id: String,
461    /// The chat or the user that changed answer to the poll.
462    #[serde(flatten)]
463    pub voter: PollAnswerVoter,
464}
465
466impl PollAnswer {
467    /// Creates a new `PollAnswer`.
468    ///
469    /// # Arguments
470    ///
471    /// * `option_ids` - 0-based identifiers of answer options, chosen by the user.
472    /// * `poll_id` - Unique poll identifier.
473    /// * `voter` - The chat or the user that changed answer to the poll.
474    pub fn new<A, B, C>(option_ids: A, poll_id: B, voter: C) -> Self
475    where
476        A: IntoIterator<Item = Integer>,
477        B: Into<String>,
478        C: Into<PollAnswerVoter>,
479    {
480        Self {
481            option_ids: option_ids.into_iter().collect(),
482            poll_id: poll_id.into(),
483            voter: voter.into(),
484        }
485    }
486}
487
488/// Represents the chat or the user that changed answer to the poll.
489#[derive(Clone, Debug, derive_more::From, Deserialize, PartialEq, Serialize)]
490#[serde(rename_all = "snake_case")]
491pub enum PollAnswerVoter {
492    /// The chat that changed the answer to the poll, if the voter is anonymous.
493    Chat(Chat),
494    /// The user that changed the answer to the poll, if the voter isn't anonymous.
495    User(User),
496}
497
498/// Contains information about one answer option in a poll to send.
499#[serde_with::skip_serializing_none]
500#[derive(Clone, Debug, Serialize)]
501pub struct InputPollOption {
502    text: String,
503    text_parse_mode: Option<ParseMode>,
504    text_entities: Option<TextEntities>,
505}
506
507impl InputPollOption {
508    /// Creates a new `InputPollOption`.
509    ///
510    /// # Arguments
511    ///
512    /// * `text` - Option text; 1-100 characters.
513    pub fn new<T>(text: T) -> Self
514    where
515        T: Into<String>,
516    {
517        Self {
518            text: text.into(),
519            text_parse_mode: None,
520            text_entities: None,
521        }
522    }
523
524    /// Sets a new list of text entities.
525    ///
526    /// # Arguments
527    ///
528    /// * `value` - A list of special entities that appear in the poll option text.
529    ///
530    /// Text parse mode will be set to [`None`] when this method is called.
531    pub fn with_entities<T>(mut self, value: T) -> Self
532    where
533        T: IntoIterator<Item = TextEntity>,
534    {
535        self.text_entities = Some(value.into_iter().collect());
536        self.text_parse_mode = None;
537        self
538    }
539
540    /// Sets a new text parse mode.
541    ///
542    /// # Arguments
543    ///
544    /// * `value` -  Mode for parsing entities in the text.
545    ///
546    /// Currently, only custom emoji entities are allowed.
547    /// Text entities will be set to [`None`] when this method is called.
548    pub fn with_parse_mode(mut self, value: ParseMode) -> Self {
549        self.text_parse_mode = Some(value);
550        self.text_entities = None;
551        self
552    }
553}
554
555impl<T> From<T> for InputPollOption
556where
557    T: Into<Text>,
558{
559    fn from(value: T) -> Self {
560        let value = value.into();
561        Self {
562            text: value.data,
563            text_entities: value.entities,
564            text_parse_mode: None,
565        }
566    }
567}
568
569#[serde_with::skip_serializing_none]
570#[derive(Clone, Debug, Serialize)]
571struct PollParameters {
572    chat_id: ChatId,
573    options: Vec<InputPollOption>,
574    question: String,
575    allow_paid_broadcast: Option<bool>,
576    allows_multiple_answers: Option<bool>,
577    business_connection_id: Option<String>,
578    close_date: Option<Integer>,
579    correct_option_id: Option<Integer>,
580    disable_notification: Option<bool>,
581    explanation: Option<String>,
582    explanation_entities: Option<TextEntities>,
583    explanation_parse_mode: Option<ParseMode>,
584    is_anonymous: Option<bool>,
585    is_closed: Option<bool>,
586    message_effect_id: Option<String>,
587    message_thread_id: Option<Integer>,
588    open_period: Option<Integer>,
589    #[serde(rename = "type")]
590    poll_type: Option<PollType>,
591    protect_content: Option<bool>,
592    question_entities: Option<TextEntities>,
593    question_parse_mode: Option<ParseMode>,
594    reply_markup: Option<ReplyMarkup>,
595    reply_parameters: Option<ReplyParameters>,
596}
597
598impl PollParameters {
599    fn new<A, B>(chat_id: ChatId, question: String, poll_type: PollType, options: A) -> Self
600    where
601        A: IntoIterator<Item = B>,
602        B: Into<InputPollOption>,
603    {
604        Self {
605            chat_id,
606            options: options.into_iter().map(Into::into).collect(),
607            question,
608            allow_paid_broadcast: None,
609            allows_multiple_answers: None,
610            business_connection_id: None,
611            close_date: None,
612            correct_option_id: None,
613            disable_notification: None,
614            explanation: None,
615            explanation_entities: None,
616            explanation_parse_mode: None,
617            is_anonymous: None,
618            is_closed: None,
619            message_effect_id: None,
620            message_thread_id: None,
621            open_period: None,
622            poll_type: Some(poll_type),
623            question_entities: None,
624            question_parse_mode: None,
625            protect_content: None,
626            reply_markup: None,
627            reply_parameters: None,
628        }
629    }
630}
631
632/// Sends a quiz.
633///
634/// On success, the sent [`Message`] is returned.
635#[derive(Clone, Debug, Serialize)]
636pub struct SendQuiz {
637    #[serde(flatten)]
638    inner: PollParameters,
639}
640
641impl SendQuiz {
642    /// Creates a new `SendQuiz`.
643    ///
644    /// # Arguments
645    ///
646    /// * `chat_id` - Unique identifier of the target chat.
647    /// * `question` - Question; 1-300 characters.
648    /// * `correct_option_id` - 0-based identifier of the correct answer option.
649    /// * `options` - Answer options; 2-12.
650    pub fn new<A, B, C, D>(chat_id: A, question: B, correct_option_id: Integer, options: C) -> Self
651    where
652        A: Into<ChatId>,
653        B: Into<String>,
654        C: IntoIterator<Item = D>,
655        D: Into<InputPollOption>,
656    {
657        let mut parameters = PollParameters::new(chat_id.into(), question.into(), PollType::Quiz, options);
658        parameters.correct_option_id = Some(correct_option_id);
659        Self { inner: parameters }
660    }
661
662    /// Sets a new value for the `allow_paid_broadcast` flag.
663    ///
664    /// # Arguments
665    ///
666    /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
667    ///   for a fee of 0.1 Telegram Stars per message.
668    ///   The relevant Stars will be withdrawn from the bot's balance.
669    pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
670        self.inner.allow_paid_broadcast = Some(value);
671        self
672    }
673
674    /// Sets a new business connection ID.
675    ///
676    /// # Arguments
677    ///
678    /// * `value` - Unique identifier of the business connection.
679    pub fn with_business_connection_id<T>(mut self, value: T) -> Self
680    where
681        T: Into<String>,
682    {
683        self.inner.business_connection_id = Some(value.into());
684        self
685    }
686
687    /// Sets a new close date.
688    ///
689    /// # Arguments
690    ///
691    /// * `value` - Point in time (Unix timestamp) when the quiz will be automatically closed.
692    ///
693    /// Must be at least 5 and no more than 600 seconds in the future.
694    /// Can't be used together with [`Self::with_open_period`] (open period will be set to [`None`]).
695    pub fn with_close_date(mut self, value: Integer) -> Self {
696        self.inner.close_date = Some(value);
697        self.inner.open_period = None;
698        self
699    }
700
701    /// Sets a new value for the `disable_notification` flag.
702    ///
703    /// # Arguments
704    ///
705    /// * `value` - Indicates whether to send the message silently or not;
706    ///   a user will receive a notification without sound.
707    pub fn with_disable_notification(mut self, value: bool) -> Self {
708        self.inner.disable_notification = Some(value);
709        self
710    }
711
712    /// Sets a new explanation.
713    ///
714    /// # Arguments
715    ///
716    /// * `value` - Text that is shown when a user chooses
717    ///   an incorrect answer or taps on the lamp icon;
718    ///   0-200 characters with at most 2 line feeds after entities parsing.
719    pub fn with_explanation<T>(mut self, value: T) -> Self
720    where
721        T: Into<String>,
722    {
723        self.inner.explanation = Some(value.into());
724        self
725    }
726
727    /// Sets a new list of explanation entities.
728    ///
729    /// # Arguments
730    ///
731    /// * `value` - List of special entities that appear in the quiz explanation.
732    ///
733    /// Explanation parse mode will be set to [`None`] when this method is called.
734    pub fn with_explanation_entities<T>(mut self, value: T) -> Self
735    where
736        T: IntoIterator<Item = TextEntity>,
737    {
738        self.inner.explanation_entities = Some(value.into_iter().collect());
739        self.inner.explanation_parse_mode = None;
740        self
741    }
742
743    /// Sets a new explanation parse mode.
744    ///
745    /// # Arguments
746    ///
747    /// * `value` - Mode for parsing entities in the explanation.
748    ///
749    /// Explanation entities will be set to [`None`] when this method is called.
750    pub fn with_explanation_parse_mode(mut self, value: ParseMode) -> Self {
751        self.inner.explanation_parse_mode = Some(value);
752        self.inner.explanation_entities = None;
753        self
754    }
755
756    /// Sets a new value for the `is_anonymous` flag.
757    ///
758    /// # Arguments
759    ///
760    /// * `value` - Indicates whether the quiz needs to be anonymous; default - `true`.
761    pub fn with_is_anonymous(mut self, value: bool) -> Self {
762        self.inner.is_anonymous = Some(value);
763        self
764    }
765
766    /// Sets a new value for the `is_closed` flag.
767    ///
768    /// # Arguments
769    ///
770    /// * `value` - Indicates whether the quiz needs to be immediately closed.
771    pub fn with_is_closed(mut self, value: bool) -> Self {
772        self.inner.is_closed = Some(value);
773        self
774    }
775
776    /// Sets a new message effect ID.
777    ///
778    /// # Arguments
779    ///
780    /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
781    pub fn with_message_effect_id<T>(mut self, value: T) -> Self
782    where
783        T: Into<String>,
784    {
785        self.inner.message_effect_id = Some(value.into());
786        self
787    }
788
789    /// Sets a new message thread ID.
790    ///
791    /// # Arguments
792    ///
793    /// * `value` - Unique identifier of the target message thread;
794    ///   supergroups only.
795    pub fn with_message_thread_id(mut self, value: Integer) -> Self {
796        self.inner.message_thread_id = Some(value);
797        self
798    }
799
800    /// Sets a new open period.
801    ///
802    /// # Arguments
803    ///
804    /// * `value` - Amount of time in seconds the quiz will be active after creation; 5-600.
805    ///
806    /// Can't be used together with [`Self::with_close_date`] (close date will be set to [`None`]).
807    pub fn with_open_period(mut self, value: Integer) -> Self {
808        self.inner.open_period = Some(value);
809        self.inner.close_date = None;
810        self
811    }
812
813    /// Sets a new value for the `protect_content` flag.
814    ///
815    /// # Arguments
816    ///
817    /// * `value` - Indicates whether to protect the contents
818    ///   of the sent message from forwarding and saving.
819    pub fn with_protect_content(mut self, value: bool) -> Self {
820        self.inner.protect_content = Some(value);
821        self
822    }
823
824    /// Sets a new list of question entities.
825    ///
826    /// # Arguments
827    ///
828    /// * `value` - A list of special entities that appear in the poll question.
829    ///
830    /// Question parse mode will be set to [`None`] when this method is called.
831    pub fn with_question_entities<T>(mut self, value: T) -> Self
832    where
833        T: IntoIterator<Item = TextEntity>,
834    {
835        self.inner.question_entities = Some(value.into_iter().collect());
836        self.inner.question_parse_mode = None;
837        self
838    }
839
840    /// Sets a new question parse mode.
841    ///
842    /// # Arguments
843    ///
844    /// * `value` - Mode for parsing entities in the question.
845    ///
846    /// Question entities will be set to [`None`] when this method is called.
847    pub fn with_question_parse_mode(mut self, value: ParseMode) -> Self {
848        self.inner.question_parse_mode = Some(value);
849        self.inner.question_entities = None;
850        self
851    }
852
853    /// Sets a new reply markup.
854    ///
855    /// # Arguments
856    ///
857    /// * `value` - Reply markup.
858    pub fn with_reply_markup<T>(mut self, value: T) -> Self
859    where
860        T: Into<ReplyMarkup>,
861    {
862        self.inner.reply_markup = Some(value.into());
863        self
864    }
865
866    /// Sets new reply parameters.
867    ///
868    /// # Arguments
869    ///
870    /// * `value` - Description of the message to reply to.
871    pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Self {
872        self.inner.reply_parameters = Some(value);
873        self
874    }
875}
876
877impl Method for SendQuiz {
878    type Response = Message;
879
880    fn into_payload(self) -> Payload {
881        Payload::json("sendPoll", self)
882    }
883}
884
885/// Sends a native poll.
886///
887/// On success, the sent [`Message`] is returned.
888#[derive(Clone, Debug, Serialize)]
889pub struct SendPoll {
890    #[serde(flatten)]
891    inner: PollParameters,
892}
893
894impl SendPoll {
895    /// Creates a new `SendPoll`.
896    ///
897    /// # Arguments
898    ///
899    /// * `chat_id` - Unique identifier of the target chat.
900    /// * `question` - Question; 1-300 characters.
901    /// * `options` - Answer options; 2-12.
902    pub fn new<A, B, C, D>(chat_id: A, question: B, options: C) -> Self
903    where
904        A: Into<ChatId>,
905        B: Into<String>,
906        C: IntoIterator<Item = D>,
907        D: Into<InputPollOption>,
908    {
909        Self {
910            inner: PollParameters::new(chat_id.into(), question.into(), PollType::Regular, options),
911        }
912    }
913
914    /// Sets a new value for the `allow_paid_broadcast` flag.
915    ///
916    /// # Arguments
917    ///
918    /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
919    ///   for a fee of 0.1 Telegram Stars per message.
920    ///   The relevant Stars will be withdrawn from the bot's balance.
921    pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
922        self.inner.allow_paid_broadcast = Some(value);
923        self
924    }
925
926    /// Sets a new value for the `allows_multiple_answers` flag.
927    ///
928    /// # Arguments
929    ///
930    /// * `value` - Indicates whether the poll allows multiple answers; default - `false`.
931    pub fn with_allows_multiple_answers(mut self, value: bool) -> Self {
932        self.inner.allows_multiple_answers = Some(value);
933        self
934    }
935
936    /// Sets a new business connection ID.
937    ///
938    /// # Arguments
939    ///
940    /// * `value` - Unique identifier of the business connection on behalf.
941    pub fn with_business_connection_id<T>(mut self, value: T) -> Self
942    where
943        T: Into<String>,
944    {
945        self.inner.business_connection_id = Some(value.into());
946        self
947    }
948
949    /// Sets a new close date.
950    ///
951    /// # Arguments
952    ///
953    /// * `value` - Point in time (Unix timestamp) when the poll will be automatically closed.
954    ///
955    /// Must be at least 5 and no more than 600 seconds in the future.
956    /// Can't be used together with [`Self::with_open_period`] (open period will be set to [`None`])
957    pub fn with_close_date(mut self, value: Integer) -> Self {
958        self.inner.close_date = Some(value);
959        self.inner.open_period = None;
960        self
961    }
962
963    /// Sets a new value for the `disable_notification` flag.
964    ///
965    /// # Arguments
966    ///
967    /// * `value` - Indicates whether to send the message silently or not;
968    ///   a user will receive a notification without sound.
969    pub fn with_disable_notification(mut self, value: bool) -> Self {
970        self.inner.disable_notification = Some(value);
971        self
972    }
973
974    /// Sets a new value for the `is_anonymous` flag.
975    ///
976    /// # Arguments
977    ///
978    /// * `value` - Indicates whether the poll needs to be anonymous; default - `true`.
979    pub fn with_is_anonymous(mut self, value: bool) -> Self {
980        self.inner.is_anonymous = Some(value);
981        self
982    }
983
984    /// Sets a new value for the `is_closed` flag.
985    ///
986    /// # Arguments
987    ///
988    /// * `value` - Indicates whether the poll needs to be immediately closed.
989    pub fn with_is_closed(mut self, value: bool) -> Self {
990        self.inner.is_closed = Some(value);
991        self
992    }
993
994    /// Sets a new message effect ID.
995    ///
996    /// # Arguments
997    ///
998    /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
999    pub fn with_message_effect_id<T>(mut self, value: T) -> Self
1000    where
1001        T: Into<String>,
1002    {
1003        self.inner.message_effect_id = Some(value.into());
1004        self
1005    }
1006
1007    /// Sets a new message thread ID.
1008    ///
1009    /// # Arguments
1010    ///
1011    /// * `value` - Unique identifier of the target message thread;
1012    ///   supergroups only.
1013    pub fn with_message_thread_id(mut self, value: Integer) -> Self {
1014        self.inner.message_thread_id = Some(value);
1015        self
1016    }
1017
1018    /// Sets a new open period.
1019    ///
1020    /// # Arguments
1021    ///
1022    /// * `value` - Amount of time in seconds the poll will be active after creation; 5-600.
1023    ///
1024    /// Can't be used together with `close_date` (`close_date` will be set to [`None`]).
1025    pub fn with_open_period(mut self, value: Integer) -> Self {
1026        self.inner.open_period = Some(value);
1027        self.inner.close_date = None;
1028        self
1029    }
1030
1031    /// Sets a new value for the `protect_content` flag.
1032    ///
1033    /// # Arguments
1034    ///
1035    /// * `value` - Indicates whether to protect the contents
1036    ///   of the sent message from forwarding and saving.
1037    pub fn with_protect_content(mut self, value: bool) -> Self {
1038        self.inner.protect_content = Some(value);
1039        self
1040    }
1041
1042    /// Sets a new list of question entities.
1043    ///
1044    /// # Arguments
1045    ///
1046    /// * `value` - A list of special entities that appear in the poll question.
1047    ///
1048    /// Question parse mode will be set to [`None`] when this method is called.
1049    pub fn with_question_entities<T>(mut self, value: T) -> Self
1050    where
1051        T: IntoIterator<Item = TextEntity>,
1052    {
1053        self.inner.question_entities = Some(value.into_iter().collect());
1054        self.inner.question_parse_mode = None;
1055        self
1056    }
1057
1058    /// Sets a new question parse mode.
1059    ///
1060    /// # Arguments
1061    ///
1062    /// * `value` - Mode for parsing entities in the question.
1063    ///
1064    /// Question entities will be set to [`None`] when this method is called.
1065    pub fn with_question_parse_mode(mut self, value: ParseMode) -> Self {
1066        self.inner.question_parse_mode = Some(value);
1067        self.inner.question_entities = None;
1068        self
1069    }
1070
1071    /// Sets a new reply markup.
1072    ///
1073    /// # Arguments
1074    ///
1075    /// * `value` - Reply markup.
1076    pub fn with_reply_markup<T>(mut self, value: T) -> Self
1077    where
1078        T: Into<ReplyMarkup>,
1079    {
1080        self.inner.reply_markup = Some(value.into());
1081        self
1082    }
1083
1084    /// Sets new reply parameters.
1085    ///
1086    /// # Arguments
1087    ///
1088    /// * `value` - Description of the message to reply to.
1089    pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Self {
1090        self.inner.reply_parameters = Some(value);
1091        self
1092    }
1093}
1094
1095impl Method for SendPoll {
1096    type Response = Message;
1097
1098    fn into_payload(self) -> Payload {
1099        Payload::json("sendPoll", self)
1100    }
1101}
1102
1103/// Stops a poll which was sent by the bot.
1104///
1105/// On success, the stopped [`Poll`] with the final results is returned.
1106#[serde_with::skip_serializing_none]
1107#[derive(Clone, Debug, Serialize)]
1108pub struct StopPoll {
1109    chat_id: ChatId,
1110    message_id: Integer,
1111    business_connection_id: Option<String>,
1112    reply_markup: Option<InlineKeyboardMarkup>,
1113}
1114
1115/// Stops a quiz which was sent by the bot.
1116///
1117/// On success, the stopped [`Quiz`] with the final results is returned.
1118pub type StopQuiz = StopPoll;
1119
1120impl StopPoll {
1121    /// Creates a new `StopPoll`.
1122    ///
1123    /// # Arguments
1124    ///
1125    /// * `chat_id` - Unique identifier of the target chat.
1126    /// * `message_id` - Identifier of the original message with the poll.
1127    pub fn new<T>(chat_id: T, message_id: Integer) -> Self
1128    where
1129        T: Into<ChatId>,
1130    {
1131        Self {
1132            chat_id: chat_id.into(),
1133            message_id,
1134            business_connection_id: None,
1135            reply_markup: None,
1136        }
1137    }
1138
1139    /// Sets a new business connection ID.
1140    ///
1141    /// # Arguments
1142    ///
1143    /// * `value` - Unique identifier of the business connection on behalf of which the message to be edited was sent.
1144    pub fn with_business_connection_id<T>(mut self, value: T) -> Self
1145    where
1146        T: Into<String>,
1147    {
1148        self.business_connection_id = Some(value.into());
1149        self
1150    }
1151
1152    /// Sets a new reply markup.
1153    ///
1154    /// # Arguments
1155    ///
1156    /// * `value` - Reply markup.
1157    pub fn with_reply_markup<T>(mut self, value: T) -> Self
1158    where
1159        T: Into<InlineKeyboardMarkup>,
1160    {
1161        self.reply_markup = Some(value.into());
1162        self
1163    }
1164}
1165
1166impl Method for StopPoll {
1167    type Response = Poll;
1168
1169    fn into_payload(self) -> Payload {
1170        Payload::json("stopPoll", self)
1171    }
1172}