Use different type wrappers instead of single EppObject
This commit is contained in:
parent
57d60807d8
commit
ce30f1599f
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <epp> 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 <extension> tag for an EPP document
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "extension")]
|
||||
pub struct Extension<E: ElementName> {
|
||||
/// Data under the <extension> 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 <epp> 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 <status> attribute on EPP XML for domain transactions
|
||||
pub type DomainStatus = ContactStatus;
|
||||
/// The <status> attribute on EPP XML for host transactions
|
||||
|
|
|
@ -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 {
|
||||
xmlns: XMLNS.to_string(),
|
||||
exp: expiration.to_string().into(),
|
||||
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 <consolidate> extension
|
||||
pub struct Sync {
|
||||
pub struct UpdateData {
|
||||
/// XML namespace for the consolidate extension
|
||||
#[serde(rename = "xmlns:sync", alias = "xmlns")]
|
||||
pub xmlns: String,
|
||||
|
|
|
@ -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 {
|
||||
xmlns: XMLNS.to_string(),
|
||||
subproduct: subproduct.into(),
|
||||
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 <namestoreExt> 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 <namestoreExt> extension
|
||||
pub struct NameStoreData {
|
||||
/// XML namespace for the RGP restore extension
|
||||
#[serde(rename = "xmlns:namestoreExt", alias = "xmlns")]
|
||||
pub xmlns: String,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::request::EppExtension;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::XMLNS;
|
||||
use super::{Update, XMLNS};
|
||||
|
||||
/// Type that represents the <epp> 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 <rgpStatus> tag for domain rgp restore request response
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <command> tag in an EPP XML request
|
||||
/// with an <extension> 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 <command> 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 <command> tag for an EPP document with a containing <extension> 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> {}
|
||||
|
|
|
@ -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 <response> tag in an EPP response XML
|
||||
/// containing an <extension> 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 <resData> tag
|
||||
pub res_data: Option<T>,
|
||||
pub res_data: Option<D>,
|
||||
/// Data under the <extension> 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 <response> tag in an EPP response XML
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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,17 +562,19 @@ mod request {
|
|||
];
|
||||
let other = "Supporting information goes here.";
|
||||
|
||||
let domain_restore_report = RgpRestoreReport::new(
|
||||
pre_data,
|
||||
post_data,
|
||||
deleted_at,
|
||||
restored_at,
|
||||
restore_reason,
|
||||
statements,
|
||||
other,
|
||||
);
|
||||
let domain_restore_report = rgp::Update {
|
||||
data: RgpRestoreReport::new(
|
||||
pre_data,
|
||||
post_data,
|
||||
deleted_at,
|
||||
restored_at,
|
||||
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,
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue