Skip to main content

rustigram_types/
poll.rs

1use serde::{Deserialize, Serialize};
2
3use crate::chat::Chat;
4use crate::message::MessageEntity;
5use crate::user::User;
6
7/// A native Telegram poll or quiz.
8///
9/// Polls are either `regular` (users vote freely) or `quiz` (one or more correct
10/// answers). Returned inside [`Message`](crate::message::Message) when a poll is
11/// sent or forwarded.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Poll {
14    /// Unique poll identifier.
15    pub id: String,
16    /// Poll question (1–300 characters).
17    pub question: String,
18    /// Special entities in the question.
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub question_entities: Option<Vec<MessageEntity>>,
21    /// List of answer options.
22    pub options: Vec<PollOption>,
23    /// Total number of users who voted.
24    pub total_voter_count: u32,
25    /// `true` if the poll is closed.
26    pub is_closed: bool,
27    /// `true` if the poll is anonymous.
28    pub is_anonymous: bool,
29    /// Poll type.
30    #[serde(rename = "type")]
31    pub kind: PollType,
32    /// `true` if the poll allows multiple answers.
33    pub allows_multiple_answers: bool,
34    /// `true` if voters can change their chosen answer options.
35    pub allows_revoting: bool,
36    /// Zero-based indices of the correct answers (quiz polls only).
37    ///
38    /// Bot API 9.6 changed this from a single `u8` to an array to support
39    /// quizzes with multiple correct answers.
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub correct_option_ids: Option<Vec<u8>>,
42    /// Explanation shown after a quiz is answered.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub explanation: Option<String>,
45    /// Special entities in the explanation.
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub explanation_entities: Option<Vec<MessageEntity>>,
48    /// Duration in seconds the poll stays active after creation.
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub open_period: Option<u32>,
51    /// Unix timestamp when the poll closes automatically.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub close_date: Option<i64>,
54    /// Description of the poll; present only inside `Message` objects.
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub description: Option<String>,
57    /// Special entities in the description.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub description_entities: Option<Vec<MessageEntity>>,
60    /// `true` if voting is limited to users who have been members of the chat for more than 24 hours.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub members_only: Option<bool>,
63    /// Two-letter ISO 3166-1 alpha-2 country codes indicating the countries from which users can vote.
64    /// If absent, users from any country can participate.
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub country_codes: Option<Vec<String>>,
67}
68
69/// One option in a [`Poll`].
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct PollOption {
72    /// Persistent identifier of this option, stable across poll edits.
73    pub persistent_id: String,
74    /// Option text (1–100 characters).
75    pub text: String,
76    /// Special entities in the option text.
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub text_entities: Option<Vec<MessageEntity>>,
79    /// Number of users who voted for this option.
80    pub voter_count: u32,
81    /// The user who added this option, if applicable.
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub added_by_user: Option<User>,
84    /// The chat that added this option, if applicable.
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub added_by_chat: Option<Chat>,
87    /// Unix timestamp when this option was added; absent if it existed at poll creation.
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub addition_date: Option<i64>,
90}
91
92/// An option to include when creating a poll with `sendPoll`.
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct InputPollOption {
95    /// Option text (1–100 characters).
96    pub text: String,
97    /// Parse mode for the option text.
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub text_parse_mode: Option<crate::message::ParseMode>,
100    /// Special entities in the option text; alternative to `text_parse_mode`.
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub text_entities: Option<Vec<MessageEntity>>,
103}
104
105impl InputPollOption {
106    /// Creates a new `InputPollOption` with the given text.
107    pub fn new(text: impl Into<String>) -> Self {
108        Self {
109            text: text.into(),
110            text_parse_mode: None,
111            text_entities: None,
112        }
113    }
114}
115
116/// The type of a poll.
117#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
118#[serde(rename_all = "snake_case")]
119pub enum PollType {
120    /// A regular poll where users can vote freely.
121    Regular,
122    /// A quiz with one or more correct answers.
123    Quiz,
124}
125
126/// An answer submitted by a user in a non-anonymous poll.
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct PollAnswer {
129    /// Unique poll identifier.
130    pub poll_id: String,
131    /// The chat that changed the answer (for anonymous polls in groups).
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub voter_chat: Option<Chat>,
134    /// The user who changed the answer (for non-anonymous polls).
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub user: Option<User>,
137    /// Zero-based indices of the chosen options; empty if the vote was retracted.
138    pub option_ids: Vec<u8>,
139    /// Persistent identifiers of the chosen options; empty if the vote was retracted.
140    pub option_persistent_ids: Vec<String>,
141}
142
143/// Service message: a new option was added to a poll.
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct PollOptionAdded {
146    /// Message containing the poll to which the option was added.
147    ///
148    /// Uses `serde_json::Value` because the API returns a `MaybeInaccessibleMessage`
149    /// union type here. Will not contain `reply_to_message`.
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub poll_message: Option<serde_json::Value>,
152    /// Persistent identifier of the added option.
153    pub option_persistent_id: String,
154    /// Text of the added option.
155    pub option_text: String,
156    /// Special entities in the option text.
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub option_text_entities: Option<Vec<MessageEntity>>,
159}
160
161/// Service message: an option was deleted from a poll.
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct PollOptionDeleted {
164    /// Message containing the poll from which the option was deleted.
165    ///
166    /// Uses `serde_json::Value` because the API returns a `MaybeInaccessibleMessage`
167    /// union type here. Will not contain `reply_to_message`.
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub poll_message: Option<serde_json::Value>,
170    /// Persistent identifier of the deleted option.
171    pub option_persistent_id: String,
172    /// Text of the deleted option.
173    pub option_text: String,
174    /// Special entities in the option text.
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub option_text_entities: Option<Vec<MessageEntity>>,
177}