From 09658decfaab03034ffb63a51859c955a5361e41 Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Thu, 19 Mar 2026 14:49:38 -0500 Subject: [PATCH] changed the locking around some --- shared/src/advent/mod.rs | 2 +- web/src/main.rs | 39 ++++++++++++++++++----------- web/src/unlock.rs | 54 ++++++++++++++++++++++++---------------- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/shared/src/advent/mod.rs b/shared/src/advent/mod.rs index a122172..63b727d 100644 --- a/shared/src/advent/mod.rs +++ b/shared/src/advent/mod.rs @@ -52,7 +52,7 @@ pub enum AdventPart { Two, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum CompletionStatus { ///None of the day's challenges have been completed None, diff --git a/web/src/main.rs b/web/src/main.rs index 5ecc207..029a4e9 100644 --- a/web/src/main.rs +++ b/web/src/main.rs @@ -258,7 +258,7 @@ async fn main() -> Result<(), Box> { "/day/{id}", match prod { true => get(handlers::day::view_day_handler) - .route_layer(middleware::from_fn(unlock::unlock)), + .route_layer(middleware::from_fn_with_state(app_state.postgres_pool.clone(), unlock::unlock)), false => get(handlers::day::view_day_handler), }, ) @@ -266,7 +266,7 @@ async fn main() -> Result<(), Box> { "/day/{id}", match prod { true => post(handlers::day::post_day_handler) - .route_layer(middleware::from_fn(unlock::unlock)), + .route_layer(middleware::from_fn_with_state(app_state.postgres_pool.clone(), unlock::unlock)), false => post(handlers::day::post_day_handler), }, ) @@ -296,19 +296,35 @@ async fn main() -> Result<(), Box> { /// The default handler that will be used during the advent month, but not during amtosphere conf async fn home_handler(State(pool): State, session: AxumSessionStore) -> impl IntoResponse { - //TODO make a helper function for this since it is similar to the middleware - let now = chrono::Utc::now(); let mut unlocked: Vec = Vec::new(); + let did = session.get_did(); + let is_logged_in = session.logged_in(); + let all_statuses = get_all_days_completion_status(&pool, did.as_ref()) + .await + .unwrap_or_else(|_| (1..=25).map(|day| (day, CompletionStatus::None)).collect()); + //HACK Yeah I don't like it either - bt let prod: bool = env::var("PROD") .map(|val| val == "true") .unwrap_or_else(|_| true); if prod { - if now.month() == 12 { - let today = now.day().min(25); - for d in 1..=today { - unlocked.push(d as u8); + // Only show implemented days, progressively unlocked as users complete them + let implemented_days: Vec = vec![1, 2, 3]; + if let Some(&first) = implemented_days.first() { + unlocked.push(first); + } + for window in implemented_days.windows(2) { + let prev = window[0]; + let prev_status = all_statuses + .iter() + .find(|(d, _)| *d == prev) + .map(|(_, s)| s) + .unwrap_or(&CompletionStatus::None); + if *prev_status == CompletionStatus::Both { + unlocked.push(window[1]); + } else { + break; } } } else { @@ -317,13 +333,6 @@ async fn home_handler(State(pool): State, session: AxumSessionStore) -> } } - // Get completion status for all days at once - let did = session.get_did(); - let is_logged_in = session.logged_in(); - let all_statuses = get_all_days_completion_status(&pool, did.as_ref()) - .await - .unwrap_or_else(|_| (1..=25).map(|day| (day, CompletionStatus::None)).collect()); - // Filter to only include unlocked days let unlocked_with_status: Vec = all_statuses .into_iter() diff --git a/web/src/unlock.rs b/web/src/unlock.rs index 3faf473..821aaaf 100644 --- a/web/src/unlock.rs +++ b/web/src/unlock.rs @@ -1,13 +1,17 @@ -use axum::extract::{Path, Request}; +use crate::session::AxumSessionStore; +use axum::extract::{Path, Request, State}; use axum::http; use axum::{ middleware, response::{self, IntoResponse}, }; -use chrono::Datelike; +use shared::advent::{CompletionStatus, get_all_days_completion_status}; +use sqlx::PgPool; pub async fn unlock( + State(pool): State, Path(mut day): Path, + session: AxumSessionStore, request: Request, next: middleware::Next, ) -> response::Response { @@ -35,34 +39,40 @@ pub async fn unlock( .into_response(); } - let now = chrono::Utc::now(); - let current_day = now.day(); - let month = now.month(); + let implemented_days: Vec = vec![1, 2, 3]; - if month != 12 { + if !implemented_days.contains(&day) { return ( http::StatusCode::FORBIDDEN, - "It's not December yet! NO PEAKING", + "This day hasn't been created yet!", ) .into_response(); } - //Show any day previous to the current day and current day - if day as u32 <= current_day { - return next.run(request).await; - } + // First implemented day is always accessible + let pos = implemented_days.iter().position(|&d| d == day).unwrap(); + if pos > 0 { + let prev_day = implemented_days[pos - 1]; + let did = session.get_did(); + + let all_statuses = get_all_days_completion_status(&pool, did.as_ref()) + .await + .unwrap_or_else(|_| (1..=25).map(|d| (d, CompletionStatus::None)).collect()); - ( - http::StatusCode::FORBIDDEN, - "Now just hold on a minute. It ain't time yet.", - ) - .into_response() + let prev_status = all_statuses + .iter() + .find(|(d, _)| *d == prev_day) + .map(|(_, s)| s) + .unwrap_or(&CompletionStatus::None); - // Just commenting out for now if we do want a json endpoint and i forgot easiest way to return it - // let error_response = axum::Json(serde_json::json!({ - // "error": "Route Locked", - // "time_remaining_seconds": time_remaining.as_secs(), - // })); + if *prev_status != CompletionStatus::Both { + return ( + http::StatusCode::FORBIDDEN, + "Now just hold on a minute. It ain't time yet.", + ) + .into_response(); + } + } - // (http::StatusCode::FORBIDDEN, error_response).into_response() + next.run(request).await } -- 2.51.2