use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use super::{DomainAuthInfo, DomainContact, HostList, Period, XMLNS};
use crate::common::{NoExtension, StringValue};
use crate::request::{Command, Transaction};
impl<'a> Transaction<NoExtension> for DomainCreate<'a> {}
impl<'a> Command for DomainCreate<'a> {
type Response = DomainCreateResponse;
const COMMAND: &'static str = "create";
}
#[derive(Serialize, Debug)]
pub struct DomainCreateRequestData<'a> {
#[serde(rename = "xmlns:domain")]
pub xmlns: &'a str,
#[serde(rename = "domain:name")]
pub name: StringValue<'a>,
#[serde(rename = "domain:period")]
pub period: Period,
#[serde(rename = "domain:ns")]
pub ns: Option<HostList<'a>>,
#[serde(rename = "domain:registrant")]
pub registrant: Option<StringValue<'a>>,
#[serde(rename = "domain:contact")]
pub contacts: Option<&'a [DomainContact<'a>]>,
#[serde(rename = "domain:authInfo")]
pub auth_info: DomainAuthInfo<'a>,
}
#[derive(Serialize, Debug)]
pub struct DomainCreate<'a> {
#[serde(rename = "domain:create")]
pub domain: DomainCreateRequestData<'a>,
}
impl<'a> DomainCreate<'a> {
pub fn new(
name: &'a str,
period: Period,
ns: Option<HostList<'a>>,
registrant_id: Option<&'a str>,
auth_password: &'a str,
contacts: Option<&'a [DomainContact<'a>]>,
) -> Self {
Self {
domain: DomainCreateRequestData {
xmlns: XMLNS,
name: name.into(),
period,
ns,
registrant: registrant_id.map(|id| id.into()),
auth_info: DomainAuthInfo::new(auth_password),
contacts,
},
}
}
}
#[derive(Deserialize, Debug)]
pub struct DomainCreateResponseData {
#[serde(rename = "xmlns:domain")]
pub xmlns: String,
pub name: StringValue<'static>,
#[serde(rename = "crDate")]
pub created_at: DateTime<Utc>,
#[serde(rename = "exDate")]
pub expiring_at: Option<DateTime<Utc>>,
}
#[derive(Deserialize, Debug)]
pub struct DomainCreateResponse {
#[serde(rename = "creData")]
pub create_data: DomainCreateResponseData,
}
#[cfg(test)]
mod tests {
use std::net::IpAddr;
use chrono::{TimeZone, Utc};
use super::{DomainContact, DomainCreate, HostList, Period};
use crate::domain::{HostAttr, HostAttrList, HostObjList};
use crate::response::ResultCode;
use crate::tests::{assert_serialized, response_from_file, CLTRID, SUCCESS_MSG, SVTRID};
#[test]
fn command() {
let contacts = &[
DomainContact {
contact_type: "admin".into(),
id: "eppdev-contact-3".into(),
},
DomainContact {
contact_type: "tech".into(),
id: "eppdev-contact-3".into(),
},
DomainContact {
contact_type: "billing".into(),
id: "eppdev-contact-3".into(),
},
];
let object = DomainCreate::new(
"eppdev-1.com",
Period::years(1).unwrap(),
None,
Some("eppdev-contact-3"),
"epP4uthd#v",
Some(contacts),
);
assert_serialized("request/domain/create.xml", &object);
}
#[test]
fn command_with_host_obj() {
let contacts = &[
DomainContact {
contact_type: "admin".into(),
id: "eppdev-contact-3".into(),
},
DomainContact {
contact_type: "tech".into(),
id: "eppdev-contact-3".into(),
},
DomainContact {
contact_type: "billing".into(),
id: "eppdev-contact-3".into(),
},
];
let hosts = &["ns1.test.com".into(), "ns2.test.com".into()];
let object = DomainCreate::new(
"eppdev-1.com",
Period::years(1).unwrap(),
Some(HostList::HostObjList(HostObjList { hosts })),
Some("eppdev-contact-3"),
"epP4uthd#v",
Some(contacts),
);
assert_serialized("request/domain/create_with_host_obj.xml", &object);
}
#[test]
fn command_with_host_attr() {
let contacts = &[
DomainContact {
contact_type: "admin".into(),
id: "eppdev-contact-3".into(),
},
DomainContact {
contact_type: "tech".into(),
id: "eppdev-contact-3".into(),
},
DomainContact {
contact_type: "billing".into(),
id: "eppdev-contact-3".into(),
},
];
let hosts = &[
HostAttr {
name: "ns1.eppdev-1.com".into(),
addresses: None,
},
HostAttr {
name: "ns2.eppdev-1.com".into(),
addresses: Some(vec![
IpAddr::from([177, 232, 12, 58]),
IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e]),
]),
},
];
let object = DomainCreate::new(
"eppdev-2.com",
Period::years(1).unwrap(),
Some(HostList::HostAttrList(HostAttrList { hosts })),
Some("eppdev-contact-3"),
"epP4uthd#v",
Some(contacts),
);
assert_serialized("request/domain/create_with_host_attr.xml", &object);
}
#[test]
fn response() {
let object = response_from_file::<DomainCreate>("response/domain/create.xml");
let result = object.res_data().unwrap();
assert_eq!(object.result.code, ResultCode::CommandCompletedSuccessfully);
assert_eq!(object.result.message, SUCCESS_MSG.into());
assert_eq!(result.create_data.name, "eppdev-2.com".into());
assert_eq!(
result.create_data.created_at,
Utc.with_ymd_and_hms(2021, 7, 25, 18, 11, 35).unwrap()
);
assert_eq!(
*result.create_data.expiring_at.as_ref().unwrap(),
Utc.with_ymd_and_hms(2022, 7, 25, 18, 11, 34).unwrap()
);
assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
}
}