1use crate::api::types::Config;
4use crate::api::errors;
5use reqwest;
6use crate::api::json::{MelcloudLoginResponse};
7use crate::api::types::devices::Devices;
8
9
10#[derive(Debug)]
11pub struct Session {
12 pub config: Config,
13 pub api_key: String
14}
15
16impl Session {
17 pub fn start(config: Config) -> Result<Session, errors::ApiError> {
19 let request_url = format!("{api_base}/Login/ClientLogin", api_base = &config.api_url);
20 let post_body = format!("{{\"Email\":\"{email}\",\"Password\":\"{password}\",\"Language\":0,\"AppVersion\":\"1.18.5.1\",\"Persist\":true,\"CaptchaResponse\":null}}", email = config.api_username, password = config.api_password);
21 let result = reqwest::Client::new()
22 .post(&request_url)
23 .body(post_body)
24 .header("Accept", "application/json")
25 .header("Content-Type", "application/json")
26 .send();
27 match result {
28 Ok(mut resp) => {
29 match resp.json() {
30 Ok(json) => Session::parse_new_session_response(config, json),
31 Err(err) => {
32 println!("Err is {:?}", err);
33 Err(errors::ApiError::InvalidLoginResponse)
34 }
35 }
36 },
37 Err(err) => Err(errors::ApiError::LoginFailure)
38 }
39 }
40
41 pub fn devices(&self) -> Devices {
42 Devices::new(self)
43 }
44
45 fn parse_new_session_response(config: Config, message: MelcloudLoginResponse) -> Result<Session, errors::ApiError> {
46 match message {
47 MelcloudLoginResponse::Success {login_data} => {
48 Ok(Session {
49 config: config,
50 api_key: login_data.context_key
51 })
52 },
53 MelcloudLoginResponse::AccessDenied {error_id} => {
54 Err(errors::ApiError::LoginFailure)
55 }
56 }
57 }
58
59}
60
61#[cfg(test)]
62mod tests {
63 use mockito::{mock, Matcher};
64 use crate::api::types::Config;
65 use crate::api::types::Session;
66 use crate::api::errors;
67
68 #[test]
69 fn test_start_session() {
70 let config = Config::new(&mockito::server_url(), "testuser", "testpassword");
72 let m = mock("POST", "/Login/ClientLogin")
73 .with_status(200)
74 .with_body("{\"ErrorId\":null,\"ErrorMessage\":null,\"LoginStatus\":0,\"UserId\":0,\"RandomKey\":null,\"AppVersionAnnouncement\":null,\"LoginData\":{\"ContextKey\":\"C71933C57FB04358B6750ED77D79AA\",\"Client\":128538,\"Terms\":1199,\"AL\":1,\"ML\":0,\"CMI\":true,\"IsStaff\":false,\"CUTF\":false,\"CAA\":false,\"ReceiveCountryNotifications\":false,\"ReceiveAllNotifications\":false,\"CACA\":false,\"CAGA\":false,\"MaximumDevices\":10,\"ShowDiagnostics\":false,\"Language\":0,\"Country\":237,\"RealClient\":0,\"Name\":\"Gary Taylor\",\"UseFahrenheit\":false,\"Duration\":525600,\"Expiry\":\"2020-10-14T13:54:42.653\",\"CMSC\":false,\"PartnerApplicationVersion\":null,\"EmailSettingsReminderShown\":true,\"EmailUnitErrors\":1,\"EmailCommsErrors\":1,\"IsImpersonated\":false,\"LanguageCode\":\"en\",\"CountryName\":\"United Kingdom\",\"CurrencySymbol\":\"£\",\"SupportEmailAddress\":\"melcloud.support@meuk.mee.com \",\"DateSeperator\":\"/\",\"TimeSeperator\":\":\",\"AtwLogoFile\":\"ecodan_logo.png\",\"DECCReport\":true,\"CSVReport1min\":true,\"HidePresetPanel\":false,\"EmailSettingsReminderRequired\":false,\"TermsText\":null,\"MapView\":false,\"MapZoom\":0,\"MapLongitude\":-133.082129213169600,\"MapLatitude\":52.621242998717900},\"ListPendingInvite\":[],\"ListOwnershipChangeRequest\":[],\"ListPendingAnnouncement\":[],\"LoginMinutes\":0,\"LoginAttempts\":0}")
75 .create();
76
77 let result = Session::start(config);
79
80 m.assert();
82 match result {
83 Ok(session) => assert!(session.api_key == "C71933C57FB04358B6750ED77D79AA", "The api key was wrong"),
84 Err(err) => assert!(false, "Something went wrong"),
85 }
86 }
87
88 #[test]
89 fn test_start_session_wrong_credentials() {
90 let config = Config::new(&mockito::server_url(), "testuser", "testpassword");
92 let m = mock("POST", "/Login/ClientLogin")
93 .with_status(200)
94 .with_body("{\"ErrorId\":1,\"ErrorMessage\":null,\"LoginStatus\":0,\"UserId\":0,\"RandomKey\":null,\"AppVersionAnnouncement\":null,\"LoginData\":null,\"ListPendingInvite\":null,\"ListOwnershipChangeRequest\":null,\"ListPendingAnnouncement\":null,\"LoginMinutes\":0,\"LoginAttempts\":1}")
95 .create();
96
97 let result = Session::start(config);
99
100 m.assert();
102 match result {
103 Ok(session) => assert!(false, "Must return an error"),
104 Err(errors::ApiError::LoginFailure) => assert!(true),
105 Err(_) => assert!(false, "Must return a Login Failure")
106 }
107 }
108}