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#[derive(Debug, Eq, PartialEq, ToXml)]
15#[xml(rename = "login", ns(EPP_XMLNS))]
16pub struct Login<'a> {
17 #[xml(rename = "clID")]
19 username: &'a str,
20 #[xml(rename = "pw")]
22 password: &'a str,
23 #[xml(rename = "newPW")]
25 new_password: Option<&'a str>,
26 options: Options<'a>,
28 #[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 pub fn options(&mut self, options: Options<'a>) {
65 self.options = options;
66 }
67
68 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}