this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

global lock

+79 -26
+3
.env.template
··· 9 9 # Set's the hostname for oauth 10 10 #OAUTH_HOST=advent.codes 11 11 12 + # Enable global day unlock via the settings table (for workshop use) 13 + #GLOBAL_UNLOCK_ENABLED=true 14 + 12 15 # Challenge account. The account that writes some records for challenges 13 16 CHALLENGE_PDS=https://skeetcentral.com 14 17 CHALLENGE_IDENTITY=
+8
migrations/20260327000000_create_settings.sql
··· 1 + CREATE TABLE IF NOT EXISTS settings ( 2 + id BIGSERIAL PRIMARY KEY, 3 + unlocked_up_to_day INT NOT NULL DEFAULT 1, 4 + CONSTRAINT settings_day_range CHECK (unlocked_up_to_day >= 1 AND unlocked_up_to_day <= 25) 5 + ); 6 + 7 + -- Insert a single default row 8 + INSERT INTO settings (unlocked_up_to_day) VALUES (1);
+10
shared/src/advent/mod.rs
··· 389 389 } 390 390 } 391 391 392 + /// Get the globally unlocked day from the settings table. 393 + /// Returns the day number that all users are unlocked up to. 394 + pub async fn get_global_unlock_day(pool: &PgPool) -> Result<u8, AdventError> { 395 + let result = sqlx::query_scalar::<_, i32>("SELECT unlocked_up_to_day FROM settings LIMIT 1") 396 + .fetch_optional(pool) 397 + .await?; 398 + 399 + Ok(result.unwrap_or(1) as u8) 400 + } 401 + 392 402 /// Get completion status for all 25 days at once 393 403 /// Returns a Vec of tuples (day_number, CompletionStatus) for days 1-25 394 404 pub async fn get_all_days_completion_status(
+39 -25
web/src/main.rs
··· 31 31 use rust_embed::RustEmbed; 32 32 use shared::{ 33 33 HandleResolver, OAuthClientType, PasswordAgent, 34 - advent::{CompletionStatus, get_all_days_completion_status}, 34 + advent::{CompletionStatus, get_all_days_completion_status, get_global_unlock_day}, 35 35 atrium::dns_resolver::HickoryDnsTxtResolver, 36 36 atrium::stores::AtriumSessionStore, 37 37 atrium::stores::AtriumStateStore, ··· 341 341 .await 342 342 .unwrap_or_else(|_| (1..=25).map(|day| (day, CompletionStatus::None)).collect()); 343 343 344 - //HACK Yeah I don't like it either - bt 345 - let prod: bool = env::var("PROD") 346 - .map(|val| val == "true") 347 - .unwrap_or_else(|_| true); 348 - if prod { 344 + let global_unlock_enabled = env::var("GLOBAL_UNLOCK_ENABLED") 345 + .map(|v| v == "true") 346 + .unwrap_or(false); 347 + 348 + if global_unlock_enabled { 349 + let global_unlock_day = get_global_unlock_day(&pool).await.unwrap_or(1); 349 350 let implemented_days = shared::advent::get_implemented_days(); 350 - if let Some(&first) = implemented_days.first() { 351 - unlocked.push(first); 352 - } 353 - for window in implemented_days.windows(2) { 354 - let prev = window[0]; 355 - let prev_status = all_statuses 356 - .iter() 357 - .find(|(d, _)| *d == prev) 358 - .map(|(_, s)| s) 359 - .unwrap_or(&CompletionStatus::None); 360 - if *prev_status == CompletionStatus::Both { 361 - unlocked.push(window[1]); 362 - } else if (prev == 4 || prev == 5) && *prev_status == CompletionStatus::PartOne { 363 - //HACK hardcoded for the workshop since we don't have a part 2 for day 4 364 - unlocked.push(window[1]); 365 - } else { 366 - break; 351 + for d in implemented_days { 352 + if d <= global_unlock_day { 353 + unlocked.push(d); 367 354 } 368 355 } 369 356 } else { 370 - for d in 1..=25 { 371 - unlocked.push(d as u8); 357 + //HACK Yeah I don't like it either - bt 358 + let prod: bool = env::var("PROD") 359 + .map(|val| val == "true") 360 + .unwrap_or_else(|_| true); 361 + if prod { 362 + let implemented_days = shared::advent::get_implemented_days(); 363 + if let Some(&first) = implemented_days.first() { 364 + unlocked.push(first); 365 + } 366 + for window in implemented_days.windows(2) { 367 + let prev = window[0]; 368 + let prev_status = all_statuses 369 + .iter() 370 + .find(|(d, _)| *d == prev) 371 + .map(|(_, s)| s) 372 + .unwrap_or(&CompletionStatus::None); 373 + if *prev_status == CompletionStatus::Both { 374 + unlocked.push(window[1]); 375 + } else if (prev == 4 || prev == 5) && *prev_status == CompletionStatus::PartOne { 376 + //HACK hardcoded for the workshop since we don't have a part 2 for day 4 377 + unlocked.push(window[1]); 378 + } else { 379 + break; 380 + } 381 + } 382 + } else { 383 + for d in 1..=25 { 384 + unlocked.push(d as u8); 385 + } 372 386 } 373 387 } 374 388
+19 -1
web/src/unlock.rs
··· 5 5 middleware, 6 6 response::{self, IntoResponse}, 7 7 }; 8 - use shared::advent::{CompletionStatus, get_all_days_completion_status}; 8 + use shared::advent::{CompletionStatus, get_all_days_completion_status, get_global_unlock_day}; 9 9 use sqlx::PgPool; 10 10 11 11 pub async fn unlock( ··· 45 45 "This day hasn't been created yet!", 46 46 ) 47 47 .into_response(); 48 + } 49 + 50 + // Check if the day is globally unlocked via the settings table 51 + let global_unlock_enabled = std::env::var("GLOBAL_UNLOCK_ENABLED") 52 + .map(|v| v == "true") 53 + .unwrap_or(false); 54 + 55 + if global_unlock_enabled { 56 + let global_unlock_day = get_global_unlock_day(&pool).await.unwrap_or(1); 57 + if day <= global_unlock_day { 58 + return next.run(request).await; 59 + } else { 60 + return ( 61 + http::StatusCode::FORBIDDEN, 62 + "Now just hold on a minute. It ain't time yet.", 63 + ) 64 + .into_response(); 65 + } 48 66 } 49 67 50 68 // First implemented day is always accessible