tasks.rs 165 lignes · 6488 octets
//! Background tasks and timing configuration
//!
//! All timeouts, intervals, expiration durations, and rate limits
//! that were previously hardcoded. Each reads from an environment
//! variable with a sensible default.

use std::env;

fn env_u64(key: &str, default: u64) -> u64 {
    env::var(key)
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(default)
}

fn env_i64(key: &str, default: i64) -> i64 {
    env::var(key)
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(default)
}

fn env_usize(key: &str, default: usize) -> usize {
    env::var(key)
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(default)
}

// ── Email queue processor ──────────────────────────────────────────

/// Interval between email queue processing runs (seconds).
/// Env: `EMAIL_QUEUE_INTERVAL_SECS` — default 30
pub fn email_queue_interval_secs() -> u64 {
    env_u64("EMAIL_QUEUE_INTERVAL_SECS", 30)
}

// ── Password change email retry ────────────────────────────────────

/// Interval between password-change email retry runs (seconds).
/// Env: `PASSWORD_CHANGE_RETRY_INTERVAL_SECS` — default 600 (10 min)
pub fn password_change_retry_interval_secs() -> u64 {
    env_u64("PASSWORD_CHANGE_RETRY_INTERVAL_SECS", 600)
}

/// Minimum gap between two retry attempts for the same request (minutes).
/// Env: `PASSWORD_CHANGE_RETRY_GAP_MINUTES` — default 20
pub fn password_change_retry_gap_minutes() -> i64 {
    env_i64("PASSWORD_CHANGE_RETRY_GAP_MINUTES", 20)
}

/// Max retry count for password-change confirmation emails.
/// Env: `PASSWORD_CHANGE_MAX_RETRIES` — default 3
pub fn password_change_max_retries() -> i64 {
    env_i64("PASSWORD_CHANGE_MAX_RETRIES", 3)
}

// ── Password change cleanup ────────────────────────────────────────

/// Interval between cleanup runs for expired password-change requests (seconds).
/// Env: `PASSWORD_CHANGE_CLEANUP_INTERVAL_SECS` — default 86400 (24 h)
pub fn password_change_cleanup_interval_secs() -> u64 {
    env_u64("PASSWORD_CHANGE_CLEANUP_INTERVAL_SECS", 86400)
}

// ── JWT blacklist cleanup ──────────────────────────────────────────

/// Interval between JWT blacklist cleanup runs (seconds).
/// Env: `JWT_CLEANUP_INTERVAL_SECS` — default 3600 (1 h)
pub fn jwt_cleanup_interval_secs() -> u64 {
    env_u64("JWT_CLEANUP_INTERVAL_SECS", 3600)
}

// ── Personal access token cleanup ──────────────────────────────────

/// Interval between PAT cleanup runs (seconds).
/// Env: `PERSONAL_TOKEN_CLEANUP_INTERVAL_SECS` — default 3600 (1 h)
pub fn personal_token_cleanup_interval_secs() -> u64 {
    env_u64("PERSONAL_TOKEN_CLEANUP_INTERVAL_SECS", 3600)
}

// ── Token expiration durations ─────────────────────────────────────

/// Password-change request expiration (hours).
/// Env: `PASSWORD_CHANGE_EXPIRATION_HOURS` — default 24
pub fn password_change_expiration_hours() -> i64 {
    env_i64("PASSWORD_CHANGE_EXPIRATION_HOURS", 24)
}

/// Password-reset token expiration (hours).
/// Env: `PASSWORD_RESET_EXPIRATION_HOURS` — default 1
pub fn password_reset_expiration_hours() -> i64 {
    env_i64("PASSWORD_RESET_EXPIRATION_HOURS", 1)
}

/// Email validation token expiration (hours).
/// Env: `EMAIL_VALIDATION_EXPIRATION_HOURS` — default 24
pub fn email_validation_expiration_hours() -> i64 {
    env_i64("EMAIL_VALIDATION_EXPIRATION_HOURS", 24)
}

// ── Rate limits (password change) ──────────────────────────────────

/// Max password-change requests per user in the rate-limit window.
/// Env: `PASSWORD_CHANGE_RATE_LIMIT_MAX` — default 3
pub fn password_change_rate_limit_max() -> usize {
    env_usize("PASSWORD_CHANGE_RATE_LIMIT_MAX", 3)
}

/// Rate-limit window for password-change requests (seconds).
/// Env: `PASSWORD_CHANGE_RATE_LIMIT_WINDOW_SECS` — default 3600 (1 h)
pub fn password_change_rate_limit_window_secs() -> u64 {
    env_u64("PASSWORD_CHANGE_RATE_LIMIT_WINDOW_SECS", 3600)
}

// ── IMAP timeouts ──────────────────────────────────────────────────

/// IMAP read/write socket timeout (seconds).
/// Env: `IMAP_SOCKET_TIMEOUT_SECS` — default 30
pub fn imap_socket_timeout_secs() -> u64 {
    env_u64("IMAP_SOCKET_TIMEOUT_SECS", 30)
}

// ── Cookie max-age ─────────────────────────────────────────────────

/// Max-age for non-session cookies like locale and theme (seconds).
/// Env: `COOKIE_PREFERENCE_MAX_AGE_SECS` — default 31536000 (1 year)
pub fn cookie_preference_max_age_secs() -> i64 {
    env_i64("COOKIE_PREFERENCE_MAX_AGE_SECS", 31536000)
}

// ── Pagination defaults ────────────────────────────────────────────

/// Default page size when not specified by the client.
/// Env: `PAGINATION_DEFAULT_PER_PAGE` — default 50
pub fn pagination_default_per_page() -> u64 {
    env_u64("PAGINATION_DEFAULT_PER_PAGE", 50)
}

/// Maximum page size a client may request.
/// Env: `PAGINATION_MAX_PER_PAGE` — default 100
pub fn pagination_max_per_page() -> u64 {
    env_u64("PAGINATION_MAX_PER_PAGE", 100)
}

// ── Default locale ─────────────────────────────────────────────────

/// Default locale when none is set.
/// Env: `DEFAULT_LOCALE` — default "fr"
pub fn default_locale() -> String {
    env::var("DEFAULT_LOCALE").unwrap_or_else(|_| "fr".to_string())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_defaults() {
        assert_eq!(email_queue_interval_secs(), 30);
        assert_eq!(password_reset_expiration_hours(), 1);
        assert_eq!(default_locale(), "fr");
        assert_eq!(pagination_max_per_page(), 100);
    }
}