Specs stay at repo root (cross-VM). Move deploy and code into logical projects with README per domain, updated manifest.yaml, and symlinks at legacy paths for VM122 backward compatibility.
101 lines
3.6 KiB
Python
101 lines
3.6 KiB
Python
"""SSE stream — purge domínio VM112 + Desk (Spec 017 Fase 2)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import queue
|
|
import threading
|
|
import time
|
|
from collections.abc import Iterator
|
|
from typing import Any
|
|
|
|
from app import auth, vm112_domains
|
|
|
|
|
|
def _sse(payload: dict[str, Any]) -> str:
|
|
return f"data: {json.dumps(payload, ensure_ascii=False)}\n\n"
|
|
|
|
|
|
def purge_sse_generator(domain: str, root_password: str, username: str) -> Iterator[str]:
|
|
domain = domain.lower().strip()
|
|
|
|
conn = auth.db()
|
|
try:
|
|
if not vm112_domains.verify_root_password(conn, root_password):
|
|
yield _sse({
|
|
"type": "error",
|
|
"step": vm112_domains._timeline_entry("Validação Root", "fail", "Senha Root incorrecta"),
|
|
})
|
|
return
|
|
finally:
|
|
conn.close()
|
|
|
|
yield _sse({"type": "step", "step": vm112_domains._timeline_entry("Validação Root + confirmação", "ok")})
|
|
yield _sse({
|
|
"type": "step",
|
|
"step": vm112_domains._timeline_entry(
|
|
"Purge VM112 — em execução",
|
|
"running",
|
|
"Carbonio, site, portal, Cloudflare, Traefik…",
|
|
),
|
|
})
|
|
|
|
vm112_result: dict[str, Any] = {"ok": False}
|
|
for kind, payload in vm112_domains.purge_vm112_with_poll(domain, poll_interval=2.0):
|
|
if kind == "step":
|
|
yield _sse({"type": "step", "step": payload, "phase": "vm112"})
|
|
elif kind == "heartbeat":
|
|
yield _sse({
|
|
"type": "heartbeat",
|
|
"elapsed": payload.get("elapsed", 0),
|
|
"label": "Purge VM112 — em execução",
|
|
})
|
|
elif kind == "final":
|
|
vm112_result = payload
|
|
if not vm112_result.get("ok", False):
|
|
yield _sse({
|
|
"type": "error",
|
|
"step": vm112_domains._timeline_entry(
|
|
"Purge VM112",
|
|
"fail",
|
|
str(vm112_result.get("error") or "falhou"),
|
|
),
|
|
})
|
|
return
|
|
break
|
|
|
|
conn = auth.db()
|
|
desk_counts: dict[str, int] = {}
|
|
try:
|
|
domain_l = domain.lower().strip()
|
|
like = f"%{domain_l}%"
|
|
desk_steps = (
|
|
("Desk — webhook_events", "webhook_events", "DELETE FROM webhook_events WHERE payload LIKE ?", (like,)),
|
|
("Desk — tickets", "tickets", "DELETE FROM tickets WHERE subject LIKE ? OR payload LIKE ?", (like, like)),
|
|
("Desk — audit_domains", "audit_domains", "DELETE FROM audit_domains WHERE domain = ?", (domain_l,)),
|
|
("Desk — assist_sessions", "assist_sessions", "DELETE FROM assist_sessions WHERE domain = ?", (domain_l,)),
|
|
("Desk — audit_checks", "audit_checks", "DELETE FROM audit_checks WHERE domain = ?", (domain_l,)),
|
|
)
|
|
for label, key, sql, params in desk_steps:
|
|
yield _sse({"type": "step", "step": vm112_domains._timeline_entry(label, "running")})
|
|
n = conn.execute(sql, params).rowcount
|
|
desk_counts[key] = n
|
|
yield _sse({
|
|
"type": "step",
|
|
"step": vm112_domains._timeline_entry(label, "ok", f"{n} registo(s) removido(s)"),
|
|
"phase": "desk",
|
|
})
|
|
conn.commit()
|
|
finally:
|
|
conn.close()
|
|
|
|
total_desk = sum(desk_counts.values())
|
|
done_step = vm112_domains._timeline_entry("Purge concluído", "ok", f"Desk: {total_desk} registo(s)")
|
|
yield _sse({
|
|
"type": "done",
|
|
"step": done_step,
|
|
"domain": domain,
|
|
"vm112": vm112_result,
|
|
"desk": desk_counts,
|
|
"by": username,
|
|
})
|