54 lines
1.8 KiB
Python
54 lines
1.8 KiB
Python
"""
|
|
routes/internal.py — Machine-callable endpoints for cron jobs.
|
|
|
|
Protected by CRON_SECRET (set in .env). No session auth required.
|
|
These routes are intentionally GET so they work with a plain `curl` call
|
|
from a systemd timer or crontab without needing CSRF tokens.
|
|
"""
|
|
|
|
import hmac
|
|
import logging
|
|
import os
|
|
|
|
from flask import Blueprint, jsonify, request
|
|
|
|
logger = logging.getLogger("routes.internal")
|
|
|
|
internal_bp = Blueprint("internal", __name__, url_prefix="/internal")
|
|
|
|
|
|
def _check_token() -> bool:
|
|
"""Return True if the request carries the correct CRON_SECRET."""
|
|
expected = os.environ.get("CRON_SECRET", "").strip()
|
|
if not expected:
|
|
logger.warning("CRON_SECRET not set — internal endpoints are disabled.")
|
|
return False
|
|
provided = request.args.get("token", "")
|
|
return hmac.compare_digest(provided, expected)
|
|
|
|
|
|
@internal_bp.route("/cron/shift-reminders")
|
|
def cron_shift_reminders():
|
|
"""
|
|
Called by a systemd timer (or any scheduler) every few minutes.
|
|
Sends reminder emails to staff with incomplete checks 40 min before shift end.
|
|
Each user+shift pair receives at most one reminder per calendar day.
|
|
|
|
Usage:
|
|
curl "https://your-server/internal/cron/shift-reminders?token=<CRON_SECRET>"
|
|
"""
|
|
if not _check_token():
|
|
return jsonify({"error": "unauthorized"}), 401
|
|
|
|
from routes.admin_shifts import do_send_incomplete_reminders
|
|
try:
|
|
result = do_send_incomplete_reminders(triggered_by_user_id=None)
|
|
logger.info(
|
|
f"cron/shift-reminders: sent={result['sent']} skipped={result['skipped']} "
|
|
f"total={result['total']}"
|
|
)
|
|
return jsonify(result)
|
|
except Exception as e:
|
|
logger.error(f"cron/shift-reminders error: {e}")
|
|
return jsonify({"error": str(e)}), 500
|