use std::fmt::Debug;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Deserializer, Serialize};
use crate::common::{Options, ServiceExtension, Services, StringValue, EPP_XMLNS};
#[derive(Debug, PartialEq, Serialize)]
struct Hello;
#[derive(Debug, PartialEq, Serialize)]
#[serde(rename = "epp")]
pub struct HelloDocument {
xmlns: &'static str,
hello: Hello,
}
impl Default for HelloDocument {
fn default() -> Self {
Self {
xmlns: EPP_XMLNS,
hello: Hello,
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ServiceMenu {
pub options: Options<'static>,
pub services: Services<'static>,
}
#[derive(Deserialize, Debug, PartialEq)]
struct FlattenedServiceMenu {
pub version: StringValue<'static>,
pub lang: StringValue<'static>,
#[serde(rename = "objURI")]
pub obj_uris: Vec<StringValue<'static>>,
#[serde(rename = "svcExtension")]
pub svc_ext: Option<ServiceExtension<'static>>,
}
impl<'a, 'de: 'a> Deserialize<'de> for ServiceMenu {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let flattened_svc_menu = FlattenedServiceMenu::deserialize(deserializer)?;
let svc_menu = ServiceMenu {
options: Options {
version: flattened_svc_menu.version,
lang: flattened_svc_menu.lang,
},
services: Services {
obj_uris: flattened_svc_menu.obj_uris,
svc_ext: flattened_svc_menu.svc_ext,
},
};
Ok(svc_menu)
}
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct All;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct NoAccess;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Null;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Personal;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct PersonalAndOther;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Other;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub enum AccessType {
#[serde(rename = "all")]
All(All),
#[serde(rename = "none")]
NoAccess(NoAccess),
#[serde(rename = "null")]
Null(Null),
#[serde(rename = "personal")]
Personal(Personal),
#[serde(rename = "personalAndOther")]
PersonalAndOther(PersonalAndOther),
#[serde(rename = "other")]
Other(Other),
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Access {
#[serde(flatten)]
pub ty: AccessType,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub enum PurposeType {
#[serde(rename = "admin")]
Admin,
#[serde(rename = "contact")]
Contact,
#[serde(rename = "prov")]
Prov,
#[serde(rename = "other")]
OtherPurpose,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Purpose {
#[serde(rename = "$value")]
pub purpose: Vec<PurposeType>,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub enum RecipientType {
#[serde(rename = "other")]
Other,
#[serde(rename = "ours")]
Ours,
#[serde(rename = "public")]
Public,
#[serde(rename = "same")]
Same,
#[serde(rename = "unrelated")]
Unrelated,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Recipient {
#[serde(rename = "$value")]
pub recipient: Vec<RecipientType>,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Business;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Indefinite;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Legal;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct No;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Stated;
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub enum RetentionType {
#[serde(rename = "business")]
Business(Business),
#[serde(rename = "indefinite")]
Indefinite(Indefinite),
#[serde(rename = "legal")]
Legal(Legal),
#[serde(rename = "none")]
No(No),
#[serde(rename = "stated")]
Stated(Stated),
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Retention {
#[serde(flatten)]
pub ty: RetentionType,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Statement {
pub purpose: Purpose,
pub recipient: Recipient,
pub retention: Retention,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Absolute {
#[serde(rename = "$value")]
pub absolute: StringValue<'static>,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Relative {
#[serde(rename = "$value")]
pub relative: StringValue<'static>,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub enum ExpiryType {
#[serde(rename = "absolute")]
Absolute(Absolute),
#[serde(rename = "relative")]
Relative(Relative),
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Expiry {
#[serde(flatten)]
pub ty: ExpiryType,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
pub struct Dcp {
pub access: Access,
pub statement: Vec<Statement>,
pub expiry: Option<Expiry>,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub struct Greeting {
#[serde(rename = "svID")]
pub service_id: String,
#[serde(rename = "svDate")]
pub service_date: DateTime<Utc>,
#[serde(rename = "svcMenu")]
pub svc_menu: ServiceMenu,
pub dcp: Dcp,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
#[serde(rename = "epp")]
pub struct GreetingDocument {
#[serde(rename = "greeting")]
pub data: Greeting,
}
#[cfg(test)]
mod tests {
use chrono::{TimeZone, Utc};
use super::{ExpiryType, GreetingDocument, HelloDocument, Relative};
use crate::tests::get_xml;
use crate::xml;
#[test]
fn hello() {
let xml = get_xml("request/hello.xml").unwrap();
let serialized = xml::serialize(&HelloDocument::default()).unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn greeting() {
let xml = get_xml("response/greeting.xml").unwrap();
let object = xml::deserialize::<GreetingDocument>(xml.as_str()).unwrap();
assert_eq!(object.data.service_id, "ISPAPI EPP Server");
assert_eq!(
object.data.service_date,
Utc.with_ymd_and_hms(2021, 7, 25, 14, 51, 17).unwrap()
);
assert_eq!(object.data.svc_menu.options.version, "1.0".into());
assert_eq!(object.data.svc_menu.options.lang, "en".into());
assert_eq!(object.data.svc_menu.services.obj_uris.len(), 4);
assert_eq!(
object
.data
.svc_menu
.services
.svc_ext
.unwrap()
.ext_uris
.unwrap()
.len(),
5
);
assert_eq!(object.data.dcp.statement.len(), 2);
assert_eq!(
object.data.dcp.expiry.unwrap().ty,
ExpiryType::Relative(Relative {
relative: "P1M".into()
})
);
}
}