Backend (5→7 files): - api_test.py: 622→479, terraform functions → operations/terraform.py (142) - api_scenario.py: 241→split into run (153) + defs (108) with _validate_steps() - db/scenario_defs.py: +client_id, stand, is_seed in list_definitions Frontend (1→10 files): - app.js: 554→16 (loader), split into: utils.js (45), instances.js (89), operations.js (249), history.js (35), scenario-list.js (90) - New CRUD: scenario-form.js (128), create (25), edit (12), delete (13) Max file size: JS 249, PY 479
109 lines
4.1 KiB
Python
109 lines
4.1 KiB
Python
"""
|
||
CRUD определений сценариев.
|
||
|
||
GET /api/scenario/definitions — список
|
||
POST /api/scenario/definitions — создать
|
||
GET /api/scenario/definitions/<id> — один
|
||
PUT /api/scenario/definitions/<id> — обновить (version → 409)
|
||
DELETE /api/scenario/definitions/<id> — мягкое удаление
|
||
"""
|
||
|
||
from flask import Blueprint, jsonify, request
|
||
from api.auth import get_client_id, get_stand, get_token_info
|
||
from db.scenario_defs import (
|
||
list_definitions, get_definition, create_definition,
|
||
update_definition, delete_definition,
|
||
)
|
||
|
||
bp_defs = Blueprint("api_scenario_defs", __name__)
|
||
|
||
|
||
def _validate_steps(steps):
|
||
"""Проверить структуру шагов сценария. Возвращает None или str с ошибкой."""
|
||
if not isinstance(steps, list) or len(steps) == 0:
|
||
return "Шаги: непустой массив"
|
||
for i, s in enumerate(steps):
|
||
if not isinstance(s, dict):
|
||
return f"Шаг {i+1}: должен быть объектом"
|
||
svc_id = s.get("service_id")
|
||
if not isinstance(svc_id, int) or svc_id <= 0:
|
||
return f"Шаг {i+1}: service_id — положительный int"
|
||
op = (s.get("operation") or "").strip()
|
||
if not op:
|
||
return f"Шаг {i+1}: operation обязателен"
|
||
if not isinstance(s.get("params", {}), dict):
|
||
return f"Шаг {i+1}: params — объект"
|
||
return None
|
||
|
||
|
||
@bp_defs.route("/api/scenario/definitions", methods=["GET", "POST"])
|
||
def api_definitions():
|
||
cid = get_client_id()
|
||
stand = get_stand()
|
||
|
||
if request.method == "GET":
|
||
try:
|
||
defs = list_definitions(cid, stand)
|
||
return jsonify(defs)
|
||
except Exception as e:
|
||
return jsonify({"error": str(e)}), 500
|
||
|
||
if request.method == "POST":
|
||
try:
|
||
data = request.get_json()
|
||
name = (data.get("name") or "").strip()
|
||
if not name:
|
||
return jsonify({"error": "name is required"}), 400
|
||
steps = data.get("steps", [])
|
||
err = _validate_steps(steps)
|
||
if err:
|
||
return jsonify({"error": err}), 400
|
||
user = get_token_info().get("email", "")
|
||
result = create_definition(cid, stand, name, steps, user)
|
||
if result is None:
|
||
return jsonify({"error": "create failed"}), 500
|
||
return jsonify(result), 201
|
||
except Exception as e:
|
||
return jsonify({"error": str(e)}), 500
|
||
|
||
|
||
@bp_defs.route("/api/scenario/definitions/<int:def_id>", methods=["GET", "PUT", "DELETE"])
|
||
def api_definition(def_id):
|
||
cid = get_client_id()
|
||
stand = get_stand()
|
||
|
||
if request.method == "GET":
|
||
d = get_definition(def_id, cid, stand)
|
||
if not d:
|
||
return jsonify({"error": "not found"}), 404
|
||
return jsonify(d)
|
||
|
||
if request.method == "PUT":
|
||
try:
|
||
data = request.get_json()
|
||
name = (data.get("name") or "").strip()
|
||
version = data.get("version")
|
||
if not name:
|
||
return jsonify({"error": "name is required"}), 400
|
||
if not isinstance(version, int):
|
||
return jsonify({"error": "version (int) is required"}), 400
|
||
steps = data.get("steps", [])
|
||
err = _validate_steps(steps)
|
||
if err:
|
||
return jsonify({"error": err}), 400
|
||
user = get_token_info().get("email", "")
|
||
result = update_definition(def_id, cid, stand, name, steps, version, user)
|
||
if result.get("conflict"):
|
||
return jsonify({"error": "Conflict: definition was modified"}), 409
|
||
if result.get("error"):
|
||
return jsonify({"error": result["error"]}), 500
|
||
return jsonify(result)
|
||
except Exception as e:
|
||
return jsonify({"error": str(e)}), 500
|
||
|
||
if request.method == "DELETE":
|
||
ok = delete_definition(def_id, cid, stand)
|
||
if not ok:
|
||
return jsonify({"error": "not found"}), 404
|
||
return jsonify({"ok": True})
|