responsibilities.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. from __future__ import annotations
  2. from flask import g, jsonify, request
  3. from app import db
  4. from app.api.system import bp
  5. from app.core.governance.responsibilities import (
  6. ResponsibilityConflict,
  7. ResponsibilityService,
  8. ResponsibilityUserUnavailable,
  9. ResponsibilityValidationError,
  10. SqlAlchemyResponsibilityRepository,
  11. )
  12. from app.core.system.permissions import (
  13. RESPONSIBILITIES_MANAGE,
  14. RESPONSIBILITIES_READ,
  15. require_permissions,
  16. )
  17. from app.models.result import failed, success
  18. def _service() -> ResponsibilityService:
  19. return ResponsibilityService(SqlAlchemyResponsibilityRepository(db.session))
  20. def _etag(response, revision: int):
  21. response.headers["ETag"] = f'"{int(revision)}"'
  22. return response
  23. def _expected_revision() -> int:
  24. raw = str(request.headers.get("If-Match") or "").strip()
  25. if raw.startswith("W/"):
  26. raw = raw[2:].strip()
  27. raw = raw.strip('"')
  28. if not raw or not raw.isdigit():
  29. raise ResponsibilityValidationError("missing valid If-Match revision")
  30. return int(raw)
  31. @bp.route(
  32. "/responsibilities/<resource_type>/<resource_uid>",
  33. methods=["GET"],
  34. )
  35. @require_permissions(RESPONSIBILITIES_READ)
  36. def get_responsibility_matrix(resource_type: str, resource_uid: str):
  37. try:
  38. result = _service().get(resource_type, resource_uid)
  39. return _etag(jsonify(success(result)), result["revision"])
  40. except ResponsibilityValidationError as exc:
  41. return jsonify(failed(str(exc), code=400)), 400
  42. @bp.route(
  43. "/responsibilities/<resource_type>/<resource_uid>",
  44. methods=["PUT"],
  45. )
  46. @require_permissions(RESPONSIBILITIES_MANAGE)
  47. def replace_responsibility_matrix(resource_type: str, resource_uid: str):
  48. try:
  49. revision = _expected_revision()
  50. body = request.get_json(silent=True) or {}
  51. result = _service().replace(
  52. resource_type=resource_type,
  53. resource_uid=resource_uid,
  54. assignments=body.get("assignments"),
  55. expected_revision=revision,
  56. actor_uid=g.current_user["id"],
  57. )
  58. db.session.commit()
  59. return _etag(jsonify(success(result, "责任矩阵已更新")), result["revision"])
  60. except ResponsibilityConflict as exc:
  61. db.session.rollback()
  62. return jsonify(failed(str(exc), code=409)), 409
  63. except ResponsibilityUserUnavailable as exc:
  64. db.session.rollback()
  65. return jsonify(failed(str(exc), code=422)), 422
  66. except ResponsibilityValidationError as exc:
  67. db.session.rollback()
  68. status = 428 if "If-Match" in str(exc) else 400
  69. return jsonify(failed(str(exc), code=status)), status