import html import json from urllib.parse import quote from fastapi import APIRouter, Depends, HTTPException, Request from fastapi.responses import HTMLResponse from app.auth import require_user from app.db.audit import log_audit_event from app.db.workers import get_worker, get_workers from app.templates.layout import page router = APIRouter() def render_worker_badge(online: bool) -> str: if online: return 'ONLINE' return 'OFFLINE' def pretty_json(value: str | None) -> str: if not value: return "{}" try: return json.dumps(json.loads(value), ensure_ascii=False, indent=2, sort_keys=True) except (TypeError, ValueError): return value @router.get("/workers", response_class=HTMLResponse) def workers_page(request: Request, user=Depends(require_user)): workers = get_workers() online_count = sum(1 for worker in workers if worker.get("online")) total_count = len(workers) offline_count = total_count - online_count log_audit_event( user, action="workers.view", target_type="workers", metadata={ "online": online_count, "offline": offline_count, "total": total_count, }, ) rows = "" for worker in workers: worker_id_raw = worker.get("worker_id", "") or "" worker_id = html.escape(worker_id_raw) worker_url_id = quote(worker_id_raw, safe="") status = html.escape(worker.get("status", "") or "") last_seen_at = html.escape(worker.get("last_seen_at", "") or "") started_at = html.escape(worker.get("started_at", "") or "") badge = render_worker_badge(bool(worker.get("online"))) current_job_id = worker.get("current_job_id") current_job = "" if current_job_id is not None: current_job_label = html.escape(str(current_job_id)) current_job = f'#{current_job_label}' rows += f""" {worker_id} {badge}
{status} {last_seen_at} {current_job} {started_at} Detail """ if not rows: rows = 'Zatím nejsou evidovaní žádní workeři.' return page( "Workers", f"""

Workers

Přehled worker procesů obsluhujících AppFactory joby.

Online Workers{online_count}
Offline Workers{offline_count}
Total Workers{total_count}

Workers

{rows}
Worker ID Status Last Seen Current Job Started At Akce
""", user=user, ) @router.get("/workers/{worker_id}", response_class=HTMLResponse) def worker_detail_page(worker_id: str, request: Request, user=Depends(require_user)): worker = get_worker(worker_id) if not worker: raise HTTPException(status_code=404, detail="Worker not found") log_audit_event( user, action="workers.view", target_type="worker", target_id=worker_id, ) worker_id_html = html.escape(worker.get("worker_id", "") or "") status = html.escape(worker.get("status", "") or "") last_seen_at = html.escape(worker.get("last_seen_at", "") or "") started_at = html.escape(worker.get("started_at", "") or "") badge = render_worker_badge(bool(worker.get("online"))) current_job_id = worker.get("current_job_id") current_job = "" if current_job_id is not None: current_job_label = html.escape(str(current_job_id)) current_job = f'#{current_job_label}' metadata = html.escape(pretty_json(worker.get("metadata_json"))) metadata_block = "" if worker.get("metadata_json"): metadata_block = f"""

Metadata

{metadata}
""" return page( f"Worker {worker_id_html}", f"""

Worker {worker_id_html}

← Zpět na workers

Souhrn

Worker ID{worker_id_html}
Status{badge}
{status}
Last Seen{last_seen_at}
Current Job{current_job}
Started At{started_at}
{metadata_block} """, user=user, )