diff --git a/backend/src/online_classroom/json_result.rs b/backend/src/online_classroom/json_result.rs
new file mode 100644
index 0000000..f19e7f5
--- /dev/null
+++ b/backend/src/online_classroom/json_result.rs
@@ -0,0 +1,23 @@
+use rocket::serde::json::Json;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize)]
+pub enum JsonResult {
+ Ok(A),
+ Error(JsonError),
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct JsonError {
+ reason: String,
+}
+
+impl JsonResult {
+ pub fn error(reason: String) -> Json> {
+ Json(JsonResult::Error(JsonError { reason }))
+ }
+
+ pub fn ok(data: A) -> Json> {
+ Json(JsonResult::Ok(data))
+ }
+}
diff --git a/backend/src/online_classroom/mod.rs b/backend/src/online_classroom/mod.rs
index 0d84ef0..0ff190c 100644
--- a/backend/src/online_classroom/mod.rs
+++ b/backend/src/online_classroom/mod.rs
@@ -4,7 +4,13 @@ use reqwest::Client;
use rocket::{http::Status, serde::json::Json};
use serde::{Deserialize, Serialize};
-static SESSION_COOKIE: OnceCell = OnceCell::new();
+use self::session::ensure_session;
+
+pub mod json_result;
+mod session;
+pub mod users;
+
+
#[derive(Debug, Serialize, Deserialize)]
pub enum ConnectionResult {
@@ -22,64 +28,10 @@ fn new_error(reason: String) -> ConnectionResult {
/// Tries to connect to the online classroom, and get a session cookie
#[get("/classroom/connect")]
pub async fn connection() -> (Status, Json) {
- // Get session cookie
- let _cookie = match get_cookie().await {
- Ok(cookie) => cookie,
- Err(reason) => return (Status::InternalServerError, Json(new_error(reason))),
- };
-
- (Status::Ok, Json(ConnectionResult::Ok()))
-}
-
-async fn get_cookie<'a>() -> Result<&'a String, String> {
- match SESSION_COOKIE.get() {
- Some(cookie) => Ok(cookie),
- None => {
- // Try to create cookie
- let _ = create_cookie().await?;
-
- // Try to get cookie again
- match SESSION_COOKIE.get() {
- Some(cookie) => Ok(cookie),
- None => Err("Error getting session cookie".into()),
- }
- }
+ match ensure_session().await {
+ Ok(_) => (Status::Ok, Json(ConnectionResult::Ok())),
+ Err(err) => (Status::Ok, Json(new_error(err))),
}
}
-/// Tries to connect to the online classroom, and get a session cookie.
-/// Stores the session coookie in a global static variable.
-pub async fn create_cookie() -> Result<(), String> {
- let clasroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
- let clasroom_user =
- std::env::var("CLASSROOM_USER").expect("CLASSROOM_USER env var is not set!");
- let clasroom_password =
- std::env::var("CLASSROOM_PASSWORD").expect("CLASSROOM_PASSWORD env var is not set!");
- let params = [
- ("login", clasroom_user),
- ("password", clasroom_password),
- ("submitAuth", "".into()),
- ("_qf__formLogin", "".into()),
- ];
- let client = Client::new();
- let result = client
- .post(format!("{}/index.php", clasroom_url))
- .form(¶ms)
- .send()
- .await;
-
- match result {
- Ok(response) => {
- let Some(session_cookie) = response.cookies().find(|c| c.name() == "ch_sid") else {
- return Err("Response succeeded, but no session cookie was foun".into());
- };
-
- match SESSION_COOKIE.set(session_cookie.value().into()) {
- Ok(_) => Ok(()),
- Err(error) => Err(format!("Error setting session cookie: {:?}", error)),
- }
- }
- Err(error) => Err(format!("Error connecting to online classroom: {:?}", error)),
- }
-}
diff --git a/backend/src/online_classroom/session.rs b/backend/src/online_classroom/session.rs
new file mode 100644
index 0000000..d2af07f
--- /dev/null
+++ b/backend/src/online_classroom/session.rs
@@ -0,0 +1,75 @@
+use std::time::{SystemTime, UNIX_EPOCH};
+
+use once_cell::sync::OnceCell;
+use reqwest::Client;
+
+static SESSION_COOKIE: OnceCell = OnceCell::new();
+static SESSION_TIME: OnceCell = OnceCell::new();
+
+/// Makes a request to the online classroom, and returns the html string
+pub async fn request(url: String) -> Result {
+ todo!()
+}
+
+
+/// Makes sure that the session cookie is set, and that it is valid
+pub async fn ensure_session() -> Result<(), String> {
+ let last_usage_time = match SESSION_TIME.get() {
+ Some(time) => *time,
+ None => 0,
+ };
+
+ // Get current time in seconds
+ let current_time = SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .expect("Time went backwards")
+ .as_secs();
+
+ let time_passed = current_time - last_usage_time;
+
+ // Default PHP session timeout is 1440 seconds. Use a 1400 seconds timeout to be safe
+ if time_passed > 1400 {
+ login().await?;
+ if let Err(err) = SESSION_TIME.set(current_time) {
+ return Err(format!("Error setting session time: {:?}", err));
+ }
+ }
+
+ Ok(())
+}
+
+/// Logins to the online classroom, and sets the session cookie
+async fn login() -> Result<(), String> {
+ let clasroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
+ let clasroom_user =
+ std::env::var("CLASSROOM_USER").expect("CLASSROOM_USER env var is not set!");
+ let clasroom_password =
+ std::env::var("CLASSROOM_PASSWORD").expect("CLASSROOM_PASSWORD env var is not set!");
+
+ let params = [
+ ("login", clasroom_user),
+ ("password", clasroom_password),
+ ("submitAuth", "".into()),
+ ("_qf__formLogin", "".into()),
+ ];
+ let client = Client::new();
+ let result = client
+ .post(format!("{}/index.php", clasroom_url))
+ .form(¶ms)
+ .send()
+ .await;
+
+ match result {
+ Ok(response) => {
+ let Some(session_cookie) = response.cookies().find(|c| c.name() == "ch_sid") else {
+ return Err("Response succeeded, but no session cookie was foun".into());
+ };
+
+ match SESSION_COOKIE.set(session_cookie.value().into()) {
+ Ok(_) => Ok(()),
+ Err(error) => Err(format!("Error setting session cookie: {:?}", error)),
+ }
+ }
+ Err(error) => Err(format!("Error connecting to online classroom: {:?}", error)),
+ }
+}
diff --git a/backend/src/online_classroom/users.rs b/backend/src/online_classroom/users.rs
new file mode 100644
index 0000000..26167ff
--- /dev/null
+++ b/backend/src/online_classroom/users.rs
@@ -0,0 +1,15 @@
+use rocket::{http::Status, serde::json::Json};
+
+use super::{ json_result::JsonResult};
+
+// Instead of requesting pages and managing session & cookies manually,
+// create a wrapper that:
+// - Checks if the session cookie is valid
+// - If not, tries to login
+// - Makes the request
+// - Returns the html string, or an error
+
+#[get("/classroom/users/")]
+pub async fn get_users(full_name: String) -> (Status, Json>) {
+ (Status::Ok, JsonResult::ok(()))
+}