1use serde::{Deserialize, Serialize};
2
3use crate::{
4 api::{Form, Method, Payload},
5 types::{
6 ChatId,
7 InputPaidMediaGroup,
8 Integer,
9 Message,
10 ParseMode,
11 PhotoSize,
12 ReplyMarkup,
13 ReplyMarkupError,
14 ReplyParameters,
15 ReplyParametersError,
16 TextEntities,
17 TextEntity,
18 TextEntityError,
19 User,
20 Video,
21 },
22};
23
24#[cfg(test)]
25mod tests;
26
27#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
29pub struct PaidMediaPurchased {
30 pub from: User,
32 #[serde(rename = "paid_media_payload")]
34 pub payload: String,
35}
36
37impl PaidMediaPurchased {
38 pub fn new<T>(from: User, payload: T) -> Self
45 where
46 T: Into<String>,
47 {
48 Self {
49 from,
50 payload: payload.into(),
51 }
52 }
53}
54
55#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
57pub struct PaidMediaInfo {
58 pub star_count: Integer,
60 pub paid_media: Vec<PaidMedia>,
62}
63
64impl PaidMediaInfo {
65 pub fn new<A, B>(star_count: Integer, paid_media: A) -> Self
72 where
73 A: IntoIterator<Item = B>,
74 B: Into<PaidMedia>,
75 {
76 Self {
77 star_count,
78 paid_media: paid_media.into_iter().map(Into::into).collect(),
79 }
80 }
81}
82
83#[derive(Clone, Debug, derive_more::From, Deserialize, PartialEq, PartialOrd, Serialize)]
85#[serde(from = "RawPaidMedia", into = "RawPaidMedia")]
86#[allow(clippy::large_enum_variant)]
87pub enum PaidMedia {
88 Photo(Vec<PhotoSize>),
90 Preview(PaidMediaPreview),
92 Video(Video),
94}
95
96#[serde_with::skip_serializing_none]
98#[derive(Clone, Debug, Default, Deserialize, PartialEq, PartialOrd, Serialize)]
99pub struct PaidMediaPreview {
100 pub duration: Option<Integer>,
102 pub height: Option<Integer>,
104 pub width: Option<Integer>,
106}
107
108impl PaidMediaPreview {
109 pub fn with_duration(mut self, value: Integer) -> Self {
115 self.duration = Some(value);
116 self
117 }
118
119 pub fn with_height(mut self, value: Integer) -> Self {
125 self.height = Some(value);
126 self
127 }
128
129 pub fn with_width(mut self, value: Integer) -> Self {
135 self.width = Some(value);
136 self
137 }
138}
139
140#[serde_with::skip_serializing_none]
141#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
142#[serde(rename_all = "snake_case", tag = "type")]
143#[allow(clippy::large_enum_variant)]
144enum RawPaidMedia {
145 Photo {
146 photo: Vec<PhotoSize>,
147 },
148 Preview {
149 duration: Option<Integer>,
150 height: Option<Integer>,
151 width: Option<Integer>,
152 },
153 Video {
154 video: Video,
155 },
156}
157
158#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
159struct RawPaidMediaPhoto {
160 photo: Vec<PhotoSize>,
161}
162
163#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
164struct RawPaidMediaVideo {
165 video: Video,
166}
167
168impl From<RawPaidMedia> for PaidMedia {
169 fn from(value: RawPaidMedia) -> Self {
170 match value {
171 RawPaidMedia::Photo { photo } => Self::Photo(photo),
172 RawPaidMedia::Preview {
173 duration,
174 height,
175 width,
176 } => Self::Preview(PaidMediaPreview {
177 duration,
178 height,
179 width,
180 }),
181 RawPaidMedia::Video { video } => Self::Video(video),
182 }
183 }
184}
185
186impl From<PaidMedia> for RawPaidMedia {
187 fn from(value: PaidMedia) -> Self {
188 match value {
189 PaidMedia::Photo(photo) => Self::Photo { photo },
190 PaidMedia::Preview(PaidMediaPreview {
191 duration,
192 height,
193 width,
194 }) => Self::Preview {
195 duration,
196 height,
197 width,
198 },
199 PaidMedia::Video(video) => Self::Video { video },
200 }
201 }
202}
203
204#[derive(Debug)]
206pub struct SendPaidMedia {
207 form: Form,
208}
209
210impl SendPaidMedia {
211 pub fn new<T>(chat_id: T, media: InputPaidMediaGroup, star_count: Integer) -> Self
219 where
220 T: Into<ChatId>,
221 {
222 let mut form: Form = media.into();
223 form.insert_field("chat_id", chat_id.into());
224 form.insert_field("star_count", star_count);
225 Self { form }
226 }
227
228 pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
236 self.form.insert_field("allow_paid_broadcast", value);
237 self
238 }
239
240 pub fn with_business_connection_id<T>(mut self, value: T) -> Self
247 where
248 T: Into<String>,
249 {
250 self.form.insert_field("business_connection_id", value.into());
251 self
252 }
253
254 pub fn with_caption<T>(mut self, value: T) -> Self
260 where
261 T: Into<String>,
262 {
263 self.form.insert_field("caption", value.into());
264 self
265 }
266
267 pub fn with_caption_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
273 where
274 T: IntoIterator<Item = TextEntity>,
275 {
276 let value = value.into_iter().collect::<TextEntities>().serialize()?;
277 self.form.insert_field("caption_entities", value);
278 self.form.remove_field("parse_mode");
279 Ok(self)
280 }
281
282 pub fn with_disable_notification(mut self, value: bool) -> Self {
290 self.form.insert_field("disable_notification", value);
291 self
292 }
293
294 pub fn with_parse_mode(mut self, value: ParseMode) -> Self {
300 self.form.insert_field("parse_mode", value);
301 self.form.remove_field("caption_entities");
302 self
303 }
304
305 pub fn with_payload<T>(mut self, value: T) -> Self
313 where
314 T: Into<String>,
315 {
316 self.form.insert_field("payload", value.into());
317 self
318 }
319
320 pub fn with_protect_content(mut self, value: bool) -> Self {
326 self.form.insert_field("protect_content", value);
327 self
328 }
329
330 pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
336 let value = value.serialize()?;
337 self.form.insert_field("reply_parameters", value);
338 Ok(self)
339 }
340
341 pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
347 where
348 T: Into<ReplyMarkup>,
349 {
350 let value = value.into().serialize()?;
351 self.form.insert_field("reply_markup", value);
352 Ok(self)
353 }
354
355 pub fn with_show_caption_above_media(mut self, value: bool) -> Self {
361 self.form.insert_field("show_caption_above_media", value);
362 self
363 }
364}
365
366impl Method for SendPaidMedia {
367 type Response = Message;
368
369 fn into_payload(self) -> Payload {
370 Payload::form("sendPaidMedia", self.form)
371 }
372}