Skip to main content

rustigram_api/methods/
stickers.rs

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
16/// Builder for the [`getStickerSet`](https://core.telegram.org/bots/api#getstickerset) method.
17pub 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
42/// Builder for the [`getCustomEmojiStickers`](https://core.telegram.org/bots/api#getcustomemojistickers) method.
43pub 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
69/// Builder for the [`uploadStickerFile`](https://core.telegram.org/bots/api#uploadstickerfile) method.
70pub 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
149/// Builder for the [`createNewStickerSet`](https://core.telegram.org/bots/api#createnewstickerset) method.
150pub 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    /// Sets the sticker set type (`Regular`, `Mask`, or `CustomEmoji`).
185    pub fn sticker_type(mut self, k: StickerType) -> Self {
186        self.params.sticker_type = Some(k);
187        self
188    }
189    /// Enables colour replacement for custom emoji stickers when `true`.
190    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
214/// Builder for the [`addStickerToSet`](https://core.telegram.org/bots/api#addstickertoset) method.
215pub 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    /// Builder for the [`setStickerPositionInSet`](https://core.telegram.org/bots/api#setstickerpositioninset) method.
270    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    /// Builder for the [`deleteStickerFromSet`](https://core.telegram.org/bots/api#deletestickerfromset) method.
289    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    /// Builder for the [`setStickerSetTitle`](https://core.telegram.org/bots/api#setstickersettitle) method.
307    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    /// Builder for the [`deleteStickerSet`](https://core.telegram.org/bots/api#deletestickerset) method.
330    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
350/// Builder for the [`setStickerEmojiList`](https://core.telegram.org/bots/api#setstickeremojilist) method.
351pub 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
389/// Builder for the [`setStickerKeywords`](https://core.telegram.org/bots/api#setstickerkeywords) method.
390pub 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    /// Sets the search keywords for this sticker (up to 20 words).
405    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
429/// Builder for the [`setStickerMaskPosition`](https://core.telegram.org/bots/api#setstickermaskposition) method.
430pub 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    /// Sets the mask position for this mask sticker.
445    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
462/// Builder for the [`getForumTopicIconStickers`](https://core.telegram.org/bots/api#getforumtopiciconstickers) method.
463pub 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}