v1.1: Add weekly introductions
- Create a new migration adding a Weeks table, allowing for new weekly introductions and paving the way for multiple week handling. - Add route to update the weekly introduction - Move the week rendering to a specific week file - Update the templates to use the week number from the week data - Update templates to render and edit weekly introductions
This commit is contained in:
parent
9911895b5b
commit
67ce54e992
12 changed files with 165 additions and 71 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -578,7 +578,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fabula_votes_server"
|
name = "fabula_votes_server"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argon2",
|
"argon2",
|
||||||
"blake2",
|
"blake2",
|
||||||
|
|
|
@ -3,7 +3,7 @@ name = "fabula_votes_server"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["trotFunky"]
|
authors = ["trotFunky"]
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
10
db/03_create-week-table.sql
Normal file
10
db/03_create-week-table.sql
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS Weeks (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
number INTEGER NOT NULL CHECK (number > 0),
|
||||||
|
is_last_week INTEGER NOT NULL,
|
||||||
|
rendered_text VARCHAR NOT NULL,
|
||||||
|
raw_text VARCHAR NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- This is to upgrade from version 1.0 to 1.1 with an existing database
|
||||||
|
INSERT INTO Weeks (number, is_last_week, rendered_text, raw_text) VALUES (1, 1, "", "");
|
|
@ -8,7 +8,6 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use argon2::{Argon2, PasswordHash, PasswordVerifier};
|
use argon2::{Argon2, PasswordHash, PasswordVerifier};
|
||||||
use blake2::{Blake2b512, Digest};
|
use blake2::{Blake2b512, Digest};
|
||||||
use blake2::digest::FixedOutput;
|
use blake2::digest::FixedOutput;
|
||||||
use sqlx::Error;
|
|
||||||
use crate::database_records::{AuthTokens, PlayerLoginInfo, Vote};
|
use crate::database_records::{AuthTokens, PlayerLoginInfo, Vote};
|
||||||
use crate::database;
|
use crate::database;
|
||||||
use database::Db;
|
use database::Db;
|
||||||
|
|
|
@ -58,3 +58,12 @@ pub struct VotingData {
|
||||||
pub struct AuthTokens {
|
pub struct AuthTokens {
|
||||||
pub token: String,
|
pub token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(sqlx::FromRow, Deserialize, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct Week {
|
||||||
|
pub number: u8,
|
||||||
|
pub is_last_week: bool,
|
||||||
|
pub rendered_text: String,
|
||||||
|
pub raw_text: String,
|
||||||
|
}
|
||||||
|
|
69
src/main.rs
69
src/main.rs
|
@ -9,76 +9,23 @@ use rocket::serde::{Serialize, Deserialize, json::Json};
|
||||||
use rocket_dyn_templates::{Template, context};
|
use rocket_dyn_templates::{Template, context};
|
||||||
|
|
||||||
use rocket_db_pools::{sqlx, sqlx::Row, Database, Connection};
|
use rocket_db_pools::{sqlx, sqlx::Row, Database, Connection};
|
||||||
|
use sqlx::Error;
|
||||||
|
|
||||||
mod database_records;
|
|
||||||
mod auth;
|
mod auth;
|
||||||
mod vote;
|
|
||||||
mod truth;
|
mod truth;
|
||||||
|
mod vote;
|
||||||
|
mod week;
|
||||||
|
|
||||||
|
|
||||||
mod database;
|
mod database;
|
||||||
|
mod database_records;
|
||||||
use database::Db;
|
use database::Db;
|
||||||
use database_records::*;
|
use database_records::*;
|
||||||
use auth::User;
|
use auth::User;
|
||||||
|
|
||||||
#[get("/<week_number>")]
|
|
||||||
async fn week(week_number: u8, mut db: Connection<Db>, 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) => {
|
|
||||||
println!("Some error while getting players : {error}");
|
|
||||||
Vec::<Player>::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Vec::<Player>::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME : This is fucking *trash* but fucking hell mate
|
|
||||||
if user.is_admin {
|
|
||||||
let truths: Vec<Truth> = 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::<Truth>::new()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Template::render("index", context! {
|
|
||||||
week_number: week_number,
|
|
||||||
truths: truths,
|
|
||||||
user: user,
|
|
||||||
other_players: other_players,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let truths: Vec<DisplayTruth> = 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::<DisplayTruth>::new()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Template::render("index", context! {
|
|
||||||
week_number: week_number,
|
|
||||||
truths: truths,
|
|
||||||
user: user,
|
|
||||||
other_players: other_players,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn index(mut db: Connection<Db>) -> Redirect {
|
async fn index(mut db: Connection<Db>) -> Redirect {
|
||||||
let current_week: u8 = match sqlx::query("SELECT max(week) AS last_week FROM Truths;")
|
let current_week: u8 = match sqlx::query("SELECT number FROM Weeks WHERE is_last_week == 1;")
|
||||||
.fetch_one(&mut **db).await {
|
.fetch_one(&mut **db).await {
|
||||||
Ok(v) => v.try_get(0).ok().unwrap_or_else(|| 1), // If error, go back to 1
|
Ok(v) => v.try_get(0).ok().unwrap_or_else(|| 1), // If error, go back to 1
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
@ -87,14 +34,14 @@ async fn index(mut db: Connection<Db>) -> Redirect {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Redirect::to(uri!("/", week(week_number = if current_week == 0 {1} else {current_week})))
|
Redirect::to(uri!(week::week(week_number = if current_week == 0 {1} else {current_week})))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[launch]
|
#[launch]
|
||||||
fn rocket() -> _ {
|
fn rocket() -> _ {
|
||||||
rocket::build()
|
rocket::build()
|
||||||
.mount("/", FileServer::from(relative!("static_files")))
|
.mount("/", FileServer::from(relative!("static_files")))
|
||||||
.mount("/", routes![index, vote::fetch_vote_data, vote::vote, truth::create_truth, truth::edit_truth, week, auth::login])
|
.mount("/", routes![index, vote::fetch_vote_data, vote::vote, truth::create_truth, truth::edit_truth, week::week, week::update_week, auth::login])
|
||||||
.attach(database::stage())
|
.attach(database::stage())
|
||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ use rocket::serde::json::Json;
|
||||||
use rocket_db_pools::{sqlx, Connection};
|
use rocket_db_pools::{sqlx, Connection};
|
||||||
|
|
||||||
use crate::{auth, database};
|
use crate::{auth, database};
|
||||||
use crate::database::Db;
|
|
||||||
use crate::database_records::{Vote, VotingData};
|
use crate::database_records::{Vote, VotingData};
|
||||||
|
|
||||||
#[derive(FromForm)]
|
#[derive(FromForm)]
|
||||||
|
|
116
src/week.rs
Normal file
116
src/week.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
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 crate::auth;
|
||||||
|
use crate::auth::User;
|
||||||
|
use crate::database::Db;
|
||||||
|
use crate::database_records::{DisplayTruth, Player, Truth, Week};
|
||||||
|
|
||||||
|
#[get("/<week_number>")]
|
||||||
|
pub async fn week(week_number: u8, mut db: Connection<Db>, 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) => {
|
||||||
|
println!("Some error while getting players : {error}");
|
||||||
|
Vec::<Player>::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vec::<Player>::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<Truth> = 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::<Truth>::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Template::render("index", context! {
|
||||||
|
week_data: week_data,
|
||||||
|
truths: truths,
|
||||||
|
user: user,
|
||||||
|
other_players: other_players,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let truths: Vec<DisplayTruth> = 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::<DisplayTruth>::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Template::render("index", context! {
|
||||||
|
week_data: week_data,
|
||||||
|
truths: truths,
|
||||||
|
user: user,
|
||||||
|
other_players: other_players,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/<week>/edit", data="<raw_intro>")]
|
||||||
|
pub async fn update_week(week: u8, raw_intro: Form<String>,
|
||||||
|
mut db: Connection<Db>, 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!("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
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!("/"))
|
||||||
|
}
|
|
@ -23,7 +23,7 @@
|
||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.truth_editor {
|
.editor {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 6eM;
|
height: 6eM;
|
||||||
font-size: large;
|
font-size: large;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<h3>Vérité {{ truth.number }}</h3>
|
<h3>Vérité {{ truth.number }}</h3>
|
||||||
<p>{{ truth.rendered_text | safe }}</p>
|
<p>{{ truth.rendered_text | safe }}</p>
|
||||||
<hr/>
|
<hr/>
|
||||||
<form action="/{{ week_number }}/edit/{{ truth.number }}" method="POST">
|
<form action="/{{ week_data.number }}/edit/{{ truth.number }}" method="POST">
|
||||||
{% include "truth_editor" %}
|
{% include "truth_editor" %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,11 +33,25 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Semaine {{ week_number }}</h2>
|
<h2>Semaine {{ week_data.number }}</h2>
|
||||||
<div class="page_body">
|
<div class="page_body">
|
||||||
<div class="truth_list">
|
<div class="truth_list">
|
||||||
|
<div class="week_intro">
|
||||||
|
{{ week_data.rendered_text | safe }}
|
||||||
|
{%- if user.is_admin == true -%}
|
||||||
|
<hr/>
|
||||||
|
<form action="/{{ week_data.number }}/edit" method="post">
|
||||||
|
<textarea class="editor" name="raw_intro">
|
||||||
|
{{- week_data.raw_text -}}
|
||||||
|
</textarea>
|
||||||
|
<button>
|
||||||
|
Modifier l'introduction
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% if user.logged_in == true and user.is_admin == false %}
|
{% if user.logged_in == true and user.is_admin == false %}
|
||||||
<form id="truths" action="/{{ week_number }}/vote" method="POST">
|
<form id="truths" action="/{{ week_data.number }}/vote" method="POST">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# Truths start at 1 but the array starts at 0 #}
|
{# Truths start at 1 but the array starts at 0 #}
|
||||||
|
@ -77,7 +91,7 @@
|
||||||
{% if user.is_admin == true %}
|
{% if user.is_admin == true %}
|
||||||
<div class="individual_truth">
|
<div class="individual_truth">
|
||||||
<h3>Nouvelle vérité</h3>
|
<h3>Nouvelle vérité</h3>
|
||||||
<form action="/{{ week_number }}/new" method="POST">
|
<form action="/{{ week_data.number }}/new" method="POST">
|
||||||
{% include "truth_editor" %}
|
{% include "truth_editor" %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<textarea class="truth_editor" name="truth_raw_text">
|
<textarea class="editor" name="truth_raw_text">
|
||||||
{%- if truth.raw_text -%}
|
{%- if truth.raw_text -%}
|
||||||
{{- truth.raw_text -}}
|
{{- truth.raw_text -}}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
|
Loading…
Add table
Reference in a new issue