use reqwest::Url;
use serde::{Deserialize, Serialize};
use crate::types::{Currency, LabeledPrice, MessageEntity, ParseMode};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum InputMessageContent {
Text(InputMessageContentText),
Location(InputMessageContentLocation),
Venue(InputMessageContentVenue),
Contact(InputMessageContentContact),
Invoice(InputMessageContentInvoice),
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct InputMessageContentText {
pub message_text: String,
pub parse_mode: Option<ParseMode>,
pub entities: Option<Vec<MessageEntity>>,
pub disable_web_page_preview: Option<bool>,
}
impl InputMessageContentText {
pub fn new<S>(message_text: S) -> Self
where
S: Into<String>,
{
Self {
message_text: message_text.into(),
parse_mode: None,
disable_web_page_preview: None,
entities: None,
}
}
pub fn message_text<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.message_text = val.into();
self
}
#[must_use]
pub fn parse_mode(mut self, val: ParseMode) -> Self {
self.parse_mode = Some(val);
self
}
pub fn entities<C>(mut self, val: C) -> Self
where
C: IntoIterator<Item = MessageEntity>,
{
self.entities = Some(val.into_iter().collect());
self
}
#[must_use]
pub fn disable_web_page_preview(mut self, val: bool) -> Self {
self.disable_web_page_preview = Some(val);
self
}
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct InputMessageContentLocation {
pub latitude: f64,
pub longitude: f64,
pub horizontal_accuracy: Option<f64>,
pub live_period: Option<u32>,
pub heading: Option<u16>,
pub proximity_alert_radius: Option<u32>,
}
impl InputMessageContentLocation {
#[must_use]
pub const fn new(latitude: f64, longitude: f64) -> Self {
Self {
latitude,
longitude,
live_period: None,
horizontal_accuracy: None,
heading: None,
proximity_alert_radius: None,
}
}
#[must_use]
pub const fn latitude(mut self, val: f64) -> Self {
self.latitude = val;
self
}
#[must_use]
pub const fn longitude(mut self, val: f64) -> Self {
self.longitude = val;
self
}
#[must_use]
pub const fn live_period(mut self, val: u32) -> Self {
self.live_period = Some(val);
self
}
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct InputMessageContentVenue {
pub latitude: f64,
pub longitude: f64,
pub title: String,
pub address: String,
pub foursquare_id: Option<String>,
pub foursquare_type: Option<String>,
pub google_place_id: Option<String>,
pub google_place_type: Option<String>,
}
impl InputMessageContentVenue {
pub fn new<S1, S2>(latitude: f64, longitude: f64, title: S1, address: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
Self {
latitude,
longitude,
title: title.into(),
address: address.into(),
foursquare_id: None,
foursquare_type: None,
google_place_id: None,
google_place_type: None,
}
}
#[must_use]
pub fn latitude(mut self, val: f64) -> Self {
self.latitude = val;
self
}
#[must_use]
pub fn longitude(mut self, val: f64) -> Self {
self.longitude = val;
self
}
pub fn title<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.title = val.into();
self
}
pub fn address<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.address = val.into();
self
}
pub fn foursquare_id<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.foursquare_id = Some(val.into());
self
}
pub fn foursquare_type<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.foursquare_type = Some(val.into());
self
}
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct InputMessageContentContact {
pub phone_number: String,
pub first_name: String,
pub last_name: Option<String>,
pub vcard: Option<String>,
}
impl InputMessageContentContact {
pub fn new<S1, S2>(phone_number: S1, first_name: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
Self {
phone_number: phone_number.into(),
first_name: first_name.into(),
last_name: None,
vcard: None,
}
}
pub fn phone_number<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.phone_number = val.into();
self
}
pub fn first_name<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.first_name = val.into();
self
}
pub fn last_name<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.last_name = Some(val.into());
self
}
pub fn vcard<S>(mut self, val: S) -> Self
where
S: Into<String>,
{
self.vcard = Some(val.into());
self
}
}
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct InputMessageContentInvoice {
pub title: String,
pub description: String,
pub payload: String,
pub provider_token: String,
pub currency: Currency,
pub prices: Vec<LabeledPrice>,
pub max_tip_amount: Option<u32>,
pub suggested_tip_amounts: Option<Vec<u32>>,
pub provider_data: Option<String>,
pub photo_url: Option<Url>,
pub photo_size: Option<u32>,
pub photo_width: Option<u32>,
pub photo_height: Option<u32>,
pub need_name: Option<bool>,
pub need_phone_number: Option<bool>,
pub need_email: Option<bool>,
pub need_shipping_address: Option<bool>,
pub send_phone_number_to_provider: Option<bool>,
pub send_email_to_provider: Option<bool>,
pub is_flexible: Option<bool>,
}
impl InputMessageContentInvoice {
pub fn new<T, D, PA, PT, PR>(
title: T,
description: D,
payload: PA,
provider_token: PT,
currency: Currency,
prices: PR,
) -> Self
where
T: Into<String>,
D: Into<String>,
PA: Into<String>,
PT: Into<String>,
PR: IntoIterator<Item = LabeledPrice>,
{
let title = title.into();
let description = description.into();
let payload = payload.into();
let provider_token = provider_token.into();
let prices = prices.into_iter().collect();
Self {
title,
description,
payload,
provider_token,
currency,
prices,
max_tip_amount: None,
suggested_tip_amounts: None,
provider_data: None,
photo_url: None,
photo_size: None,
photo_width: None,
photo_height: None,
need_name: None,
need_phone_number: None,
need_email: None,
need_shipping_address: None,
send_phone_number_to_provider: None,
send_email_to_provider: None,
is_flexible: None,
}
}
pub fn title<T>(mut self, val: T) -> Self
where
T: Into<String>,
{
self.title = val.into();
self
}
pub fn description<T>(mut self, val: T) -> Self
where
T: Into<String>,
{
self.description = val.into();
self
}
pub fn payload<T>(mut self, val: T) -> Self
where
T: Into<String>,
{
self.payload = val.into();
self
}
pub fn provider_token<T>(mut self, val: T) -> Self
where
T: Into<String>,
{
self.provider_token = val.into();
self
}
#[must_use]
pub fn currency(mut self, val: Currency) -> Self {
self.currency = val;
self
}
pub fn prices<T>(mut self, val: T) -> Self
where
T: IntoIterator<Item = LabeledPrice>,
{
self.prices = val.into_iter().collect();
self
}
#[must_use]
pub fn max_tip_amount(mut self, val: u32) -> Self {
self.max_tip_amount = Some(val);
self
}
pub fn suggested_tip_amounts<T>(mut self, val: T) -> Self
where
T: IntoIterator<Item = u32>,
{
self.suggested_tip_amounts = Some(val.into_iter().collect());
self
}
pub fn provider_data<T>(mut self, val: T) -> Self
where
T: Into<String>,
{
self.provider_data = Some(val.into());
self
}
#[must_use]
pub fn photo_url(mut self, val: Url) -> Self {
self.photo_url = Some(val);
self
}
#[must_use]
pub fn photo_size(mut self, val: u32) -> Self {
self.photo_size = Some(val);
self
}
#[must_use]
pub fn photo_width(mut self, val: u32) -> Self {
self.photo_width = Some(val);
self
}
#[must_use]
pub fn photo_height(mut self, val: u32) -> Self {
self.photo_height = Some(val);
self
}
#[must_use]
pub fn need_name(mut self, val: bool) -> Self {
self.need_name = Some(val);
self
}
#[must_use]
pub fn need_phone_number(mut self, val: bool) -> Self {
self.need_phone_number = Some(val);
self
}
#[must_use]
pub fn need_email(mut self, val: bool) -> Self {
self.need_email = Some(val);
self
}
#[must_use]
pub fn need_shipping_address(mut self, val: bool) -> Self {
self.need_shipping_address = Some(val);
self
}
#[must_use]
pub fn send_phone_number_to_provider(mut self, val: bool) -> Self {
self.send_phone_number_to_provider = Some(val);
self
}
#[must_use]
pub fn send_email_to_provider(mut self, val: bool) -> Self {
self.send_email_to_provider = Some(val);
self
}
#[allow(clippy::wrong_self_convention)]
#[must_use]
pub fn is_flexible(mut self, val: bool) -> Self {
self.is_flexible = Some(val);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn text_serialize() {
let expected_json = r#"{"message_text":"text"}"#;
let text_content = InputMessageContent::Text(InputMessageContentText {
message_text: String::from("text"),
parse_mode: None,
disable_web_page_preview: None,
entities: None,
});
let actual_json = serde_json::to_string(&text_content).unwrap();
assert_eq!(expected_json, actual_json);
}
#[test]
fn location_serialize() {
let expected_json = r#"{"latitude":59.08,"longitude":38.4326}"#;
let location_content = InputMessageContent::Location(InputMessageContentLocation {
latitude: 59.08,
longitude: 38.4326,
live_period: None,
horizontal_accuracy: None,
heading: None,
proximity_alert_radius: None,
});
let actual_json = serde_json::to_string(&location_content).unwrap();
assert_eq!(expected_json, actual_json);
}
#[test]
fn venue_serialize() {
let expected_json = r#"{"latitude":59.08,"longitude":38.4326,"title":"some title","address":"some address"}"#;
let venue_content = InputMessageContent::Venue(InputMessageContentVenue {
latitude: 59.08,
longitude: 38.4326,
title: String::from("some title"),
address: String::from("some address"),
foursquare_id: None,
foursquare_type: None,
google_place_id: None,
google_place_type: None,
});
let actual_json = serde_json::to_string(&venue_content).unwrap();
assert_eq!(expected_json, actual_json);
}
#[test]
fn contact_serialize() {
let expected_json = r#"{"phone_number":"+3800000000","first_name":"jhon"}"#;
let contact_content = InputMessageContent::Contact(InputMessageContentContact {
phone_number: String::from("+3800000000"),
first_name: String::from("jhon"),
last_name: None,
vcard: None,
});
let actual_json = serde_json::to_string(&contact_content).unwrap();
assert_eq!(expected_json, actual_json);
}
}