use pulldown_cmark::{Options, Parser}; use rocket::fairing::AdHoc; use rocket::form::Form; use rocket::http::CookieJar; use rocket::response::Redirect; use rocket_db_pools::{sqlx, Connection}; use rocket_dyn_templates::{context, Template}; use sqlx::{Acquire, Executor}; use crate::auth; use crate::auth::User; use crate::database::Db; use crate::database_records::{DisplayTruth, Player, Truth, Week}; #[get("/")] pub async fn week(week_number: u8, mut db: Connection, cookies: &CookieJar<'_>) -> Template { let user: User = auth::get_user(week_number, &mut db, cookies).await; let other_players = if user.logged_in { match sqlx::query_as("SELECT id, name FROM Players WHERE id <> $1 AND is_admin == 0 ORDER BY name") .bind(user.id) .fetch_all(&mut **db).await { Ok(v) => v, Err(error) => { error!("Some error while getting players : {error}"); Vec::::new() } } } else { Vec::::new() }; let week_data: Week = match sqlx::query_as("SELECT number, is_last_week, rendered_text, raw_text FROM Weeks WHERE number == $1") .bind(week_number) .fetch_one(&mut **db) .await { Ok(week) => week, Err(error) => { error!("Error while retrieving week data : {error}"); Week {number: 0, is_last_week: true, rendered_text: "".to_string(), raw_text: "".to_string() } } }; // FIXME : This is fucking *trash* but fucking hell mate if user.is_admin { let truths: Vec = match sqlx::query_as("SELECT * FROM Truths WHERE week == $1 ORDER BY number") .bind(week_number) .fetch_all(&mut **db).await { Ok(v) => v, Err(error) => { error!("Error while getting truths : {error}"); Vec::::new() } }; Template::render("index", context! { week_data: week_data, truths: truths, user: user, other_players: other_players, }) } else { let truths: Vec = match sqlx::query_as("SELECT id, number, author_id, rendered_text FROM Truths WHERE week == $1 ORDER BY number") .bind(week_number) .fetch_all(&mut **db).await { Ok(v) => v, Err(error) => { error!("Error while getting truths : {error}"); Vec::::new() } }; Template::render("index", context! { week_data: week_data, truths: truths, user: user, other_players: other_players, }) } } #[post("//edit", data="")] pub async fn update_week(week: u8, raw_intro: Form, mut db: Connection, cookies: &CookieJar<'_>) -> Redirect { let user = auth::get_user(week, &mut db, cookies).await; if !user.is_admin { cookies.add(("toast_error", "Vous n'avez pas la permission de changer la semaine.")); return Redirect::to(uri!(week(week))); } let mut options = Options::empty(); options.insert(Options::ENABLE_STRIKETHROUGH); options.insert(Options::ENABLE_FOOTNOTES); options.insert(Options::ENABLE_MATH); options.insert(Options::ENABLE_TABLES); let markdown_parser = Parser::new_ext(raw_intro.as_str(), options); let mut rendered_markdown = String::new(); pulldown_cmark::html::push_html(&mut rendered_markdown, markdown_parser); match sqlx::query("UPDATE Weeks SET raw_text = $1, rendered_text = $2 WHERE number == $3;") .bind(&raw_intro.as_str()) .bind(rendered_markdown) .bind(week) .fetch_optional(&mut **db) .await { Ok(_) => { debug!("Week successfully updated") } Err(error) => { error!("Error while updating week {week} data : {error}"); cookies.add(("toast_error", "Il y a eu un problème lors du changement de la semaine")); } }; Redirect::to(uri!(week(week))) } #[post("//set_last")] pub async fn set_last_week(week: u8, mut db: Connection, cookies: &CookieJar<'_>) -> Redirect { let user = auth::get_user(week, &mut db, cookies).await; if !user.is_admin { cookies.add(("toast_error", "Vous n'avez pas la permission de changer la semaine.")); return Redirect::to(uri!(week(week))); } let add_error_cookie = || cookies.add(("toast_error", "Erreur lors du changement d'état de la semaine.")); let db_transaction_connection = db.begin().await; if db_transaction_connection.is_err() { error!("Could not start database transaction for last week change : {:?}", db_transaction_connection.unwrap_err()); add_error_cookie(); return Redirect::to(uri!(week(week))); } let mut db_transaction = db_transaction_connection.unwrap(); // Remove the last flag from other weeks, if set. match db_transaction.execute("UPDATE Weeks SET is_last_week = 0 WHERE is_last_week == 1;") .await { Ok(_) => debug!("Succesfully cleared is_last_week"), Err(error) => { error!("Failed to clear last week status : {error}"); add_error_cookie(); return Redirect::to(uri!(week(week))); } }; // We should set one week, if not there's something wrong : rollback. if match sqlx::query("UPDATE Weeks SET is_last_week = 1 WHERE number == $1;") .bind(week) .execute(&mut *db_transaction) .await { Ok(result) => result.rows_affected(), Err(error) => { error!("Error while setting last week status : {error}"); 0 } } == 1 { db_transaction.commit().await.unwrap_or_else(|error| { error!("Error while committing week is last transaction : {error}"); add_error_cookie(); }) } else { db_transaction.rollback().await.unwrap_or_else(|error| { error!("Error while rolling back week is last transaction : {error}"); add_error_cookie(); }) } Redirect::to(uri!(week(week))) } #[get("//create")] pub async fn create_week(week: u8, mut db: Connection, cookies: &CookieJar<'_>) -> Redirect { let user = auth::get_user(week, &mut db, cookies).await; if !user.is_admin { cookies.add(("toast_error", "Vous n'avez pas la permission de changer la semaine.")); return Redirect::to(uri!(week(week - 1))); } let week_check: Result, sqlx::Error> = sqlx::query_scalar("SELECT number from Weeks WHERE number == $1;") .bind(week) .fetch_optional(&mut **db) .await; if week_check.is_err() { error!("Error while checking week existence : {:?}", week_check.unwrap_err()); cookies.add(("toast_error", "Erreur en vérifiant que la semaine n'existe pas déjà")); return Redirect::to(uri!(week(week - 1))); } if week_check.unwrap().is_some() { debug!("Week {week} already exists, not creating."); return Redirect::to(uri!(week(week))); } match sqlx::query("INSERT INTO Weeks (number, is_last_week, rendered_text, raw_text) VALUES ($1, 0, \"\", \"\");") .bind(week) .execute(&mut **db) .await { Ok(_) => { debug!("Succesfully created new week {week}"); Redirect::to(uri!(week(week))) }, Err(error) => { error!("Error while creating new week {week} : {error}"); cookies.add(("toast_error", "Erreur en créant la nouvelle selmaine.")); Redirect::to(uri!(week(week - 1))) } } } pub fn stage() -> AdHoc { AdHoc::on_ignite("Week stage", |rocket| async { rocket.mount("/", routes![week, create_week, update_week, set_last_week]) }) }