instant_epp/
login.rs

1use std::fmt::Debug;
2
3use instant_xml::ToXml;
4
5use crate::{
6    common::{NoExtension, Options, ServiceExtension, Services, EPP_XMLNS},
7    contact, domain, host,
8    request::{Command, Transaction, EPP_LANG, EPP_VERSION},
9};
10
11impl<'a> Transaction<NoExtension> for Login<'a> {}
12
13/// Type corresponding to the `<login>` tag in an EPP XML login request
14#[derive(Debug, Eq, PartialEq, ToXml)]
15#[xml(rename = "login", ns(EPP_XMLNS))]
16pub struct Login<'a> {
17    /// The username to use for the login
18    #[xml(rename = "clID")]
19    username: &'a str,
20    /// The password to use for the login
21    #[xml(rename = "pw")]
22    password: &'a str,
23    /// A new password which should be set
24    #[xml(rename = "newPW")]
25    new_password: Option<&'a str>,
26    /// Data under the `<options>` tag
27    options: Options<'a>,
28    /// Data under the `<svcs>` tag
29    #[xml(rename = "svcs")]
30    services: Services<'a>,
31}
32
33impl<'a> Login<'a> {
34    pub fn new(
35        username: &'a str,
36        password: &'a str,
37        new_password: Option<&'a str>,
38        ext_uris: Option<&'_ [&'a str]>,
39    ) -> Self {
40        Self {
41            username,
42            password,
43            new_password,
44            options: Options {
45                version: EPP_VERSION.into(),
46                lang: EPP_LANG.into(),
47            },
48            services: Services {
49                obj_uris: vec![
50                    host::XMLNS.into(),
51                    contact::XMLNS.into(),
52                    domain::XMLNS.into(),
53                ],
54                svc_ext: ext_uris.and_then(|uris| {
55                    (!uris.is_empty()).then(|| ServiceExtension {
56                        ext_uris: uris.iter().map(|&u| u.into()).collect(),
57                    })
58                }),
59            },
60        }
61    }
62
63    /// Sets the `<options>` tag data
64    pub fn options(&mut self, options: Options<'a>) {
65        self.options = options;
66    }
67
68    /// Sets the `<svcs>` tag data
69    pub fn services(&mut self, services: Services<'a>) {
70        self.services = services;
71    }
72}
73
74impl<'a> Command for Login<'a> {
75    type Response = ();
76    const COMMAND: &'static str = "login";
77}
78
79#[cfg(test)]
80mod tests {
81    use super::Login;
82    use crate::response::ResultCode;
83    use crate::tests::{assert_serialized, response_from_file, CLTRID, SUCCESS_MSG, SVTRID};
84
85    #[test]
86    fn command() {
87        let ext_uris = Some(&["http://schema.ispapi.net/epp/xml/keyvalue-1.0"][..]);
88        let object = Login::new("username", "password", Some("new-password"), ext_uris);
89        assert_serialized("request/login.xml", &object);
90    }
91
92    #[test]
93    fn command_no_extension() {
94        let object = Login::new("username", "password", None, None);
95        assert_serialized("request/login_no_extension.xml", &object);
96        let object = Login::new("username", "password", None, Some(&[]));
97        assert_serialized("request/login_no_extension.xml", &object);
98    }
99
100    #[test]
101    fn response() {
102        let object = response_from_file::<Login>("response/login.xml");
103        assert_eq!(object.result.code, ResultCode::CommandCompletedSuccessfully);
104        assert_eq!(object.result.message, SUCCESS_MSG);
105        assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID);
106        assert_eq!(object.tr_ids.server_tr_id, SVTRID);
107    }
108}