1use std::fmt::Debug;
2
3use serde::Serialize;
4
5use crate::{
6 common::{NoExtension, Options, ServiceExtension, Services, StringValue},
7 contact, domain, host,
8 request::{Command, Transaction, EPP_LANG, EPP_VERSION},
9};
10
11impl<'a> Transaction<NoExtension> for Login<'a> {}
12
13#[derive(Serialize, Debug, Eq, PartialEq)]
14pub struct Login<'a> {
16 #[serde(rename(serialize = "clID", deserialize = "clID"))]
18 username: StringValue<'a>,
19 #[serde(rename = "pw", default)]
21 password: StringValue<'a>,
22 #[serde(rename = "newPW", default, skip_serializing_if = "Option::is_none")]
24 new_password: Option<StringValue<'a>>,
25 options: Options<'a>,
27 #[serde(rename = "svcs")]
29 services: Services<'a>,
30}
31
32impl<'a> Login<'a> {
33 pub fn new(
34 username: &'a str,
35 password: &'a str,
36 new_password: Option<&'a str>,
37 ext_uris: Option<&'_ [&'a str]>,
38 ) -> Self {
39 let svc_ext = match ext_uris {
40 Some(uris) if !uris.is_empty() => Some(ServiceExtension {
41 ext_uris: Some(uris.iter().map(|&u| u.into()).collect()),
42 }),
43 _ => None,
44 };
45
46 Self {
47 username: username.into(),
48 password: password.into(),
49 new_password: new_password.map(Into::into),
50 options: Options {
51 version: EPP_VERSION.into(),
52 lang: EPP_LANG.into(),
53 },
54 services: Services {
55 obj_uris: vec![
56 host::XMLNS.into(),
57 contact::XMLNS.into(),
58 domain::XMLNS.into(),
59 ],
60 svc_ext,
61 },
62 }
63 }
64
65 pub fn options(&mut self, options: Options<'a>) {
67 self.options = options;
68 }
69
70 pub fn services(&mut self, services: Services<'a>) {
72 self.services = services;
73 }
74}
75
76impl<'a> Command for Login<'a> {
77 type Response = ();
78 const COMMAND: &'static str = "login";
79}
80
81#[cfg(test)]
82mod tests {
83 use super::Login;
84 use crate::response::ResultCode;
85 use crate::tests::{assert_serialized, response_from_file, CLTRID, SUCCESS_MSG, SVTRID};
86
87 #[test]
88 fn command() {
89 let ext_uris = Some(&["http://schema.ispapi.net/epp/xml/keyvalue-1.0"][..]);
90 let object = Login::new("username", "password", Some("new-password"), ext_uris);
91 assert_serialized("request/login.xml", &object);
92 }
93
94 #[test]
95 fn command_no_extension() {
96 let object = Login::new("username", "password", Some("new-password"), None);
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.into());
105 assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
106 assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
107 }
108}