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