diff --git a/src/core/parse_mode.rs b/src/core/parse_mode.rs deleted file mode 100644 index 3a4f7054..00000000 --- a/src/core/parse_mode.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub enum ParseMode { - HTML, - Markdown, -} \ No newline at end of file diff --git a/src/core/types/input_file.rs b/src/core/types/input_file.rs index 5475c572..0c3110f1 100644 --- a/src/core/types/input_file.rs +++ b/src/core/types/input_file.rs @@ -1,8 +1,25 @@ use serde::Deserialize; -#[derive(Debug, Deserialize, Hash, PartialEq, Eq)] +#[derive(Debug, Hash, PartialEq, Eq)] pub enum InputFile { - File(std::fs::File), + File(std::path::PathBuf), Url(String), FileId(String), } + +impl serde::Serialize for InputFile { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { + match self { + InputFile::File(path) => { + // NOTE: file should be actually attached with multipart/form-data + serializer.serialize_str( + // TODO: remove unwrap (?) + &format!("attach://{}", path.file_name().unwrap().to_string_lossy()) + ) + }, + InputFile::Url(url) => serializer.serialize_str(url), + InputFile::FileId(id) => serializer.serialize_str(id), + } + } + +} diff --git a/src/core/types/input_media.rs b/src/core/types/input_media.rs index 435fb48f..e9cdc5fd 100644 --- a/src/core/types/input_media.rs +++ b/src/core/types/input_media.rs @@ -1,69 +1,245 @@ use serde::Deserialize; -use crate::core::types::InputFile; +use crate::core::types::{InputFile, ParseMode}; +// TODO: should variants use new-type? +#[derive(Debug, Serialize, PartialEq, Eq)] +#[serde(tag = "type")] +#[serde(rename_all = "snake_case")] +/// This object represents the content of a media message to be sent. +/// [More](https://core.telegram.org/bots/api#inputmedia) pub enum InputMedia { - InputMediaPhoto(InputMediaPhoto), - InputMediaVideo(InputMediaVideo), - InputMediaAnimation(InputMediaAnimation), - InputMediaAudio(InputMediaAudiotype), - InputMediaDocument(InputMediaDocument), + /// Represents a photo to be sent. + Photo { + /// File to send. + media: InputFile, + /// Caption of the photo to be sent, 0-1024 characters + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Send [Markdown] or [HTML], + /// if you want Telegram apps to show [bold, italic, fixed-width text or inline URLs] + /// in the media caption. + /// + /// [Markdown]: crate::core::types::ParseMode::Markdown + /// [Html]: crate::core::types::ParseMode::Html + /// [bold, italic, fixed-width text or inline URLs]: crate::core::types::ParseMode + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + }, + Video { + /// File to send.File to send. + media: InputFile, + #[serde(skip_serializing_if = "Option::is_none")] + /// Thumbnail of the file sent; can be ignored if thumbnail generation for the file is + /// supported server-side. + /// The thumbnail should be in JPEG format and less than 200 kB in size. + /// A thumbnail‘s width and height should not exceed 320. + /// Ignored if the file is not uploaded using [InputFile::File]. + /// + /// [InputFile::File]: crate::core::types::InputFile::File + thumb: Option, + /// Caption of the video to be sent, 0-1024 characters. + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Send [Markdown] or [HTML], + /// if you want Telegram apps to show [bold, italic, fixed-width text or inline URLs] + /// in the media caption. + /// + /// [Markdown]: crate::core::types::ParseMode::Markdown + /// [Html]: crate::core::types::ParseMode::Html + /// [bold, italic, fixed-width text or inline URLs]: crate::core::types::ParseMode + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + /// Video width + #[serde(skip_serializing_if = "Option::is_none")] + width: Option, + /// Video height + #[serde(skip_serializing_if = "Option::is_none")] + height: Option, + /// Video duration + #[serde(skip_serializing_if = "Option::is_none")] + duration: Option, + /// Pass `true`, if the uploaded video is suitable for streaming + #[serde(skip_serializing_if = "Option::is_none")] + supports_streaming: Option, + }, + /// Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent. + Animation { + /// File to send. + media: InputFile, + /// Thumbnail of the file sent; can be ignored if thumbnail generation for the file is + /// supported server-side. + /// The thumbnail should be in JPEG format and less than 200 kB in size. + /// A thumbnail‘s width and height should not exceed 320. + /// Ignored if the file is not uploaded using [InputFile::File]. + /// + /// [InputFile::File]: crate::core::types::InputFile::File + #[serde(skip_serializing_if = "Option::is_none")] + thumb: Option, + /// Caption of the animation to be sent, 0-1024 characters + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Send [Markdown] or [HTML], + /// if you want Telegram apps to show [bold, italic, fixed-width text or inline URLs] + /// in the media caption. + /// + /// [Markdown]: crate::core::types::ParseMode::Markdown + /// [Html]: crate::core::types::ParseMode::Html + /// [bold, italic, fixed-width text or inline URLs]: crate::core::types::ParseMode + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + /// Animation width + #[serde(skip_serializing_if = "Option::is_none")] + width: Option, + /// Animation height + #[serde(skip_serializing_if = "Option::is_none")] + height: Option, + /// Animation duration + #[serde(skip_serializing_if = "Option::is_none")] + duration: Option, + }, + /// Represents an audio file to be treated as music to be sent. + Audio { + /// File to send, + media: InputFile, + /// Thumbnail of the file sent; can be ignored if thumbnail generation for the file is + /// supported server-side. + /// The thumbnail should be in JPEG format and less than 200 kB in size. + /// A thumbnail‘s width and height should not exceed 320. + /// Ignored if the file is not uploaded using [InputFile::File]. + /// + /// [InputFile::File]: crate::core::types::InputFile::File + #[serde(skip_serializing_if = "Option::is_none")] + thumb: Option, + /// Caption of the audio to be sent, 0-1024 characters + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Send [Markdown] or [HTML], + /// if you want Telegram apps to show [bold, italic, fixed-width text or inline URLs] + /// in the media caption. + /// + /// [Markdown]: crate::core::types::ParseMode::Markdown + /// [Html]: crate::core::types::ParseMode::Html + /// [bold, italic, fixed-width text or inline URLs]: crate::core::types::ParseMode + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + /// Duration of the audio in seconds + #[serde(skip_serializing_if = "Option::is_none")] + duration: Option, + /// Performer of the audio + #[serde(skip_serializing_if = "Option::is_none")] + performer: Option, + /// Title of the audio + #[serde(skip_serializing_if = "Option::is_none")] + title: Option + }, + /// Represents a general file to be sent. + Document { + /// File to send. + media: InputFile, + /// Thumbnail of the file sent; can be ignored if thumbnail generation for the file is + /// supported server-side. + /// The thumbnail should be in JPEG format and less than 200 kB in size. + /// A thumbnail‘s width and height should not exceed 320. + /// Ignored if the file is not uploaded using [InputFile::File]. + /// + /// [InputFile::File]: crate::core::types::InputFile::File + #[serde(skip_serializing_if = "Option::is_none")] + thumb: Option, + /// Caption of the document to be sent, 0-1024 characters + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Send [Markdown] or [HTML], + /// if you want Telegram apps to show [bold, italic, fixed-width text or inline URLs] + /// in the media caption. + /// + /// [Markdown]: crate::core::types::ParseMode::Markdown + /// [Html]: crate::core::types::ParseMode::Html + /// [bold, italic, fixed-width text or inline URLs]: crate::core::types::ParseMode + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + }, } -pub enum ThumbKind { - InputFile, - String, -} +#[cfg(test)] +mod tests { + use super::*; -#[derive(Debug, Serialize, Deserialize)] -pub struct InputMediaPhoto { - type_: String, - media: String, - caption: Option, - parse_mode: Option, -} + #[test] + fn photo_serialize() { + let expected_json = r#"{"type":"photo","media":"123456"}"#; + let photo = InputMedia::Photo { + media: InputFile::FileId(String::from("123456")), + caption: None, + parse_mode: None, + }; -#[derive(Debug, Serialize), Deserialize] -pub struct InputMediaVideo { - type_: String, - media: String, - thumb: ThumbKind, - caption: Option, - parse_mode: Option, - width: Option, - height: Option, - duration: Option, - supports_streaming: Option, -} + let actual_json = serde_json::to_string(&photo).unwrap(); + assert_eq!(expected_json, actual_json); + } -#[derive(Debug, Serialize, Deserialize)] -pub struct InputMediaAnimation { - type_: String, - media: String, - thumb: Option, - caption: Option, - parse_mode: Option, - width: Option, - height: Option, - duration: Option, -} + #[test] + fn video_serialize() { + let expected_json = r#"{"type":"video","media":"123456"}"#; + let video = InputMedia::Video { + media: InputFile::FileId(String::from("123456")), + thumb: None, + caption: None, + parse_mode: None, + width: None, + height: None, + duration: None, + supports_streaming: None, + }; -#[derive(Debug, Serialize, Deserialize)] -pub struct InputMediaAudio { - type_: String, - media: String, - thumb: Option, - caption: Option, - parse_mode: Option, - duration: Option, - performer: Option, - title: Option -} + let actual_json = serde_json::to_string(&video).unwrap(); + assert_eq!(expected_json, actual_json); + } -#[derive(Debug, Serialize, Deserialize)] -pub struct InputMediaDocument { - type_: String, - media: String, - thumb: Option, - caption: Option, - parse_mode: parse_mode, -} \ No newline at end of file + #[test] + fn animation_serialize() { + let expected_json = r#"{"type":"animation","media":"123456"}"#; + let video = InputMedia::Animation { + media: InputFile::FileId(String::from("123456")), + thumb: None, + caption: None, + parse_mode: None, + width: None, + height: None, + duration: None, + }; + + let actual_json = serde_json::to_string(&video).unwrap(); + assert_eq!(expected_json, actual_json); + } + + #[test] + fn audio_serialize() { + let expected_json = r#"{"type":"audio","media":"123456"}"#; + let video = InputMedia::Audio { + media: InputFile::FileId(String::from("123456")), + thumb: None, + caption: None, + parse_mode: None, + duration: None, + performer: None, + title: None + }; + + let actual_json = serde_json::to_string(&video).unwrap(); + assert_eq!(expected_json, actual_json); + } + + #[test] + fn document_serialize() { + let expected_json = r#"{"type":"document","media":"123456"}"#; + let video = InputMedia::Document { + media: InputFile::FileId(String::from("123456")), + thumb: None, + caption: None, + parse_mode: None, + }; + + let actual_json = serde_json::to_string(&video).unwrap(); + assert_eq!(expected_json, actual_json); + } +} diff --git a/src/core/types/mod.rs b/src/core/types/mod.rs index 3d815491..568022a3 100644 --- a/src/core/types/mod.rs +++ b/src/core/types/mod.rs @@ -22,6 +22,9 @@ pub use self::{ sticker::Sticker, successful_payment::SuccessfulPayment, user::User, + input_file::InputFile, + input_media::InputMedia, + parse_mode::ParseMode, }; mod answer_pre_checkout_query; @@ -43,3 +46,6 @@ mod shipping_query; mod sticker; mod successful_payment; mod user; +mod input_file; +mod input_media; +mod parse_mode; diff --git a/src/core/types/parse_mode.rs b/src/core/types/parse_mode.rs new file mode 100644 index 00000000..5c885cfe --- /dev/null +++ b/src/core/types/parse_mode.rs @@ -0,0 +1,63 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] +/// ## Formatting options +/// The Bot API supports basic formatting for messages. +/// You can use **bold** and *italic* text, as well as [inline links](https://example.com) and `pre-formatted code` in +/// your bots' messages. Telegram clients will render them accordingly. You can use either +/// markdown-style or HTML-style formatting. +/// +/// Note that Telegram clients will display an alert to the user before opening an inline link +/// (‘Open this link?’ together with the full URL). +/// +/// Links `tg://user?id=` can be used to mention a user by their id without using a username. +/// Please note: +/// +/// - These links will work only if they are used inside an inline link. +/// For example, they will not work, when used in an inline keyboard button or in a message text. +/// - The mentions are only guaranteed to work if: **A**. the user is a member in the group where he +/// was mentioned or **B**. the user has contacted the bot in the past or has sent a callback +/// query to the bot via inline button and has not restricted linking to their account in +/// `Settings > Privacy & Security > Forwarded Messages`. +/// +/// ## Markdown style +/// To use this mode, pass [Markdown] in the `parse_mode` field when using [SendMessage] (or other methods). +/// +/// Use the following syntax in your message: +/// +/// ```ignore +/// *bold text* +/// _italic text_ +/// [inline URL](http://www.example.com/) +/// [inline mention of a user](tg://user?id=123456789) +/// `inline fixed-width code` +/// ```block_language +/// pre-formatted fixed-width code block +/// ``` +/// ``` +/// +/// ## HTML style +/// To use this mode, pass [HTML] in the `parse_mode` field when using [SendMessage] (or other methods). +/// +/// The following tags are currently supported: +/// +/// ```ignore +/// bold, bold +/// italic, italic +/// inline URL +/// inline mention of a user +/// inline fixed-width code +///
pre-formatted fixed-width code block
+/// ``` +/// +/// Please note: +/// +/// - Only the tags mentioned above are currently supported. +/// - Tags must not be nested. +/// - All `<`, `>` and `&` symbols that are not a part of a tag or an HTML entity must be replaced with the corresponding HTML entities (`<` with `<`, `>` with `>` and `&` with `&`). +/// - All numerical HTML entities are supported. +/// - The API currently supports only the following named HTML entities: `<`, `>`, `&` and `"`. +pub enum ParseMode { + HTML, + Markdown, +} \ No newline at end of file