flows_connector_dsi/
telegram.rs

1use std::collections::HashMap;
2
3use serde::Deserialize;
4use serde_json::Value;
5
6#[derive(Deserialize, Debug)]
7pub struct User {
8    /// Unique identifier for this user or bot.
9    pub id: u64,
10    /// True, if this user is a bot.
11    pub is_bot: bool,
12    /// User's or bot's first name.
13    pub first_name: String,
14    /// User's or bot's username.
15    pub username: Option<String>,
16    /// [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag).
17    pub language_code: Option<String>,
18    /// True, if this user is a Telegram Premium user.
19    #[serde(default = "bool::default")]
20    pub is_premium: bool,
21    /// True, if this user added the bot to the attachment menu.
22    #[serde(default = "bool::default")]
23    pub added_to_attachment_menu: bool,
24}
25
26#[derive(Deserialize, Debug)]
27pub struct Chat {
28    /// Unique identifier for this chat.
29    pub id: i64,
30    /// Type of chat, can be either “private”, “group”, “supergroup” or “channel”.
31    pub r#type: String,
32    /// Title, for supergroups, channels and group chats.
33    pub title: Option<String>,
34    /// Username, for private chats, supergroups and channels if available.
35    pub username: Option<String>,
36    /// First name of the other party in a private chat.
37    pub first_name: Option<String>,
38    /// Last name of the other party in a private chat.
39    pub last_name: Option<String>,
40}
41
42#[derive(Deserialize, Debug)]
43pub struct MessageEntity {
44    /// Type of the entity. Currently, can be “mention” (@username), “hashtag” (#hashtag),
45    /// “cashtag” ($USD), “bot_command” (/start@jobs_bot), “url” (https://telegram.org),
46    /// “email” (do-not-reply@telegram.org), “phone_number” (+1-212-555-0123),
47    /// “bold” (bold text), “italic” (italic text), “underline” (underlined text),
48    /// “strikethrough” (strikethrough text), “spoiler” (spoiler message),
49    /// “code” (monowidth string), “pre” (monowidth block),
50    /// “text_link” (for clickable text URLs), “text_mention” (for users without usernames),
51    /// “custom_emoji” (for inline custom emoji stickers).
52    pub r#type: String,
53    /// Offset in UTF-16 code units to the start of the entity.
54    pub offset: i64,
55    /// Length of the entity in UTF-16 code units.
56    pub length: i64,
57    /// For “text_link” only, URL that will be opened after user taps on the text.
58    pub url: Option<String>,
59    /// For “text_mention” only, the mentioned user.
60    pub user: Option<User>,
61    /// For “pre” only, the programming language of the entity text.
62    pub language: Option<String>,
63    // custom_emoji_id: Option<String>,
64}
65
66#[derive(Deserialize, Debug)]
67pub struct Message {
68    /// Unique message identifier inside this chat.
69    pub message_id: i64,
70    /// Conversation the message belongs to.
71    pub chat: Chat,
72    /// Date the message was sent in Unix time.
73    pub date: u64,
74    /// Sender of the message; empty for messages sent to channels.
75    /// For backward compatibility, the field contains a fake sender user in non-channel chats,
76    /// if the message was sent on behalf of a chat.
77    pub from: Option<User>,
78    /// Sender of the message, sent on behalf of a chat.
79    /// For example, the channel itself for channel posts,
80    /// the supergroup itself for messages from anonymous group administrators,
81    /// the linked channel for messages automatically forwarded to the discussion group.
82    /// For backward compatibility,
83    /// the field from contains a fake sender user in non-channel chats,
84    /// if the message was sent on behalf of a chat.
85    pub sender_chat: Option<Chat>,
86    /// For text messages..
87    #[serde(default = "String::new")]
88    pub text: String,
89    /// For messages forwarded from channels or from anonymous administrators,
90    /// information about the original sender chat.
91    pub forward_from: Option<User>,
92    /// For messages forwarded from channels or from anonymous administrators,
93    /// information about the original sender chat.
94    pub forward_from_chat: Option<Chat>,
95    /// For messages forwarded from channels,
96    /// identifier of the original message in the channel
97    pub forward_from_message_id: Option<i64>,
98    /// For forwarded messages, date the original message was sent in Unix time.
99    pub forward_date: Option<u64>,
100    /// For replies, the original message.
101    /// Note that the Message object in this field will not contain further
102    /// reply_to_message fields even if it itself is a reply.
103    pub reply_to_message: Option<Box<Message>>,
104    /// Bot through which the message was sent.
105    pub via_bot: Option<User>,
106    /// Date the message was last edited in Unix time.
107    pub edit_date: Option<u64>,
108    /// New members that were added to the group or supergroup
109    /// and information about them (the bot itself may be one of these members)
110    #[serde(default = "Vec::new")]
111    pub new_chat_members: Vec<User>,
112    /// A member was removed from the group,
113    /// information about them (this member may be the bot itself)
114    pub left_chat_member: Option<User>,
115    #[serde(default = "Vec::new")]
116    pub entities: Vec<MessageEntity>,
117}
118
119#[derive(Deserialize, Debug)]
120pub struct ChatInviteLink {
121    /// The invite link. If the link was created by another chat administrator,
122    /// then the second part of the link will be replaced with “…”.
123    pub invite_link: String,
124    /// Creator of the link.
125    pub creator: User,
126    /// True, if users joining the chat via the link need
127    /// to be approved by chat administrators.
128    pub creates_join_request: bool,
129    /// True, if the link is primary.
130    pub is_primary: bool,
131    /// True, if the link is revoked.
132    pub is_revoked: bool,
133    /// Optional. Invite link name.
134    pub name: Option<String>,
135    /// Point in time (Unix timestamp) when the link will expire or has been expired.
136    pub expire_date: Option<u64>,
137    /// The maximum number of users that can be members of the chat simultaneously.
138    /// after joining the chat via this invite link; 1-99999.
139    pub member_limit: Option<u64>,
140    /// Number of pending join requests created using this link.
141    pub pending_join_request_count: Option<u64>,
142}
143
144#[derive(Deserialize, Debug)]
145pub struct ChatMember {
146    /// Status of the chat member. it can be “creator” (owner) , "administrator",
147    /// "member", “restricted”, “left” (member who left), "kicked” (member who was banned) .
148    pub status: String,
149    /// Information about the user.
150    pub user: User,
151
152    #[serde(flatten)]
153    pub extra: HashMap<String, Value>,
154}
155
156#[derive(Deserialize, Debug)]
157pub struct ChatMemberUpdated {
158    /// Chat the user belongs to.
159    pub chat: Chat,
160    /// Performer of the action, which resulted in the change.
161    pub from: User,
162    /// Date the change was done in Unix time.
163    pub date: u64,
164    /// Previous information about the chat member.
165    pub old_chat_member: ChatMember,
166    /// New information about the chat member.
167    pub new_chat_member: ChatMember,
168    /// Chat invite link, which was used by the user to join the chat;
169    /// for joining by invite link events only.
170    pub invite_link: Option<ChatInviteLink>,
171}
172
173#[derive(Deserialize, Debug)]
174pub struct ChatJoinRequest {
175    /// Chat to which the request was sent.
176    pub chat: Chat,
177    /// User that sent the join request.
178    pub from: User,
179    /// Date the request was sent in Unix time.
180    pub date: u64,
181    /// Bio of the user.
182    #[serde(default = "String::new")]
183    pub bio: String,
184    /// Chat invite link that was used by the user to send the join request.
185    pub invite_link: Option<ChatInviteLink>,
186}
187
188#[derive(Deserialize, Debug)]
189pub enum InboundData {
190    #[serde(rename = "message")]
191    Message(Message),
192    #[serde(rename = "edited_message")]
193    EditedMessage(Message),
194    #[serde(rename = "channel_post")]
195    ChannelPost(Message),
196    #[serde(rename = "edited_channel_post")]
197    EditedChannelPost(Message),
198    #[serde(rename = "my_chat_member")]
199    MyChatMember(ChatMemberUpdated),
200    #[serde(rename = "chat_member")]
201    ChatMember(ChatMemberUpdated),
202    #[serde(rename = "chat_join_request")]
203    ChatJoinRequest(ChatJoinRequest),
204}
205
206pub fn inbound(s: String) -> Result<InboundData, String> {
207    #[cfg(debug_assertions)]
208    return serde_json::from_str::<InboundData>(&s)
209        .map_err(|e| format!("Parsing Telegram Webhook payload failed: {}", e.to_string()));
210
211    #[cfg(not(debug_assertions))]
212    serde_json::from_str::<InboundData>(&s)
213        .map_err(|_| format!("Parsing Telegram Webhook payload failed: {}", s))
214}
215
216impl InboundData {
217    pub fn as_message(&self) -> Result<&Message, String> {
218        match self {
219            InboundData::Message(ref m) => Ok(m),
220            _ => Err("as_message failed".to_string()),
221        }
222    }
223
224    pub fn as_edited_message(&self) -> Result<&Message, String> {
225        match self {
226            InboundData::EditedMessage(ref m) => Ok(m),
227            _ => Err("as_edited_message failed".to_string()),
228        }
229    }
230
231    pub fn as_channel_post(&self) -> Result<&Message, String> {
232        match self {
233            InboundData::ChannelPost(ref m) => Ok(m),
234            _ => Err("as_channel_post failed".to_string()),
235        }
236    }
237
238    pub fn as_edited_channel_post(&self) -> Result<&Message, String> {
239        match self {
240            InboundData::EditedChannelPost(ref m) => Ok(m),
241            _ => Err("as_edited_channel_post failed".to_string()),
242        }
243    }
244
245    pub fn as_my_chat_member(&self) -> Result<&ChatMemberUpdated, String> {
246        match self {
247            InboundData::MyChatMember(ref c) => Ok(c),
248            _ => Err("as_my_chat_member failed".to_string()),
249        }
250    }
251
252    pub fn as_chat_member(&self) -> Result<&ChatMemberUpdated, String> {
253        match self {
254            InboundData::ChatMember(ref c) => Ok(c),
255            _ => Err("as_chat_member failed".to_string()),
256        }
257    }
258
259    pub fn as_chat_join_request(&self) -> Result<&ChatJoinRequest, String> {
260        match self {
261            InboundData::ChatJoinRequest(ref c) => Ok(c),
262            _ => Err("as_chat_join_request failed".to_string()),
263        }
264    }
265}
266
267pub mod outbound {
268    use std::collections::HashMap;
269
270    use serde::Serialize;
271    use serde_json::{json, Value};
272
273    #[derive(Serialize)]
274    pub struct OutboundData {
275        chat_id: String,
276
277        #[serde(flatten)]
278        extra: HashMap<String, Value>,
279    }
280
281    pub enum ChatId {
282        /// Unique identifier for the target chat
283        Id(i64),
284        /// Username of the target chat (in the format `@channelusername`)
285        Name(String),
286    }
287
288    impl From<i64> for ChatId {
289        fn from(n: i64) -> Self {
290            Self::Id(n)
291        }
292    }
293
294    impl From<String> for ChatId {
295        fn from(n: String) -> Self {
296            Self::Name(n)
297        }
298    }
299
300    impl ToString for ChatId {
301        fn to_string(&self) -> String {
302            match &*self {
303                ChatId::Id(n) => n.to_string(),
304                ChatId::Name(n) => n.clone(),
305            }
306        }
307    }
308
309    #[derive(Serialize)]
310    pub enum ParseMode {
311        Markdown,
312        MarkdownV2,
313        HTML,
314    }
315
316    /// Send a text message. 
317    /// Click [here](https://core.telegram.org/bots/api#sendmessage) for other fields.
318    ///
319    /// eg.
320    /// ```rust
321    /// outbound::message(message.chat.id, "__PONG\\!__")
322    ///     .reply(message.message_id)
323    ///     .parse_mode(ParseMode::MarkdownV2)
324    ///     .build()
325    /// ```
326    pub fn message<C: Into<ChatId>, T: Into<String>>(chat_id: C, message: T) -> OutboundData {
327        OutboundData {
328            chat_id: chat_id.into().to_string(),
329            extra: [("text".to_string(), json!(message.into()))]
330                .into_iter()
331                .collect(),
332        }
333    }
334
335    /// Edit a text message.
336    /// Click [here](https://core.telegram.org/bots/api#editmessagetext) for other fields.
337    ///
338    /// eg.
339    /// ```rust
340    /// outbound::edit_message(message.chat.id, message.message_id, "__PONG\\!__")
341    ///     .parse_mode(ParseMode::MarkdownV2)
342    ///     .build()
343    /// ```
344    pub fn edit_message<C: Into<ChatId>, M: Into<String>, T: Into<String>>(
345        chat_id: C,
346        message_id: M,
347        message: T,
348    ) -> OutboundData {
349        OutboundData {
350            chat_id: chat_id.into().to_string(),
351            extra: [
352                ("message_id".to_string(), json!(message_id.into())),
353                ("text".to_string(), json!(message.into())),
354            ]
355            .into_iter()
356            .collect(),
357        }
358    }
359
360    /// Ban a user in a chat.
361    /// Click [here](https://core.telegram.org/bots/api#banchatmember) for other fields.
362    ///
363    /// eg.
364    /// ```rust
365    /// outbound::ban(message.chat.id, message.from.id)
366    ///     .build()
367    /// ```
368    pub fn ban<C: Into<ChatId>, T: Into<String>>(chat_id: C, user_id: T) -> OutboundData {
369        OutboundData {
370            chat_id: chat_id.into().to_string(),
371            extra: [("user_id".to_string(), json!(user_id.into()))]
372                .into_iter()
373                .collect(),
374        }
375    }
376
377    impl OutboundData {
378        /// Build outbound JSON data.
379        pub fn build(self) -> Result<String, String> {
380            if self.extra.is_empty() {
381                return Err("OutboundData build failed: Too few fields".to_string());
382            }
383
384            serde_json::to_string(&self)
385                .map_err(|e| format!("OutboundData build failed: {}", e.to_string()))
386        }
387
388        /// Reply to by original message ID.
389        pub fn reply<M: Into<String>>(mut self, message_id: M) -> Self {
390            self.extra
391                .insert("reply_to_message_id".to_string(), json!(message_id.into()));
392            self
393        }
394
395        /// Mode for parsing entities in the message text.
396        pub fn parse_mode(mut self, mode: ParseMode) -> Self {
397            self.extra.insert("parse_mode".to_string(), json!(mode));
398            self
399        }
400
401        /// Add extra field.
402        pub fn field<K: Into<String>>(mut self, name: K, value: Value) -> Self {
403            self.extra.insert(name.into(), value);
404            self
405        }
406    }
407}