Skip to main content

rustigram_types/
poll.rs

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