ucas_iclass/
login.rs

1//! Login related logic.
2
3use super::{IClass, IClassError, Response};
4use serde::{Deserialize, Serialize};
5use std::{
6    fs::File,
7    io::{BufReader, BufWriter, Error as IoError, Write},
8    path::Path,
9};
10
11impl IClass {
12    /// Logs in to the iClass platform.
13    ///
14    /// # Errors
15    ///
16    /// See [`IClassError`].
17    pub async fn login(&mut self, username: &str, password: &str) -> Result<(), IClassError> {
18        // /app/user/login.action
19        let url = self.api_root.join("app/user/login.action")?;
20        let response: Response<UserSessionInfo> = self
21            .client
22            .post(url)?
23            .form(&[("phone", username), ("password", password)])?
24            .send()
25            .await?
26            .json()
27            .await?;
28        let login_result = response.into_result()?;
29        self.user_session.replace(login_result);
30
31        Ok(())
32    }
33
34    /// Restores user session from given file.
35    ///
36    /// # Errors
37    ///
38    /// IO errors during file operations.
39    pub fn restore_session_from_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), IoError> {
40        let session_info = UserSessionInfo::load_from_file(path)?;
41        self.user_session.replace(session_info);
42        Ok(())
43    }
44
45    /// Saves user session to given file, if any. Returns whether a session existed.
46    ///
47    /// # Errors
48    ///
49    /// IO errors during file operations.
50    pub fn save_session_to_file<P: AsRef<Path>>(&self, path: P) -> Result<bool, IoError> {
51        let exists = if let Some(session_info) = &self.user_session {
52            session_info.save_to_file(path)?;
53            true
54        } else {
55            false
56        };
57        Ok(exists)
58    }
59}
60
61/// User session information returned after login.
62#[derive(Clone, Debug, Serialize, Deserialize)]
63#[serde(rename_all = "camelCase")]
64pub struct UserSessionInfo {
65    /// ID of the user.
66    pub id: String,
67    /// Session ID.
68    pub session_id: String,
69    /// Real name.
70    pub real_name: String,
71    /// Student number.
72    pub student_no: String,
73}
74
75impl UserSessionInfo {
76    /// Saves the information to a file.
77    ///
78    /// # Errors
79    ///
80    /// [IO errors](IoError) during file operations.
81    pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), IoError> {
82        let file = File::create(path)?;
83        let mut writer = BufWriter::new(file);
84        serde_json::to_writer_pretty(&mut writer, self)?;
85        writer.flush()?;
86        Ok(())
87    }
88
89    /// Loads the information from a file.
90    ///
91    /// # Errors
92    ///
93    /// [IO errors](IoError) during file operations.
94    pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, IoError> {
95        let file = File::open(path)?;
96        let reader = BufReader::new(file);
97        let session_info = serde_json::from_reader(reader)?;
98        Ok(session_info)
99    }
100}