From 120472354c0e76b7e783344041653cd6d8108842 Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sat, 27 Jul 2024 21:08:24 +0100 Subject: [PATCH 01/14] auth: Remove auth bypass function The authentication bypass function was mostly used for testing, before the full flow was implemented. Remove it now that it is no longer useful. --- src/auth.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index e022532..eb56446 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -210,18 +210,3 @@ pub async fn logout(week: u8, mut db: Connection, cookies: &CookieJar<'_>) - Redirect::to(uri!(week::week(week))) } - -pub fn bypass_auth_debug(cookies: &CookieJar<'_>) { - if cookies.get_private("auth_token").is_some() { - return - } - let mut hasher = Blake2b512::new(); - hasher.update(b"8"); - hasher.update(SystemTime::now().duration_since(UNIX_EPOCH).expect("Non monotonous time event").as_secs().to_le_bytes()); - let hash = hasher.finalize_fixed().to_ascii_lowercase(); - let hash_str = String::from_utf8_lossy(hash.as_slice()).to_ascii_lowercase(); - cookies.add_private(("auth_token", hash_str.clone())); - cookies.add_private(("auth_id", 8.to_string())); - - println!("Generated hash string : {hash_str}"); -} \ No newline at end of file From 222acbb4f86837c04ce5b7db38fb63f51a98ed7d Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sat, 27 Jul 2024 21:22:34 +0100 Subject: [PATCH 02/14] Rocket: Use fairings for routes of sub-files Instead of adding all routes manually in the Launch function for Rocket, implement fairings for all the different files that adds the routing to the rocket in a self-contained manner. --- README.md | 3 ++- src/auth.rs | 7 +++++++ src/main.rs | 12 +++++------- src/truth.rs | 7 +++++++ src/vote.rs | 3 +-- src/week.rs | 6 ++++++ 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2b6d940..e289d5b 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,9 @@ A list of things that could be implemented/added to the application, some of the - [ ] Move the database queries to their own functions - [ ] Cache those results - [ ] Centralize Markdown parsing ? - - [ ] Use fairings for the different elements ? + - [x] Use fairings for the different elements - [ ] Use guards for User calls ? + - [ ] Use SQLite Row ID for User IDs rather than regular IDs, for randomness ? # Dependencies diff --git a/src/auth.rs b/src/auth.rs index eb56446..34c0bec 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -8,6 +8,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use argon2::{Argon2, PasswordHash, PasswordVerifier}; use blake2::{Blake2b512, Digest}; use blake2::digest::FixedOutput; +use rocket::fairing::AdHoc; use crate::database_records::{AuthTokens, PlayerLoginInfo, Vote}; use crate::{database, week}; use database::Db; @@ -210,3 +211,9 @@ pub async fn logout(week: u8, mut db: Connection, cookies: &CookieJar<'_>) - Redirect::to(uri!(week::week(week))) } + +pub fn stage() -> AdHoc { + AdHoc::on_ignite("Auth stage", |rocket| async { + rocket.mount("/", routes![login, logout]) + }) +} diff --git a/src/main.rs b/src/main.rs index ac5bc3f..a7d56c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,13 +36,11 @@ async fn index(mut db: Connection) -> Redirect { fn rocket() -> _ { rocket::build() .mount("/", FileServer::from(relative!("static_files"))) - .mount("/", routes![index, - vote::fetch_vote_data, vote::vote, - truth::create_truth, truth::edit_truth, - week::week, week::update_week, week::set_last_week, week::create_week, - auth::login, auth::logout]) + .attach(auth::stage()) + .attach(week::stage()) + .attach(truth::stage()) + .attach(vote::stage()) + .mount("/", routes![index]) .attach(database::stage()) .attach(Template::fairing()) } - -// TODO: Random Row ID \ No newline at end of file diff --git a/src/truth.rs b/src/truth.rs index 861449c..b9df46a 100644 --- a/src/truth.rs +++ b/src/truth.rs @@ -5,6 +5,7 @@ use rocket::response::Redirect; use rocket_db_pools::{sqlx, Connection}; use pulldown_cmark::{Parser, Options}; +use rocket::fairing::AdHoc; use sqlx::Row; use crate::{auth, database, week}; @@ -110,3 +111,9 @@ pub async fn create_truth(week: u8, form: Form, Redirect::to(uri!(week::week(week))) } + +pub fn stage() -> AdHoc { + AdHoc::on_ignite("Truth stage", |rocket| async { + rocket.mount("/", routes![create_truth, edit_truth]) + }) +} diff --git a/src/vote.rs b/src/vote.rs index 7bd400f..ff1e555 100644 --- a/src/vote.rs +++ b/src/vote.rs @@ -164,9 +164,8 @@ pub async fn fetch_vote_data(week: u8, mut db: Connection, cookies Some(Json(VoteData{truth_count: truth_count, votes: vote_data})) } -// FIXME: pub fn stage() -> AdHoc { - AdHoc::on_ignite("SQLx Stage", |rocket| async { + AdHoc::on_ignite("Vote stage", |rocket| async { rocket.mount("/", routes![vote, fetch_vote_data]) }) } diff --git a/src/week.rs b/src/week.rs index 1eb52db..8744ce2 100644 --- a/src/week.rs +++ b/src/week.rs @@ -210,3 +210,9 @@ pub async fn create_week(week: u8, mut db: Connection, cookies: &CookieJar<' } } } + +pub fn stage() -> AdHoc { + AdHoc::on_ignite("Week stage", |rocket| async { + rocket.mount("/", routes![week, create_week, update_week, set_last_week]) + }) +} From 36b2e61e26d373fa5b986965393258374dd83990 Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sat, 27 Jul 2024 21:47:26 +0100 Subject: [PATCH 03/14] main: Serve static files from /static path Static files served with FileServer have a low priority : all other possible routes a this root will be checked first, before they get returned. As we have a lot of routes at the root, they will be hit a lot before we get to the static files. Move the static files to a dedicated path to reduce those internal redirections, update the paths in the HTML and add one for the favicon so it continues to work. --- src/main.rs | 2 +- templates/index.html.tera | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index a7d56c7..7a8e434 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,7 @@ async fn index(mut db: Connection) -> Redirect { #[launch] fn rocket() -> _ { rocket::build() - .mount("/", FileServer::from(relative!("static_files"))) + .mount("/static/", FileServer::from(relative!("static_files"))) .attach(auth::stage()) .attach(week::stage()) .attach(truth::stage()) diff --git a/templates/index.html.tera b/templates/index.html.tera index e10d6f5..ff9a273 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -4,12 +4,13 @@ {{ title }} - + + {% if user.logged_in == true and not user.is_admin %} - + {% endif %} - + {#{% import "week_change_arrows" as week_macro %}#} From afdac98dead48d260538d27409ff8e0515545d6c Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sat, 27 Jul 2024 22:41:06 +0100 Subject: [PATCH 04/14] templates: Move week-related includes to a folder In preparation to adding a new page, move the week-related included files in a specific sub-folder. Change includes accordingly. --- templates/index.html.tera | 6 +++--- templates/{ => weeks}/editable_truth.tera | 2 +- templates/{ => weeks}/truth.html.tera | 0 templates/{ => weeks}/truth_editor.html.tera | 0 4 files changed, 4 insertions(+), 4 deletions(-) rename templates/{ => weeks}/editable_truth.tera (84%) rename templates/{ => weeks}/truth.html.tera (100%) rename templates/{ => weeks}/truth_editor.html.tera (100%) diff --git a/templates/index.html.tera b/templates/index.html.tera index ff9a273..2e7a831 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -102,9 +102,9 @@ {% set truth_index = truth.number - index_delta %} {% if user.is_admin == true %} - {% include "editable_truth" %} + {% include "weeks/editable_truth" %} {% else %} - {% include "truth" %} + {% include "weeks/truth" %} {% endif %} {% endfor %} @@ -125,7 +125,7 @@

Nouvelle vérité

- {% include "truth_editor" %} + {% include "weeks/truth_editor" %}
{% endif %} diff --git a/templates/editable_truth.tera b/templates/weeks/editable_truth.tera similarity index 84% rename from templates/editable_truth.tera rename to templates/weeks/editable_truth.tera index 22d3470..501302a 100644 --- a/templates/editable_truth.tera +++ b/templates/weeks/editable_truth.tera @@ -3,6 +3,6 @@

{{ truth.rendered_text | safe }}


- {% include "truth_editor" %} + {% include "weeks/truth_editor" %}
diff --git a/templates/truth.html.tera b/templates/weeks/truth.html.tera similarity index 100% rename from templates/truth.html.tera rename to templates/weeks/truth.html.tera diff --git a/templates/truth_editor.html.tera b/templates/weeks/truth_editor.html.tera similarity index 100% rename from templates/truth_editor.html.tera rename to templates/weeks/truth_editor.html.tera From b1f37a4e4af611502b66218f125c6f4cd0b4dd94 Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sat, 27 Jul 2024 23:16:19 +0100 Subject: [PATCH 05/14] templates: Make the index a class The index is a full HTML page with some boilerplate that would be needed in all pages deviating from the truth list, specifically the head and general structure. Make the core structure a base template, rebuild the week index page inheriting from it. Change which template is used by the route accordingly. --- src/week.rs | 4 +- static_files/style.css | 2 +- templates/base_page.html.tera | 36 ++++++++ templates/index.html.tera | 142 -------------------------------- templates/weeks/index.html.tera | 120 +++++++++++++++++++++++++++ 5 files changed, 159 insertions(+), 145 deletions(-) create mode 100644 templates/base_page.html.tera delete mode 100644 templates/index.html.tera create mode 100644 templates/weeks/index.html.tera diff --git a/src/week.rs b/src/week.rs index 8744ce2..5168b1c 100644 --- a/src/week.rs +++ b/src/week.rs @@ -53,7 +53,7 @@ pub async fn week(week_number: u8, mut db: Connection, cookies: &CookieJar<' } }; - Template::render("index", context! { + Template::render("weeks/index", context! { week_data: week_data, truths: truths, user: user, @@ -70,7 +70,7 @@ pub async fn week(week_number: u8, mut db: Connection, cookies: &CookieJar<' } }; - Template::render("index", context! { + Template::render("weeks/index", context! { week_data: week_data, truths: truths, user: user, diff --git a/static_files/style.css b/static_files/style.css index edc39a7..ddb3d5c 100644 --- a/static_files/style.css +++ b/static_files/style.css @@ -5,7 +5,7 @@ margin-right: 2em; } -.page_body { +.truth_page_body { display: flex; flex-direction: row; justify-content: space-between; diff --git a/templates/base_page.html.tera b/templates/base_page.html.tera new file mode 100644 index 0000000..42f0895 --- /dev/null +++ b/templates/base_page.html.tera @@ -0,0 +1,36 @@ + + +{% set title = "Vérités Fabula Ultima" %} + + + {{ title }} + + + {% block scripts %} + {% endblock %} + + + +{% block top_bar %} +
+

{{ title }}

+ {% if user.logged_in == true %} + + {% else %} + + {% endif %} +
+{% endblock %} + +{% block body %} +{% endblock %} + + + diff --git a/templates/index.html.tera b/templates/index.html.tera deleted file mode 100644 index 2e7a831..0000000 --- a/templates/index.html.tera +++ /dev/null @@ -1,142 +0,0 @@ - - -{% set title = "Vérités Fabula Ultima" %} - - - {{ title }} - - - {% if user.logged_in == true and not user.is_admin %} - - {% endif %} - - - - -{#{% import "week_change_arrows" as week_macro %}#} -{# For some reason the import does not work ? Figure it out at some point... #} -{%- macro display(display_character, to, enabled) -%} - {%- set class = "week_change" -%} - {%- if enabled == true %} - {% set target = ("href=/" ~ to) %} - {%- else -%} - {% set class = class ~ " week_change_hidden" -%} - {% set target = "" %} - {%- endif -%} - {%- if enabled == true -%}{{- display_character -}}{%- endif -%} -{%- endmacro display -%} - - -{% set back_arrow_enabled = week_data.number > 1 %} -{% set next_arrow_enabled = (week_data.is_last_week != true or user.is_admin == true) %} -{% set next_arrow_href = (week_data.number + 1) %} -{% if user.is_admin == true %} - {% set next_arrow_href = next_arrow_href ~ "/create" %} - {% set next_arrow_chara = '⥅' %} -{% else %} - {% set next_arrow_chara = '⟹' %} -{% endif %} - -{# Remove the form if all votes are locked, to reduce confusion. #} -{% set lock_truth_form = user.votes | length + 1 == truths | length and week_data.is_last_week != true %} - - -
-

{{ title }}

- {% if user.logged_in == true %} - - {% else %} - - {% endif %} -
- -

{{- self::display(display_character='⟸', to=(week_data.number - 1), enabled=back_arrow_enabled) }} - Semaine {{ week_data.number }} - {{- self::display(display_character=next_arrow_chara, to=next_arrow_href, enabled=next_arrow_enabled) -}}

-
-
- {% if user.is_admin == true and week_data.is_last_week != true %} -
- -
- {% endif %} -
- {{ week_data.rendered_text | safe }} - {%- if user.is_admin == true -%} -
-
- - -
- {% endif %} -
- {% if user.logged_in == true and user.is_admin == false and not lock_truth_form %} -
- {% endif %} - - {# Truths start at 1 but the array starts at 0 #} - {% set index_delta = 1 %} - {% for truth in truths %} - {# - The truths are in an ordered array, but one of them might be the user's. - In this case, we need to stop the array index from incrementing if the current - truth is the user's, as they cannot have voted for themselves, leading to one - less votes than there are truths. - #} - {%- if truth.author_id == user.id -%} - {%- set_global index_delta = 2 -%} - {% endif %} - {% set truth_index = truth.number - index_delta %} - - {% if user.is_admin == true %} - {% include "weeks/editable_truth" %} - {% else %} - {% include "weeks/truth" %} - {% endif %} - {% endfor %} - - {% if user.logged_in == true and user.is_admin == false and not lock_truth_form %} -
- -
- {% endif %} - - {# If admin, show an additional box for creating a new Truth. #} - {% if user.is_admin == true %} -
-

Nouvelle vérité

-
- {% include "weeks/truth_editor" %} -
-
- {% endif %} -
- -
-
- -
-
-
- - - diff --git a/templates/weeks/index.html.tera b/templates/weeks/index.html.tera new file mode 100644 index 0000000..ddf8c70 --- /dev/null +++ b/templates/weeks/index.html.tera @@ -0,0 +1,120 @@ +{% extends "base_page" %} + +{% block scripts %} + {% if user.logged_in == true and not user.is_admin %} + + {% endif %} + + +{% endblock %} + +{#{% import "week_change_arrows" as week_macro %}#} +{# For some reason the import does not work ? Figure it out at some point... #} +{%- macro display(display_character, to, enabled) -%} + {%- set class = "week_change" -%} + {%- if enabled == true %} + {% set target = ("href=/" ~ to) %} + {%- else -%} + {% set class = class ~ " week_change_hidden" -%} + {% set target = "" %} + {%- endif -%} + {%- if enabled == true -%}{{- display_character -}}{%- endif -%} +{%- endmacro display -%} + +{# Remove the form if all votes are locked, to reduce confusion. #} +{% set lock_truth_form = user.votes | length + 1 == truths | length and week_data.is_last_week != true %} + +{% block body %} + + {# Apparently needs to be inside the block ? #} + {% set back_arrow_enabled = week_data.number > 1 %} + {% set next_arrow_enabled = (week_data.is_last_week != true or user.is_admin == true) %} + {% set next_arrow_href = (week_data.number + 1) %} + {% if user.is_admin == true %} + {% set next_arrow_href = next_arrow_href ~ "/create" %} + {% set next_arrow_chara = '⥅' %} + {% else %} + {% set next_arrow_chara = '⟹' %} + {% endif %} + +

{{- self::display(display_character='⟸', to=(week_data.number - 1), enabled=back_arrow_enabled) }} + Semaine {{ week_data.number }} + {{- self::display(display_character=next_arrow_chara, to=next_arrow_href, enabled=next_arrow_enabled) -}}

+
+
+ {% if user.is_admin == true and week_data.is_last_week != true %} +
+ +
+ {% endif %} +
+ {{ week_data.rendered_text | safe }} + {%- if user.is_admin == true -%} +
+
+ + +
+ {% endif %} +
+ {% if user.logged_in == true and user.is_admin == false and not lock_truth_form %} +
+ {% endif %} + + {# Truths start at 1 but the array starts at 0 #} + {% set index_delta = 1 %} + {% for truth in truths %} + {# + The truths are in an ordered array, but one of them might be the user's. + In this case, we need to stop the array index from incrementing if the current + truth is the user's, as they cannot have voted for themselves, leading to one + less votes than there are truths. + #} + {%- if truth.author_id == user.id -%} + {%- set_global index_delta = 2 -%} + {% endif %} + {% set truth_index = truth.number - index_delta %} + + {% if user.is_admin == true %} + {% include "weeks/editable_truth" %} + {% else %} + {% include "weeks/truth" %} + {% endif %} + {% endfor %} + + {% if user.logged_in == true and user.is_admin == false and not lock_truth_form %} +
+ +
+ {% endif %} + + {# If admin, show an additional box for creating a new Truth. #} + {% if user.is_admin == true %} +
+

Nouvelle vérité

+
+ {% include "weeks/truth_editor" %} +
+
+ {% endif %} +
+ +
+
+ +
+
+
+{% endblock %} From 1419bb6d51a0e1c3e2dd623b954b15b4c0d9b324 Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sat, 27 Jul 2024 23:20:20 +0100 Subject: [PATCH 06/14] tempates/base: Change language, update title Now that we have the name of the world, we can show it in the title. The base I used supposed an english language page, which is incorrect here. Set language as French. --- templates/base_page.html.tera | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/base_page.html.tera b/templates/base_page.html.tera index 42f0895..f56242b 100644 --- a/templates/base_page.html.tera +++ b/templates/base_page.html.tera @@ -1,6 +1,6 @@ - -{% set title = "Vérités Fabula Ultima" %} + +{% set title = "Vérités Nova Borealis" %} {{ title }} From 1b4a934398c355fffe22a13ac00ca73b11063797 Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sun, 28 Jul 2024 14:36:52 +0100 Subject: [PATCH 07/14] auth: Split off vote data from the user Now that the application is going to have multiple pages, vote data makes no sense to keep with the user. The user struct will be used everywhere to check for authentication, which is not the case for previous votes. Create a new struct and function in src/vote.rs to retrieve existing votes and use them in places where user.votes was used previously. Remove vote-related code from src/auth.rs and the week number dependence that it required. --- README.md | 1 + src/auth.rs | 23 ++--------------------- src/truth.rs | 4 ++-- src/vote.rs | 31 ++++++++++++++++++++++++++++--- src/week.rs | 15 ++++++++++----- templates/weeks/index.html.tera | 4 ++-- templates/weeks/truth.html.tera | 4 ++-- 7 files changed, 47 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index e289d5b..949ac31 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ A list of things that could be implemented/added to the application, some of the - [x] Use fairings for the different elements - [ ] Use guards for User calls ? - [ ] Use SQLite Row ID for User IDs rather than regular IDs, for randomness ? + - [x] Split user from vote data # Dependencies diff --git a/src/auth.rs b/src/auth.rs index 34c0bec..672b79d 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -9,7 +9,7 @@ use argon2::{Argon2, PasswordHash, PasswordVerifier}; use blake2::{Blake2b512, Digest}; use blake2::digest::FixedOutput; use rocket::fairing::AdHoc; -use crate::database_records::{AuthTokens, PlayerLoginInfo, Vote}; +use crate::database_records::{AuthTokens, PlayerLoginInfo}; use crate::{database, week}; use database::Db; @@ -21,11 +21,9 @@ pub struct User { pub is_admin: bool, pub id: u16, pub name: String, - pub has_week_vote: bool, - pub votes: Vec } -pub async fn get_user(week: u8, db: &mut Connection, cookies: &CookieJar<'_>) -> User { +pub async fn get_user(db: &mut Connection, cookies: &CookieJar<'_>) -> User { let auth_token: Option = match cookies.get_private("auth_token") { Some(cookie) => Some(cookie.value().to_string()), None => None @@ -87,27 +85,12 @@ pub async fn get_user(week: u8, db: &mut Connection, cookies: &CookieJar<'_> (String::new(), false) }; - // TODO: Move to src/vote.rs - let votes: Vec = if logged_in && !is_admin { - sqlx::query_as("SELECT Votes.* FROM Votes JOIN Truths ON Votes.truth_id == Truths.id AND Truths.week == $1 WHERE voter_id == $2 ORDER BY Truths.number;") - .bind(week) - .bind(&id_str) - .fetch_all(&mut ***db).await.unwrap_or_else(|error| { - error!("Error while getting votes : {error}"); - Vec::::new() - }) - } else { - Vec::::new() - }; - if logged_in { User { logged_in, is_admin, id: id_str.parse::().unwrap(), name, - has_week_vote: if votes.is_empty() { false } else { true }, - votes } } else { User { @@ -115,8 +98,6 @@ pub async fn get_user(week: u8, db: &mut Connection, cookies: &CookieJar<'_> is_admin: false, id: 0, name, - has_week_vote: false, - votes } } } diff --git a/src/truth.rs b/src/truth.rs index b9df46a..f3b6add 100644 --- a/src/truth.rs +++ b/src/truth.rs @@ -18,7 +18,7 @@ pub struct TruthUpdateForm { #[post("//edit/", data="
")] pub async fn edit_truth(week: u8, truth_number: u8, form: Form, mut db: Connection, cookies: &CookieJar<'_>) -> Redirect { - let user = auth::get_user(week, &mut db, cookies).await; + let user = auth::get_user(&mut db, cookies).await; if !user.is_admin { cookies.add(("toast_error", "Vous n'avez pas la permission de changer la vérité.")); return Redirect::to(uri!(week::week(week))); @@ -57,7 +57,7 @@ pub async fn edit_truth(week: u8, truth_number: u8, form: Form, #[post("//new_truth", data="")] pub async fn create_truth(week: u8, form: Form, mut db: Connection, cookies: &CookieJar<'_>) -> Redirect { - let user = auth::get_user(week, &mut db, cookies).await; + let user = auth::get_user(&mut db, cookies).await; if !user.is_admin { cookies.add(("toast_error", "Vous n'avez pas la permission d'ajouter de vérité.")); return Redirect::to(uri!(week::week(week))); diff --git a/src/vote.rs b/src/vote.rs index ff1e555..550707c 100644 --- a/src/vote.rs +++ b/src/vote.rs @@ -12,6 +12,29 @@ use rocket_db_pools::{sqlx, Connection}; use crate::{auth, database, week}; use crate::database_records::{Vote, VotingData}; +#[derive(Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +pub struct WeeklyUserVotes { + pub has_week_vote: bool, + pub votes: Vec +} + +pub async fn get_weekly_user_votes(week: u8, user: &auth::User, db: &mut Connection) -> WeeklyUserVotes { + let votes: Vec = if user.logged_in && !user.is_admin { + sqlx::query_as("SELECT Votes.* FROM Votes JOIN Truths ON Votes.truth_id == Truths.id AND Truths.week == $1 WHERE voter_id == $2 ORDER BY Truths.number;") + .bind(week) + .bind(user.id) + .fetch_all(&mut ***db).await.unwrap_or_else(|error| { + error!("Error while getting votes : {error}"); + Vec::::new() + }) + } else { + Vec::::new() + }; + + WeeklyUserVotes {has_week_vote: if votes.is_empty() { false } else { true }, votes} +} + #[derive(FromForm)] pub struct VoteForm { truth_votes: HashMap @@ -20,7 +43,7 @@ pub struct VoteForm { #[post("//vote", data="")] pub async fn vote(week: u8, form: Form, mut db: Connection, cookies: &CookieJar<'_>) -> Redirect { - let user = auth::get_user(week, &mut db, cookies).await; + let user = auth::get_user(&mut db, cookies).await; if !user.logged_in { cookies.add(("toast_error", "Vous n'avez pas la permission de changer de vote.")); @@ -37,9 +60,11 @@ pub async fn vote(week: u8, form: Form, } ); + let existing_votes = get_weekly_user_votes(week, &user, &mut db).await; + let mut had_error = false; for (truth_id, voted_id) in filtered_votes { - match user.votes.iter().find(|vote: &&Vote| {vote.truth_id == *truth_id}) { + match existing_votes.votes.iter().find(|vote: &&Vote| {vote.truth_id == *truth_id}) { Some(vote) => { if *voted_id == vote.voted_id { continue; @@ -97,7 +122,7 @@ pub struct VoteData { // TODO: Cache vote count ? Maintain in state ? #[get("//votes", format = "application/json")] pub async fn fetch_vote_data(week: u8, mut db: Connection, cookies: &CookieJar<'_>) -> Option> { - let user = auth::get_user(week, &mut db, cookies).await; + let user = auth::get_user(&mut db, cookies).await; let raw_votes: Vec = sqlx::query_as(" SELECT Players.name as votes_for, Truths.number as truth_number, count(*) as votes FROM Votes JOIN Players ON Votes.voted_id == Players.id diff --git a/src/week.rs b/src/week.rs index 5168b1c..06bbbb6 100644 --- a/src/week.rs +++ b/src/week.rs @@ -7,14 +7,15 @@ 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, vote}; use crate::auth::User; use crate::database::Db; use crate::database_records::{DisplayTruth, Player, Truth, Week}; +use crate::vote::WeeklyUserVotes; #[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 user: User = auth::get_user(&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") @@ -41,6 +42,8 @@ pub async fn week(week_number: u8, mut db: Connection, cookies: &CookieJar<' } }; + let vote_data: WeeklyUserVotes = vote::get_weekly_user_votes(week_number,&user, &mut db).await; + // 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") @@ -58,6 +61,7 @@ pub async fn week(week_number: u8, mut db: Connection, cookies: &CookieJar<' truths: truths, user: user, other_players: other_players, + vote_data: vote_data }) } else { let truths: Vec = match sqlx::query_as("SELECT id, number, author_id, rendered_text FROM Truths WHERE week == $1 ORDER BY number") @@ -75,6 +79,7 @@ pub async fn week(week_number: u8, mut db: Connection, cookies: &CookieJar<' truths: truths, user: user, other_players: other_players, + vote_data: vote_data }) } } @@ -82,7 +87,7 @@ pub async fn week(week_number: u8, mut db: Connection, cookies: &CookieJar<' #[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; + let user = auth::get_user(&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))); @@ -118,7 +123,7 @@ pub async fn update_week(week: u8, raw_intro: Form, #[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; + let user = auth::get_user(&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))); @@ -173,7 +178,7 @@ pub async fn set_last_week(week: u8, mut db: Connection, cookies: &CookieJar #[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; + let user = auth::get_user(&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))); diff --git a/templates/weeks/index.html.tera b/templates/weeks/index.html.tera index ddf8c70..b3527d5 100644 --- a/templates/weeks/index.html.tera +++ b/templates/weeks/index.html.tera @@ -22,7 +22,7 @@ {%- endmacro display -%} {# Remove the form if all votes are locked, to reduce confusion. #} -{% set lock_truth_form = user.votes | length + 1 == truths | length and week_data.is_last_week != true %} +{% set lock_truth_form = vote_data.votes | length + 1 == truths | length and week_data.is_last_week != true %} {% block body %} @@ -91,7 +91,7 @@ {% if user.logged_in == true and user.is_admin == false and not lock_truth_form %}
- - {% else %} - - {% endif %} +
+

{{ title }}

+ +
+
+ {% block top_bar_side %} +
+ {% if user.logged_in == true %} + + {% else %} + + {% endif %} +
+ {% endblock %} +
{% endblock %} diff --git a/templates/tags/filtered_truths.html.tera b/templates/tags/filtered_truths.html.tera new file mode 100644 index 0000000..ad2ffb9 --- /dev/null +++ b/templates/tags/filtered_truths.html.tera @@ -0,0 +1,28 @@ +{% extends "base_page" %} + +{% block top_bar_side %} +{% endblock %} + +{% block body %} + {% if tags | length == 0 %} +

Ensemble des vérités à ce jour

+ {% elif tags | length == 1 %} +

Vérités correponsdantes au thème

+ {% else %} +

Vérités correponsdantes aux thèmes

+ {% endif %} + +
+ {% for tag in tags %} + {{ tag.name }} + {% endfor %} +
+ + {% for truth in truths %} +
+

Semaine {{ truth.week }} - Vérité {{ truth.number }}

+

{{ truth.rendered_text | safe }}

+
+ {% endfor %} +{% endblock %} diff --git a/templates/tags/index.html.tera b/templates/tags/index.html.tera new file mode 100644 index 0000000..5e423d4 --- /dev/null +++ b/templates/tags/index.html.tera @@ -0,0 +1,42 @@ +{% extends "base_page" %} + +{% block top_bar_side %} +{% endblock %} + +{% block body %} +

Liste des thèmes de Vérité

+ +
+ {% for tag in tags %} +
+ +
+ {% endfor %} +
+ + + {% if user.is_admin %} +
+ +

Éditer les thèmes

+ +
+ {% for tag in tags %} +
+ + + + +
+ {% endfor %} +
+ +
+
+ + +
+ +
+ {% endif %} +{% endblock %} diff --git a/templates/weeks/editable_truth.tera b/templates/weeks/editable_truth.tera index 501302a..3c2c968 100644 --- a/templates/weeks/editable_truth.tera +++ b/templates/weeks/editable_truth.tera @@ -1,8 +1,30 @@

Vérité {{ truth.number }}

{{ truth.rendered_text | safe }}

+
+ {% for tag in truth.tags %} +
+ +
+ + {{ tag.name }} + + {% endfor %} +

-
+ {% include "weeks/truth_editor" %}
+
+ + +
diff --git a/templates/weeks/truth.html.tera b/templates/weeks/truth.html.tera index ca52998..5a420e6 100644 --- a/templates/weeks/truth.html.tera +++ b/templates/weeks/truth.html.tera @@ -7,6 +7,12 @@

Vérité {{ truth.number }}

{{ truth.rendered_text | safe }}

+
+
+ {% for tag in truth.tags %} + {{ tag.name }} + {% endfor %} +
{% if user.logged_in %}