maker: camera e modo di analisi nel task visione (Refs #97)

Rotte /maker/api/camera/servizi e /maker/api/camera/sorgenti (url ammesso solo
se e' un servizio delle stazioni), sezione «Acquisizione» nell'editor task
(servizio, sorgente, analisi impulsiva/in linea) salvata come acquisition_json.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbf7qKuxsnAVjxthRy7dnB
This commit is contained in:
2026-10-24 18:26:00 +02:00
parent 552f96bb47
commit 25f8b4d609
4 changed files with 350 additions and 4 deletions
@@ -541,6 +541,55 @@ def api_list_stations_for_maker():
return jsonify(out), 200
def _camera_services() -> list[dict]:
"""#97: servizi di acquisizione distinti delle stazioni che hanno una camera_url."""
services: dict[str, list[str]] = {}
for st in _stations_for_maker():
url = (st.get("camera_url") or "").strip().rstrip("/")
if not url:
continue
label = f"{st.get('code') or ''} - {st.get('name') or ''}"
services.setdefault(url, []).append(label)
return [{"camera_url": u, "stazioni": s} for u, s in services.items()]
@maker_bp.route("/api/camera/servizi", methods=["GET"])
@login_required
@maker_or_admin_required
def api_camera_services():
"""#97: servizi di acquisizione fra cui scegliere la camera di un task."""
return jsonify({"servizi": _camera_services()}), 200
@maker_bp.route("/api/camera/sorgenti", methods=["GET"])
@login_required
@maker_or_admin_required
def api_camera_sources():
"""#97: proxy di GET {url}/camera/sources; solo per i servizi delle stazioni."""
url = (request.args.get("url") or "").strip().rstrip("/")
# Niente richieste verso indirizzi arbitrari: url ammesso solo se e' un servizio noto
if not url or url not in {s["camera_url"] for s in _camera_services()}:
return jsonify({
"error": True,
"detail": _("Servizio di acquisizione non ammesso"),
}), 400
try:
resp = http_requests.get(f"{url}/camera/sources", timeout=15)
body = resp.json() if resp.status_code == 200 else None
except (http_requests.RequestException, ValueError) as exc:
return jsonify({
"error": True,
"detail": _("Servizio camera non raggiungibile: %(detail)s", detail=str(exc)),
}), 502
sources = body.get("sources") if isinstance(body, dict) else None
if not isinstance(sources, list):
return jsonify({
"error": True,
"detail": _("Risposta del servizio camera non valida (%(status)s)", status=resp.status_code),
}), 502
return jsonify({"sources": sources}), 200
# Copia minima della logica di measure.api_vision_grab, ma per una stazione scelta per id
@maker_bp.route("/api/stations/<int:station_id>/camera/grab", methods=["GET", "POST"])
@login_required