diff --git a/Cargo.toml b/Cargo.toml index d4710e1..cdbaadd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,6 @@ actix-web = {version = "4.11.0"} serde = "1.0.228" serde_json = "1.0.145" toml = "0.9.7" -sqlx = {version = "0.8.6", features = ["postgres"]} +sqlx = {version = "0.8.6", features = ["postgres", "runtime-tokio"]} futures-util = "0.3.31" clap = { version = "4.5.50", features = ["derive"] } \ No newline at end of file diff --git a/migrations/20251027081447_projects.sql b/migrations/20251027081447_projects.sql new file mode 100644 index 0000000..f178368 --- /dev/null +++ b/migrations/20251027081447_projects.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS Projects ( +"id" TEXT NOT NULL, +"title" TEXT NOT NULL, +"description" TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS Project_Detail ( +"id" TEXT PRIMARY KEY NOT NULL, +"title" TEXT NOT NULL, +"git_url" TEXT NOT NULL, +"git_title" TEXT NOT NULL, +"description" TEXT NOT NULL +) \ No newline at end of file diff --git a/migrations/20251027102341_website_project.sql b/migrations/20251027102341_website_project.sql new file mode 100644 index 0000000..2fa6ff5 --- /dev/null +++ b/migrations/20251027102341_website_project.sql @@ -0,0 +1,13 @@ +INSERT INTO Projects ("id", "title", "description") VALUES ( +'website', +'website', +'This project is the website you currently are on.' +); + +INSERT INTO Project_Detail ("id", "title", "git_url", "git_title", "description") VALUES ( +'website', +'website', +'https://git.aindustries.be/AINDUSTRIES/aindustries.be', +'aindustries-be', +'This project, the website you are on, is made in Rust such that all the pages are generated by code.
That is that each html element is represented by a struct which implements the Render trait (as in render the element to html).
As it is right now the system is not that impressive but I believe it can do amazing things in the future.' +) \ No newline at end of file diff --git a/src/pages/projects.rs b/src/pages/projects.rs index 813dcba..652d81b 100644 --- a/src/pages/projects.rs +++ b/src/pages/projects.rs @@ -3,9 +3,20 @@ use crate::html::layouts::Division; use crate::html::pages::BasePage; use crate::html::{Render, boxed_vec}; use actix_web::{Responder, get, web}; +use actix_web::web::Data; +use serde::Deserialize; +use sqlx::query_as; +use crate::AppState; + +#[derive(Deserialize)] +struct Project { + id: String, + title: String, + description: String +} #[get("/projects")] -async fn projects() -> impl Responder { +async fn projects(app_state: Data) -> impl Responder { let title = Heading::builder().text("My projects").build(); let desc = Heading::builder() .level(2) @@ -14,37 +25,47 @@ async fn projects() -> impl Responder { (I've done a lot of small projects but they are not worth it.)", ) .build(); - let website_title = Heading::builder().text("Website").build(); - let website_desc = Paragraph::builder() - .classes(vec!["project-desc"]) - .text("This project is the website you currently are on.") - .build(); - let view = Anchor::builder() - .classes(vec!["project-view"]) - .href("/projects/website") - .text("Learn More") - .build(); - let info = Division::builder() + let projects = match query_as!(Project, "SELECT id, title, description FROM Projects").fetch_all(&app_state.pool).await { + Ok(projects) => projects, + Err(_) => {vec![]} + }; + let items: Vec> = projects.into_iter().map(|p| { + let title = Heading::builder().text(p.title).build(); + let description = Paragraph::builder().classes(vec!["project-desc"]).text(p.description).build(); + let view = Anchor::builder().classes(vec!["project-view"]).href(format!("/projects/{}", p.id)).text("Learn More").build(); + let info = Division::builder() .classes(vec!["project-info"]) - .elements(boxed_vec![website_desc, view]) + .elements(boxed_vec![description, view]) .build(); - let website = Division::builder() + Box::new(Division::builder() .classes(vec!["project"]) - .elements(boxed_vec![website_title, info]) - .build(); + .elements(boxed_vec![title, info]) + .build()) as Box + }).collect(); let css = Link::builder() .rel("stylesheet") .href("/static/css/projects.css") .build(); + let mut body = boxed_vec![title, desc]; + body.extend(items); let page = BasePage::builder() .title("Projects") .head(boxed_vec![css]) - .body(boxed_vec![title, desc, website]) + .body(body) .build(); page.render() } + +#[derive(Deserialize)] +struct ProjectDetail { + id: String, + title: String, + git_url: String, + git_title: String, + description: String +} #[get("/projects/{project}")] -async fn project(project: web::Path) -> impl Responder { +async fn project(project: web::Path, app_state: Data) -> impl Responder { let project = project.into_inner(); let css = Link::builder() .rel("stylesheet") @@ -54,25 +75,23 @@ async fn project(project: web::Path) -> impl Responder { .title(format!("Project-{}", project)) .head(boxed_vec![css]) .build(); - match project.as_str() { - "website" => { - let title = Heading::builder().text("Website").build(); - let gitea = Anchor::builder() - .href("https://git.aindustries.be/AINDUSTRIES/aindustries.be") - .text("aindustries-be") - .build(); - let desc = Paragraph::builder().classes(vec!["description"]).text( - format!("This project, the website you are on, \ - is made in Rust such that all the pages are generated by code.
\ - That is that each html element is represented by a struct which implements the Render trait (as in render the element to html).
\ - As it is right now the system is not that impressive but I believe it can do amazing things in the futur.
\ -
\ - Wish to see more? Check out the gitea repository: {}", gitea.render()), - ).build(); - page.append_element_to_body(title); - page.append_element_to_body(desc); + let project = match query_as!(ProjectDetail, "SELECT * FROM Project_Detail WHERE id = $1", project).fetch_one(&app_state.pool).await { + Ok(project) => project, + Err(error) => { + // return not found page + eprintln!("Error fetching project: {:?}", error); + return page.render() } - _ => {} - } + }; + let title = Heading::builder().text(project.title).build(); + let gitea = Anchor::builder() + .href(project.git_url) + .text(project.git_title) + .build(); + let desc = Paragraph::builder().classes(vec!["description"]).text( + format!("{}

Wish to see more? Check out the gitea repository: {}", project.description, gitea.render()), + ).build(); + page.append_element_to_body(title); + page.append_element_to_body(desc); page.render() }