Fixed bug related to new Vote struct, id and submit date can be None

(useful for posting new votes, ie without id and submit date)
This commit is contained in:
2024-10-05 15:09:51 +02:00
parent 98dbcd11f1
commit 8a7c321044
3 changed files with 53 additions and 79 deletions

View File

@@ -3,7 +3,7 @@ use argon2::{
Argon2,
};
use bytes::{Buf, Bytes};
use chrono::{DateTime, Days, Utc};
use chrono::{DateTime, Days, NaiveTime, Timelike, Utc};
#[cfg(target_os = "linux")]
use daemonize::Daemonize;
use http_body_util::{BodyExt, Full};
@@ -66,9 +66,10 @@ struct Player {
name: String,
}
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Debug)]
struct Vote {
id: i64,
id: Option<i64>,
submit_date: Option<String>,
plus_player_id: i64,
plus_nickname: String,
plus_reason: String,
@@ -100,9 +101,9 @@ async fn service(
req: Request<Incoming>,
db: Arc<Mutex<SqlitePool>>,
) -> Result<Response<Body>, Error> {
match req.method() {
&Method::GET => get(req, db).await,
&Method::POST => post(req, db).await,
match *req.method() {
Method::GET => get(req, db).await,
Method::POST => post(req, db).await,
_ => Ok(Response::builder()
.status(StatusCode::IM_A_TEAPOT)
.body(Body::Empty)
@@ -224,17 +225,13 @@ async fn get_data(
let mut plus_results: HashMap<i64, i64> = HashMap::new();
let mut minus_results: HashMap<i64, i64> = HashMap::new();
let _ = ids.iter().for_each(|x| {
ids.iter().for_each(|x| {
let plus_id = x.0;
if !plus_results.contains_key(&plus_id) {
plus_results.insert(plus_id, 0);
}
plus_results.entry(plus_id).or_insert(0);
*plus_results.get_mut(&plus_id).unwrap() += 1;
let minus_id = x.1;
if !minus_results.contains_key(&minus_id) {
minus_results.insert(minus_id, 0);
}
minus_results.entry(minus_id).or_insert(0);
*minus_results.get_mut(&minus_id).unwrap() += 1;
});
@@ -260,11 +257,10 @@ async fn get_votes(req: &Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Vec<V
let date = match headers.get("Date-to-fetch") {
Some(date) => {
let date = date.to_str().unwrap();
let parsed_date = date.parse::<i64>();
if parsed_date.is_err() {
None
if let Ok(parsed_date) = date.parse::<i64>() {
DateTime::from_timestamp_millis(parsed_date)
} else {
DateTime::from_timestamp_millis(parsed_date.unwrap())
None
}
}
None => Some(DateTime::from(SystemTime::now())),
@@ -273,25 +269,14 @@ async fn get_votes(req: &Request<Incoming>, db: Arc<Mutex<SqlitePool>>) -> Vec<V
return Vec::new();
}
let formatted_date = format!("{}", date.unwrap().format("%d/%m/%Y"));
let items = sqlx::query!(
sqlx::query_as!(
Vote,
r#"SELECT * FROM votes WHERE submit_date = ?1 ORDER BY id"#,
formatted_date
)
.fetch_all(&pool)
.await
.unwrap();
items
.iter()
.map(|x| Vote {
id: x.id,
plus_player_id: x.plus_player_id,
plus_nickname: x.plus_nickname.clone(),
plus_reason: x.plus_reason.clone(),
minus_player_id: x.minus_player_id,
minus_nickname: x.minus_nickname.clone(),
minus_reason: x.minus_reason.clone(),
})
.collect()
.unwrap()
}
async fn get_admin(
@@ -301,7 +286,7 @@ async fn get_admin(
) -> Result<Response<Body>, Error> {
let authorised = is_authorised(req, db.clone(), 3).await;
if !authorised {
return get_page(&req, "/unauthorised", db).await;
return get_page(req, "/unauthorised", db).await;
}
match path {
"/admin" => get_page(req, path, db).await,
@@ -320,38 +305,19 @@ async fn get_admin(
}
"/admin/players" => {
let pool = db.clone().lock().unwrap().clone();
let players = sqlx::query!(r#"SELECT id, name FROM players"#)
let players = sqlx::query_as!(Player, r#"SELECT id, name FROM players"#)
.fetch_all(&pool)
.await
.unwrap();
let players: Vec<Player> = players
.iter()
.map(|x| Player {
id: x.id,
name: x.name.clone(),
})
.collect();
let stringed = serde_json::to_string(&players).unwrap_or("".to_string());
Ok(Response::builder().body(Body::new(stringed)).unwrap())
}
"/admin/votes" => {
let pool = db.clone().lock().unwrap().clone();
let votes = sqlx::query!(r#"SELECT * FROM votes"#)
let votes = sqlx::query_as!(Vote, r#"SELECT * FROM votes"#)
.fetch_all(&pool)
.await
.unwrap();
let votes: Vec<Vote> = votes
.iter()
.map(|x| Vote {
id: x.id,
plus_player_id: x.plus_player_id,
plus_nickname: x.plus_nickname.clone(),
plus_reason: x.plus_reason.clone(),
minus_player_id: x.minus_player_id,
minus_nickname: x.minus_nickname.clone(),
minus_reason: x.minus_reason.clone(),
})
.collect();
let stringed = serde_json::to_string(&votes).unwrap_or("".to_string());
Ok(Response::builder().body(Body::new(stringed)).unwrap())
}
@@ -402,7 +368,21 @@ async fn post_vote(
.body(Body::Empty)
.unwrap());
}
ok().await
let date: DateTime<Utc> = DateTime::from(SystemTime::now());
let date = date.checked_add_days(Days::new(1)).unwrap();
let date = date
.with_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap())
.unwrap();
Ok(Response::builder()
.header(
SET_COOKIE,
format!(
"hasvoted=true; Expires={}; Secure; SameSite=Strict",
date.to_rfc2822()
),
)
.body(Body::Empty)
.unwrap())
}
async fn post_player(
@@ -550,16 +530,21 @@ async fn post_admin(
},
"/admin/edit/vote" => match req_json::<Vote>(req).await {
Some(vote) => {
if vote.id.is_none() || vote.submit_date.is_none() {
return bad_request().await;
}
let pool = db.clone().lock().unwrap().clone();
let _ = sqlx::query!(
r#"UPDATE votes
SET plus_player_id = ?1,
plus_nickname = ?2,
plus_reason = ?3,
minus_player_id = ?4,
minus_nickname = ?5,
minus_reason = ?6
WHERE id = ?7"#,
SET submit_date = ?1,
plus_player_id = ?2,
plus_nickname = ?3,
plus_reason = ?4,
minus_player_id = ?5,
minus_nickname = ?6,
minus_reason = ?7
WHERE id = ?8"#,
vote.submit_date,
vote.plus_player_id,
vote.plus_nickname,
vote.plus_reason,
@@ -589,7 +574,7 @@ async fn post_admin(
ok().await
}
_ => bad_request().await,
}
},
_ => bad_request().await,
}
}
@@ -749,14 +734,11 @@ async fn is_authorised(req: &Request<Incoming>, db: Arc<Mutex<SqlitePool>>, leve
let perm = user.permissions as u8;
perm >= level
}
_ => match level {
0 => true,
_ => false,
},
_ => matches!(level, 0),
}
}
fn check_username(username: &String) -> bool {
fn check_username(username: &str) -> bool {
if username.len() > 21 {
return false;
}
@@ -768,7 +750,7 @@ fn check_username(username: &String) -> bool {
true
}
fn check_password(password: &String) -> bool {
fn check_password(password: &str) -> bool {
// one symbol, 10 chars min, one capital letter, one number
if password.len() < 10 {
return false;