Skip to main content

rustigram_types/
poll.rs

1use serde::{Deserialize, Serialize};
2
3use crate::chat::{Chat, Location, Venue};
4use crate::file::{Animation, Audio, Document, LivePhoto, PhotoSize, Video};
5use crate::message::MessageEntity;
6use crate::sticker::Sticker;
7use crate::user::User;
8
9/// Media attached to a poll description, quiz explanation, or poll option.
10///
11/// At most one of the optional fields will be `Some`.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct PollMedia {
14    /// Animation media.
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub animation: Option<Animation>,
17    /// Audio file; currently not receivable in poll options.
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub audio: Option<Audio>,
20    /// General file; currently not receivable in poll options.
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub document: Option<Document>,
23    /// Live photo media.
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub live_photo: Option<LivePhoto>,
26    /// Location media.
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub location: Option<Location>,
29    /// Photo media (available sizes).
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub photo: Option<Vec<PhotoSize>>,
32    /// Sticker media; only for poll options.
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub sticker: Option<Sticker>,
35    /// Venue media.
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub venue: Option<Venue>,
38    /// Video media.
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub video: Option<Video>,
41}
42
43/// Media content for a poll description or quiz explanation to be sent.
44#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(tag = "type", rename_all = "snake_case")]
46pub enum InputPollMedia {
47    /// An animation.
48    Animation(crate::file::InputMediaAnimation),
49    /// An audio file.
50    Audio(crate::file::InputMediaAudio),
51    /// A document.
52    Document(crate::file::InputMediaDocument),
53    /// A live photo.
54    LivePhoto(crate::file::InputMediaLivePhoto),
55    /// A location.
56    Location(crate::file::InputMediaLocation),
57    /// A photo.
58    Photo(crate::file::InputMediaPhoto),
59    /// A venue.
60    Venue(crate::file::InputMediaVenue),
61    /// A video.
62    Video(crate::file::InputMediaVideo),
63}
64
65/// Media content for a poll option to be sent.
66#[derive(Debug, Clone, Serialize, Deserialize)]
67#[serde(tag = "type", rename_all = "snake_case")]
68pub enum InputPollOptionMedia {
69    /// An animation.
70    Animation(crate::file::InputMediaAnimation),
71    /// A live photo.
72    LivePhoto(crate::file::InputMediaLivePhoto),
73    /// A location.
74    Location(crate::file::InputMediaLocation),
75    /// A photo.
76    Photo(crate::file::InputMediaPhoto),
77    /// A sticker.
78    Sticker(crate::file::InputMediaSticker),
79    /// A venue.
80    Venue(crate::file::InputMediaVenue),
81    /// A video.
82    Video(crate::file::InputMediaVideo),
83}
84
85/// A native Telegram poll or quiz.
86///
87/// Polls are either `regular` (users vote freely) or `quiz` (one or more correct
88/// answers). Returned inside [`Message`](crate::message::Message) when a poll is
89/// sent or forwarded.
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct Poll {
92    /// Unique poll identifier.
93    pub id: String,
94    /// Poll question (1–300 characters).
95    pub question: String,
96    /// Special entities in the question.
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub question_entities: Option<Vec<MessageEntity>>,
99    /// List of answer options.
100    pub options: Vec<PollOption>,
101    /// Total number of users who voted.
102    pub total_voter_count: u32,
103    /// `true` if the poll is closed.
104    pub is_closed: bool,
105    /// `true` if the poll is anonymous.
106    pub is_anonymous: bool,
107    /// Poll type.
108    #[serde(rename = "type")]
109    pub kind: PollType,
110    /// `true` if the poll allows multiple answers.
111    pub allows_multiple_answers: bool,
112    /// `true` if voters can change their chosen answer options.
113    pub allows_revoting: bool,
114    /// Zero-based indices of the correct answers (quiz polls only).
115    ///
116    /// Bot API 9.6 changed this from a single `u8` to an array to support
117    /// quizzes with multiple correct answers.
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub correct_option_ids: Option<Vec<u8>>,
120    /// Explanation shown after a quiz is answered.
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub explanation: Option<String>,
123    /// Special entities in the explanation.
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub explanation_entities: Option<Vec<MessageEntity>>,
126    /// Duration in seconds the poll stays active after creation.
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub open_period: Option<u32>,
129    /// Unix timestamp when the poll closes automatically.
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub close_date: Option<i64>,
132    /// Description of the poll; present only inside `Message` objects.
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub description: Option<String>,
135    /// Special entities in the description.
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub description_entities: Option<Vec<MessageEntity>>,
138    /// Media added to the poll description; present only inside `Message` objects.
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub media: Option<PollMedia>,
141    /// Media added to the quiz explanation.
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub explanation_media: Option<PollMedia>,
144    /// `true` if voting is limited to users who have been members of the chat for more than 24 hours.
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub members_only: Option<bool>,
147    /// Two-letter ISO 3166-1 alpha-2 country codes indicating the countries from which users can vote.
148    /// If absent, users from any country can participate.
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub country_codes: Option<Vec<String>>,
151}
152
153/// One option in a [`Poll`].
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct PollOption {
156    /// Persistent identifier of this option, stable across poll edits.
157    pub persistent_id: String,
158    /// Option text (1–100 characters).
159    pub text: String,
160    /// Special entities in the option text.
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub text_entities: Option<Vec<MessageEntity>>,
163    /// Number of users who voted for this option.
164    pub voter_count: u32,
165    /// The user who added this option, if applicable.
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub added_by_user: Option<User>,
168    /// The chat that added this option, if applicable.
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub added_by_chat: Option<Chat>,
171    /// Unix timestamp when this option was added; absent if it existed at poll creation.
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub addition_date: Option<i64>,
174    /// Media added to this poll option.
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub media: Option<PollMedia>,
177}
178
179/// An option to include when creating a poll with `sendPoll`.
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct InputPollOption {
182    /// Option text (1–100 characters).
183    pub text: String,
184    /// Parse mode for the option text.
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub text_parse_mode: Option<crate::message::ParseMode>,
187    /// Special entities in the option text; alternative to `text_parse_mode`.
188    #[serde(skip_serializing_if = "Option::is_none")]
189    pub text_entities: Option<Vec<MessageEntity>>,
190    /// Media added to this poll option.
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub media: Option<InputPollOptionMedia>,
193}
194
195impl InputPollOption {
196    /// Creates a new `InputPollOption` with the given text.
197    pub fn new(text: impl Into<String>) -> Self {
198        Self {
199            text: text.into(),
200            text_parse_mode: None,
201            text_entities: None,
202            media: None,
203        }
204    }
205}
206
207/// The type of a poll.
208#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
209#[serde(rename_all = "snake_case")]
210pub enum PollType {
211    /// A regular poll where users can vote freely.
212    Regular,
213    /// A quiz with one or more correct answers.
214    Quiz,
215}
216
217/// An answer submitted by a user in a non-anonymous poll.
218#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct PollAnswer {
220    /// Unique poll identifier.
221    pub poll_id: String,
222    /// The chat that changed the answer (for anonymous polls in groups).
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub voter_chat: Option<Chat>,
225    /// The user who changed the answer (for non-anonymous polls).
226    #[serde(skip_serializing_if = "Option::is_none")]
227    pub user: Option<User>,
228    /// Zero-based indices of the chosen options; empty if the vote was retracted.
229    pub option_ids: Vec<u8>,
230    /// Persistent identifiers of the chosen options; empty if the vote was retracted.
231    pub option_persistent_ids: Vec<String>,
232}
233
234/// Service message: a new option was added to a poll.
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct PollOptionAdded {
237    /// Message containing the poll to which the option was added.
238    ///
239    /// Uses `serde_json::Value` because the API returns a `MaybeInaccessibleMessage`
240    /// union type here. Will not contain `reply_to_message`.
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub poll_message: Option<serde_json::Value>,
243    /// Persistent identifier of the added option.
244    pub option_persistent_id: String,
245    /// Text of the added option.
246    pub option_text: String,
247    /// Special entities in the option text.
248    #[serde(skip_serializing_if = "Option::is_none")]
249    pub option_text_entities: Option<Vec<MessageEntity>>,
250}
251
252/// Service message: an option was deleted from a poll.
253#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct PollOptionDeleted {
255    /// Message containing the poll from which the option was deleted.
256    ///
257    /// Uses `serde_json::Value` because the API returns a `MaybeInaccessibleMessage`
258    /// union type here. Will not contain `reply_to_message`.
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub poll_message: Option<serde_json::Value>,
261    /// Persistent identifier of the deleted option.
262    pub option_persistent_id: String,
263    /// Text of the deleted option.
264    pub option_text: String,
265    /// Special entities in the option text.
266    #[serde(skip_serializing_if = "Option::is_none")]
267    pub option_text_entities: Option<Vec<MessageEntity>>,
268}