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}
61
62/// One option in a [`Poll`].
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct PollOption {
65 /// Persistent identifier of this option, stable across poll edits.
66 pub persistent_id: String,
67 /// Option text (1–100 characters).
68 pub text: String,
69 /// Special entities in the option text.
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub text_entities: Option<Vec<MessageEntity>>,
72 /// Number of users who voted for this option.
73 pub voter_count: u32,
74 /// The user who added this option, if applicable.
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub added_by_user: Option<User>,
77 /// The chat that added this option, if applicable.
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub added_by_chat: Option<Chat>,
80 /// Unix timestamp when this option was added; absent if it existed at poll creation.
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub addition_date: Option<i64>,
83}
84
85/// An option to include when creating a poll with `sendPoll`.
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct InputPollOption {
88 /// Option text (1–100 characters).
89 pub text: String,
90 /// Parse mode for the option text.
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub text_parse_mode: Option<crate::message::ParseMode>,
93 /// Special entities in the option text; alternative to `text_parse_mode`.
94 #[serde(skip_serializing_if = "Option::is_none")]
95 pub text_entities: Option<Vec<MessageEntity>>,
96}
97
98impl InputPollOption {
99 /// Creates a new `InputPollOption` with the given text.
100 pub fn new(text: impl Into<String>) -> Self {
101 Self {
102 text: text.into(),
103 text_parse_mode: None,
104 text_entities: None,
105 }
106 }
107}
108
109/// The type of a poll.
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
111#[serde(rename_all = "snake_case")]
112pub enum PollType {
113 /// A regular poll where users can vote freely.
114 Regular,
115 /// A quiz with one or more correct answers.
116 Quiz,
117}
118
119/// An answer submitted by a user in a non-anonymous poll.
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct PollAnswer {
122 /// Unique poll identifier.
123 pub poll_id: String,
124 /// The chat that changed the answer (for anonymous polls in groups).
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub voter_chat: Option<Chat>,
127 /// The user who changed the answer (for non-anonymous polls).
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub user: Option<User>,
130 /// Zero-based indices of the chosen options; empty if the vote was retracted.
131 pub option_ids: Vec<u8>,
132 /// Persistent identifiers of the chosen options; empty if the vote was retracted.
133 pub option_persistent_ids: Vec<String>,
134}
135
136/// Service message: a new option was added to a poll.
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct PollOptionAdded {
139 /// Message containing the poll to which the option was added.
140 ///
141 /// Uses `serde_json::Value` because the API returns a `MaybeInaccessibleMessage`
142 /// union type here. Will not contain `reply_to_message`.
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub poll_message: Option<serde_json::Value>,
145 /// Persistent identifier of the added option.
146 pub option_persistent_id: String,
147 /// Text of the added option.
148 pub option_text: String,
149 /// Special entities in the option text.
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub option_text_entities: Option<Vec<MessageEntity>>,
152}
153
154/// Service message: an option was deleted from a poll.
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct PollOptionDeleted {
157 /// Message containing the poll from which the option was deleted.
158 ///
159 /// Uses `serde_json::Value` because the API returns a `MaybeInaccessibleMessage`
160 /// union type here. Will not contain `reply_to_message`.
161 #[serde(skip_serializing_if = "Option::is_none")]
162 pub poll_message: Option<serde_json::Value>,
163 /// Persistent identifier of the deleted option.
164 pub option_persistent_id: String,
165 /// Text of the deleted option.
166 pub option_text: String,
167 /// Special entities in the option text.
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub option_text_entities: Option<Vec<MessageEntity>>,
170}