From 99be91941a2a96a11c4f1336edc341a7fffc56a1 Mon Sep 17 00:00:00 2001 From: Mariano Riefolo Date: Tue, 3 Sep 2024 16:36:44 +0200 Subject: [PATCH] feat(frontend): add main page with both html and javascript --- Cargo.lock | 145 +++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/frontend/mod.rs | 23 ++++++ src/main.rs | 5 +- static/index.js | 175 +++++++++++++++++++++++++++++++++++++++++++ templates/index.html | 70 +++++++++++++++++ 6 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 src/frontend/mod.rs create mode 100644 static/index.js create mode 100644 templates/index.html diff --git a/Cargo.lock b/Cargo.lock index c70ddc0..ebb6513 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,6 +30,50 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", + "humansize", + "num-traits", + "percent-encoding", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.76", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "async-trait" version = "0.1.81" @@ -129,6 +173,15 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -582,6 +635,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" + [[package]] name = "httparse" version = "1.9.4" @@ -594,6 +653,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" version = "1.4.1" @@ -715,6 +783,12 @@ version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -775,6 +849,22 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -819,6 +909,25 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.4" @@ -882,6 +991,7 @@ dependencies = [ name = "orario-scolastico-itet" version = "0.1.0" dependencies = [ + "askama", "axum", "csv", "failure", @@ -892,6 +1002,7 @@ dependencies = [ "serde_json", "sha1", "tokio", + "tower-http", ] [[package]] @@ -1679,6 +1790,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1723,6 +1859,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index c157f05..ceed4c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +askama = "0.12.1" axum = "0.7.5" csv = "1.3.0" failure = "0.1.8" @@ -14,3 +15,4 @@ serde = { version = "1.0.209", features = ["derive"] } serde_json = "1.0.127" sha1 = "0.10.6" tokio = { version = "1.40.0", features = ["full"] } +tower-http = { version = "0.5.2", features = ["fs"] } diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs new file mode 100644 index 0000000..6f9ab56 --- /dev/null +++ b/src/frontend/mod.rs @@ -0,0 +1,23 @@ +use askama::Template; +use axum::{ + http::StatusCode, + response::{Html, IntoResponse}, + routing::get, +}; +use tower_http::services::ServeDir; + +pub fn get_routes() -> axum::Router { + axum::Router::new() + .route("/", get(index)) + .nest_service("/static", ServeDir::new("static")) +} + +#[derive(Template)] +#[template(path = "index.html")] +struct IndexTemplate {} + +async fn index() -> impl IntoResponse { + let template = IndexTemplate {}; + let html = template.render().unwrap(); + (StatusCode::OK, Html(html).into_response()) +} diff --git a/src/main.rs b/src/main.rs index c5a0676..e168c52 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,13 @@ use std::net::SocketAddr; mod api; +mod frontend; #[tokio::main] async fn main() { - let app = axum::Router::new().merge(api::get_routes()); + let app = axum::Router::new() + .merge(api::get_routes()) + .merge(frontend::get_routes()); let addr = SocketAddr::from(([0, 0, 0, 0], 3000)); let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); diff --git a/static/index.js b/static/index.js new file mode 100644 index 0000000..1bfd103 --- /dev/null +++ b/static/index.js @@ -0,0 +1,175 @@ +function load_links() { + fetch("/api/pdf") + .then((response) => response.json()) + .then((data) => { + let i = 0; + data.links.forEach((el) => { + const select = document.getElementById("links"); + const option = document.createElement("option"); + option.value = i; + option.text = el.split("/").pop().split(".pdf")[0]; + select.appendChild(option); + i++; + }); + }); +} + +function load_teachers(id) { + fetch(`/api/professori?id=${id}`) + .then((response) => response.json()) + .then((data) => { + let i = 0; + data.forEach((el) => { + const select = document.getElementById("teachers"); + const option = document.createElement("option"); + option.value = el; + select.appendChild(option); + i++; + }); + }); +} + +function load_classes(id) { + fetch(`/api/classi?id=${id}`) + .then((response) => response.json()) + .then((data) => { + for (let i = 0; i < data.length; i++) { + const select = document.getElementById("year"); + const option = document.createElement("option"); + option.value = i; + option.text = i + 1; + select.appendChild(option); + } + sessionStorage.setItem("classes", JSON.stringify(data)); + }); +} + +function make_teacher_table(id, teacher) { + fetch(`/api/professore?id=${id}&professore=${teacher}`) + .then((response) => response.json()) + .then((data) => { + let table = document.getElementById("table"); + let tbody = document.createElement("tbody"); + let week = [ + "Lunedì", + "Martedì", + "Mercoledì", + "Giovedì", + "Venerdì", + "Sabato", + ]; + week.forEach((weekday) => { + let tr = document.createElement("tr"); + let th = document.createElement("th"); + th.scope = "row"; + th.textContent = weekday; + tr.appendChild(th); + data[weekday].forEach((teacher_class) => { + let td = document.createElement("td"); + td.textContent = teacher_class; + tr.appendChild(td); + }); + tbody.appendChild(tr); + }); + table.appendChild(tbody); + }); +} + +function make_student_table(id, student_class) { + fetch(`/api/classe?id=${id}&classe=${student_class}`) + .then((response) => response.json()) + .then((data) => { + let table = document.getElementById("table"); + let tbody = document.createElement("tbody"); + let week = [ + "Lunedì", + "Martedì", + "Mercoledì", + "Giovedì", + "Venerdì", + "Sabato", + ]; + week.forEach((weekday) => { + let tr = document.createElement("tr"); + let th = document.createElement("th"); + th.scope = "row"; + th.textContent = weekday; + tr.appendChild(th); + data[weekday].forEach((student_class) => { + let td = document.createElement("td"); + td.textContent = student_class; + tr.appendChild(td); + }); + tbody.appendChild(tr); + }); + table.appendChild(tbody); + }); +} + +function select_pdf() { + Cookies.set("id", document.getElementById("links").value); + document.getElementById("form-type").removeAttribute("hidden"); +} + +function select_type() { + let id = document.getElementById("links").value; + let value = document.getElementById("type").value; + if (value === "teacher") { + load_teachers(id); + document.getElementById("form-teacher").removeAttribute("hidden"); + document.getElementById("form-classes").setAttribute("hidden", ""); + } else if (value === "student") { + load_classes(id); + document.getElementById("form-classes").removeAttribute("hidden"); + document.getElementById("form-teacher").setAttribute("hidden", ""); + } +} + +function load_section() { + let data = JSON.parse(sessionStorage.getItem("classes")); + let year = document.getElementById("year").value; + Object.keys(data[year]).forEach((el) => { + const select = document.getElementById("section"); + const option = document.createElement("option"); + option.value = el; + option.text = el; + select.appendChild(option); + }); +} + +function load_major() { + let data = JSON.parse(sessionStorage.getItem("classes")); + let year = document.getElementById("year").value; + let section = document.getElementById("section").value; + data[year][section].forEach((el) => { + const select = document.getElementById("major"); + const option = document.createElement("option"); + option.value = el; + option.text = el; + select.appendChild(option); + }); +} + +function select_teacher() { + Cookies.set("type", "teacher"); + Cookies.set("teacher", document.getElementById("teacher").value); +} + +function select_class() { + Cookies.set("type", "student"); + let student_class = document.getElementById("year").value; + student_class += document.getElementById("section").value; + student_class += document.getElementById("major").value; + Cookies.set("class", student_class); +} + +if (Cookies.get("id") && Cookies.get("type")) { + if (Cookies.get("type") === "teacher" && Cookies.get("teacher")) { + make_teacher_table(Cookies.get("id"), Cookies.get("teacher")); + } else if (Cookies.get("type") === "student" && Cookies.get("class")) { + make_student_table(Cookies.get("id"), Cookies.get("class")); + } +} else { + document.getElementById("forms").removeAttribute("hidden"); + load_links(); +} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..a09a34b --- /dev/null +++ b/templates/index.html @@ -0,0 +1,70 @@ + + + + + + Orario scolastico + + + + + +
+ +
+
+ +