From 68cf43164d6b353ee4886bd61584415f98f5ebca Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Tue, 16 May 2023 02:06:56 +1000 Subject: [PATCH] Implement cleanup route --- api/Cargo.toml | 2 +- api/src/docs.rs | 7 +++++++ api/src/main.rs | 5 +++-- api/src/routes/tasks.rs | 23 +++++++++++++++++------ 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/api/Cargo.toml b/api/Cargo.toml index 0d5ff31..066af92 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -33,5 +33,5 @@ tower-http = { version = "0.4.0", features = ["cors", "trace"] } tower_governor = "0.0.4" tower = "0.4.13" utoipa = { version = "3.3.0", features = ["axum_extras", "preserve_order"] } -utoipa-swagger-ui = { version = "3.1.3", features = ["axum"] } +utoipa-swagger-ui = { version = "3.1.3", features = ["axum", "debug-embed"] } base64 = "0.21.0" diff --git a/api/src/docs.rs b/api/src/docs.rs index ae3ad11..34710a0 100644 --- a/api/src/docs.rs +++ b/api/src/docs.rs @@ -1,6 +1,8 @@ use crate::payloads; use crate::routes; +use utoipa::openapi::security::ApiKey; +use utoipa::openapi::security::ApiKeyValue; use utoipa::{ openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme}, Modify, OpenApi, @@ -30,6 +32,7 @@ use utoipa::{ (name = "info"), (name = "event"), (name = "person"), + (name = "tasks"), ), modifiers(&SecurityAddon), )] @@ -49,5 +52,9 @@ impl Modify for SecurityAddon { .build(), ), ); + openapi.components.as_mut().unwrap().add_security_scheme( + "cron-key", + SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::new("X-Cron-Key"))), + ); } } diff --git a/api/src/main.rs b/api/src/main.rs index 44bca8b..5459081 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -12,6 +12,7 @@ use tokio::sync::Mutex; use tower::ServiceBuilder; use tower_governor::{errors::display_error, governor::GovernorConfigBuilder, GovernorLayer}; use tower_http::{cors::CorsLayer, trace::TraceLayer}; +use tracing::Level; use utoipa::OpenApi; use utoipa_swagger_ui::SwaggerUi; @@ -32,7 +33,7 @@ pub type State = extract::State>>>; #[tokio::main] async fn main() { - tracing_subscriber::fmt::init(); + tracing_subscriber::fmt().with_max_level(Level::INFO).init(); // Load env dotenvy::dotenv().ok(); @@ -82,7 +83,7 @@ async fn main() { "/event/:event_id/people/:person_name", patch(person::update_person), ) - .route("/tasks/cleanup", patch(tasks::cleanup)) + .route("/tasks/cleanup", get(tasks::cleanup)) .with_state(shared_state) .layer(cors) .layer(rate_limit) diff --git a/api/src/routes/tasks.rs b/api/src/routes/tasks.rs index 4017f6d..b7a328f 100644 --- a/api/src/routes/tasks.rs +++ b/api/src/routes/tasks.rs @@ -1,6 +1,7 @@ use std::env; use axum::{extract, http::HeaderMap}; +use chrono::{Duration, Utc}; use common::Adaptor; use tracing::info; @@ -14,6 +15,7 @@ use crate::{errors::ApiError, State}; (status = 401, description = "Missing or incorrect X-Cron-Key header"), (status = 429, description = "Too many requests"), ), + security((), ("cron-key" = [])), tag = "tasks", )] /// Delete events older than 3 months @@ -22,10 +24,12 @@ pub async fn cleanup( headers: HeaderMap, ) -> Result<(), ApiError> { // Check cron key - let cron_key = headers.get("X-Cron-Key").ok_or(ApiError::NotAuthorized)?; - if let Ok(key) = env::var("CRON_KEY") { - if !key.is_empty() && *cron_key != key { - return Err(ApiError::NotAuthorized); + let cron_key_header = headers.get("X-Cron-Key"); + if let Some(cron_key) = cron_key_header { + if let Ok(key) = env::var("CRON_KEY") { + if !key.is_empty() && *cron_key != key { + return Err(ApiError::NotAuthorized); + } } } @@ -33,8 +37,15 @@ pub async fn cleanup( let adaptor = &state.lock().await.adaptor; - // TODO: - //let stats = adaptor.get_stats().await.map_err(ApiError::AdaptorError)?; + let result = adaptor + .delete_events(Utc::now() - Duration::days(90)) + .await + .map_err(ApiError::AdaptorError)?; + + info!( + "Cleanup successful: {} events and {} people removed", + result.event_count, result.person_count + ); Ok(()) }