use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct SmsMessage {
pub message_id: Option<i64>,
pub phone_number: String,
pub message_content: String,
pub message_reference: Option<u8>,
pub is_outgoing: bool,
pub created_at: Option<u32>,
pub completed_at: Option<u32>,
pub status: Option<u8>,
}
impl SmsMessage {
#[must_use]
pub fn with_message_id(&self, id: Option<i64>) -> Self {
Self {
message_id: id,
..self.clone()
}
}
#[must_use]
pub fn created_at(&self) -> Option<std::time::SystemTime> {
self.created_at
.map(|ts| std::time::UNIX_EPOCH + std::time::Duration::from_secs(u64::from(ts)))
}
}
#[derive(Serialize, PartialEq, Default, Debug, Clone)]
pub struct SmsOutgoingMessage {
pub to: String,
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub validity_period: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub flash: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<u32>,
}
impl SmsOutgoingMessage {
pub fn simple_message(to: impl Into<String>, content: impl Into<String>) -> Self {
Self {
to: to.into(),
content: content.into(),
..Default::default()
}
}
#[must_use]
pub fn with_flash(mut self, flash: bool) -> Self {
self.flash = Some(flash);
self
}
#[must_use]
pub fn with_validity_period(mut self, period: u8) -> Self {
self.validity_period = Some(period);
self
}
#[must_use]
pub fn with_timeout(mut self, timeout: u32) -> Self {
self.timeout = Some(timeout);
self
}
#[must_use]
pub fn get_validity_period(&self) -> u8 {
if self.flash.unwrap_or(false) {
return 0;
}
self.validity_period.unwrap_or(167) }
}
impl From<&SmsOutgoingMessage> for SmsMessage {
fn from(outgoing: &SmsOutgoingMessage) -> Self {
SmsMessage {
message_id: None,
phone_number: outgoing.to.clone(),
message_content: outgoing.content.clone(),
message_reference: None,
is_outgoing: true,
status: None,
created_at: None,
completed_at: None,
}
}
}
#[derive(Debug, Clone)]
pub struct SmsIncomingMessage {
pub phone_number: String,
pub user_data_header: Option<SmsMultipartHeader>,
pub content: String,
}
impl From<&SmsIncomingMessage> for SmsMessage {
fn from(incoming: &SmsIncomingMessage) -> Self {
SmsMessage {
message_id: None,
phone_number: incoming.phone_number.clone(),
message_content: incoming.content.clone(),
message_reference: None,
is_outgoing: false,
status: None,
created_at: None,
completed_at: None,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct SmsDeliveryReport {
pub report_id: Option<i64>,
pub status: u8,
pub is_final: bool,
pub created_at: Option<u32>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct SmsPartialDeliveryReport {
pub phone_number: String,
pub reference_id: u8,
pub status: u8,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub enum SmsDeliveryReportStatusCategory {
Sent,
Received,
Retrying,
Failed,
}
impl From<u8> for SmsDeliveryReportStatusCategory {
fn from(value: u8) -> Self {
match value {
0x00 => SmsDeliveryReportStatusCategory::Received, 0x01..=0x02 => SmsDeliveryReportStatusCategory::Sent, 0x03..=0x1F => SmsDeliveryReportStatusCategory::Sent, 0x20..=0x3F => SmsDeliveryReportStatusCategory::Retrying,
0x40..=0x6F => SmsDeliveryReportStatusCategory::Failed,
_ => SmsDeliveryReportStatusCategory::Failed,
}
}
}
impl std::fmt::Display for SmsDeliveryReportStatusCategory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
SmsDeliveryReportStatusCategory::Sent => "Sent",
SmsDeliveryReportStatusCategory::Received => "Received",
SmsDeliveryReportStatusCategory::Retrying => "Retrying",
SmsDeliveryReportStatusCategory::Failed => "Failed",
})
}
}
impl From<&SmsDeliveryReport> for SmsDeliveryReportStatusCategory {
fn from(value: &SmsDeliveryReport) -> Self {
SmsDeliveryReportStatusCategory::from(value.status)
}
}
impl From<&SmsPartialDeliveryReport> for SmsDeliveryReportStatusCategory {
fn from(value: &SmsPartialDeliveryReport) -> Self {
SmsDeliveryReportStatusCategory::from(value.status)
}
}
#[derive(Debug, Clone, Copy)]
pub struct SmsMultipartHeader {
pub message_reference: u8,
pub total: u8,
pub index: u8,
}
impl TryFrom<Vec<u8>> for SmsMultipartHeader {
type Error = &'static str;
fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
if data.len() != 3 {
return Err("Invalid user data length!");
}
Ok(Self {
message_reference: data[0],
total: data[1],
index: data[2],
})
}
}