routes.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. from datetime import datetime
  2. from typing import TypeVar
  3. from uuid import uuid4
  4. from core_domain import ServiceHealth
  5. from core_shared import error_detail
  6. from fastapi import APIRouter, Depends, HTTPException
  7. from sqlalchemy import text
  8. from sqlalchemy.orm import Session
  9. from app.application.services import SkillApplicationService
  10. from app.db.session import get_db
  11. from app.domain.repositories import (
  12. SkillDefinitionRepository,
  13. SkillInstallationRepository,
  14. SkillRunRepository,
  15. )
  16. from app.schemas.skill import (
  17. ApiResponse,
  18. DeleteData,
  19. PageResult,
  20. SkillCreateRequestDto,
  21. SkillDefinitionDto,
  22. SkillDeleteRequestDto,
  23. SkillDetailRequestDto,
  24. SkillInstallRequestDto,
  25. SkillInstallationDto,
  26. SkillInstallationListRequestDto,
  27. SkillInstallationStatusRequestDto,
  28. SkillListRequestDto,
  29. SkillRunCreateRequestDto,
  30. SkillRunDto,
  31. SkillRunExecuteRequestDto,
  32. SkillStatusRequestDto,
  33. SkillUpdateRequestDto,
  34. )
  35. router = APIRouter()
  36. T = TypeVar("T")
  37. def ok(data: T) -> ApiResponse[T]:
  38. return ApiResponse(
  39. success=True,
  40. data=data,
  41. error=None,
  42. requestId=str(uuid4()),
  43. serverTime=datetime.utcnow())
  44. def get_skill_application_service(db: Session = Depends(get_db)) -> SkillApplicationService:
  45. return SkillApplicationService(
  46. skill_repository=SkillDefinitionRepository(db),
  47. installation_repository=SkillInstallationRepository(db),
  48. skill_run_repository=SkillRunRepository(db))
  49. @router.get("/health", response_model=ServiceHealth)
  50. def health_check(db: Session = Depends(get_db)) -> ServiceHealth:
  51. db.execute(text("SELECT 1"))
  52. return ServiceHealth(service="skill-service", status="ok", database="ok")
  53. @router.post("/list", response_model=ApiResponse[PageResult[SkillDefinitionDto]])
  54. def list_skills_contract(
  55. payload: SkillListRequestDto,
  56. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[PageResult[SkillDefinitionDto]]:
  57. items, total = service.list_skills_contract(payload)
  58. return ok(PageResult[SkillDefinitionDto].from_items(
  59. items=[SkillDefinitionDto.from_entity(item) for item in items],
  60. total=total,
  61. page=payload.page,
  62. page_size=payload.pageSize))
  63. @router.post("/create", response_model=ApiResponse[SkillDefinitionDto])
  64. def create_skill_contract(
  65. payload: SkillCreateRequestDto,
  66. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillDefinitionDto]:
  67. return ok(SkillDefinitionDto.from_entity(service.create_skill_from_contract(payload)))
  68. @router.post("/detail", response_model=ApiResponse[SkillDefinitionDto])
  69. def detail_skill_contract(
  70. payload: SkillDetailRequestDto,
  71. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillDefinitionDto]:
  72. entity = service.skill_repository.get_by_id(skill_id=payload.skillId)
  73. if entity is None:
  74. raise HTTPException(status_code=404, detail=error_detail("error.skill.not_found", id=payload.skillId))
  75. return ok(SkillDefinitionDto.from_entity(entity))
  76. @router.post("/update", response_model=ApiResponse[SkillDefinitionDto])
  77. def update_skill_contract(
  78. payload: SkillUpdateRequestDto,
  79. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillDefinitionDto]:
  80. entity = service.update_skill(payload)
  81. if entity is None:
  82. raise HTTPException(status_code=404, detail=error_detail("error.skill.not_found", id=payload.skillId))
  83. return ok(SkillDefinitionDto.from_entity(entity))
  84. @router.post("/status", response_model=ApiResponse[SkillDefinitionDto])
  85. def update_skill_status_contract(
  86. payload: SkillStatusRequestDto,
  87. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillDefinitionDto]:
  88. entity = service.update_skill_status_contract(payload)
  89. if entity is None:
  90. raise HTTPException(status_code=404, detail=error_detail("error.skill.not_found", id=payload.skillId))
  91. return ok(SkillDefinitionDto.from_entity(entity))
  92. @router.post("/delete", response_model=ApiResponse[DeleteData])
  93. def delete_skill_contract(
  94. payload: SkillDeleteRequestDto,
  95. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[DeleteData]:
  96. entity = service.delete_skill(payload)
  97. if entity is None:
  98. raise HTTPException(status_code=404, detail=error_detail("error.skill.not_found", id=payload.skillId))
  99. return ok(DeleteData(deleted=True, skillId=payload.skillId))
  100. @router.post("/installations/list", response_model=ApiResponse[PageResult[SkillInstallationDto]])
  101. def list_installations_contract(
  102. payload: SkillInstallationListRequestDto,
  103. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[PageResult[SkillInstallationDto]]:
  104. items, total = service.list_installations_contract(payload)
  105. return ok(PageResult[SkillInstallationDto].from_items(
  106. items=[SkillInstallationDto.from_entity(item) for item in items],
  107. total=total,
  108. page=payload.page,
  109. page_size=payload.pageSize))
  110. @router.post("/installations/create", response_model=ApiResponse[SkillInstallationDto])
  111. def install_skill_contract(
  112. payload: SkillInstallRequestDto,
  113. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillInstallationDto]:
  114. try:
  115. return ok(SkillInstallationDto.from_entity(service.install_skill_from_contract(payload)))
  116. except ValueError as exc:
  117. raise HTTPException(status_code=422, detail=error_detail("error.validation", message=str(exc))) from exc
  118. @router.post("/installations/status", response_model=ApiResponse[SkillInstallationDto])
  119. def update_installation_status_contract(
  120. payload: SkillInstallationStatusRequestDto,
  121. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillInstallationDto]:
  122. entity = service.update_installation_status_contract(payload)
  123. if entity is None:
  124. raise HTTPException(status_code=404, detail=error_detail("error.skill_installation.not_found", id=payload.installationId))
  125. return ok(SkillInstallationDto.from_entity(entity))
  126. @router.post("/runs/create", response_model=ApiResponse[SkillRunDto])
  127. def create_skill_run(
  128. payload: SkillRunCreateRequestDto,
  129. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillRunDto]:
  130. try:
  131. return ok(SkillRunDto.from_entity(service.create_skill_run_from_contract(payload)))
  132. except ValueError as exc:
  133. raise HTTPException(status_code=422, detail=error_detail("error.validation", message=str(exc))) from exc
  134. @router.post("/runs/execute", response_model=ApiResponse[SkillRunDto])
  135. def execute_skill_run(
  136. payload: SkillRunExecuteRequestDto,
  137. service: SkillApplicationService = Depends(get_skill_application_service)) -> ApiResponse[SkillRunDto]:
  138. entity = service.execute_skill_run_from_contract(payload)
  139. if entity is None:
  140. raise HTTPException(status_code=404, detail=error_detail("error.skill_run.not_found", id=payload.skillRunId))
  141. return ok(SkillRunDto.from_entity(entity))