Make contact's organization, province, postal code and voice optional.

This changes the signature for `contact::Address::new`,
`contact::ContactCreate::new` and the type of fields
`contact::InfoData::voice` and `contact::ContactCreateRequest::voice`.

Fixes issue #13.
This commit is contained in:
Kim Minh Kaplan 2023-04-03 09:20:33 +00:00 committed by Dirkjan Ochtman
parent bf5b444ff7
commit 1451ffb8e5
6 changed files with 148 additions and 25 deletions

View File

@ -25,7 +25,7 @@ pub struct ContactCreateRequest<'a> {
/// Contact `<postalInfo>` tag /// Contact `<postalInfo>` tag
postal_info: PostalInfo<'a>, postal_info: PostalInfo<'a>,
/// Contact `<voice>` tag /// Contact `<voice>` tag
voice: Voice<'a>, voice: Option<Voice<'a>>,
/// Contact `<fax>` tag,] /// Contact `<fax>` tag,]
fax: Option<Fax<'a>>, fax: Option<Fax<'a>>,
/// Contact `<email>` tag /// Contact `<email>` tag
@ -47,7 +47,7 @@ impl<'a> ContactCreate<'a> {
id: &'a str, id: &'a str,
email: &'a str, email: &'a str,
postal_info: PostalInfo<'a>, postal_info: PostalInfo<'a>,
voice: Voice<'a>, voice: Option<Voice<'a>>,
auth_password: &'a str, auth_password: &'a str,
) -> Self { ) -> Self {
Self { Self {
@ -93,8 +93,14 @@ mod tests {
#[test] #[test]
fn command() { fn command() {
let street = &["58", "Orchid Road"]; let street = &["58", "Orchid Road"];
let address = Address::new(street, "Paris", "Paris", "392374", "FR".parse().unwrap()); let address = Address::new(
let postal_info = PostalInfo::new("int", "John Doe", "Acme Widgets", address); street,
"Paris",
Some("Paris"),
Some("392374"),
"FR".parse().unwrap(),
);
let postal_info = PostalInfo::new("int", "John Doe", Some("Acme Widgets"), address);
let mut voice = Voice::new("+33.47237942"); let mut voice = Voice::new("+33.47237942");
voice.set_extension("123"); voice.set_extension("123");
let mut fax = Fax::new("+33.86698799"); let mut fax = Fax::new("+33.86698799");
@ -104,7 +110,7 @@ mod tests {
"eppdev-contact-3", "eppdev-contact-3",
"contact@eppdev.net", "contact@eppdev.net",
postal_info, postal_info,
voice, Some(voice),
"eppdev-387323", "eppdev-387323",
); );
object.set_fax(fax); object.set_fax(fax);
@ -112,6 +118,21 @@ mod tests {
assert_serialized("request/contact/create.xml", &object); assert_serialized("request/contact/create.xml", &object);
} }
#[test]
fn command_minimal() {
let address = Address::new(&[], "Paris", None, None, "FR".parse().unwrap());
let postal_info = PostalInfo::new("int", "John Doe", None, address);
let object = ContactCreate::new(
"eppdev-contact-3",
"contact@eppdev.net",
postal_info,
None,
"eppdev-387323",
);
assert_serialized("request/contact/create_minimal.xml", &object);
}
#[test] #[test]
fn response() { fn response() {
let object = response_from_file::<ContactCreate>("response/contact/create.xml"); let object = response_from_file::<ContactCreate>("response/contact/create.xml");

View File

@ -60,7 +60,7 @@ pub struct InfoData {
/// The postal info for the contact /// The postal info for the contact
pub postal_info: PostalInfo<'static>, pub postal_info: PostalInfo<'static>,
/// The voice data for the contact /// The voice data for the contact
pub voice: Voice<'static>, pub voice: Option<Voice<'static>>,
/// The fax data for the contact /// The fax data for the contact
pub fax: Option<Fax<'static>>, pub fax: Option<Fax<'static>>,
/// The email for the contact /// The email for the contact
@ -109,7 +109,7 @@ mod tests {
let result = object.res_data().unwrap(); let result = object.res_data().unwrap();
let fax = result.fax.as_ref().unwrap(); let fax = result.fax.as_ref().unwrap();
let voice_ext = result.voice.extension.as_ref().unwrap(); let voice_ext = result.voice.as_ref().unwrap().extension.as_ref().unwrap();
let fax_ext = fax.extension.as_ref().unwrap(); let fax_ext = fax.extension.as_ref().unwrap();
let auth_info = result.auth_info.as_ref().unwrap(); let auth_info = result.auth_info.as_ref().unwrap();
@ -120,14 +120,20 @@ mod tests {
assert_eq!(result.statuses[0], Status::Ok); assert_eq!(result.statuses[0], Status::Ok);
assert_eq!(result.postal_info.info_type, "loc"); assert_eq!(result.postal_info.info_type, "loc");
assert_eq!(result.postal_info.name, "John Doe"); assert_eq!(result.postal_info.name, "John Doe");
assert_eq!(result.postal_info.organization, "Acme Widgets"); assert_eq!(result.postal_info.organization, Some("Acme Widgets".into()));
assert_eq!(result.postal_info.address.street[0], "58"); assert_eq!(result.postal_info.address.street[0], "58");
assert_eq!(result.postal_info.address.street[1], "Orchid Road"); assert_eq!(result.postal_info.address.street[1], "Orchid Road");
assert_eq!(result.postal_info.address.city, "Paris"); assert_eq!(result.postal_info.address.city, "Paris");
assert_eq!(result.postal_info.address.province, "Paris"); assert_eq!(result.postal_info.address.province, Some("Paris".into()));
assert_eq!(result.postal_info.address.postal_code, "392374"); assert_eq!(
result.postal_info.address.postal_code,
Some("392374".into())
);
assert_eq!(result.postal_info.address.country.alpha2, "FR"); assert_eq!(result.postal_info.address.country.alpha2, "FR");
assert_eq!(result.voice.number, "+33.47237942".to_string()); assert_eq!(
result.voice.as_ref().unwrap().number,
"+33.47237942".to_string()
);
assert_eq!(*voice_ext, "123".to_string()); assert_eq!(*voice_ext, "123".to_string());
assert_eq!(fax.number, "+33.86698799".to_string()); assert_eq!(fax.number, "+33.86698799".to_string());
assert_eq!(*fax_ext, "243".to_string()); assert_eq!(*fax_ext, "243".to_string());
@ -147,4 +153,40 @@ mod tests {
assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID); assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID);
assert_eq!(object.tr_ids.server_tr_id, SVTRID); assert_eq!(object.tr_ids.server_tr_id, SVTRID);
} }
#[test]
fn response_minimal() {
let object = response_from_file::<ContactInfo>("response/contact/info_minimal.xml");
let result = object.res_data().unwrap();
assert_eq!(object.result.code, ResultCode::CommandCompletedSuccessfully);
assert_eq!(object.result.message, SUCCESS_MSG);
assert_eq!(result.id, "eppdev-contact-3");
assert_eq!(result.roid, "UNDEF-ROID");
assert_eq!(result.statuses[0], Status::Ok);
assert_eq!(result.postal_info.info_type, "loc");
assert_eq!(result.postal_info.name, "John Doe");
assert_eq!(result.postal_info.organization, None);
assert_eq!(result.postal_info.address.street[0], "58");
assert_eq!(result.postal_info.address.street[1], "Orchid Road");
assert_eq!(result.postal_info.address.city, "Paris");
assert_eq!(result.postal_info.address.province, None);
assert_eq!(result.postal_info.address.postal_code, None);
assert_eq!(result.postal_info.address.country.alpha2, "FR");
assert_eq!(result.voice, None);
assert_eq!(result.fax, None);
assert_eq!(result.email, "contact@eppdev.net");
assert_eq!(result.client_id, "eppdev");
assert_eq!(result.creator_id, "SYSTEM");
assert_eq!(
result.created_at,
Utc.with_ymd_and_hms(2021, 7, 23, 13, 9, 9).unwrap(),
);
assert_eq!(result.updater_id, None);
assert_eq!(result.updated_at, None);
assert_eq!(result.auth_info, None);
assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID);
assert_eq!(object.tr_ids.server_tr_id, SVTRID);
}
} }

View File

@ -75,7 +75,7 @@ impl std::ops::Deref for Country {
} }
/// The `<authInfo>` tag for domain and contact transactions /// The `<authInfo>` tag for domain and contact transactions
#[derive(Debug, Clone, FromXml, ToXml)] #[derive(Debug, Clone, PartialEq, FromXml, ToXml)]
#[xml(rename = "authInfo", ns(XMLNS))] #[xml(rename = "authInfo", ns(XMLNS))]
pub struct ContactAuthInfo<'a> { pub struct ContactAuthInfo<'a> {
/// The `<pw>` tag under `<authInfo>` /// The `<pw>` tag under `<authInfo>`
@ -93,7 +93,7 @@ impl<'a> ContactAuthInfo<'a> {
} }
/// The data for `<voice>` types on domain transactions /// The data for `<voice>` types on domain transactions
#[derive(Debug, Clone, FromXml, ToXml)] #[derive(Debug, Clone, PartialEq, FromXml, ToXml)]
#[xml(rename = "voice", ns(XMLNS))] #[xml(rename = "voice", ns(XMLNS))]
pub struct Voice<'a> { pub struct Voice<'a> {
/// The value of the 'x' attr on `<voice>` and `<fax>` tags /// The value of the 'x' attr on `<voice>` and `<fax>` tags
@ -120,7 +120,7 @@ impl<'a> Voice<'a> {
} }
/// The data for `<voice>` and `<fax>` types on domain transactions /// The data for `<voice>` and `<fax>` types on domain transactions
#[derive(Debug, Clone, FromXml, ToXml)] #[derive(Debug, Clone, FromXml, ToXml, PartialEq)]
#[xml(rename = "fax", ns(XMLNS))] #[xml(rename = "fax", ns(XMLNS))]
pub struct Fax<'a> { pub struct Fax<'a> {
/// The value of the 'x' attr on `<voice>` and `<fax>` tags /// The value of the 'x' attr on `<voice>` and `<fax>` tags
@ -156,10 +156,10 @@ pub struct Address<'a> {
pub city: Cow<'a, str>, pub city: Cow<'a, str>,
/// The `<sp>` tag under `<addr>` /// The `<sp>` tag under `<addr>`
#[xml(rename = "sp")] #[xml(rename = "sp")]
pub province: Cow<'a, str>, pub province: Option<Cow<'a, str>>,
/// The `<pc>` tag under `<addr>` /// The `<pc>` tag under `<addr>`
#[xml(rename = "pc")] #[xml(rename = "pc")]
pub postal_code: Cow<'a, str>, pub postal_code: Option<Cow<'a, str>>,
/// The `<cc>` tag under `<addr>` /// The `<cc>` tag under `<addr>`
#[xml(rename = "cc")] #[xml(rename = "cc")]
pub country: Country, pub country: Country,
@ -170,8 +170,8 @@ impl<'a> Address<'a> {
pub fn new( pub fn new(
street: &[&'a str], street: &[&'a str],
city: &'a str, city: &'a str,
province: &'a str, province: Option<&'a str>,
postal_code: &'a str, postal_code: Option<&'a str>,
country: Country, country: Country,
) -> Self { ) -> Self {
let street = street.iter().map(|&s| s.into()).collect(); let street = street.iter().map(|&s| s.into()).collect();
@ -179,8 +179,8 @@ impl<'a> Address<'a> {
Self { Self {
street, street,
city: city.into(), city: city.into(),
province: province.into(), province: province.map(|sp| sp.into()),
postal_code: postal_code.into(), postal_code: postal_code.map(|pc| pc.into()),
country, country,
} }
} }
@ -197,7 +197,7 @@ pub struct PostalInfo<'a> {
pub name: Cow<'a, str>, pub name: Cow<'a, str>,
/// The `<org>` tag under `<postalInfo>` /// The `<org>` tag under `<postalInfo>`
#[xml(rename = "org")] #[xml(rename = "org")]
pub organization: Cow<'a, str>, pub organization: Option<Cow<'a, str>>,
/// The `<addr>` tag under `<postalInfo>` /// The `<addr>` tag under `<postalInfo>`
pub address: Address<'a>, pub address: Address<'a>,
} }
@ -207,13 +207,13 @@ impl<'a> PostalInfo<'a> {
pub fn new( pub fn new(
info_type: &'a str, info_type: &'a str,
name: &'a str, name: &'a str,
organization: &'a str, organization: Option<&'a str>,
address: Address<'a>, address: Address<'a>,
) -> Self { ) -> Self {
Self { Self {
info_type: info_type.into(), info_type: info_type.into(),
name: name.into(), name: name.into(),
organization: organization.into(), organization: organization.map(|org| org.into()),
address, address,
} }
} }

View File

@ -120,8 +120,14 @@ mod tests {
let mut object = ContactUpdate::new("eppdev-contact-3"); let mut object = ContactUpdate::new("eppdev-contact-3");
let street = &["58", "Orchid Road"]; let street = &["58", "Orchid Road"];
let address = Address::new(street, "Paris", "Paris", "392374", "FR".parse().unwrap()); let address = Address::new(
let postal_info = PostalInfo::new("loc", "John Doe", "Acme Widgets", address); street,
"Paris",
Some("Paris"),
Some("392374"),
"FR".parse().unwrap(),
);
let postal_info = PostalInfo::new("loc", "John Doe", Some("Acme Widgets"), address);
let voice = Voice::new("+33.47237942"); let voice = Voice::new("+33.47237942");
object.set_info("newemail@eppdev.net", postal_info, voice, "eppdev-387323"); object.set_info("newemail@eppdev.net", postal_info, voice, "eppdev-387323");

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<create xmlns="urn:ietf:params:xml:ns:contact-1.0">
<id>eppdev-contact-3</id>
<postalInfo type="int">
<name>John Doe</name>
<addr>
<city>Paris</city>
<cc>FR</cc>
</addr>
</postalInfo>
<email>contact@eppdev.net</email>
<authInfo>
<pw>eppdev-387323</pw>
</authInfo>
</create>
</create>
<clTRID>cltrid:1626454866</clTRID>
</command>
</epp>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<contact:infData xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<contact:id>eppdev-contact-3</contact:id>
<contact:roid>UNDEF-ROID</contact:roid>
<contact:status s="ok"/>
<contact:postalInfo type="loc">
<contact:name>John Doe</contact:name>
<contact:addr>
<contact:street>58</contact:street>
<contact:street>Orchid Road</contact:street>
<contact:city>Paris</contact:city>
<contact:cc>FR</contact:cc>
</contact:addr>
</contact:postalInfo>
<contact:email>contact@eppdev.net</contact:email>
<contact:clID>eppdev</contact:clID>
<contact:crID>SYSTEM</contact:crID>
<contact:crDate>2021-07-23T13:09:09.0Z</contact:crDate>
</contact:infData>
</resData>
<trID>
<clTRID>cltrid:1626454866</clTRID>
<svTRID>RO-6879-1627224678242975</svTRID>
</trID>
</response>
</epp>