diff --git a/src/core/types/answer_pre_checkout_query.rs b/src/core/types/answer_pre_checkout_query.rs index 708aea12..02231abe 100644 --- a/src/core/types/answer_pre_checkout_query.rs +++ b/src/core/types/answer_pre_checkout_query.rs @@ -1,8 +1,7 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct AnswerPreCheckoutQuery { pub pre_checkout_query_id: String, pub ok: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub error_message: Option, } diff --git a/src/core/types/answer_shipping_query.rs b/src/core/types/answer_shipping_query.rs index bb7fa311..bb6e472d 100644 --- a/src/core/types/answer_shipping_query.rs +++ b/src/core/types/answer_shipping_query.rs @@ -1,11 +1,11 @@ -use serde::Deserialize; - use crate::core::types::ShippingOption; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct AnswerShippingQuery { pub shipping_query_id: String, pub ok: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub shipping_options: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub error_message: Option, } diff --git a/src/core/types/audio.rs b/src/core/types/audio.rs new file mode 100644 index 00000000..bcad5f21 --- /dev/null +++ b/src/core/types/audio.rs @@ -0,0 +1,18 @@ +use crate::core::types::PhotoSize; + + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct Audio { + pub file_id: String, + pub duration: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub performer: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub mime_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub file_size: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub thumb: Option +} \ No newline at end of file diff --git a/src/core/types/callback_query.rs b/src/core/types/callback_query.rs index 3fb17e76..c08e0e2b 100644 --- a/src/core/types/callback_query.rs +++ b/src/core/types/callback_query.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - /// This object represents an incoming callback query from a callback button in an inline keyboard. #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct CallbackQuery { diff --git a/src/core/types/chat.rs b/src/core/types/chat.rs index 92b491f9..3d8f72df 100644 --- a/src/core/types/chat.rs +++ b/src/core/types/chat.rs @@ -1,20 +1,72 @@ -use serde::Deserialize; +use crate::core::types::{ChatPermissions, ChatPhoto, Message, Integer}; -use crate::core::types::{ChatPermissions, ChatPhoto, Message}; -#[derive(Debug, Deserialize, Hash, PartialEq, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq)] pub struct Chat { - pub id: i64, - pub chat_type: String, - pub title: Option, - pub username: Option, - pub first_name: Option, - pub last_name: Option, + pub id: Integer, + #[serde(flatten)] + pub type_: ChatType, pub photo: Option, - pub description: Option, - pub invite_link: Option, - pub pinned_message: Option>, - pub permissions: Option, - pub sticker_set_name: Option, - pub can_set_sticker_set: Option, +} + + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq)] +#[serde(rename_all = "snake_case")] +#[serde(untagged)] +pub enum ChatType { + NotPrivate { + title: Option, + #[serde(flatten)] + type_: NotPrivateChatType, + description: Option, + invite_link: Option, + pinned_message: Option> + }, + Private { + username: Option, + first_name: Option, + last_name: Option + } +} + + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq)] +#[serde(rename_all = "snake_case")] +#[serde(tag = "type")] +pub enum NotPrivateChatType { + Channel { + username: Option + }, + Group { + permissions: Option + }, + Supergroup { + username: Option, + sticker_set_name: Option, + can_set_sticker_set: Option, + permissions: Option + } +} + + +#[test] +fn test_chat_de() { + use serde_json::from_str; + + assert_eq!( + Chat { + id: 0, + type_: ChatType::NotPrivate { + title: None, + type_: NotPrivateChatType::Channel { + username: Some("channelname".into()) + }, + description: None, + invite_link: None, + pinned_message: None + }, + photo: None, + }, + from_str(r#"{"id":0,"type":"channel","username":"channelname"}"#).unwrap() + ); } diff --git a/src/core/types/chat_member.rs b/src/core/types/chat_member.rs index 1ffb0c5c..b4b5007c 100644 --- a/src/core/types/chat_member.rs +++ b/src/core/types/chat_member.rs @@ -1,4 +1,6 @@ -use serde::Deserialize; +use crate::core::types::{ + User, ChatMemberStatus, Integer +}; /// This object contains information about one member of the chat. #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/chat_permissions.rs b/src/core/types/chat_permissions.rs index de09b983..5e59cfc4 100644 --- a/src/core/types/chat_permissions.rs +++ b/src/core/types/chat_permissions.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct ChatPermissions { pub can_send_messages: Option, diff --git a/src/core/types/chat_photo.rs b/src/core/types/chat_photo.rs index 070ddfa2..463284c7 100644 --- a/src/core/types/chat_photo.rs +++ b/src/core/types/chat_photo.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct ChatPhoto { pub small_file_id: String, diff --git a/src/core/types/chosen_inline_result.rs b/src/core/types/chosen_inline_result.rs index 489acfaa..2adc3a45 100644 --- a/src/core/types/chosen_inline_result.rs +++ b/src/core/types/chosen_inline_result.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::user::User; #[derive(Debug, Deserealize)] diff --git a/src/core/types/document.rs b/src/core/types/document.rs index 6ff03d81..fe1e4c2c 100644 --- a/src/core/types/document.rs +++ b/src/core/types/document.rs @@ -1,10 +1,11 @@ -use crate::core::types::PhotoSize; +use crate::core::types::{PhotoSize, UnsignedInteger}; -#[derive(Debug, Deserialize, Hash, PartialEq, Eq)] + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq)] pub struct Document { pub file_id: String, pub thumb: Option, pub file_name: Option, pub mime_type: Option, - pub file_size: Option, + pub file_size: Option, } diff --git a/src/core/types/force_reply.rs b/src/core/types/force_reply.rs index 6689065a..dc663f2b 100644 --- a/src/core/types/force_reply.rs +++ b/src/core/types/force_reply.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - /// Upon receiving a message with this object, Telegram clients will /// display a reply interface to the user (act as if the user has /// selected the bot‘s message and tapped ’Reply'). This can be diff --git a/src/core/types/inline_keyboard_button.rs b/src/core/types/inline_keyboard_button.rs index 6792df0f..f0746c50 100644 --- a/src/core/types/inline_keyboard_button.rs +++ b/src/core/types/inline_keyboard_button.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - /// This object represents one button of an inline keyboard. #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct InlineKeyboardButton { diff --git a/src/core/types/inline_keyboard_markup.rs b/src/core/types/inline_keyboard_markup.rs index 18aafc49..ae513a14 100644 --- a/src/core/types/inline_keyboard_markup.rs +++ b/src/core/types/inline_keyboard_markup.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - /// This object represents an inline keyboard that appears right next to the message it belongs to. #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct InlineKeyboardMarkup { diff --git a/src/core/types/input_file.rs b/src/core/types/input_file.rs index 0c3110f1..6a30686e 100644 --- a/src/core/types/input_file.rs +++ b/src/core/types/input_file.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Hash, PartialEq, Eq)] pub enum InputFile { File(std::path::PathBuf), diff --git a/src/core/types/input_media.rs b/src/core/types/input_media.rs index e9cdc5fd..4fd34baf 100644 --- a/src/core/types/input_media.rs +++ b/src/core/types/input_media.rs @@ -1,4 +1,3 @@ -use serde::Deserialize; use crate::core::types::{InputFile, ParseMode}; // TODO: should variants use new-type? diff --git a/src/core/types/invoice.rs b/src/core/types/invoice.rs index 385465f1..26b4b07b 100644 --- a/src/core/types/invoice.rs +++ b/src/core/types/invoice.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct Invoice { pub title: String, diff --git a/src/core/types/keyboard_button.rs b/src/core/types/keyboard_button.rs index 9021bf72..ee4899d9 100644 --- a/src/core/types/keyboard_button.rs +++ b/src/core/types/keyboard_button.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - /// This object represents one button of the reply keyboard. #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct KeyboardButton { diff --git a/src/core/types/label_price.rs b/src/core/types/label_price.rs index f26a98bb..14b126fc 100644 --- a/src/core/types/label_price.rs +++ b/src/core/types/label_price.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct LabeledPrice { pub label: String, diff --git a/src/core/types/login_url.rs b/src/core/types/login_url.rs index d9b65771..bed6b7cb 100644 --- a/src/core/types/login_url.rs +++ b/src/core/types/login_url.rs @@ -1,9 +1,10 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct LoginUrl { url: String, + #[serde(skip_serializing_if = "Option::is_none")] forward_text: Option, + #[serde(skip_serializing_if = "Option::is_none")] bot_username: Option, + #[serde(skip_serializing_if = "Option::is_none")] request_write_access: Option, } \ No newline at end of file diff --git a/src/core/types/mask_position.rs b/src/core/types/mask_position.rs index d186cb18..435ff67a 100644 --- a/src/core/types/mask_position.rs +++ b/src/core/types/mask_position.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct MaskPosition { pub point: String, diff --git a/src/core/types/message.rs b/src/core/types/message.rs index f53bb5a6..be10ac77 100644 --- a/src/core/types/message.rs +++ b/src/core/types/message.rs @@ -1,12 +1,10 @@ -// use serde::Deserialize; - use crate::core::types::{ Animation, Audio, Chat, Contact, Document, Game, InlineKeyboardMarkup, Invoice, Location, MessageEntity, PassportData, PhotoSize, Poll, Sticker, SuccessfulPayment, User, Venue, Video, VideoNote, Voice, }; -#[derive(Debug, Deserialize, Hash, PartialEq, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq)] pub struct Message { pub message_id: i64, pub from: Option>, diff --git a/src/core/types/message_entity.rs b/src/core/types/message_entity.rs index 9235bd2f..caf19ee5 100644 --- a/src/core/types/message_entity.rs +++ b/src/core/types/message_entity.rs @@ -1,6 +1,7 @@ use crate::core::types::User; -#[derive(Deserialize, Debug, PartialEq, Hash, Eq)] + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq)] pub struct MessageEntity { #[serde(flatten)] pub kind: MessageEntityKind, @@ -8,7 +9,8 @@ pub struct MessageEntity { pub length: usize, } -#[derive(Deserialize, Debug, PartialEq, Hash, Eq)] + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq)] #[serde(rename_all = "snake_case")] #[serde(tag = "type")] pub enum MessageEntityKind { diff --git a/src/core/types/mod.rs b/src/core/types/mod.rs index f25ffcf5..1580d138 100644 --- a/src/core/types/mod.rs +++ b/src/core/types/mod.rs @@ -1,22 +1,46 @@ use self::not_implemented_types::*; + + +pub type Integer = i32; +pub type UnsignedInteger = u32; + + pub use self::{ - answer_pre_checkout_query::AnswerPreCheckoutQuery, answer_shipping_query::AnswerShippingQuery, - chat::Chat, chat_permissions::ChatPermissions, chat_photo::ChatPhoto, document::Document, - invoice::Invoice, label_price::LabeledPrice, message::Message, message_entity::MessageEntity, - order_info::OrderInfo, pre_checkout_query::PreCheckoutQuery, send_invoice::SendInvoice, - shipping_address::ShippingAddress, shipping_option::ShippingOption, - shipping_query::ShippingQuery, sticker::Sticker, successful_payment::SuccessfulPayment, + answer_pre_checkout_query::AnswerPreCheckoutQuery, + answer_shipping_query::AnswerShippingQuery, + audio::Audio, + chat::Chat, + chat_permissions::ChatPermissions, + chat_photo::ChatPhoto, + chat_member::ChatMember, + document::Document, + invoice::Invoice, + label_price::LabeledPrice, + message::Message, + message_entity::MessageEntity, + order_info::OrderInfo, + photo_size::PhotoSize, + pre_checkout_query::PreCheckoutQuery, + send_invoice::SendInvoice, + shipping_address::ShippingAddress, + shipping_option::ShippingOption, + shipping_query::ShippingQuery, + sticker::Sticker, + successful_payment::SuccessfulPayment, user::User, input_file::InputFile, input_media::InputMedia, parse_mode::ParseMode, + video::Video }; mod answer_pre_checkout_query; mod answer_shipping_query; +mod audio; mod chat; mod chat_permissions; mod chat_photo; +mod chat_member; mod document; mod invoice; mod label_price; @@ -24,6 +48,7 @@ mod message; mod message_entity; mod not_implemented_types; mod order_info; +mod photo_size; mod pre_checkout_query; mod send_invoice; mod shipping_address; @@ -35,3 +60,4 @@ mod user; mod input_file; mod input_media; mod parse_mode; +mod video; diff --git a/src/core/types/not_implemented_types.rs b/src/core/types/not_implemented_types.rs index cb66a40b..be5e7cce 100644 --- a/src/core/types/not_implemented_types.rs +++ b/src/core/types/not_implemented_types.rs @@ -1,41 +1,35 @@ -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] -pub struct PhotoSize; - -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct Location; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct InlineKeyboardMarkup; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct PassportData; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct Poll; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct Animation; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] -pub struct Audio; - -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct Game; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct Contact; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] -pub struct Video; - -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct VideoNote; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct Venue; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct Voice; -#[derive(Debug, Deserialize, Serialize, PartialEq, Hash, Eq)] +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct MaskPosition; + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct ChatMemberStatus; diff --git a/src/core/types/order_info.rs b/src/core/types/order_info.rs index e60af685..24c1d4be 100644 --- a/src/core/types/order_info.rs +++ b/src/core/types/order_info.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::ShippingAddress; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/photo_size.rs b/src/core/types/photo_size.rs new file mode 100644 index 00000000..da00b17f --- /dev/null +++ b/src/core/types/photo_size.rs @@ -0,0 +1,10 @@ +use crate::core::types::{Integer, UnsignedInteger}; + + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct PhotoSize { + pub file_id: String, + pub width: Integer, + pub heigth: Integer, + pub file_size: Option +} diff --git a/src/core/types/pre_checkout_query.rs b/src/core/types/pre_checkout_query.rs index 85fb1252..23a7de1b 100644 --- a/src/core/types/pre_checkout_query.rs +++ b/src/core/types/pre_checkout_query.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::{OrderInfo, User}; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/reply_keyboard_markup.rs b/src/core/types/reply_keyboard_markup.rs index 8587b805..aee5583f 100644 --- a/src/core/types/reply_keyboard_markup.rs +++ b/src/core/types/reply_keyboard_markup.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - /// This object represents a custom keyboard with reply options. #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct ReplyKeyboardMarkup { diff --git a/src/core/types/reply_keyboard_remove.rs b/src/core/types/reply_keyboard_remove.rs index 6a445502..d5836042 100644 --- a/src/core/types/reply_keyboard_remove.rs +++ b/src/core/types/reply_keyboard_remove.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - /// Upon receiving a message with this object, Telegram clients will remove /// the current custom keyboard and display the default letter-keyboard. /// By default, custom keyboards are displayed until a new keyboard is sent diff --git a/src/core/types/response_paramter.rs b/src/core/types/response_paramter.rs index 66a8d10d..dd07eb36 100644 --- a/src/core/types/response_paramter.rs +++ b/src/core/types/response_paramter.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct ResponseParameters { migrate_to_chat_id: Option, diff --git a/src/core/types/shipping_address.rs b/src/core/types/shipping_address.rs index 3f669ef8..bef6c29d 100644 --- a/src/core/types/shipping_address.rs +++ b/src/core/types/shipping_address.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct ShippingAddress { pub country_code: String, diff --git a/src/core/types/shipping_option.rs b/src/core/types/shipping_option.rs index 7a9c5c21..612580b2 100644 --- a/src/core/types/shipping_option.rs +++ b/src/core/types/shipping_option.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::LabeledPrice; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/shipping_query.rs b/src/core/types/shipping_query.rs index 96eec275..b5a48e99 100644 --- a/src/core/types/shipping_query.rs +++ b/src/core/types/shipping_query.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::{ShippingAddress, User}; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/sticker.rs b/src/core/types/sticker.rs index cea09669..021cb828 100644 --- a/src/core/types/sticker.rs +++ b/src/core/types/sticker.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::{MaskPosition, PhotoSize}; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/sticker_set.rs b/src/core/types/sticker_set.rs index e107cf73..d2ea699c 100644 --- a/src/core/types/sticker_set.rs +++ b/src/core/types/sticker_set.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::Sticker; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/successful_payment.rs b/src/core/types/successful_payment.rs index 07e4de48..f9331fd3 100644 --- a/src/core/types/successful_payment.rs +++ b/src/core/types/successful_payment.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - use crate::core::types::OrderInfo; #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] diff --git a/src/core/types/user.rs b/src/core/types/user.rs index 0a6f6c43..2e8ab8c3 100644 --- a/src/core/types/user.rs +++ b/src/core/types/user.rs @@ -1,5 +1,3 @@ -use serde::Deserialize; - #[derive(Debug, Deserialize, Hash, PartialEq, Eq)] pub struct User { pub id: i64, diff --git a/src/core/types/venue.rs b/src/core/types/venue.rs new file mode 100644 index 00000000..77e02b31 --- /dev/null +++ b/src/core/types/venue.rs @@ -0,0 +1,13 @@ +use crate::core::types::Location; + + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct Venue { + pub location: Location, + pub title: String, + pub address: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub foursquare_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub foursquare_type: Option +} \ No newline at end of file diff --git a/src/core/types/video.rs b/src/core/types/video.rs new file mode 100644 index 00000000..f8d69a37 --- /dev/null +++ b/src/core/types/video.rs @@ -0,0 +1,13 @@ +use crate::core::types::{PhotoSize, UnsignedInteger}; + + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct Video { + pub file_id: String, + pub width: UnsignedInteger, + pub height: UnsignedInteger, + pub duration: UnsignedInteger, + pub thumb: Option, + pub mime_type: Option, + pub file_size: Option +} \ No newline at end of file