Frnic contact create (#16)
This commit is contained in:
parent
1b6a774232
commit
7024bcd7a5
|
@ -0,0 +1,183 @@
|
||||||
|
//! Types for EPP FRNIC contact requests
|
||||||
|
use instant_xml::{Id, ToXml};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use crate::request::{Extension, Transaction};
|
||||||
|
|
||||||
|
use super::{Create, Ext, XMLNS};
|
||||||
|
|
||||||
|
impl<'a> Transaction<Ext<Create<ContactCreate<'a>>>> for crate::contact::create::ContactCreate<'a> {}
|
||||||
|
|
||||||
|
impl<'a> Extension for Ext<Create<ContactCreate<'a>>> {
|
||||||
|
type Response = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For french TLDs, a contact is either an individual (PP) or a legal
|
||||||
|
/// entity (PM). We use the `ContactCreate` extension to differentiate
|
||||||
|
/// between the creation of a PP and a PM.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ContactCreate<'a> {
|
||||||
|
/// This contact is an individual.
|
||||||
|
NaturalPerson {
|
||||||
|
/// First name of the contact. The `<contact:name>` element
|
||||||
|
/// will be the family name.
|
||||||
|
first_name: Cow<'a, str>,
|
||||||
|
},
|
||||||
|
/// This contact is a legal entity.
|
||||||
|
LegalEntity(Box<LegalEntityInfos<'a>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<ContactCreate<'a>> for Ext<Create<ContactCreate<'a>>> {
|
||||||
|
fn from(data: ContactCreate<'a>) -> Self {
|
||||||
|
Ext {
|
||||||
|
data: Create { data },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ContactCreate<'a> {
|
||||||
|
pub fn new_natural_person(first_name: &'a str) -> Self {
|
||||||
|
Self::NaturalPerson {
|
||||||
|
first_name: first_name.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_company(
|
||||||
|
siren: Option<&'a str>,
|
||||||
|
vat: Option<&'a str>,
|
||||||
|
trademark: Option<&'a str>,
|
||||||
|
duns: Option<&'a str>,
|
||||||
|
local: Option<&'a str>,
|
||||||
|
) -> Self {
|
||||||
|
Self::LegalEntity(Box::new(LegalEntityInfos {
|
||||||
|
legal_status: LegalStatus::Company,
|
||||||
|
siren: siren.map(|s| s.into()),
|
||||||
|
vat: vat.map(|v| v.into()),
|
||||||
|
trademark: trademark.map(|t| t.into()),
|
||||||
|
asso: None,
|
||||||
|
duns: duns.map(|d| d.into()),
|
||||||
|
local: local.map(|l| l.into()),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_non_profit(
|
||||||
|
waldec: Option<&'a str>,
|
||||||
|
declaration: Option<&'a str>,
|
||||||
|
publication: Option<Publication<'a>>,
|
||||||
|
) -> Self {
|
||||||
|
Self::LegalEntity(Box::new(LegalEntityInfos {
|
||||||
|
legal_status: LegalStatus::Association,
|
||||||
|
siren: None,
|
||||||
|
vat: None,
|
||||||
|
trademark: None,
|
||||||
|
asso: Some(Association {
|
||||||
|
waldec: waldec.map(|w| w.into()),
|
||||||
|
declaration: declaration.map(|d| d.into()),
|
||||||
|
publication,
|
||||||
|
}),
|
||||||
|
duns: None,
|
||||||
|
local: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToXml for ContactCreate<'a> {
|
||||||
|
fn serialize<W: core::fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
_: Option<Id<'_>>,
|
||||||
|
serializer: &mut instant_xml::Serializer<'_, W>,
|
||||||
|
) -> Result<(), instant_xml::Error> {
|
||||||
|
let contact_nc_name = "contact";
|
||||||
|
let prefix = serializer.write_start(contact_nc_name, XMLNS)?;
|
||||||
|
serializer.end_start()?;
|
||||||
|
match self {
|
||||||
|
Self::NaturalPerson { first_name } => {
|
||||||
|
let first_name_nc_name = "firstName";
|
||||||
|
let prefix = serializer.write_start(first_name_nc_name, XMLNS)?;
|
||||||
|
serializer.end_start()?;
|
||||||
|
first_name.serialize(None, serializer)?;
|
||||||
|
serializer.write_close(prefix, first_name_nc_name)?;
|
||||||
|
}
|
||||||
|
Self::LegalEntity(infos) => infos.serialize(None, serializer)?,
|
||||||
|
}
|
||||||
|
serializer.write_close(prefix, contact_nc_name)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, ToXml)]
|
||||||
|
#[xml(rename = "legalEntityInfos", ns(XMLNS))]
|
||||||
|
pub struct LegalEntityInfos<'a> {
|
||||||
|
pub legal_status: LegalStatus<'a>,
|
||||||
|
pub siren: Option<Cow<'a, str>>,
|
||||||
|
pub vat: Option<Cow<'a, str>>,
|
||||||
|
pub trademark: Option<Cow<'a, str>>,
|
||||||
|
pub asso: Option<Association<'a>>,
|
||||||
|
pub duns: Option<Cow<'a, str>>,
|
||||||
|
pub local: Option<Cow<'a, str>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LegalStatus<'a> {
|
||||||
|
Company,
|
||||||
|
Association,
|
||||||
|
Other(Cow<'a, str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToXml for LegalStatus<'a> {
|
||||||
|
fn serialize<W: core::fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
_field: Option<Id<'_>>,
|
||||||
|
serializer: &mut instant_xml::Serializer<W>,
|
||||||
|
) -> Result<(), instant_xml::Error> {
|
||||||
|
let ncname = "legalStatus";
|
||||||
|
let (s, data) = match self {
|
||||||
|
LegalStatus::Company => ("company", None),
|
||||||
|
LegalStatus::Association => ("association", None),
|
||||||
|
LegalStatus::Other(text) => ("other", Some(&text.as_ref()[2..])),
|
||||||
|
};
|
||||||
|
let prefix = serializer.write_start(ncname, XMLNS)?;
|
||||||
|
debug_assert_eq!(prefix, None);
|
||||||
|
serializer.write_attr("s", XMLNS, s)?;
|
||||||
|
if let Some(text) = data {
|
||||||
|
serializer.end_start()?;
|
||||||
|
text.serialize(None, serializer)?;
|
||||||
|
serializer.write_close(prefix, ncname)?;
|
||||||
|
} else {
|
||||||
|
serializer.end_empty()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains information that permits the identification of associations.
|
||||||
|
#[derive(Debug, ToXml)]
|
||||||
|
#[xml(rename = "asso", ns(XMLNS))]
|
||||||
|
pub struct Association<'a> {
|
||||||
|
/// The Waldec registration number. "Waldec" is the acronym for
|
||||||
|
/// the french "[Web des associations librement
|
||||||
|
/// déclarées](https://www.associations.gouv.fr/le-rna-repertoire-national-des-associations.html)"
|
||||||
|
pub waldec: Option<Cow<'a, str>>,
|
||||||
|
/// Date of declaration to the prefecture
|
||||||
|
#[xml(rename = "decl")]
|
||||||
|
pub declaration: Option<Cow<'a, str>>,
|
||||||
|
/// Information of publication in the official gazette
|
||||||
|
#[xml(rename = "publ")]
|
||||||
|
pub publication: Option<Publication<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Holds information about the publication in the
|
||||||
|
/// official gazette for the association.
|
||||||
|
#[derive(Debug, ToXml)]
|
||||||
|
#[xml(rename = "publ", ns(XMLNS))]
|
||||||
|
pub struct Publication<'a> {
|
||||||
|
/// Page number of the announcement
|
||||||
|
#[xml(attribute)]
|
||||||
|
pub page: u32,
|
||||||
|
#[xml(attribute)]
|
||||||
|
/// Number of the announcement
|
||||||
|
pub announce: u32,
|
||||||
|
/// Date of publication
|
||||||
|
#[xml(direct)]
|
||||||
|
pub date: Cow<'a, str>,
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
//! Mapping for the [frnic-2.0
|
||||||
|
//! extension](https://www.afnic.fr/wp-media/uploads/2022/10/guide_d_integration_technique_EN_FRandoverseasTLD_30_09_VF.pdf)
|
||||||
|
use instant_xml::{FromXml, ToXml};
|
||||||
|
|
||||||
|
pub mod contact;
|
||||||
|
|
||||||
|
pub use contact::ContactCreate;
|
||||||
|
|
||||||
|
pub const XMLNS: &str = "http://www.afnic.fr/xml/epp/frnic-2.0";
|
||||||
|
|
||||||
|
#[derive(Debug, FromXml, ToXml)]
|
||||||
|
#[xml(rename = "ext", ns(XMLNS))]
|
||||||
|
pub struct Ext<T> {
|
||||||
|
pub data: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromXml, ToXml)]
|
||||||
|
#[xml(rename = "create", ns(XMLNS))]
|
||||||
|
pub struct Create<T> {
|
||||||
|
pub data: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::contact::ContactCreate;
|
||||||
|
use crate::contact::{Address, PostalInfo, Voice};
|
||||||
|
use crate::extensions::frnic;
|
||||||
|
use crate::tests::assert_serialized;
|
||||||
|
use frnic::{contact, Ext};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_contact_create_natural_person() {
|
||||||
|
// Technical Integration Guide, page 23.
|
||||||
|
let frnic_contact = Ext::from(frnic::ContactCreate::new_natural_person("Michel"));
|
||||||
|
let object = ContactCreate::new(
|
||||||
|
"XXX000",
|
||||||
|
"test@test.fr",
|
||||||
|
PostalInfo::new(
|
||||||
|
"loc",
|
||||||
|
"Dupont",
|
||||||
|
None,
|
||||||
|
Address::new(
|
||||||
|
&["1 Rue des fleurs"],
|
||||||
|
"Paris",
|
||||||
|
None,
|
||||||
|
Some("75000"),
|
||||||
|
"FR".parse().unwrap(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Some(Voice::new("+33.1234567890")),
|
||||||
|
"Afn-12345678",
|
||||||
|
);
|
||||||
|
assert_serialized(
|
||||||
|
"request/extensions/frnic_create_contact_natural_person.xml",
|
||||||
|
(&object, &frnic_contact),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_contact_create_company() {
|
||||||
|
// Technical Integration Guide, page 27.
|
||||||
|
let frnic_contact = Ext::from(frnic::ContactCreate::new_company(
|
||||||
|
None, None, None, None, None,
|
||||||
|
));
|
||||||
|
let object = ContactCreate::new(
|
||||||
|
"XXXXXXX",
|
||||||
|
"test@test.fr",
|
||||||
|
PostalInfo::new(
|
||||||
|
"loc",
|
||||||
|
"SARL DUPONT",
|
||||||
|
None,
|
||||||
|
Address::new(
|
||||||
|
&["1 Rue des coquelicots"],
|
||||||
|
"Paris",
|
||||||
|
None,
|
||||||
|
Some("75000"),
|
||||||
|
"FR".parse().unwrap(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Some(Voice::new("+33.1234567890")),
|
||||||
|
"Afn-123456",
|
||||||
|
);
|
||||||
|
assert_serialized(
|
||||||
|
"request/extensions/frnic_create_contact_company.xml",
|
||||||
|
(&object, &frnic_contact),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_contact_create_corporation_with_siren() {
|
||||||
|
// Technical Integration Guide, page 28.
|
||||||
|
let frnic_contact = Ext::from(frnic::ContactCreate::new_company(
|
||||||
|
Some("123456789"),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
let object = ContactCreate::new(
|
||||||
|
"XXXX0000",
|
||||||
|
"test@test.fr",
|
||||||
|
PostalInfo::new(
|
||||||
|
"loc",
|
||||||
|
"SARL DUPONT SIREN",
|
||||||
|
None,
|
||||||
|
Address::new(
|
||||||
|
&["1 Rue des Sirenes"],
|
||||||
|
"Paris",
|
||||||
|
None,
|
||||||
|
Some("75000"),
|
||||||
|
"FR".parse().unwrap(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Some(Voice::new("+33.1234567890")),
|
||||||
|
"Afn-123456",
|
||||||
|
);
|
||||||
|
assert_serialized(
|
||||||
|
"request/extensions/frnic_create_contact_siren.xml",
|
||||||
|
(&object, &frnic_contact),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_contact_create_non_profit() {
|
||||||
|
// Technical Integration Guide, page 38.
|
||||||
|
let frnic_contact = Ext::from(frnic::ContactCreate::new_non_profit(
|
||||||
|
None,
|
||||||
|
Some("2011-05-02"),
|
||||||
|
Some(contact::Publication {
|
||||||
|
announce: 123456,
|
||||||
|
page: 15,
|
||||||
|
date: "2011-05-07".into(),
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
let object = ContactCreate::new(
|
||||||
|
"XXXX0000",
|
||||||
|
"test@test.fr",
|
||||||
|
PostalInfo::new(
|
||||||
|
"loc",
|
||||||
|
"Dupont JO",
|
||||||
|
None,
|
||||||
|
Address::new(
|
||||||
|
&["1 Rue des Fleurs"],
|
||||||
|
"Paris",
|
||||||
|
None,
|
||||||
|
Some("75000"),
|
||||||
|
"FR".parse().unwrap(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Some(Voice::new("+33.1234567890")),
|
||||||
|
"Afn-123456",
|
||||||
|
);
|
||||||
|
assert_serialized(
|
||||||
|
"request/extensions/frnic_create_contact_non_profit.xml",
|
||||||
|
(&object, &frnic_contact),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,6 +61,8 @@ pub mod extensions {
|
||||||
|
|
||||||
pub const XMLNS: &str = "urn:ietf:params:xml:ns:rgp-1.0";
|
pub const XMLNS: &str = "urn:ietf:params:xml:ns:rgp-1.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod frnic;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use client::EppClient;
|
pub use client::EppClient;
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?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>XXXXXXX</id>
|
||||||
|
<postalInfo type="loc">
|
||||||
|
<name>SARL DUPONT</name>
|
||||||
|
<addr>
|
||||||
|
<street>1 Rue des coquelicots</street>
|
||||||
|
<city>Paris</city>
|
||||||
|
<pc>75000</pc>
|
||||||
|
<cc>FR</cc>
|
||||||
|
</addr>
|
||||||
|
</postalInfo>
|
||||||
|
<voice>+33.1234567890</voice>
|
||||||
|
<email>test@test.fr</email>
|
||||||
|
<authInfo>
|
||||||
|
<pw>Afn-123456</pw>
|
||||||
|
</authInfo>
|
||||||
|
</create>
|
||||||
|
</create>
|
||||||
|
<extension>
|
||||||
|
<ext xmlns="http://www.afnic.fr/xml/epp/frnic-2.0">
|
||||||
|
<create>
|
||||||
|
<contact>
|
||||||
|
<legalEntityInfos>
|
||||||
|
<legalStatus s="company" />
|
||||||
|
</legalEntityInfos>
|
||||||
|
</contact>
|
||||||
|
</create>
|
||||||
|
</ext>
|
||||||
|
</extension>
|
||||||
|
<clTRID>cltrid:1626454866</clTRID>
|
||||||
|
</command>
|
||||||
|
</epp>
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?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>XXX000</id>
|
||||||
|
<postalInfo type="loc">
|
||||||
|
<name>Dupont</name>
|
||||||
|
<addr>
|
||||||
|
<street>1 Rue des fleurs</street>
|
||||||
|
<city>Paris</city>
|
||||||
|
<pc>75000</pc>
|
||||||
|
<cc>FR</cc>
|
||||||
|
</addr>
|
||||||
|
</postalInfo>
|
||||||
|
<voice>+33.1234567890</voice>
|
||||||
|
<email>test@test.fr</email>
|
||||||
|
<authInfo>
|
||||||
|
<pw>Afn-12345678</pw>
|
||||||
|
</authInfo>
|
||||||
|
</create>
|
||||||
|
</create>
|
||||||
|
<extension>
|
||||||
|
<ext xmlns="http://www.afnic.fr/xml/epp/frnic-2.0">
|
||||||
|
<create>
|
||||||
|
<contact>
|
||||||
|
<firstName>Michel</firstName>
|
||||||
|
</contact>
|
||||||
|
</create>
|
||||||
|
</ext>
|
||||||
|
</extension>
|
||||||
|
<clTRID>cltrid:1626454866</clTRID>
|
||||||
|
</command>
|
||||||
|
</epp>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?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>XXXX0000</id>
|
||||||
|
<postalInfo type="loc">
|
||||||
|
<name>Dupont JO</name>
|
||||||
|
<addr>
|
||||||
|
<street>1 Rue des Fleurs</street>
|
||||||
|
<city>Paris</city>
|
||||||
|
<pc>75000</pc>
|
||||||
|
<cc>FR</cc>
|
||||||
|
</addr>
|
||||||
|
</postalInfo>
|
||||||
|
<voice>+33.1234567890</voice>
|
||||||
|
<email>test@test.fr</email>
|
||||||
|
<authInfo>
|
||||||
|
<pw>Afn-123456</pw>
|
||||||
|
</authInfo>
|
||||||
|
</create>
|
||||||
|
</create>
|
||||||
|
<extension>
|
||||||
|
<ext xmlns="http://www.afnic.fr/xml/epp/frnic-2.0">
|
||||||
|
<create>
|
||||||
|
<contact>
|
||||||
|
<legalEntityInfos>
|
||||||
|
<legalStatus s="association" />
|
||||||
|
<asso>
|
||||||
|
<decl>2011-05-02</decl>
|
||||||
|
<publ page="15" announce="123456">2011-05-07</publ>
|
||||||
|
</asso>
|
||||||
|
</legalEntityInfos>
|
||||||
|
</contact>
|
||||||
|
</create>
|
||||||
|
</ext>
|
||||||
|
</extension>
|
||||||
|
<clTRID>cltrid:1626454866</clTRID>
|
||||||
|
</command>
|
||||||
|
</epp>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?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>XXXX0000</id>
|
||||||
|
<postalInfo type="loc">
|
||||||
|
<name>SARL DUPONT SIREN</name>
|
||||||
|
<addr>
|
||||||
|
<street>1 Rue des Sirenes</street>
|
||||||
|
<city>Paris</city>
|
||||||
|
<pc>75000</pc>
|
||||||
|
<cc>FR</cc>
|
||||||
|
</addr>
|
||||||
|
</postalInfo>
|
||||||
|
<voice>+33.1234567890</voice>
|
||||||
|
<email>test@test.fr</email>
|
||||||
|
<authInfo>
|
||||||
|
<pw>Afn-123456</pw>
|
||||||
|
</authInfo>
|
||||||
|
</create>
|
||||||
|
</create>
|
||||||
|
<extension>
|
||||||
|
<ext xmlns="http://www.afnic.fr/xml/epp/frnic-2.0">
|
||||||
|
<create>
|
||||||
|
<contact>
|
||||||
|
<legalEntityInfos>
|
||||||
|
<legalStatus s="company" />
|
||||||
|
<siren>123456789</siren>
|
||||||
|
</legalEntityInfos>
|
||||||
|
</contact>
|
||||||
|
</create>
|
||||||
|
</ext>
|
||||||
|
</extension>
|
||||||
|
<clTRID>cltrid:1626454866</clTRID>
|
||||||
|
</command>
|
||||||
|
</epp>
|
Loading…
Reference in New Issue