diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 1022bdd..3848171 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -237,6 +237,17 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time 0.3.27", + "version_check", +] + [[package]] name = "cookie" version = "0.17.0" @@ -248,6 +259,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "cookie_store" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa" +dependencies = [ + "cookie 0.16.2", + "idna 0.2.3", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time 0.3.27", + "url", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -828,6 +856,27 @@ dependencies = [ "cc", ] +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.4.0" @@ -984,6 +1033,12 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "md-5" version = "0.10.5" @@ -1366,6 +1421,22 @@ dependencies = [ "yansi 1.0.0-rc.1", ] +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +dependencies = [ + "idna 0.3.0", + "psl-types", +] + [[package]] name = "quote" version = "1.0.33" @@ -1486,6 +1557,8 @@ checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "base64", "bytes", + "cookie 0.16.2", + "cookie_store", "encoding_rs", "futures-core", "futures-util", @@ -1615,7 +1688,7 @@ version = "0.5.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "936012c99162a03a67f37f9836d5f938f662e26f2717809761a9ac46432090f4" dependencies = [ - "cookie", + "cookie 0.17.0", "either", "futures", "http", @@ -2552,7 +2625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", - "idna", + "idna 0.4.0", "percent-encoding", ] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index ba7169a..931aa50 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -reqwest = { version = "0.11", features = ["json"] } +reqwest = { version = "0.11", features = ["json", "cookies"] } rocket = { version = "=0.5.0-rc.3" , features = ["json", "msgpack", "uuid"] } sqlx = { version = "0.7.1", features = [ "runtime-tokio", "tls-rustls", "mysql", "macros", "chrono" ] } once_cell = "1.18.0" diff --git a/backend/src/main.rs b/backend/src/main.rs index 570249d..73af7c3 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -50,6 +50,10 @@ async fn rocket() -> _ { controller::register::get_by_dni, controller::register::delete, controller::custom_label::get_all, + // + // Online classroom routes + // + online_classroom::connection, ], ) } diff --git a/backend/src/online_classroom/mod.rs b/backend/src/online_classroom/mod.rs index 61bc0dd..0d84ef0 100644 --- a/backend/src/online_classroom/mod.rs +++ b/backend/src/online_classroom/mod.rs @@ -1,6 +1,85 @@ +use once_cell::sync::OnceCell; -pub fn get_cookie() { +use reqwest::Client; +use rocket::{http::Status, serde::json::Json}; +use serde::{Deserialize, Serialize}; +static SESSION_COOKIE: OnceCell = OnceCell::new(); + +#[derive(Debug, Serialize, Deserialize)] +pub enum ConnectionResult { + Ok(), + Error(ConnectionError), +} +#[derive(Debug, Serialize, Deserialize)] +pub struct ConnectionError { + reason: String, +} +fn new_error(reason: String) -> ConnectionResult { + ConnectionResult::Error(ConnectionError { reason }) } +/// 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()), + } + } + } +} + +/// 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/frontend/src/OnlineClassroom/ConnectionStatus.tsx b/frontend/src/OnlineClassroom/ConnectionStatus.tsx new file mode 100644 index 0000000..6cc2114 --- /dev/null +++ b/frontend/src/OnlineClassroom/ConnectionStatus.tsx @@ -0,0 +1,58 @@ +import { Match, Switch, createSignal, onMount } from "solid-js"; + +type ConnectionStatus = "connected" | "connecting" | "disconnected" | "error"; +export function ClassroomConection() { + const [status, setStatus] = createSignal("disconnected"); + + const connectToRemote = () => { + setStatus("connecting"); + + fetch(`${import.meta.env.VITE_BACKEND_URL}/api/classroom/connect`) + .then((response) => { + if (response.ok) { + setStatus("connected"); + } else { + response.json().then((json) => { + console.error(json); + setStatus("error"); + }); + } + }) + .catch((err) => { + console.error(err); + setStatus("error"); + }); + + // setTimeout(() => setStatus("disconnected"), 5000); + }; + + onMount(connectToRemote); + + return ( +
+ Conexión al aula virtual:  + + + + Conectado + + + + + Conectando... + + + + + Error + + + + + Desconectado + + + +
+ ); +} diff --git a/frontend/src/OnlineClassroom/index.tsx b/frontend/src/OnlineClassroom/index.tsx index b12cc9f..442f3a1 100644 --- a/frontend/src/OnlineClassroom/index.tsx +++ b/frontend/src/OnlineClassroom/index.tsx @@ -1,6 +1,7 @@ import { Show, createSignal } from "solid-js"; import { Search } from "../certs/Search"; import { Person } from "../types/Person"; +import { ClassroomConection } from "./ConnectionStatus"; export function OnlineClassroom() { const [person, setPerson] = createSignal(null); @@ -18,13 +19,7 @@ export function OnlineClassroom() { ); } -function ClassroomConection() { - return ( -
- Connection status -
- ); -} + function ClassroomUsers(props: {person: Person}) { return ( diff --git a/frontend/src/colors.css b/frontend/src/colors.css index 7d0627f..f2eeb04 100644 --- a/frontend/src/colors.css +++ b/frontend/src/colors.css @@ -17,6 +17,9 @@ --c-green-outline: #8d9387; --c-green-surface-variant: #43483f; --c-green-on-surface-variant: #c3c8bc; + + --c-green-success: #adc6ff; + --c-green-on-success: #002e69; } @media (prefers-color-scheme: light) { :root {