semantic_routes.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. """HTTP boundary for governed terms, code sets, metrics and field mappings."""
  2. from __future__ import annotations
  3. import io
  4. from flask import g, jsonify, request, send_file
  5. from app import db
  6. from app.api.data_development import bp
  7. from app.models.result import failed, success
  8. def get_semantic_governance_service():
  9. from app.core.data_research.semantic_governance import (
  10. SemanticGovernanceService,
  11. )
  12. from app.core.data_research.semantic_repository import (
  13. SqlAlchemySemanticGovernanceRepository,
  14. )
  15. from app.core.events.outbox import enqueue_outbox
  16. return SemanticGovernanceService(
  17. SqlAlchemySemanticGovernanceRepository(db.session),
  18. outbox_enqueue=lambda **event: enqueue_outbox(db.session, **event),
  19. )
  20. def _actor_uid():
  21. identity = getattr(g, "current_user", {}) or {}
  22. return identity.get("id") or identity.get("sub")
  23. def _error(error):
  24. db.session.rollback()
  25. if isinstance(error, LookupError):
  26. return jsonify(failed(str(error), code=404)), 404
  27. if isinstance(error, ValueError):
  28. return jsonify(failed(str(error), code=400)), 400
  29. if isinstance(error, RuntimeError):
  30. return jsonify(failed(str(error), code=409)), 409
  31. return jsonify(failed("语义治理请求处理失败", code=500)), 500
  32. @bp.route("/semantic-assets", methods=["GET"])
  33. def list_semantic_assets():
  34. try:
  35. records = get_semantic_governance_service().list(
  36. asset_kind=request.args.get("asset_kind"),
  37. status=request.args.get("status"),
  38. )
  39. return jsonify(success(records)), 200
  40. except Exception as error:
  41. return _error(error)
  42. @bp.route("/semantic-assets", methods=["POST"])
  43. def create_semantic_asset():
  44. payload = request.get_json(silent=True) or {}
  45. try:
  46. record = get_semantic_governance_service().create_draft(
  47. payload.get("asset_kind"),
  48. {key: value for key, value in payload.items() if key != "asset_kind"},
  49. actor_uid=_actor_uid(),
  50. )
  51. db.session.commit()
  52. return jsonify(success(record)), 201
  53. except Exception as error:
  54. return _error(error)
  55. @bp.route("/semantic-assets/<asset_uid>", methods=["GET"])
  56. def get_semantic_asset(asset_uid):
  57. try:
  58. return jsonify(
  59. success(get_semantic_governance_service().get(asset_uid))
  60. ), 200
  61. except Exception as error:
  62. return _error(error)
  63. @bp.route("/semantic-assets/<asset_uid>/versions", methods=["GET"])
  64. def list_semantic_asset_versions(asset_uid):
  65. try:
  66. return jsonify(
  67. success(
  68. get_semantic_governance_service().list_versions(asset_uid)
  69. )
  70. ), 200
  71. except Exception as error:
  72. return _error(error)
  73. @bp.route("/semantic-assets/<asset_uid>/reviews", methods=["GET"])
  74. def list_semantic_asset_reviews(asset_uid):
  75. try:
  76. return jsonify(
  77. success(get_semantic_governance_service().list_reviews(asset_uid))
  78. ), 200
  79. except Exception as error:
  80. return _error(error)
  81. @bp.route("/semantic-assets/<asset_uid>/audits", methods=["GET"])
  82. def list_semantic_asset_audits(asset_uid):
  83. try:
  84. return jsonify(
  85. success(get_semantic_governance_service().list_audits(asset_uid))
  86. ), 200
  87. except Exception as error:
  88. return _error(error)
  89. @bp.route("/semantic-assets/<asset_uid>/revisions", methods=["POST"])
  90. def revise_semantic_asset(asset_uid):
  91. payload = request.get_json(silent=True) or {}
  92. try:
  93. record = get_semantic_governance_service().revise(
  94. asset_uid,
  95. payload.get("definition") or {},
  96. expected_version=int(payload.get("expected_version")),
  97. reason=payload.get("reason"),
  98. actor_uid=_actor_uid(),
  99. )
  100. db.session.commit()
  101. return jsonify(success(record)), 201
  102. except Exception as error:
  103. return _error(error)
  104. @bp.route("/semantic-assets/<asset_uid>/submit", methods=["POST"])
  105. def submit_semantic_asset(asset_uid):
  106. payload = request.get_json(silent=True) or {}
  107. try:
  108. record = get_semantic_governance_service().submit(
  109. asset_uid,
  110. expected_version=int(payload.get("expected_version")),
  111. actor_uid=_actor_uid(),
  112. )
  113. db.session.commit()
  114. return jsonify(success(record)), 200
  115. except Exception as error:
  116. return _error(error)
  117. @bp.route("/semantic-assets/<asset_uid>/review", methods=["POST"])
  118. def review_semantic_asset(asset_uid):
  119. payload = request.get_json(silent=True) or {}
  120. try:
  121. record = get_semantic_governance_service().review(
  122. asset_uid,
  123. expected_version=int(payload.get("expected_version")),
  124. decision=payload.get("decision"),
  125. reason=payload.get("reason"),
  126. actor_uid=_actor_uid(),
  127. )
  128. db.session.commit()
  129. return jsonify(success(record)), 200
  130. except Exception as error:
  131. return _error(error)
  132. @bp.route("/semantic-assets/<asset_uid>/publish", methods=["POST"])
  133. def publish_semantic_asset(asset_uid):
  134. payload = request.get_json(silent=True) or {}
  135. try:
  136. record = get_semantic_governance_service().publish(
  137. asset_uid,
  138. expected_version=int(payload.get("expected_version")),
  139. actor_uid=_actor_uid(),
  140. )
  141. db.session.commit()
  142. return jsonify(success(record)), 200
  143. except Exception as error:
  144. return _error(error)
  145. @bp.route("/semantic-assets/<asset_uid>/rollback", methods=["POST"])
  146. def rollback_semantic_asset(asset_uid):
  147. payload = request.get_json(silent=True) or {}
  148. try:
  149. record = get_semantic_governance_service().rollback(
  150. asset_uid,
  151. target_version=int(payload.get("target_version")),
  152. expected_version=int(payload.get("expected_version")),
  153. reason=payload.get("reason"),
  154. actor_uid=_actor_uid(),
  155. )
  156. db.session.commit()
  157. return jsonify(success(record)), 200
  158. except Exception as error:
  159. return _error(error)
  160. @bp.route("/semantic-field-mappings", methods=["GET"])
  161. def list_semantic_field_mappings():
  162. try:
  163. records = get_semantic_governance_service().list_field_mappings(
  164. asset_uid=request.args.get("asset_uid"),
  165. data_element_uid=request.args.get("data_element_uid"),
  166. )
  167. return jsonify(success(records)), 200
  168. except Exception as error:
  169. return _error(error)
  170. @bp.route("/semantic-field-mappings", methods=["POST"])
  171. def create_semantic_field_mapping():
  172. try:
  173. record = get_semantic_governance_service().map_physical_field(
  174. request.get_json(silent=True) or {},
  175. actor_uid=_actor_uid(),
  176. )
  177. db.session.commit()
  178. return jsonify(success(record)), 201
  179. except Exception as error:
  180. return _error(error)
  181. @bp.route("/semantic-assets/export", methods=["GET"])
  182. def export_semantic_assets():
  183. from app.core.data_research.semantic_governance import SemanticExchange
  184. export_format = str(request.args.get("format") or "json").lower()
  185. try:
  186. assets = get_semantic_governance_service().list(status="published")
  187. exchange = SemanticExchange()
  188. if export_format == "rdf":
  189. content = exchange.export_rdf(assets)
  190. filename = "semantic-governance.rdf"
  191. mimetype = "application/rdf+xml"
  192. elif export_format == "json":
  193. content = exchange.export_json(assets)
  194. filename = "semantic-governance.json"
  195. mimetype = "application/json"
  196. else:
  197. raise ValueError("semantic export format is unsupported")
  198. return send_file(
  199. io.BytesIO(content),
  200. mimetype=mimetype,
  201. as_attachment=True,
  202. download_name=filename,
  203. )
  204. except Exception as error:
  205. return _error(error)