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]]
|
||||
name = "fabula_votes_server"
|
||||
version = "1.2.1"
|
||||
version = "1.3.0"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"blake2",
|
||||
|
|
|
@ -3,7 +3,7 @@ name = "fabula_votes_server"
|
|||
license = "MPL-2.0"
|
||||
readme = "README.md"
|
||||
authors = ["trotFunky"]
|
||||
version = "1.2.1"
|
||||
version = "1.3.0"
|
||||
edition = "2021"
|
||||
|
||||
# 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)))
|
||||
}
|
||||
|
||||
#[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<'_>) {
|
||||
if cookies.get_private("auth_token").is_some() {
|
||||
return
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -1,18 +1,13 @@
|
|||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::{Rocket, Build, futures};
|
||||
use rocket::fs::{FileServer, relative};
|
||||
use rocket::http::CookieJar;
|
||||
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 sqlx::Error;
|
||||
use rocket_db_pools::{sqlx, sqlx::Row, Connection};
|
||||
|
||||
mod auth;
|
||||
use auth::User;
|
||||
|
||||
mod truth;
|
||||
mod vote;
|
||||
|
@ -21,7 +16,6 @@ mod week;
|
|||
|
||||
mod database;
|
||||
mod database_records;
|
||||
use database_records::*;
|
||||
use database::Db;
|
||||
|
||||
#[get("/")]
|
||||
|
@ -46,7 +40,7 @@ fn rocket() -> _ {
|
|||
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::login, auth::logout])
|
||||
.attach(database::stage())
|
||||
.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 rocket::fairing::AdHoc;
|
||||
use rocket::form::Form;
|
||||
use rocket::futures::TryFutureExt;
|
||||
use rocket::http::CookieJar;
|
||||
use rocket::response::Redirect;
|
||||
use rocket::serde::{Serialize, Deserialize};
|
||||
|
@ -91,12 +90,14 @@ pub async fn vote(week: u8, form: Form<VoteForm>,
|
|||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct VoteData {
|
||||
truth_count: u8,
|
||||
votes: HashMap<String, Vec<u8>>,
|
||||
}
|
||||
|
||||
// TODO: Cache vote count ? Maintain in state ?
|
||||
#[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("
|
||||
SELECT Players.name as votes_for, Truths.number as truth_number, count(*) as votes FROM Votes
|
||||
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()
|
||||
});
|
||||
|
||||
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});
|
||||
// Only show the graph if we have all the votes and this is not the last week.
|
||||
// FIXME: Make the 42 not hardcoded
|
||||
if vote_count < 42 || week == sqlx::query_scalar("SELECT number from Weeks WHERE is_last_week == 1;")
|
||||
.fetch_optional(&mut **db)
|
||||
.await.unwrap_or(Some(0)).unwrap_or(0) {
|
||||
if !user.is_admin && (max_vote_count == 0
|
||||
|| vote_count < max_vote_count
|
||||
|| week == sqlx::query_scalar("SELECT number from Weeks WHERE is_last_week == 1;")
|
||||
.fetch_optional(&mut **db)
|
||||
.await.unwrap_or(Some(0)).unwrap_or(0)) {
|
||||
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;
|
||||
}
|
||||
|
||||
Some(Json(VoteData{votes: vote_data}))
|
||||
Some(Json(VoteData{truth_count: truth_count, votes: vote_data}))
|
||||
}
|
||||
|
||||
// FIXME:
|
||||
|
|
|
@ -23,6 +23,12 @@
|
|||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.individual_truth > h3 {
|
||||
text-align: center;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: slategray solid 0.15em;
|
||||
}
|
||||
|
||||
.editor {
|
||||
width: calc(100% - 1.25em); /* The width is calculated *inside* the padding, so adjust for it. */
|
||||
height: 6eM;
|
||||
|
@ -77,8 +83,8 @@
|
|||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 2px solid #9ec5fe;
|
||||
color: #9ec5fe;
|
||||
border-top: 2px dotted slategray;
|
||||
color: slategray;
|
||||
overflow: visible;
|
||||
text-align: center;
|
||||
height: 5px;
|
||||
|
|
|
@ -6,18 +6,20 @@ async function main() {
|
|||
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 = []
|
||||
|
||||
try {
|
||||
const vote_data = (await vote_response.json()).votes;
|
||||
for (let player in vote_data) {
|
||||
const vote_data = (await vote_response.json());
|
||||
for (let player in vote_data.votes) {
|
||||
datasets.push({
|
||||
parsing: true,
|
||||
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) {
|
||||
console.error("Failed to parse vote data : \n\t" + error.message);
|
||||
return;
|
||||
|
|
|
@ -36,11 +36,17 @@
|
|||
{% 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 %}
|
||||
|
||||
<body>
|
||||
<div class="top_bar">
|
||||
<h1>{{ title }}</h1>
|
||||
{% 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 %}
|
||||
<form class="login" id="login" action="/{{ week_data.number }}/login" method="POST">
|
||||
<label>Pseudo <input form="login" type="text" name="name"/></label>
|
||||
|
@ -76,7 +82,7 @@
|
|||
</form>
|
||||
{% endif %}
|
||||
</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">
|
||||
{% endif %}
|
||||
|
||||
|
@ -101,7 +107,7 @@
|
|||
{% endif %}
|
||||
{% 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/>
|
||||
<button form="truths">
|
||||
{%- if user.logged_in == true and user.has_week_vote == true -%}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue