use std::fmt::Debug;
use chrono::{DateTime, Utc};
use instant_xml::{Deserializer, FromXml, ToXml};
use crate::common::{Options, ServiceExtension, Services, EPP_XMLNS};
#[derive(Debug, PartialEq, ToXml)]
#[xml(rename = "hello", ns(EPP_XMLNS))]
pub(crate) struct Hello;
#[derive(Debug, Eq, PartialEq)]
pub struct ServiceMenu {
pub options: Options<'static>,
pub services: Services<'static>,
}
#[derive(Debug, FromXml, PartialEq)]
#[xml(ns(EPP_XMLNS), rename = "svcMenu")]
struct FlattenedServiceMenu {
version: String,
lang: String,
#[xml(rename = "objURI")]
obj_uris: Vec<String>,
#[xml(rename = "svcExtension")]
svc_ext: Option<ServiceExtension<'static>>,
}
impl<'xml> FromXml<'xml> for ServiceMenu {
fn matches(id: instant_xml::Id<'_>, field: Option<instant_xml::Id<'_>>) -> bool {
FlattenedServiceMenu::matches(id, field)
}
fn deserialize<'cx>(
into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), instant_xml::Error> {
let mut value = None;
FlattenedServiceMenu::deserialize(&mut value, field, deserializer)?;
let flattened = match value {
Some(value) => value,
None => return Ok(()),
};
*into = Some(Self {
options: Options {
version: flattened.version.into(),
lang: flattened.lang.into(),
},
services: Services {
obj_uris: flattened.obj_uris.into_iter().map(|s| s.into()).collect(),
svc_ext: flattened.svc_ext,
},
});
Ok(())
}
type Accumulator = Option<Self>;
const KIND: instant_xml::Kind = FlattenedServiceMenu::KIND;
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "all", ns(EPP_XMLNS))]
pub struct All;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "noAccess", ns(EPP_XMLNS))]
pub struct NoAccess;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "null", ns(EPP_XMLNS))]
pub struct Null;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "personal", ns(EPP_XMLNS))]
pub struct Personal;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "personalAndOther", ns(EPP_XMLNS))]
pub struct PersonalAndOther;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "other", ns(EPP_XMLNS))]
pub struct Other;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(forward)]
pub enum AccessType {
All(All),
NoAccess(NoAccess),
Null(Null),
Personal(Personal),
PersonalAndOther(PersonalAndOther),
Other(Other),
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "access", ns(EPP_XMLNS))]
pub struct Access {
inner: AccessType,
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(forward)]
pub enum PurposeType {
Admin(Admin),
Contact(Contact),
Prov(Prov),
OtherPurpose(OtherPurpose),
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "admin", ns(EPP_XMLNS))]
pub struct Admin;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "contact", ns(EPP_XMLNS))]
pub struct Contact;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "prov", ns(EPP_XMLNS))]
pub struct Prov;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "otherPurpose", ns(EPP_XMLNS))]
pub struct OtherPurpose;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "purpose", ns(EPP_XMLNS))]
pub struct Purpose {
pub purpose: Vec<PurposeType>,
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(forward)]
pub enum RecipientType {
Other(Other),
Ours(Ours),
Public(Public),
Same(Same),
Unrelated(Unrelated),
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "ours", ns(EPP_XMLNS))]
pub struct Ours;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "public", ns(EPP_XMLNS))]
pub struct Public;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "unrelated", ns(EPP_XMLNS))]
pub struct Unrelated;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "same", ns(EPP_XMLNS))]
pub struct Same;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "recipient", ns(EPP_XMLNS))]
pub struct Recipient {
pub recipient: Vec<RecipientType>,
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "business", ns(EPP_XMLNS))]
pub struct Business;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "indefinite", ns(EPP_XMLNS))]
pub struct Indefinite;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "legal", ns(EPP_XMLNS))]
pub struct Legal;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "none", ns(EPP_XMLNS))]
pub struct No;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "stated", ns(EPP_XMLNS))]
pub struct Stated;
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(forward, rename = "retention", ns(EPP_XMLNS))]
pub enum RetentionType {
Business(Business),
Indefinite(Indefinite),
Legal(Legal),
None(No),
Stated(Stated),
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "retention", ns(EPP_XMLNS))]
pub struct Retention {
inner: RetentionType,
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "statement", ns(EPP_XMLNS))]
pub struct Statement {
pub purpose: Purpose,
pub recipient: Recipient,
pub retention: Retention,
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "absolute", ns(EPP_XMLNS))]
pub struct Absolute(String);
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "relative", ns(EPP_XMLNS))]
pub struct Relative(String);
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(forward)]
pub enum ExpiryType {
Absolute(Absolute),
Relative(Relative),
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "expiry", ns(EPP_XMLNS))]
pub struct Expiry {
inner: ExpiryType,
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(rename = "dcp", ns(EPP_XMLNS))]
pub struct Dcp {
pub access: Access,
pub statement: Vec<Statement>,
pub expiry: Option<Expiry>,
}
#[derive(Debug, Eq, FromXml, PartialEq)]
#[xml(ns(EPP_XMLNS), rename = "greeting", rename_all = "lowercase")]
pub struct Greeting {
#[xml(rename = "svID")]
pub service_id: String,
#[xml(rename = "svDate")]
pub service_date: DateTime<Utc>,
pub svc_menu: ServiceMenu,
pub dcp: Dcp,
}
#[cfg(test)]
mod tests {
use chrono::{TimeZone, Utc};
use super::{ExpiryType, Greeting, Hello, Relative};
use crate::tests::get_xml;
use crate::xml;
#[test]
fn hello() {
let xml = get_xml("request/hello.xml").unwrap();
let serialized = xml::serialize(Hello).unwrap();
assert_eq!(xml, serialized);
}
#[test]
fn greeting() {
let xml = get_xml("response/greeting.xml").unwrap();
let object = xml::deserialize::<Greeting>(xml.as_str()).unwrap();
assert_eq!(object.service_id, "ISPAPI EPP Server");
assert_eq!(
object.service_date,
Utc.with_ymd_and_hms(2021, 7, 25, 14, 51, 17).unwrap()
);
assert_eq!(object.svc_menu.options.version, "1.0");
assert_eq!(object.svc_menu.options.lang, "en");
assert_eq!(object.svc_menu.services.obj_uris.len(), 4);
assert_eq!(object.svc_menu.services.svc_ext.unwrap().ext_uris.len(), 5);
assert_eq!(object.dcp.statement.len(), 2);
assert_eq!(
object.dcp.expiry.unwrap().inner,
ExpiryType::Relative(Relative("P1M".into()))
);
}
}