Skip to main content

epp_client/domain/
info.rs

1//! Types for EPP domain info request
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use super::{DomainAuthInfo, DomainContact, HostAttr, XMLNS};
7use crate::common::{NoExtension, ObjectStatus, StringValue};
8use crate::request::{Command, Transaction};
9
10impl<'a> Transaction<NoExtension> for DomainInfo<'a> {}
11
12impl<'a> Command for DomainInfo<'a> {
13    type Response = DomainInfoResponse;
14    const COMMAND: &'static str = "info";
15}
16
17impl<'a> DomainInfo<'a> {
18    pub fn new(name: &'a str, auth_password: Option<&'a str>) -> Self {
19        Self {
20            info: DomainInfoRequestData {
21                xmlns: XMLNS,
22                domain: Domain { hosts: "all", name },
23                auth_info: auth_password.map(|password| DomainAuthInfo {
24                    password: password.into(),
25                }),
26            },
27        }
28    }
29}
30
31// Request
32
33/// Type for data under the &lt;name&gt; element tag for the domain &lt;info&gt; tag
34#[derive(Serialize, Debug)]
35pub struct Domain<'a> {
36    /// The hosts attribute. Default value is "all"
37    hosts: &'a str,
38    /// The name of the domain
39    #[serde(rename = "$value")]
40    name: &'a str,
41}
42
43/// Type for &lt;name&gt; element under the domain &lt;info&gt; tag
44#[derive(Serialize, Debug)]
45pub struct DomainInfoRequestData<'a> {
46    /// XML namespace for domain commands
47    #[serde(rename = "xmlns:domain")]
48    xmlns: &'a str,
49    /// The data for the domain to be queried
50    #[serde(rename = "domain:name")]
51    domain: Domain<'a>,
52    /// The auth info for the domain
53    #[serde(rename = "domain:authInfo")]
54    auth_info: Option<DomainAuthInfo<'a>>,
55}
56
57#[derive(Serialize, Debug)]
58/// Type for EPP XML &lt;info&gt; command for domains
59pub struct DomainInfo<'a> {
60    /// The data under the &lt;info&gt; tag for domain info
61    #[serde(rename = "domain:info")]
62    info: DomainInfoRequestData<'a>,
63}
64
65// Response
66
67/// The two types of ns lists, hostObj and hostAttr, that may be returned in the
68/// domain info response
69#[derive(Deserialize, Debug)]
70pub struct DomainNsList {
71    /// List of &lt;hostObj&gt; ns elements
72    #[serde(rename = "hostObj")]
73    pub host_obj: Option<Vec<StringValue<'static>>>,
74    /// List of &lt;hostAttr&gt; ns elements
75    pub host_attr: Option<Vec<HostAttr<'static>>>,
76}
77
78/// Type that represents the &lt;infData&gt; tag for domain info response
79#[derive(Deserialize, Debug)]
80pub struct DomainInfoResponseData {
81    /// The domain name
82    pub name: StringValue<'static>,
83    /// The domain ROID
84    pub roid: StringValue<'static>,
85    /// The list of domain statuses
86    #[serde(rename = "status")]
87    pub statuses: Option<Vec<ObjectStatus<'static>>>,
88    /// The domain registrant
89    pub registrant: Option<StringValue<'static>>,
90    /// The list of domain contacts
91    #[serde(rename = "contact")]
92    pub contacts: Option<Vec<DomainContact<'static>>>,
93    /// The list of domain nameservers
94    #[serde(rename = "ns")]
95    pub ns: Option<DomainNsList>,
96    /// The list of domain hosts
97    #[serde(rename = "host")]
98    pub hosts: Option<Vec<StringValue<'static>>>,
99    /// The epp user who owns the domain
100    #[serde(rename = "clID")]
101    pub client_id: StringValue<'static>,
102    /// The epp user who created the domain
103    #[serde(rename = "crID")]
104    pub creator_id: Option<StringValue<'static>>,
105    /// The domain creation date
106    #[serde(rename = "crDate")]
107    pub created_at: Option<DateTime<Utc>>,
108    /// The domain expiry date
109    #[serde(rename = "exDate")]
110    pub expiring_at: Option<DateTime<Utc>>,
111    /// The epp user who last updated the domain
112    #[serde(rename = "upID")]
113    pub updater_id: Option<StringValue<'static>>,
114    /// The domain last updated date
115    #[serde(rename = "upDate")]
116    pub updated_at: Option<DateTime<Utc>>,
117    /// The domain transfer date
118    #[serde(rename = "trDate")]
119    pub transferred_at: Option<DateTime<Utc>>,
120    /// The domain auth info
121    #[serde(rename = "authInfo")]
122    pub auth_info: Option<DomainAuthInfo<'static>>,
123}
124
125/// Type that represents the &lt;resData&gt; tag for domain info response
126#[derive(Deserialize, Debug)]
127pub struct DomainInfoResponse {
128    /// Data under the &lt;resData&gt; tag
129    #[serde(rename = "infData")]
130    pub info_data: DomainInfoResponseData,
131}
132
133#[cfg(test)]
134mod tests {
135    use super::DomainInfo;
136    use crate::response::ResultCode;
137    use crate::tests::{assert_serialized, response_from_file, CLTRID, SUCCESS_MSG, SVTRID};
138    use chrono::{TimeZone, Utc};
139
140    #[test]
141    fn command() {
142        let object = DomainInfo::new("eppdev.com", Some("2fooBAR"));
143        assert_serialized("request/domain/info.xml", &object);
144    }
145
146    #[test]
147    fn response() {
148        let object = response_from_file::<DomainInfo>("response/domain/info.xml");
149
150        let result = object.res_data().unwrap();
151        let auth_info = result.info_data.auth_info.as_ref().unwrap();
152        let ns_list = result.info_data.ns.as_ref().unwrap();
153        let ns = ns_list.host_obj.as_ref().unwrap();
154        let hosts = result.info_data.hosts.as_ref().unwrap();
155        let statuses = result.info_data.statuses.as_ref().unwrap();
156        let registrant = result.info_data.registrant.as_ref().unwrap();
157        let contacts = result.info_data.contacts.as_ref().unwrap();
158
159        assert_eq!(object.result.code, ResultCode::CommandCompletedSuccessfully);
160        assert_eq!(object.result.message, SUCCESS_MSG.into());
161        assert_eq!(result.info_data.name, "eppdev-1.com".into());
162        assert_eq!(result.info_data.roid, "125899511_DOMAIN_COM-VRSN".into());
163        assert_eq!(statuses[0].status, "ok".to_string());
164        assert_eq!(statuses[1].status, "clientTransferProhibited".to_string());
165        assert_eq!(*registrant, "eppdev-contact-2".into());
166        assert_eq!(contacts[0].id, "eppdev-contact-2".to_string());
167        assert_eq!(contacts[0].contact_type, "admin".to_string());
168        assert_eq!(contacts[1].id, "eppdev-contact-2".to_string());
169        assert_eq!(contacts[1].contact_type, "tech".to_string());
170        assert_eq!(contacts[2].id, "eppdev-contact-2".to_string());
171        assert_eq!(contacts[2].contact_type, "billing".to_string());
172        assert_eq!((*ns)[0], "ns1.eppdev-1.com".into());
173        assert_eq!((*ns)[1], "ns2.eppdev-1.com".into());
174        assert_eq!((*hosts)[0], "ns1.eppdev-1.com".into());
175        assert_eq!((*hosts)[1], "ns2.eppdev-1.com".into());
176        assert_eq!(result.info_data.client_id, "eppdev".into());
177        assert_eq!(
178            *result.info_data.creator_id.as_ref().unwrap(),
179            "SYSTEM".into()
180        );
181        assert_eq!(
182            *result.info_data.created_at.as_ref().unwrap(),
183            Utc.with_ymd_and_hms(2021, 7, 23, 15, 31, 20).unwrap()
184        );
185        assert_eq!(
186            *result.info_data.updater_id.as_ref().unwrap(),
187            "SYSTEM".into()
188        );
189        assert_eq!(
190            *result.info_data.updated_at.as_ref().unwrap(),
191            Utc.with_ymd_and_hms(2021, 7, 23, 15, 31, 21).unwrap()
192        );
193        assert_eq!(
194            *result.info_data.expiring_at.as_ref().unwrap(),
195            Utc.with_ymd_and_hms(2023, 7, 23, 15, 31, 20).unwrap()
196        );
197        assert_eq!(auth_info.password, "epP4uthd#v".into());
198        assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
199        assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
200    }
201
202    #[test]
203    fn response_alt() {
204        response_from_file::<DomainInfo>("response/domain/info_alt.xml");
205    }
206}