Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 0 additions & 32 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,6 @@ impl Extension for NoExtension {
type Response = Self;
}

/// The `<option>` type in EPP XML login requests
#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
#[xml(rename = "options", ns(EPP_XMLNS))]
pub struct Options<'a> {
/// The EPP version being used
pub version: Cow<'a, str>,
/// The language that will be used during EPP transactions
pub lang: Cow<'a, str>,
}

impl<'a> Options<'a> {
/// Creates an Options object with version and lang data
pub fn build(version: &'a str, lang: &'a str) -> Self {
Self {
version: version.into(),
lang: lang.into(),
}
}
}

/// The `<svcExtension>` type in EPP XML
#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
#[xml(rename = "svcExtension", ns(EPP_XMLNS))]
Expand All @@ -60,15 +40,3 @@ pub struct ServiceExtension<'a> {
#[xml(rename = "extURI")]
pub ext_uris: Vec<Cow<'a, str>>,
}

/// The `<svcs>` type in EPP XML
#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
#[xml(rename = "svcs", ns(EPP_XMLNS))]
pub struct Services<'a> {
/// The service URIs being used by this EPP session represented by `<objURI>` in EPP XML
#[xml(rename = "objURI")]
pub obj_uris: Vec<Cow<'a, str>>,
// The `<svcExtension>` being used in this EPP session
#[xml(rename = "svcExtension")]
pub svc_ext: Option<ServiceExtension<'a>>,
}
59 changes: 46 additions & 13 deletions src/hello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::Debug;
use chrono::{DateTime, Utc};
use instant_xml::{Deserializer, FromXml, ToXml};

use crate::common::{Options, ServiceExtension, Services, EPP_XMLNS};
use crate::common::{ServiceExtension, EPP_XMLNS};

// Request

Expand All @@ -16,16 +16,29 @@ pub(crate) struct Hello;
/// Type for data within the `<svcMenu>` section of an EPP greeting
#[derive(Debug, Eq, PartialEq)]
pub struct ServiceMenu {
pub options: Options<'static>,
pub services: Services<'static>,
pub version: String,
pub langs: Vec<String>,
pub services: Services,
Comment thread
djc marked this conversation as resolved.
}

/// Offered services by the remote EPP server, represented by the `<svcs>` tag in EPP greeting XML
#[derive(Debug, Eq, PartialEq)]
pub struct Services {
/// The service URIs being offered by the EPP server represented by `<objURI>` in EPP XML
pub obj_uris: Vec<String>,
/// The service extensions being offered by the EPP server represented by `<svcExtension>` in EPP XML
pub svc_ext: Option<ServiceExtension<'static>>,
}

/// Simplified service menu type for deserialization to `ServiceMenu` type from EPP greeting XML
///
/// Implements the `epp:svcMenuType` type defined in RFC 5730.
#[derive(Debug, FromXml, PartialEq)]
#[xml(ns(EPP_XMLNS), rename = "svcMenu")]
struct FlattenedServiceMenu {
version: String,
lang: String,
#[xml(rename = "lang")]
langs: Vec<String>,
#[xml(rename = "objURI")]
obj_uris: Vec<String>,
#[xml(rename = "svcExtension")]
Expand All @@ -51,12 +64,10 @@ impl<'xml> FromXml<'xml> for ServiceMenu {
};

*into = Some(Self {
options: Options {
version: flattened.version.into(),
lang: flattened.lang.into(),
},
version: flattened.version,
langs: flattened.langs,
services: Services {
obj_uris: flattened.obj_uris.into_iter().map(|s| s.into()).collect(),
obj_uris: flattened.obj_uris,
svc_ext: flattened.svc_ext,
},
});
Expand Down Expand Up @@ -338,8 +349,30 @@ mod tests {
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.version, "1.0");
assert_eq!(object.svc_menu.langs.first().unwrap(), "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()))
);
}

#[test]
fn greeting_multi_lang() {
let xml = get_xml("response/greeting_multi_lang.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.version, "1.0");
assert_eq!(object.svc_menu.langs.first().unwrap(), "en");
assert_eq!(object.svc_menu.langs.get(1).unwrap(), "fr");
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);
Expand All @@ -359,8 +392,8 @@ mod tests {
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.version, "1.0");
assert_eq!(object.svc_menu.langs.first().unwrap(), "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);
Expand Down
40 changes: 38 additions & 2 deletions src/login.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::fmt::Debug;
use std::{borrow::Cow, fmt::Debug};

use instant_xml::ToXml;

use crate::{
common::{NoExtension, Options, ServiceExtension, Services, EPP_XMLNS},
common::{NoExtension, ServiceExtension, EPP_XMLNS},
contact, domain, host,
request::{Command, Transaction, EPP_LANG, EPP_VERSION},
};
Expand Down Expand Up @@ -71,6 +71,42 @@ impl<'a> Login<'a> {
}
}

/// The `<options>` type in EPP XML login requests
///
/// Implements the `epp:credsOptionsType` type defined in RFC 5730.
#[derive(Debug, Eq, PartialEq, ToXml)]
#[xml(rename = "options", ns(EPP_XMLNS))]
pub struct Options<'a> {
/// The EPP version being used
pub version: Cow<'a, str>,
/// The language that will be used during EPP transactions
pub lang: Cow<'a, str>,
}

impl<'a> Options<'a> {
/// Creates a LoginOptions object with version and lang data
pub fn build(version: &'a str, lang: &'a str) -> Self {
Self {
version: version.into(),
lang: lang.into(),
}
}
}

/// The `<svcs>` type in EPP XML
///
/// Implements the `epp:loginSvcType` type defined in RFC 5730.
#[derive(Debug, Eq, PartialEq, ToXml)]
#[xml(rename = "svcs", ns(EPP_XMLNS))]
pub struct Services<'a> {
/// The service URIs being used by this EPP session represented by `<objURI>` in EPP XML
#[xml(rename = "objURI")]
pub obj_uris: Vec<Cow<'a, str>>,
// The `<svcExtension>` being used in this EPP session
#[xml(rename = "svcExtension")]
pub svc_ext: Option<ServiceExtension<'a>>,
}

impl Command for Login<'_> {
type Response = ();
const COMMAND: &'static str = "login";
Expand Down
55 changes: 55 additions & 0 deletions tests/resources/response/greeting_multi_lang.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<greeting>
<svID>ISPAPI EPP Server</svID>
<svDate>2021-07-25T14:51:17.0Z</svDate>
<svcMenu>
<version>1.0</version>
<lang>en</lang>
<lang>fr</lang>
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
<objURI>http://schema.ispapi.net/epp/xml/keyvalue-1.0</objURI>
<svcExtension>
<extURI>urn:ietf:params:xml:ns:secDNS-1.1</extURI>
<extURI>urn:ietf:params:xml:ns:secDNS-1.0</extURI>
<extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
<extURI>urn:ietf:params:xml:ns:fee-0.7</extURI>
<extURI>http://schema.ispapi.net/epp/xml/keyvalue-1.0</extURI>
</svcExtension>
</svcMenu>
<dcp>
<access>
<all />
</access>
<statement>
<purpose>
<admin />
<prov />
</purpose>
<recipient>
<ours />
<public />
</recipient>
<retention>
<stated />
</retention>
</statement>
<statement>
<purpose>
<other />
</purpose>
<recipient>
<unrelated />
</recipient>
<retention>
<none />
</retention>
</statement>
<expiry>
<relative>P1M</relative>
</expiry>
</dcp>
</greeting>
</epp>
Loading