1use crate::client::BotClient;
2use crate::error::Result;
3use reqwest::multipart::{Form, Part};
4use rustigram_types::sticker::{
5 InputSticker, MaskPosition, Sticker, StickerFormat, StickerSet, StickerType,
6};
7use serde::Serialize;
8use std::future::{Future, IntoFuture};
9use std::pin::Pin;
10
11#[derive(Serialize)]
12struct GetStickerSetParams {
13 name: String,
14}
15
16pub struct GetStickerSet {
18 client: BotClient,
19 params: GetStickerSetParams,
20}
21impl GetStickerSet {
22 pub(crate) fn new(client: BotClient, name: impl Into<String>) -> Self {
23 Self {
24 client,
25 params: GetStickerSetParams { name: name.into() },
26 }
27 }
28}
29impl IntoFuture for GetStickerSet {
30 type Output = Result<StickerSet>;
31 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
32 fn into_future(self) -> Self::IntoFuture {
33 Box::pin(async move { self.client.post_json("getStickerSet", &self.params).await })
34 }
35}
36
37#[derive(Serialize)]
38struct GetCustomEmojiStickersParams {
39 custom_emoji_ids: Vec<String>,
40}
41
42pub struct GetCustomEmojiStickers {
44 client: BotClient,
45 params: GetCustomEmojiStickersParams,
46}
47impl GetCustomEmojiStickers {
48 pub(crate) fn new(client: BotClient, ids: Vec<impl Into<String>>) -> Self {
49 Self {
50 client,
51 params: GetCustomEmojiStickersParams {
52 custom_emoji_ids: ids.into_iter().map(Into::into).collect(),
53 },
54 }
55 }
56}
57impl IntoFuture for GetCustomEmojiStickers {
58 type Output = Result<Vec<Sticker>>;
59 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
60 fn into_future(self) -> Self::IntoFuture {
61 Box::pin(async move {
62 self.client
63 .post_json("getCustomEmojiStickers", &self.params)
64 .await
65 })
66 }
67}
68
69pub struct UploadStickerFile {
71 client: BotClient,
72 user_id: i64,
73 sticker: rustigram_types::file::InputFile,
74 sticker_format: StickerFormat,
75}
76impl UploadStickerFile {
77 pub(crate) fn new(
78 client: BotClient,
79 user_id: i64,
80 sticker: rustigram_types::file::InputFile,
81 format: StickerFormat,
82 ) -> Self {
83 Self {
84 client,
85 user_id,
86 sticker,
87 sticker_format: format,
88 }
89 }
90}
91impl IntoFuture for UploadStickerFile {
92 type Output = Result<rustigram_types::file::File>;
93 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
94 fn into_future(self) -> Self::IntoFuture {
95 Box::pin(async move {
96 match self.sticker {
97 rustigram_types::file::InputFile::Bytes {
98 filename,
99 data,
100 mime_type,
101 } => {
102 let part = Part::bytes(data)
103 .file_name(filename)
104 .mime_str(&mime_type)
105 .map_err(|e| crate::error::Error::Decode(e.to_string()))?;
106 let fmt = match self.sticker_format {
107 StickerFormat::Static => "static",
108 StickerFormat::Animated => "animated",
109 StickerFormat::Video => "video",
110 };
111 let form = Form::new()
112 .text("user_id", self.user_id.to_string())
113 .text("sticker_format", fmt)
114 .part("sticker", part);
115 self.client.post_multipart("uploadStickerFile", form).await
116 }
117 ref other => {
118 let body = serde_json::json!({ "user_id": self.user_id, "sticker": other.as_str(), "sticker_format": self.sticker_format });
119 self.client.post_json("uploadStickerFile", &body).await
120 }
121 }
122 })
123 }
124}
125
126#[derive(Serialize)]
127struct InputStickerJson {
128 sticker: String,
129 format: StickerFormat,
130 emoji_list: Vec<String>,
131 #[serde(skip_serializing_if = "Option::is_none")]
132 mask_position: Option<MaskPosition>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 keywords: Option<Vec<String>>,
135}
136
137#[derive(Serialize)]
138struct CreateNewStickerSetParams {
139 user_id: i64,
140 name: String,
141 title: String,
142 stickers: Vec<InputStickerJson>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 sticker_type: Option<StickerType>,
145 #[serde(skip_serializing_if = "Option::is_none")]
146 needs_repainting: Option<bool>,
147}
148
149pub struct CreateNewStickerSet {
151 client: BotClient,
152 params: CreateNewStickerSetParams,
153}
154impl CreateNewStickerSet {
155 pub(crate) fn new(
156 client: BotClient,
157 user_id: i64,
158 name: impl Into<String>,
159 title: impl Into<String>,
160 stickers: Vec<InputSticker>,
161 ) -> Self {
162 let stickers_json = stickers
163 .into_iter()
164 .map(|s| InputStickerJson {
165 sticker: s.sticker,
166 format: s.format,
167 emoji_list: s.emoji_list,
168 mask_position: s.mask_position,
169 keywords: s.keywords,
170 })
171 .collect();
172 Self {
173 client,
174 params: CreateNewStickerSetParams {
175 user_id,
176 name: name.into(),
177 title: title.into(),
178 stickers: stickers_json,
179 sticker_type: None,
180 needs_repainting: None,
181 },
182 }
183 }
184 pub fn sticker_type(mut self, k: StickerType) -> Self {
186 self.params.sticker_type = Some(k);
187 self
188 }
189 pub fn needs_repainting(mut self, v: bool) -> Self {
191 self.params.needs_repainting = Some(v);
192 self
193 }
194}
195impl IntoFuture for CreateNewStickerSet {
196 type Output = Result<bool>;
197 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
198 fn into_future(self) -> Self::IntoFuture {
199 Box::pin(async move {
200 self.client
201 .post_json("createNewStickerSet", &self.params)
202 .await
203 })
204 }
205}
206
207#[derive(Serialize)]
208struct AddStickerToSetParams {
209 user_id: i64,
210 name: String,
211 sticker: InputStickerJson,
212}
213
214pub struct AddStickerToSet {
216 client: BotClient,
217 params: AddStickerToSetParams,
218}
219impl AddStickerToSet {
220 pub(crate) fn new(
221 client: BotClient,
222 user_id: i64,
223 name: impl Into<String>,
224 sticker: InputSticker,
225 ) -> Self {
226 Self {
227 client,
228 params: AddStickerToSetParams {
229 user_id,
230 name: name.into(),
231 sticker: InputStickerJson {
232 sticker: sticker.sticker,
233 format: sticker.format,
234 emoji_list: sticker.emoji_list,
235 mask_position: sticker.mask_position,
236 keywords: sticker.keywords,
237 },
238 },
239 }
240 }
241}
242impl IntoFuture for AddStickerToSet {
243 type Output = Result<bool>;
244 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
245 fn into_future(self) -> Self::IntoFuture {
246 Box::pin(async move { self.client.post_json("addStickerToSet", &self.params).await })
247 }
248}
249
250macro_rules! simple_sticker_action {
251 ($(#[$doc:meta])* $name:ident, $params_ty:ident { $($f:ident: $t:ty),+ }, $method:literal, $ret:ty) => {
252 #[derive(Serialize)]
253 struct $params_ty { $($f: $t),+ }
254
255 $(#[$doc])*
256 pub struct $name { client: BotClient, params: $params_ty }
257
258 impl IntoFuture for $name {
259 type Output = Result<$ret>;
260 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
261 fn into_future(self) -> Self::IntoFuture {
262 Box::pin(async move { self.client.post_json($method, &self.params).await })
263 }
264 }
265 };
266}
267
268simple_sticker_action!(
269 SetStickerPositionInSet,
271 SetStickerPositionInSetParams { sticker: String, position: u32 },
272 "setStickerPositionInSet",
273 bool
274);
275impl SetStickerPositionInSet {
276 pub(crate) fn new(client: BotClient, sticker: impl Into<String>, position: u32) -> Self {
277 Self {
278 client,
279 params: SetStickerPositionInSetParams {
280 sticker: sticker.into(),
281 position,
282 },
283 }
284 }
285}
286
287simple_sticker_action!(
288 DeleteStickerFromSet,
290 DeleteStickerFromSetParams { sticker: String },
291 "deleteStickerFromSet",
292 bool
293);
294impl DeleteStickerFromSet {
295 pub(crate) fn new(client: BotClient, sticker: impl Into<String>) -> Self {
296 Self {
297 client,
298 params: DeleteStickerFromSetParams {
299 sticker: sticker.into(),
300 },
301 }
302 }
303}
304
305simple_sticker_action!(
306 SetStickerSetTitle,
308 SetStickerSetTitleParams { name: String, title: String },
309 "setStickerSetTitle",
310 bool
311);
312impl SetStickerSetTitle {
313 pub(crate) fn new(
314 client: BotClient,
315 name: impl Into<String>,
316 title: impl Into<String>,
317 ) -> Self {
318 Self {
319 client,
320 params: SetStickerSetTitleParams {
321 name: name.into(),
322 title: title.into(),
323 },
324 }
325 }
326}
327
328simple_sticker_action!(
329 DeleteStickerSet,
331 DeleteStickerSetParams { name: String },
332 "deleteStickerSet",
333 bool
334);
335impl DeleteStickerSet {
336 pub(crate) fn new(client: BotClient, name: impl Into<String>) -> Self {
337 Self {
338 client,
339 params: DeleteStickerSetParams { name: name.into() },
340 }
341 }
342}
343
344#[derive(Serialize)]
345struct SetStickerEmojiListParams {
346 sticker: String,
347 emoji_list: Vec<String>,
348}
349
350pub struct SetStickerEmojiList {
352 client: BotClient,
353 params: SetStickerEmojiListParams,
354}
355impl SetStickerEmojiList {
356 pub(crate) fn new(
357 client: BotClient,
358 sticker: impl Into<String>,
359 emoji_list: Vec<impl Into<String>>,
360 ) -> Self {
361 Self {
362 client,
363 params: SetStickerEmojiListParams {
364 sticker: sticker.into(),
365 emoji_list: emoji_list.into_iter().map(Into::into).collect(),
366 },
367 }
368 }
369}
370impl IntoFuture for SetStickerEmojiList {
371 type Output = Result<bool>;
372 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
373 fn into_future(self) -> Self::IntoFuture {
374 Box::pin(async move {
375 self.client
376 .post_json("setStickerEmojiList", &self.params)
377 .await
378 })
379 }
380}
381
382#[derive(Serialize)]
383struct SetStickerKeywordsParams {
384 sticker: String,
385 #[serde(skip_serializing_if = "Option::is_none")]
386 keywords: Option<Vec<String>>,
387}
388
389pub struct SetStickerKeywords {
391 client: BotClient,
392 params: SetStickerKeywordsParams,
393}
394impl SetStickerKeywords {
395 pub(crate) fn new(client: BotClient, sticker: impl Into<String>) -> Self {
396 Self {
397 client,
398 params: SetStickerKeywordsParams {
399 sticker: sticker.into(),
400 keywords: None,
401 },
402 }
403 }
404 pub fn keywords(mut self, kw: Vec<impl Into<String>>) -> Self {
406 self.params.keywords = Some(kw.into_iter().map(Into::into).collect());
407 self
408 }
409}
410impl IntoFuture for SetStickerKeywords {
411 type Output = Result<bool>;
412 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
413 fn into_future(self) -> Self::IntoFuture {
414 Box::pin(async move {
415 self.client
416 .post_json("setStickerKeywords", &self.params)
417 .await
418 })
419 }
420}
421
422#[derive(Serialize)]
423struct SetStickerMaskPositionParams {
424 sticker: String,
425 #[serde(skip_serializing_if = "Option::is_none")]
426 mask_position: Option<MaskPosition>,
427}
428
429pub struct SetStickerMaskPosition {
431 client: BotClient,
432 params: SetStickerMaskPositionParams,
433}
434impl SetStickerMaskPosition {
435 pub(crate) fn new(client: BotClient, sticker: impl Into<String>) -> Self {
436 Self {
437 client,
438 params: SetStickerMaskPositionParams {
439 sticker: sticker.into(),
440 mask_position: None,
441 },
442 }
443 }
444 pub fn mask_position(mut self, mp: MaskPosition) -> Self {
446 self.params.mask_position = Some(mp);
447 self
448 }
449}
450impl IntoFuture for SetStickerMaskPosition {
451 type Output = Result<bool>;
452 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
453 fn into_future(self) -> Self::IntoFuture {
454 Box::pin(async move {
455 self.client
456 .post_json("setStickerMaskPosition", &self.params)
457 .await
458 })
459 }
460}
461
462pub struct GetForumTopicIconStickers {
464 client: BotClient,
465}
466impl GetForumTopicIconStickers {
467 pub(crate) fn new(client: BotClient) -> Self {
468 Self { client }
469 }
470}
471impl IntoFuture for GetForumTopicIconStickers {
472 type Output = Result<Vec<Sticker>>;
473 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
474 fn into_future(self) -> Self::IntoFuture {
475 Box::pin(async move {
476 self.client
477 .post_json("getForumTopicIconStickers", &serde_json::json!({}))
478 .await
479 })
480 }
481}