workbench.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. from __future__ import annotations
  2. import json
  3. from flask import g, jsonify, request
  4. from sqlalchemy import text
  5. from app import db
  6. from app.api.system import bp
  7. from app.core.system.permissions import READ_GOVERNANCE, require_permissions
  8. from app.core.workbench.registry import DEFAULT_LAYOUT, WIDGET_REGISTRY, validate_layout
  9. from app.models.result import failed, success
  10. @bp.route("/workbench/registry", methods=["GET"])
  11. @require_permissions(READ_GOVERNANCE)
  12. def workbench_registry():
  13. return jsonify(success(WIDGET_REGISTRY))
  14. @bp.route("/workbench/layout", methods=["GET"])
  15. @require_permissions(READ_GOVERNANCE)
  16. def get_workbench_layout():
  17. row = db.session.execute(text("SELECT layout_version, widgets FROM public.workbench_layouts WHERE user_id = CAST(:id AS uuid)"), {"id": g.current_user["id"]}).one_or_none()
  18. data = {"version": row[0], "widgets": row[1]} if row else {"version": 0, "widgets": DEFAULT_LAYOUT}
  19. return jsonify(success(data))
  20. @bp.route("/workbench/layout", methods=["PUT"])
  21. @require_permissions(READ_GOVERNANCE)
  22. def put_workbench_layout():
  23. body = request.get_json(silent=True) or {}
  24. try:
  25. widgets = validate_layout(body.get("widgets"))
  26. expected = int(request.headers.get("If-Match", body.get("version", 0)))
  27. except (ValueError, TypeError) as exc:
  28. return jsonify(failed(str(exc), code=400)), 400
  29. current = db.session.execute(text("SELECT layout_version FROM public.workbench_layouts WHERE user_id = CAST(:id AS uuid) FOR UPDATE"), {"id": g.current_user["id"]}).scalar_one_or_none()
  30. if (current or 0) != expected:
  31. db.session.rollback()
  32. return jsonify(failed("布局已被其他会话修改", code=409, data={"current_version": current or 0})), 409
  33. new_version = expected + 1
  34. db.session.execute(text("INSERT INTO public.workbench_layouts (user_id, layout_version, widgets) VALUES (CAST(:id AS uuid), :version, CAST(:widgets AS jsonb)) ON CONFLICT (user_id) DO UPDATE SET layout_version = EXCLUDED.layout_version, widgets = EXCLUDED.widgets, updated_at = CURRENT_TIMESTAMP"), {"id": g.current_user["id"], "version": new_version, "widgets": json.dumps(widgets)})
  35. db.session.commit()
  36. return jsonify(success({"version": new_version, "widgets": widgets}))