use crate::session::AxumSessionStore; use axum::extract::{Path, Request, State}; use axum::http; use axum::{ middleware, response::{self, IntoResponse}, }; use shared::advent::{CompletionStatus, get_all_days_completion_status, get_global_unlock_day}; use sqlx::PgPool; pub async fn unlock( State(pool): State, Path(mut day): Path, session: AxumSessionStore, request: Request, next: middleware::Next, ) -> response::Response { if day == 0 { day = 1; } if day == 69 { return (http::StatusCode::FORBIDDEN, "Really?").into_response(); } if day == 42 { return ( http::StatusCode::FORBIDDEN, "Oh, you have all the answers, huh?", ) .into_response(); } if day > 25 || day < 1 { return ( http::StatusCode::FORBIDDEN, "This isn't even a day in the advent calendar????", ) .into_response(); } let implemented_days = shared::advent::get_implemented_days(); if !implemented_days.contains(&day) { return ( http::StatusCode::FORBIDDEN, "This day hasn't been created yet!", ) .into_response(); } // Check if the day is globally unlocked via the settings table let global_unlock_enabled = std::env::var("GLOBAL_UNLOCK_ENABLED") .map(|v| v == "true") .unwrap_or(false); if global_unlock_enabled { let global_unlock_day = get_global_unlock_day(&pool).await.unwrap_or(1); if day <= global_unlock_day { return next.run(request).await; } else { return ( http::StatusCode::FORBIDDEN, "Now just hold on a minute. It ain't time yet.", ) .into_response(); } } // 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()); let prev_status = all_statuses .iter() .find(|(d, _)| *d == prev_day) .map(|(_, s)| s) .unwrap_or(&CompletionStatus::None); //HACK hardcoded for the workshop since we don't have a part 2 for day 4 if (pos == 4 || pos == 5) && *prev_status == CompletionStatus::PartOne { return next.run(request).await; } if *prev_status != CompletionStatus::Both { return ( http::StatusCode::FORBIDDEN, "Now just hold on a minute. It ain't time yet.", ) .into_response(); } } next.run(request).await }