Use different type wrappers instead of single EppObject

This commit is contained in:
Dirkjan Ochtman 2021-12-08 16:38:58 +01:00 committed by masalachai
parent 57d60807d8
commit ce30f1599f
13 changed files with 211 additions and 194 deletions

View File

@ -45,10 +45,9 @@
use std::{error::Error, fmt::Debug};
use crate::common::EppObject;
use crate::config::EppClientConfig;
use crate::error;
use crate::hello::{Greeting, Hello};
use crate::hello::{Greeting, GreetingDocument, HelloDocument};
use crate::registry::{epp_connect, EppConnection};
use crate::request::{EppExtension, EppRequest};
use crate::response::Response;
@ -81,11 +80,11 @@ impl EppClient {
/// Executes an EPP Hello call and returns the response as an `Greeting`
pub async fn hello(&mut self) -> Result<Greeting, Box<dyn Error>> {
let hello_xml = EppObject::<Hello>::build(Hello).serialize()?;
let hello_xml = HelloDocument::default().serialize()?;
let response = self.connection.transact(&hello_xml).await?;
Ok(EppObject::<Greeting>::deserialize(&response)?.data)
Ok(GreetingDocument::deserialize(&response)?.data)
}
pub async fn transact<T, E>(
@ -117,6 +116,6 @@ impl EppClient {
/// Returns the greeting received on establishment of the connection as an `Greeting`
pub fn greeting(&self) -> Result<Greeting, error::Error> {
EppObject::<Greeting>::deserialize(&self.connection.greeting).map(|obj| obj.data)
GreetingDocument::deserialize(&self.connection.greeting).map(|obj| obj.data)
}
}

View File

@ -3,11 +3,11 @@
use std::{fmt::Display, str::FromStr};
use epp_client_macros::ElementName;
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use serde::{Deserialize, Serialize};
use crate::request::EppExtension;
const EPP_XMLNS: &str = "urn:ietf:params:xml:ns:epp-1.0";
pub(crate) const EPP_XMLNS: &str = "urn:ietf:params:xml:ns:epp-1.0";
/// Wraps String for easier serialization to and from values that are inner text
/// for tags rather than attributes
@ -46,33 +46,6 @@ impl EppExtension for NoExtension {
type Response = NoExtension;
}
/// An EPP XML Document that is used either as an EPP XML request or
/// an EPP XML response
#[derive(Deserialize, Debug, PartialEq)]
#[serde(rename = "epp")]
pub struct EppObject<T: ElementName> {
/// XML namespace for the &lt;epp&gt; tag
pub xmlns: String,
/// the request or response object that is set or received in the EPP XML document
#[serde(alias = "greeting", alias = "response")]
pub data: T,
// TODO: save serialized xml in the instance for debugging or client logging purposes
// #[serde(skip)]
// pub xml: Option<String>,
}
impl<T: ElementName + Serialize> Serialize for EppObject<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("epp", 4)?;
state.serialize_field("xmlns", &self.xmlns)?;
state.serialize_field(T::ELEMENT, &self.data)?;
state.end()
}
}
/// The <option> type in EPP XML login requests
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename = "options")]
@ -93,26 +66,6 @@ impl Options {
}
}
/// Type representing the &lt;extension&gt; tag for an EPP document
#[derive(Deserialize, Debug, PartialEq)]
#[serde(rename = "extension")]
pub struct Extension<E: ElementName> {
/// Data under the &lt;extension&gt; tag
#[serde(alias = "upData", alias = "namestoreExt", alias = "infData")]
pub data: E,
}
impl<E: ElementName + Serialize> Serialize for Extension<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("extension", 1)?;
state.serialize_field(E::ELEMENT, &self.data)?;
state.end()
}
}
/// The <svcExtension> type in EPP XML
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename = "svcExtension")]
@ -133,17 +86,6 @@ pub struct Services {
pub svc_ext: Option<ServiceExtension>,
}
impl<T: ElementName> EppObject<T> {
/// Create the enclosing EPP XML tag &lt;epp&gt; for data that represents an EPP XML request or response
pub fn build(data: T) -> EppObject<T> {
EppObject {
// xml: None,
data,
xmlns: EPP_XMLNS.to_string(),
}
}
}
/// The &lt;status&gt; attribute on EPP XML for domain transactions
pub type DomainStatus = ContactStatus;
/// The &lt;status&gt; attribute on EPP XML for host transactions

View File

@ -3,11 +3,10 @@
use std::fmt;
use chrono::FixedOffset;
use epp_client_macros::ElementName;
use serde::{Deserialize, Serialize};
use crate::{
common::{ElementName, NoExtension, StringValue},
common::{NoExtension, StringValue},
request::EppExtension,
};
@ -64,7 +63,6 @@ impl fmt::Display for GMonthDay {
/// use epp_client::config::{EppClientConfig, RegistryConfig};
/// use epp_client::EppClient;
/// use epp_client::common::{DomainStatus, DomainContact};
/// use epp_client::extensions::consolidate::Sync;
/// use epp_client::domain::update::DomainUpdate;
/// use epp_client::extensions::consolidate;
/// use epp_client::extensions::consolidate::GMonthDay;
@ -98,10 +96,10 @@ impl fmt::Display for GMonthDay {
/// client.transact(login, "transaction-id").await.unwrap();
///
/// let exp = GMonthDay::new(5, 31, None).unwrap();
/// let consolidate_ext = consolidate::Sync::new(exp);
/// let consolidate_ext = consolidate::Update::new(exp);
///
/// // Create an DomainUpdate instance
/// let mut domain_update = DomainUpdate::<consolidate::Sync>::new("eppdev-100.com").with_extension(consolidate_ext);
/// let mut domain_update = DomainUpdate::<consolidate::Update>::new("eppdev-100.com").with_extension(consolidate_ext);
///
/// // send it to the registry and receive a response of type EppDomainUpdateResponse
/// let response = client.transact(domain_update, "transaction-id").await.unwrap();
@ -112,24 +110,32 @@ impl fmt::Display for GMonthDay {
/// client.transact(logout, "transaction-id").await.unwrap();
/// }
/// ```
impl Sync {
impl Update {
/// Create a new RGP restore report request
pub fn new(expiration: GMonthDay) -> Sync {
Sync {
pub fn new(expiration: GMonthDay) -> Self {
Self {
data: UpdateData {
xmlns: XMLNS.to_string(),
exp: expiration.to_string().into(),
},
}
}
}
impl EppExtension for Sync {
impl EppExtension for Update {
type Response = NoExtension;
}
#[derive(Serialize, Deserialize, Debug, ElementName)]
#[element_name(name = "sync:update")]
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename = "extension")]
pub struct Update {
#[serde(rename = "sync:update")]
pub data: UpdateData,
}
#[derive(Serialize, Deserialize, Debug)]
/// Type for EPP XML &lt;consolidate&gt; extension
pub struct Sync {
pub struct UpdateData {
/// XML namespace for the consolidate extension
#[serde(rename = "xmlns:sync", alias = "xmlns")]
pub xmlns: String,

View File

@ -1,12 +1,8 @@
//! Types for EPP namestore request and responses
use epp_client_macros::ElementName;
use serde::{Deserialize, Serialize};
use crate::{
common::{ElementName, StringValue},
request::EppExtension,
};
use crate::{common::StringValue, request::EppExtension};
pub const XMLNS: &str = "http://www.verisign-grs.com/epp/namestoreExt-1.1";
@ -68,8 +64,10 @@ impl NameStore {
/// Create a new RGP restore report request
pub fn new(subproduct: &str) -> NameStore {
NameStore {
data: NameStoreData {
xmlns: XMLNS.to_string(),
subproduct: subproduct.into(),
},
}
}
}
@ -78,10 +76,16 @@ impl EppExtension for NameStore {
type Response = NameStore;
}
#[derive(Serialize, Deserialize, Debug, ElementName)]
#[element_name(name = "namestoreExt:namestoreExt")]
/// Type for EPP XML &lt;namestoreExt&gt; extension
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename = "namestoreExt:namestoreExt")]
pub struct NameStore {
#[serde(rename = "namestoreExt:namestoreExt", alias = "namestoreExt")]
pub data: NameStoreData,
}
#[derive(Serialize, Deserialize, Debug)]
/// Type for EPP XML &lt;namestoreExt&gt; extension
pub struct NameStoreData {
/// XML namespace for the RGP restore extension
#[serde(rename = "xmlns:namestoreExt", alias = "xmlns")]
pub xmlns: String,

View File

@ -7,7 +7,7 @@ use crate::request::EppExtension;
use chrono::{DateTime, SecondsFormat, Utc};
use serde::{Deserialize, Serialize};
use super::XMLNS;
use super::{Update, XMLNS};
/// Type that represents the domain rgp restore report extension
///
@ -19,7 +19,7 @@ use super::XMLNS;
/// use epp_client::config::{EppClientConfig, RegistryConfig};
/// use epp_client::EppClient;
/// use epp_client::common::{DomainStatus, DomainContact};
/// use epp_client::extensions::rgp::report::RgpRestoreReport;
/// use epp_client::extensions::rgp::{Update, report::RgpRestoreReport};
/// use epp_client::domain::update::DomainUpdate;
/// use epp_client::common::NoExtension;
/// use epp_client::login::Login;
@ -63,7 +63,7 @@ use super::XMLNS;
/// ];
/// let other = "Supporting information goes here.";
///
/// let domain_restore_report = RgpRestoreReport::new(
/// let domain_restore_report = Update { data: RgpRestoreReport::new(
/// pre_data,
/// post_data,
/// deleted_at,
@ -71,10 +71,10 @@ use super::XMLNS;
/// restore_reason,
/// &statements,
/// other
/// );
/// ) };
///
/// // Create an DomainUpdate instance
/// let mut domain_update = DomainUpdate::<RgpRestoreReport>::new("eppdev-100.com").with_extension(domain_restore_report);
/// let mut domain_update = DomainUpdate::<Update<RgpRestoreReport>>::new("eppdev-100.com").with_extension(domain_restore_report);
///
/// // send it to the registry and receive a response of type EppDomainUpdateResponse
/// let response = client.transact(domain_update, "transaction-id").await.unwrap();
@ -120,7 +120,7 @@ impl RgpRestoreReport {
}
}
impl EppExtension for RgpRestoreReport {
impl EppExtension for Update<RgpRestoreReport> {
type Response = NoExtension;
}

View File

@ -8,7 +8,7 @@ use crate::request::EppExtension;
use serde::{Deserialize, Serialize};
use super::XMLNS;
use super::{Update, XMLNS};
/// Type that represents the &lt;epp&gt; request for a domain rgp restore request command
///
@ -19,7 +19,7 @@ use super::XMLNS;
///
/// use epp_client::config::{EppClientConfig, RegistryConfig};
/// use epp_client::EppClient;
/// use epp_client::extensions::rgp::request::RgpRestoreRequest;
/// use epp_client::extensions::rgp::{Update, request::RgpRestoreRequest};
/// use epp_client::domain::update::DomainUpdate;
/// use epp_client::login::Login;
/// use epp_client::logout::Logout;
@ -49,10 +49,10 @@ use super::XMLNS;
/// client.transact(login, "transaction-id").await.unwrap();
///
/// // Create an RgpRestoreRequest instance
/// let domain_restore_req = RgpRestoreRequest::new();
/// let domain_restore_req = Update { data: RgpRestoreRequest::default() };
///
/// // Create an DomainUpdate instance
/// let mut domain_update = DomainUpdate::<RgpRestoreRequest>::new("eppdev-100.com").with_extension(domain_restore_req);
/// let mut domain_update = DomainUpdate::<Update<RgpRestoreRequest>>::new("eppdev-100.com").with_extension(domain_restore_req);
///
/// // send it to the registry and receive a response of type EppDomainUpdateResponse
/// let response = client.transact(domain_update, "transaction-id").await.unwrap();
@ -63,26 +63,9 @@ use super::XMLNS;
/// client.transact(logout, "transaction-id").await.unwrap();
/// }
/// ```
impl RgpRestoreRequest {
/// Creates a new instance of EppDomainRgpRestoreRequest
pub fn new() -> RgpRestoreRequest {
RgpRestoreRequest {
xmlns: XMLNS.to_string(),
restore: RgpRestoreRequestData {
op: "request".to_string(),
},
}
}
}
impl Default for RgpRestoreRequest {
fn default() -> Self {
Self::new()
}
}
impl EppExtension for RgpRestoreRequest {
type Response = RgpRequestResponse;
impl EppExtension for Update<RgpRestoreRequest> {
type Response = Update<RgpRequestResponse>;
}
// Request
@ -106,6 +89,17 @@ pub struct RgpRestoreRequest {
restore: RgpRestoreRequestData,
}
impl Default for RgpRestoreRequest {
fn default() -> Self {
Self {
xmlns: XMLNS.to_string(),
restore: RgpRestoreRequestData {
op: "request".to_string(),
},
}
}
}
// Response
/// Type that represents the &lt;rgpStatus&gt; tag for domain rgp restore request response

View File

@ -3,14 +3,31 @@ use std::fmt::Debug;
use epp_client_macros::ElementName;
use serde::{Deserialize, Deserializer, Serialize};
use crate::common::{ElementName, Options, ServiceExtension, Services, StringValue};
use crate::common::{ElementName, Options, ServiceExtension, Services, StringValue, EPP_XMLNS};
use crate::xml::EppXml;
// Request
#[derive(Serialize, Deserialize, Debug, PartialEq, ElementName)]
#[element_name(name = "hello")]
/// Type corresponding to the <hello> tag in an EPP XML hello request
pub struct Hello;
#[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,
}
}
}
impl EppXml for HelloDocument {}
// Response
@ -278,3 +295,12 @@ pub struct Greeting {
/// Data under the <dcp> element
pub dcp: Dcp,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename = "epp")]
pub struct GreetingDocument {
#[serde(rename = "greeting")]
pub data: Greeting,
}
impl EppXml for GreetingDocument {}

View File

@ -136,10 +136,23 @@ pub mod extensions {
pub mod consolidate;
pub mod namestore;
pub mod rgp {
use serde::{Deserialize, Serialize};
pub mod report;
pub mod request;
pub const XMLNS: &str = "urn:ietf:params:xml:ns:rgp-1.0";
#[derive(Debug, Deserialize, Serialize)]
pub struct Update<T> {
#[serde(
rename = "rgp:update",
alias = "update",
alias = "upData",
alias = "infData"
)]
pub data: T,
}
}
}

View File

@ -4,8 +4,8 @@ use serde::{de::DeserializeOwned, ser::SerializeStruct, ser::Serializer, Deseria
use std::fmt::Debug;
use crate::{
common::{ElementName, EppObject, Extension, StringValue},
response::{Response, ResponseStatus},
common::{ElementName, StringValue, EPP_XMLNS},
response::{Response, ResponseDocument, ResponseStatus},
xml::EppXml,
};
use epp_client_macros::ElementName;
@ -15,16 +15,16 @@ pub const EPP_LANG: &str = "en";
/// Trait to set correct value for xml tags when tags are being generated from generic types
pub trait EppRequest<E: EppExtension>: Sized + Debug {
type Input: ElementName + DeserializeOwned + Serialize + Sized + Debug;
type Output: DeserializeOwned + Serialize + Debug;
type Input: ElementName + Serialize + Sized + Debug;
type Output: DeserializeOwned + Debug;
fn into_parts(self) -> (Self::Input, Option<E>);
fn serialize_request(self, client_tr_id: &str) -> Result<String, Box<dyn std::error::Error>> {
let (command, extension) = self.into_parts();
let extension = extension.map(|data| Extension { data });
EppXml::serialize(&EppObject::build(Command {
command,
<CommandDocument<Self::Input, E> as EppXml>::serialize(&CommandDocument::new(Command {
command: <Self::Input as ElementName>::ELEMENT,
data: command,
extension,
client_tr_id: client_tr_id.into(),
}))
@ -33,7 +33,7 @@ pub trait EppRequest<E: EppExtension>: Sized + Debug {
fn deserialize_response(
epp_xml: &str,
) -> Result<Response<Self::Output, E::Response>, crate::error::Error> {
let rsp = <EppObject<Response<Self::Output, E::Response>> as EppXml>::deserialize(epp_xml)?;
let rsp = <ResponseDocument<Self::Output, E::Response> as EppXml>::deserialize(epp_xml)?;
match rsp.data.result.code {
0..=2000 => Ok(rsp.data),
_ => Err(crate::error::Error::EppCommandError(ResponseStatus {
@ -44,44 +44,52 @@ pub trait EppRequest<E: EppExtension>: Sized + Debug {
}
}
pub trait EppExtension: ElementName + DeserializeOwned + Serialize + Sized + Debug {
type Response: ElementName + DeserializeOwned + Serialize + Debug;
pub trait EppExtension: Serialize + Sized + Debug {
type Response: DeserializeOwned + Debug;
}
#[derive(Deserialize, Debug, PartialEq, ElementName)]
#[element_name(name = "command")]
/// Type corresponding to the &lt;command&gt; tag in an EPP XML request
/// with an &lt;extension&gt; tag
pub struct Command<T: ElementName, E: ElementName> {
pub struct Command<D, E> {
pub command: &'static str,
/// The instance that will be used to populate the &lt;command&gt; tag
pub command: T,
pub data: D,
/// The client TRID
pub extension: Option<Extension<E>>,
pub extension: Option<E>,
#[serde(rename = "clTRID")]
pub client_tr_id: StringValue,
}
impl<T: ElementName + Serialize, E: ElementName + Serialize> Serialize for Command<T, E> {
impl<D: Serialize, E: Serialize> Serialize for Command<D, E> {
/// Serializes the generic type T to the proper XML tag (set by the `#[element_name(name = <tagname>)]` attribute) for the request
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("command", 3)?;
state.serialize_field(T::ELEMENT, &self.command)?;
state.serialize_field(self.command, &self.data)?;
state.serialize_field("extension", &self.extension)?;
state.serialize_field("clTRID", &self.client_tr_id)?;
state.end()
}
}
impl<T: ElementName, E: ElementName> Command<T, E> {
/// Creates a new &lt;command&gt; tag for an EPP document with a containing &lt;extension&gt; tag
pub fn build(command: T, ext: E, client_tr_id: &str) -> Command<T, E> {
Command {
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename = "epp")]
pub struct CommandDocument<D, E> {
xmlns: &'static str,
command: Command<D, E>,
}
impl<D, E> CommandDocument<D, E> {
pub fn new(command: Command<D, E>) -> Self {
Self {
xmlns: EPP_XMLNS,
command,
extension: Some(Extension { data: ext }),
client_tr_id: client_tr_id.into(),
}
}
}
impl<D: Serialize, E: Serialize> EppXml for CommandDocument<D, E> {}

View File

@ -1,10 +1,11 @@
//! Types for EPP responses
use epp_client_macros::*;
use serde::{Deserialize, Serialize};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::fmt::Debug;
use crate::common::{ElementName, Extension, StringValue};
use crate::common::{ElementName, StringValue};
use crate::xml::EppXml;
/// Type corresponding to the <undef> tag an EPP response XML
#[derive(Serialize, Deserialize, Debug, PartialEq)]
@ -70,10 +71,9 @@ pub struct MessageQueue {
#[derive(Serialize, Deserialize, Debug, PartialEq, ElementName)]
#[serde(rename_all = "lowercase")]
#[element_name(name = "response")]
/// Type corresponding to the &lt;response&gt; tag in an EPP response XML
/// containing an &lt;extension&gt; tag
pub struct Response<T, E: ElementName> {
pub struct Response<D, E> {
/// Data under the <result> tag
pub result: EppResult,
/// Data under the <msgQ> tag
@ -81,14 +81,32 @@ pub struct Response<T, E: ElementName> {
pub message_queue: Option<MessageQueue>,
#[serde(rename = "resData")]
/// Data under the &lt;resData&gt; tag
pub res_data: Option<T>,
pub res_data: Option<D>,
/// Data under the &lt;extension&gt; tag
pub extension: Option<Extension<E>>,
pub extension: Option<E>,
/// Data under the <trID> tag
#[serde(rename = "trID")]
pub tr_ids: ResponseTRID,
}
#[derive(Deserialize, Debug, PartialEq)]
#[serde(rename = "epp")]
pub struct ResponseDocument<D, E> {
#[serde(rename = "response")]
pub data: Response<D, E>,
}
impl<D: DeserializeOwned, E: DeserializeOwned> EppXml for ResponseDocument<D, E> {}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename = "epp")]
pub struct ResultDocument {
#[serde(rename = "response")]
pub data: ResponseStatus,
}
impl EppXml for ResultDocument {}
#[derive(Serialize, Deserialize, Debug, PartialEq, ElementName)]
#[element_name(name = "response")]
/// Type corresponding to the &lt;response&gt; tag in an EPP response XML

View File

@ -3,7 +3,7 @@
mod response {
use super::super::get_xml;
use super::super::CLTRID;
use crate::common::{EppObject, NoExtension};
use crate::common::NoExtension;
use crate::contact::check::ContactCheck;
use crate::contact::create::ContactCreate;
use crate::contact::delete::ContactDelete;
@ -21,9 +21,9 @@ mod response {
use crate::domain::transfer::DomainTransferRequest;
use crate::domain::update::DomainUpdate;
use crate::extensions::namestore::NameStore;
use crate::extensions::rgp::request::RgpRestoreRequest;
use crate::extensions::rgp;
use crate::hello::ExpiryType;
use crate::hello::Greeting;
use crate::hello::GreetingDocument;
use crate::hello::Relative;
use crate::host::check::HostCheck;
use crate::host::create::HostCreate;
@ -35,7 +35,7 @@ mod response {
use crate::message::ack::MessageAck;
use crate::message::poll::MessagePoll;
use crate::request::EppRequest;
use crate::response::ResponseStatus;
use crate::response::ResultDocument;
use crate::xml::EppXml;
const SVTRID: &str = "RO-6879-1627224678242975";
@ -44,7 +44,7 @@ mod response {
#[test]
fn greeting() {
let xml = get_xml("response/greeting.xml").unwrap();
let object = EppObject::<Greeting>::deserialize(xml.as_str()).unwrap();
let object = GreetingDocument::deserialize(xml.as_str()).unwrap();
assert_eq!(object.data.service_id, "ISPAPI EPP Server");
assert_eq!(object.data.service_date, "2021-07-25T14:51:17.0Z");
@ -75,7 +75,7 @@ mod response {
#[test]
fn error() {
let xml = get_xml("response/error.xml").unwrap();
let object = EppObject::<ResponseStatus>::deserialize(xml.as_str()).unwrap();
let object = ResultDocument::deserialize(xml.as_str()).unwrap();
assert_eq!(object.data.result.code, 2303);
assert_eq!(object.data.result.message, "Object does not exist".into());
@ -637,7 +637,11 @@ mod response {
#[test]
fn rgp_restore_response() {
let xml = get_xml("response/extensions/rgp_restore.xml").unwrap();
let object = DomainUpdate::<RgpRestoreRequest>::deserialize_response(xml.as_str()).unwrap();
let object =
DomainUpdate::<rgp::Update<rgp::request::RgpRestoreRequest>>::deserialize_response(
xml.as_str(),
)
.unwrap();
let ext = object.extension.unwrap();
@ -650,7 +654,11 @@ mod response {
#[test]
fn rgp_restore_domain_info_response() {
let xml = get_xml("response/extensions/domain_info_rgp.xml").unwrap();
let object = DomainInfo::<RgpRestoreRequest>::deserialize_response(xml.as_str()).unwrap();
let object =
DomainInfo::<rgp::Update<rgp::request::RgpRestoreRequest>>::deserialize_response(
xml.as_str(),
)
.unwrap();
let ext = object.extension.unwrap();

View File

@ -8,8 +8,8 @@ mod request {
use crate::common::HostObjList;
use crate::common::NoExtension;
use crate::common::{
Address, ContactStatus, DomainAuthInfo, DomainContact, DomainStatus, EppObject, HostAddr,
HostAttr, HostStatus, Phone, PostalInfo,
Address, ContactStatus, DomainAuthInfo, DomainContact, DomainStatus, HostAddr, HostAttr,
HostStatus, Phone, PostalInfo,
};
use crate::contact::check::ContactCheck;
use crate::contact::create::ContactCreate;
@ -32,9 +32,8 @@ mod request {
use crate::extensions::consolidate;
use crate::extensions::consolidate::GMonthDay;
use crate::extensions::namestore::NameStore;
use crate::extensions::rgp::report::RgpRestoreReport;
use crate::extensions::rgp::request::RgpRestoreRequest;
use crate::hello::Hello;
use crate::extensions::rgp::{self, report::RgpRestoreReport, request::RgpRestoreRequest};
use crate::hello::HelloDocument;
use crate::host::check::HostCheck;
use crate::host::create::HostCreate;
use crate::host::delete::HostDelete;
@ -54,7 +53,7 @@ mod request {
#[test]
fn hello() {
let xml = get_xml("request/hello.xml").unwrap();
let serialized = EppObject::<Hello>::build(Hello).serialize().unwrap();
let serialized = HelloDocument::default().serialize().unwrap();
assert_eq!(xml, serialized);
}
@ -527,9 +526,11 @@ mod request {
fn rgp_restore_request() {
let xml = get_xml("request/extensions/rgp_restore_request.xml").unwrap();
let domain_restore_request = RgpRestoreRequest::new();
let domain_restore_request = rgp::Update {
data: RgpRestoreRequest::default(),
};
let mut object = DomainUpdate::<RgpRestoreReport>::new("eppdev.com")
let mut object = DomainUpdate::<rgp::Update<RgpRestoreRequest>>::new("eppdev.com")
.with_extension(domain_restore_request);
let change_info = DomainChangeInfo {
@ -561,7 +562,8 @@ mod request {
];
let other = "Supporting information goes here.";
let domain_restore_report = RgpRestoreReport::new(
let domain_restore_report = rgp::Update {
data: RgpRestoreReport::new(
pre_data,
post_data,
deleted_at,
@ -569,9 +571,10 @@ mod request {
restore_reason,
statements,
other,
);
),
};
let mut object = DomainUpdate::<RgpRestoreReport>::new("eppdev.com")
let mut object = DomainUpdate::<rgp::Update<RgpRestoreReport>>::new("eppdev.com")
.with_extension(domain_restore_report);
let change_info = DomainChangeInfo {
@ -607,10 +610,10 @@ mod request {
let exp = GMonthDay::new(5, 31, None).unwrap();
let consolidate_ext = consolidate::Sync::new(exp);
let consolidate_ext = consolidate::Update::new(exp);
let mut object =
DomainUpdate::<consolidate::Sync>::new("eppdev.com").with_extension(consolidate_ext);
DomainUpdate::<consolidate::Update>::new("eppdev.com").with_extension(consolidate_ext);
object.info(DomainChangeInfo {
registrant: None,

View File

@ -3,26 +3,30 @@
use quick_xml::de::from_str;
use quick_xml::se;
use serde::{de::DeserializeOwned, Serialize};
use std::{error::Error, fmt::Debug};
use std::error::Error;
use crate::common::{ElementName, EppObject};
use crate::error;
pub const EPP_XML_HEADER: &str = r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#;
impl<T: Serialize + DeserializeOwned + ElementName + Debug> EppXml for EppObject<T> {
type Output = EppObject<T>;
/// Trait to be implemented by serializers. Currently the only included serializer is `quick-xml`
pub trait EppXml: Sized {
/// Serializes the EppObject instance to an EPP XML document
fn serialize(&self) -> Result<String, Box<dyn Error>> {
fn serialize(&self) -> Result<String, Box<dyn Error>>
where
Self: Serialize,
{
let epp_xml = format!("{}\r\n{}", EPP_XML_HEADER, se::to_string(self)?);
Ok(epp_xml)
}
/// Deserializes an EPP XML document to an EppObject instance
fn deserialize(epp_xml: &str) -> Result<Self::Output, error::Error> {
let object: Self::Output = match from_str(epp_xml) {
fn deserialize(epp_xml: &str) -> Result<Self, error::Error>
where
Self: DeserializeOwned + Sized,
{
let object: Self = match from_str(epp_xml) {
Ok(v) => v,
Err(e) => {
return Err(error::Error::EppDeserializationError(format!(
@ -35,11 +39,3 @@ impl<T: Serialize + DeserializeOwned + ElementName + Debug> EppXml for EppObject
Ok(object)
}
}
/// Trait to be implemented by serializers. Currently the only included serializer is `quick-xml`
pub trait EppXml {
type Output: Debug;
fn serialize(&self) -> Result<String, Box<dyn Error>>;
fn deserialize(epp_xml: &str) -> Result<Self::Output, error::Error>;
}