Compare commits
5 commits
4e1b13dc85
...
0c162d3b42
Author | SHA1 | Date | |
---|---|---|---|
0c162d3b42 | |||
c4e252dbc2 | |||
36be6b51ae | |||
07d8cf42d7 | |||
ba98c3be84 |
8 changed files with 76 additions and 28 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.2.1"
|
version = "1.3.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.2.1"
|
version = "1.3.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
|
||||||
|
|
26
src/auth.rs
26
src/auth.rs
|
@ -185,6 +185,32 @@ pub async fn login(week: u8, form: Form<AuthForm>, mut db: Connection<Db>, cooki
|
||||||
Redirect::to(uri!(week::week(week)))
|
Redirect::to(uri!(week::week(week)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/<week>/logout")]
|
||||||
|
pub async fn logout(week: u8, mut db: Connection<Db>, cookies: &CookieJar<'_>) -> Redirect {
|
||||||
|
let auth_token: Option<String> = match cookies.get_private("auth_token") {
|
||||||
|
Some(cookie) => Some(cookie.value().to_string()),
|
||||||
|
None => None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should not be able to log out ?
|
||||||
|
if auth_token.is_none() {
|
||||||
|
return Redirect::to(uri!(week::week(week)))
|
||||||
|
}
|
||||||
|
|
||||||
|
match sqlx::query("DELETE FROM AuthTokens WHERE token == $1;")
|
||||||
|
.bind(auth_token)
|
||||||
|
.execute(&mut **db)
|
||||||
|
.await {
|
||||||
|
Ok(_) => debug!("Auth token deletion successful"),
|
||||||
|
Err(error) => debug!("Auth token could not be removed ({error}), proceeding anyway.")
|
||||||
|
}
|
||||||
|
|
||||||
|
cookies.remove_private("auth_token");
|
||||||
|
cookies.remove_private("auth_id");
|
||||||
|
|
||||||
|
Redirect::to(uri!(week::week(week)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn bypass_auth_debug(cookies: &CookieJar<'_>) {
|
pub fn bypass_auth_debug(cookies: &CookieJar<'_>) {
|
||||||
if cookies.get_private("auth_token").is_some() {
|
if cookies.get_private("auth_token").is_some() {
|
||||||
return
|
return
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -1,18 +1,13 @@
|
||||||
#[macro_use] extern crate rocket;
|
#[macro_use] extern crate rocket;
|
||||||
|
|
||||||
use rocket::{Rocket, Build, futures};
|
|
||||||
use rocket::fs::{FileServer, relative};
|
use rocket::fs::{FileServer, relative};
|
||||||
use rocket::http::CookieJar;
|
|
||||||
use rocket::response::Redirect;
|
use rocket::response::Redirect;
|
||||||
use rocket::serde::{Serialize, Deserialize, json::Json};
|
|
||||||
|
|
||||||
use rocket_dyn_templates::{Template, context};
|
use rocket_dyn_templates::Template;
|
||||||
|
|
||||||
use rocket_db_pools::{sqlx, sqlx::Row, Database, Connection};
|
use rocket_db_pools::{sqlx, sqlx::Row, Connection};
|
||||||
use sqlx::Error;
|
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
use auth::User;
|
|
||||||
|
|
||||||
mod truth;
|
mod truth;
|
||||||
mod vote;
|
mod vote;
|
||||||
|
@ -21,7 +16,6 @@ mod week;
|
||||||
|
|
||||||
mod database;
|
mod database;
|
||||||
mod database_records;
|
mod database_records;
|
||||||
use database_records::*;
|
|
||||||
use database::Db;
|
use database::Db;
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
|
@ -46,7 +40,7 @@ fn rocket() -> _ {
|
||||||
vote::fetch_vote_data, vote::vote,
|
vote::fetch_vote_data, vote::vote,
|
||||||
truth::create_truth, truth::edit_truth,
|
truth::create_truth, truth::edit_truth,
|
||||||
week::week, week::update_week, week::set_last_week, week::create_week,
|
week::week, week::update_week, week::set_last_week, week::create_week,
|
||||||
auth::login])
|
auth::login, auth::logout])
|
||||||
.attach(database::stage())
|
.attach(database::stage())
|
||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
}
|
}
|
||||||
|
|
28
src/vote.rs
28
src/vote.rs
|
@ -2,7 +2,6 @@ use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use rocket::fairing::AdHoc;
|
use rocket::fairing::AdHoc;
|
||||||
use rocket::form::Form;
|
use rocket::form::Form;
|
||||||
use rocket::futures::TryFutureExt;
|
|
||||||
use rocket::http::CookieJar;
|
use rocket::http::CookieJar;
|
||||||
use rocket::response::Redirect;
|
use rocket::response::Redirect;
|
||||||
use rocket::serde::{Serialize, Deserialize};
|
use rocket::serde::{Serialize, Deserialize};
|
||||||
|
@ -91,12 +90,14 @@ pub async fn vote(week: u8, form: Form<VoteForm>,
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
pub struct VoteData {
|
pub struct VoteData {
|
||||||
|
truth_count: u8,
|
||||||
votes: HashMap<String, Vec<u8>>,
|
votes: HashMap<String, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Cache vote count ? Maintain in state ?
|
// TODO: Cache vote count ? Maintain in state ?
|
||||||
#[get("/<week>/votes", format = "application/json")]
|
#[get("/<week>/votes", format = "application/json")]
|
||||||
pub async fn fetch_vote_data(week: u8, mut db: Connection<database::Db>) -> Option<Json<VoteData>> {
|
pub async fn fetch_vote_data(week: u8, mut db: Connection<database::Db>, cookies: &CookieJar<'_>) -> Option<Json<VoteData>> {
|
||||||
|
let user = auth::get_user(week, &mut db, cookies).await;
|
||||||
let raw_votes: Vec<VotingData> = sqlx::query_as("
|
let raw_votes: Vec<VotingData> = sqlx::query_as("
|
||||||
SELECT Players.name as votes_for, Truths.number as truth_number, count(*) as votes FROM Votes
|
SELECT Players.name as votes_for, Truths.number as truth_number, count(*) as votes FROM Votes
|
||||||
JOIN Players ON Votes.voted_id == Players.id
|
JOIN Players ON Votes.voted_id == Players.id
|
||||||
|
@ -110,12 +111,25 @@ pub async fn fetch_vote_data(week: u8, mut db: Connection<database::Db>) -> Opti
|
||||||
Vec::<VotingData>::new()
|
Vec::<VotingData>::new()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let truth_count: u8 = sqlx::query_scalar("SELECT count(id) from Truths WHERE week == $1;")
|
||||||
|
.bind(week)
|
||||||
|
.fetch_one(&mut **db)
|
||||||
|
.await.unwrap_or(0);
|
||||||
|
|
||||||
|
let player_count: u8 = sqlx::query_scalar("SELECT count(id) from Players WHERE is_admin == 0;")
|
||||||
|
.fetch_one(&mut **db)
|
||||||
|
.await.unwrap_or(0);
|
||||||
|
|
||||||
|
// Each player should have a truth assigned to them which they cannot vote on.
|
||||||
|
let max_vote_count = truth_count * (player_count - 1);
|
||||||
|
|
||||||
let vote_count = raw_votes.iter().fold(0, |count, votes| {count + votes.votes});
|
let vote_count = raw_votes.iter().fold(0, |count, votes| {count + votes.votes});
|
||||||
// Only show the graph if we have all the votes and this is not the last week.
|
// Only show the graph if we have all the votes and this is not the last week.
|
||||||
// FIXME: Make the 42 not hardcoded
|
if !user.is_admin && (max_vote_count == 0
|
||||||
if vote_count < 42 || week == sqlx::query_scalar("SELECT number from Weeks WHERE is_last_week == 1;")
|
|| vote_count < max_vote_count
|
||||||
.fetch_optional(&mut **db)
|
|| week == sqlx::query_scalar("SELECT number from Weeks WHERE is_last_week == 1;")
|
||||||
.await.unwrap_or(Some(0)).unwrap_or(0) {
|
.fetch_optional(&mut **db)
|
||||||
|
.await.unwrap_or(Some(0)).unwrap_or(0)) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +161,7 @@ pub async fn fetch_vote_data(week: u8, mut db: Connection<database::Db>) -> Opti
|
||||||
next_truth_number = raw_vote.truth_number + 1;
|
next_truth_number = raw_vote.truth_number + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Json(VoteData{votes: vote_data}))
|
Some(Json(VoteData{truth_count: truth_count, votes: vote_data}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME:
|
// FIXME:
|
||||||
|
|
|
@ -23,6 +23,12 @@
|
||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.individual_truth > h3 {
|
||||||
|
text-align: center;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
border-bottom: slategray solid 0.15em;
|
||||||
|
}
|
||||||
|
|
||||||
.editor {
|
.editor {
|
||||||
width: calc(100% - 1.25em); /* The width is calculated *inside* the padding, so adjust for it. */
|
width: calc(100% - 1.25em); /* The width is calculated *inside* the padding, so adjust for it. */
|
||||||
height: 6eM;
|
height: 6eM;
|
||||||
|
@ -77,8 +83,8 @@
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 2px solid #9ec5fe;
|
border-top: 2px dotted slategray;
|
||||||
color: #9ec5fe;
|
color: slategray;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
|
|
|
@ -6,18 +6,20 @@ async function main() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = ["Vérité 1", "Vérité 2", "Vérité 3", "Vérité 4", "Vérité 5", "Vérité 6", "Vérité 7"]
|
let keys = []
|
||||||
let datasets = []
|
let datasets = []
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const vote_data = (await vote_response.json()).votes;
|
const vote_data = (await vote_response.json());
|
||||||
for (let player in vote_data) {
|
for (let player in vote_data.votes) {
|
||||||
datasets.push({
|
datasets.push({
|
||||||
parsing: true,
|
parsing: true,
|
||||||
label: player,
|
label: player,
|
||||||
data: vote_data[player],
|
data: vote_data.votes[player],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
for (let i = 1; i <= vote_data.truth_count; i++) {
|
||||||
|
keys.push("Vérité " + i)
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to parse vote data : \n\t" + error.message);
|
console.error("Failed to parse vote data : \n\t" + error.message);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -36,11 +36,17 @@
|
||||||
{% set next_arrow_chara = '⟹' %}
|
{% set next_arrow_chara = '⟹' %}
|
||||||
{% endif %}
|
{% 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 %}
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="top_bar">
|
<div class="top_bar">
|
||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
{% if user.logged_in == true %}
|
{% if user.logged_in == true %}
|
||||||
<p>Connecté en tant que <b>{{ user.name }}</b></p>
|
<form class="login" id="logout" action="/{{ week_data.number }}/logout" method="POST">
|
||||||
|
Connecté en tant que <b>{{ user.name }}</b>
|
||||||
|
<button form="logout">Déconnecter</button>
|
||||||
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<form class="login" id="login" action="/{{ week_data.number }}/login" method="POST">
|
<form class="login" id="login" action="/{{ week_data.number }}/login" method="POST">
|
||||||
<label>Pseudo <input form="login" type="text" name="name"/></label>
|
<label>Pseudo <input form="login" type="text" name="name"/></label>
|
||||||
|
@ -76,7 +82,7 @@
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if user.logged_in == true and user.is_admin == false %}
|
{% if user.logged_in == true and user.is_admin == false and not lock_truth_form %}
|
||||||
<form id="truths" action="/{{ week_data.number }}/vote" method="POST">
|
<form id="truths" action="/{{ week_data.number }}/vote" method="POST">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -101,7 +107,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if user.logged_in == true and user.is_admin == false %}
|
{% if user.logged_in == true and user.is_admin == false and not lock_truth_form %}
|
||||||
<br/>
|
<br/>
|
||||||
<button form="truths">
|
<button form="truths">
|
||||||
{%- if user.logged_in == true and user.has_week_vote == true -%}
|
{%- if user.logged_in == true and user.has_week_vote == true -%}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue