import asyncio import logging from datetime import datetime, timedelta, timezone from ..db import ( get_users_expiring_by, get_expired_users, get_user_contact, mark_expiry_warning_sent, mark_expiry_disabled, mark_expiry_deleted, set_user_blocked, delete_user, ) from ..runtime import get_runtime_settings from .notifications import send_notification logger = logging.getLogger(__name__) async def run_expiry_loop() -> None: while True: runtime = get_runtime_settings() now = datetime.now(timezone.utc) warn_days = int(runtime.expiry_warning_days or 0) if warn_days > 0: cutoff = (now + timedelta(days=warn_days)).isoformat() for user in get_users_expiring_by(cutoff): contact = get_user_contact(user["username"]) or {} email = contact.get("email") await send_notification( "Account expiring soon", f"Your account expires on {user['expires_at']}.", channels=["email"] if email else [], email=email, ) mark_expiry_warning_sent(user["username"]) for expired in get_expired_users(now.isoformat()): action = (expired.get("action") or "disable").lower() if action in {"disable", "disable_then_delete"}: set_user_blocked(expired["username"], True) mark_expiry_disabled(expired["username"]) if action in {"delete", "disable_then_delete"}: delete_user(expired["username"]) mark_expiry_deleted(expired["username"]) delay = max(60, int(runtime.expiry_check_interval_minutes or 60) * 60) await asyncio.sleep(delay)