routes.py 6.9 KB

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