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}