vehicles.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. from typing import List, Optional
  2. from fastapi import APIRouter, Depends, HTTPException, Query, Path
  3. from web.schemas import (
  4. VehicleBase,
  5. VersionOut,
  6. BoardOut,
  7. StandardArtifactOut,
  8. FeatureOut,
  9. )
  10. from web.services.vehicles import get_vehicles_service, VehiclesService
  11. router = APIRouter(prefix="/vehicles", tags=["vehicles"])
  12. @router.get("", response_model=List[VehicleBase])
  13. async def list_vehicles(
  14. service: VehiclesService = Depends(get_vehicles_service)
  15. ):
  16. """
  17. Get list of all available vehicles.
  18. Returns:
  19. List of vehicles with their IDs and names.
  20. """
  21. return service.get_all_vehicles()
  22. @router.get(
  23. "/{vehicle_id}",
  24. response_model=VehicleBase,
  25. responses={
  26. 404: {"description": "Vehicle not found"}
  27. }
  28. )
  29. async def get_vehicle(
  30. vehicle_id: str = Path(..., description="Unique vehicle identifier"),
  31. service: VehiclesService = Depends(get_vehicles_service)
  32. ):
  33. """
  34. Get a specific vehicle by ID.
  35. Args:
  36. vehicle_id: The vehicle identifier (e.g., 'copter', 'plane')
  37. Returns:
  38. Vehicle details
  39. """
  40. vehicle = service.get_vehicle(vehicle_id)
  41. if not vehicle:
  42. raise HTTPException(
  43. status_code=404,
  44. detail=f"Vehicle with id '{vehicle_id}' not found"
  45. )
  46. return vehicle
  47. # --- Version Endpoints ---
  48. @router.get("/{vehicle_id}/versions", response_model=List[VersionOut])
  49. async def list_versions(
  50. vehicle_id: str = Path(..., description="Vehicle identifier"),
  51. type: Optional[str] = Query(
  52. None,
  53. description=(
  54. "Filter by version type "
  55. "(beta, stable, latest, tag)"
  56. )
  57. ),
  58. service: VehiclesService = Depends(get_vehicles_service)
  59. ):
  60. """
  61. Get all versions available for a specific vehicle.
  62. Args:
  63. vehicle_id: The vehicle identifier
  64. type: Optional filter by version type
  65. Returns:
  66. List of versions for the vehicle
  67. """
  68. return service.get_versions(vehicle_id, type_filter=type)
  69. @router.get(
  70. "/{vehicle_id}/versions/{version_id}",
  71. response_model=VersionOut,
  72. responses={
  73. 404: {"description": "Version not found for the vehicle"}
  74. }
  75. )
  76. async def get_version(
  77. vehicle_id: str = Path(..., description="Vehicle identifier"),
  78. version_id: str = Path(..., description="Version identifier"),
  79. service: VehiclesService = Depends(get_vehicles_service)
  80. ):
  81. """
  82. Get details of a specific version for a vehicle.
  83. Args:
  84. vehicle_id: The vehicle identifier
  85. version_id: The version identifier
  86. Returns:
  87. Version details
  88. """
  89. version = service.get_version(vehicle_id, version_id)
  90. if not version:
  91. raise HTTPException(
  92. status_code=404,
  93. detail=(
  94. f"Version '{version_id}' not found for "
  95. f"vehicle '{vehicle_id}'"
  96. )
  97. )
  98. return version
  99. # --- Board Endpoints ---
  100. @router.get(
  101. "/{vehicle_id}/versions/{version_id}/boards",
  102. response_model=List[BoardOut],
  103. responses={
  104. 404: {"description": "No boards found for the vehicle version"}
  105. }
  106. )
  107. async def list_boards(
  108. vehicle_id: str = Path(..., description="Vehicle identifier"),
  109. version_id: str = Path(..., description="Version identifier"),
  110. service: VehiclesService = Depends(get_vehicles_service)
  111. ):
  112. """
  113. Get all boards available for a specific vehicle version.
  114. Args:
  115. vehicle_id: The vehicle identifier
  116. version_id: The version identifier
  117. Returns:
  118. List of boards for the vehicle version
  119. """
  120. boards = service.get_boards(vehicle_id, version_id)
  121. if not boards:
  122. raise HTTPException(
  123. status_code=404,
  124. detail=(
  125. f"No boards found for vehicle '{vehicle_id}' and "
  126. f"version '{version_id}'"
  127. )
  128. )
  129. return boards
  130. @router.get(
  131. "/{vehicle_id}/versions/{version_id}/boards/{board_id}",
  132. response_model=BoardOut,
  133. responses={
  134. 404: {"description": "Board not found"}
  135. }
  136. )
  137. async def get_board(
  138. vehicle_id: str = Path(..., description="Vehicle identifier"),
  139. version_id: str = Path(..., description="Version identifier"),
  140. board_id: str = Path(..., description="Board identifier"),
  141. service: VehiclesService = Depends(get_vehicles_service)
  142. ):
  143. """
  144. Get details of a specific board for a vehicle version.
  145. Args:
  146. vehicle_id: The vehicle identifier
  147. version_id: The version identifier
  148. board_id: The board identifier
  149. Returns:
  150. Board details
  151. """
  152. board = service.get_board(vehicle_id, version_id, board_id)
  153. if not board:
  154. raise HTTPException(
  155. status_code=404,
  156. detail=f"Board '{board_id}' not found"
  157. )
  158. return board
  159. @router.get(
  160. "/{vehicle_id}/versions/{version_id}/boards/{board_id}/standard_artifacts",
  161. response_model=List[StandardArtifactOut],
  162. responses={
  163. 404: {"description": "Standard artifacts not found"},
  164. },
  165. )
  166. async def list_board_standard_artifacts(
  167. vehicle_id: str = Path(..., description="Vehicle identifier"),
  168. version_id: str = Path(..., description="Version identifier"),
  169. board_id: str = Path(..., description="Board identifier"),
  170. service: VehiclesService = Depends(get_vehicles_service),
  171. ):
  172. """
  173. Get standard build artifact files from firmware.ardupilot.org for a board.
  174. Only official manifest-backed versions include per-board artifact URLs.
  175. """
  176. artifacts = service.get_board_standard_artifacts(
  177. vehicle_id, version_id, board_id
  178. )
  179. if artifacts is None:
  180. raise HTTPException(
  181. status_code=404,
  182. detail=(
  183. f"Standard artifacts not found for board '{board_id}' "
  184. f"in vehicle '{vehicle_id}' version '{version_id}'"
  185. ),
  186. )
  187. return artifacts
  188. # --- Feature Endpoints ---
  189. @router.get(
  190. "/{vehicle_id}/versions/{version_id}/boards/{board_id}/features",
  191. response_model=List[FeatureOut]
  192. )
  193. async def list_features(
  194. vehicle_id: str = Path(..., description="Vehicle identifier"),
  195. version_id: str = Path(..., description="Version identifier"),
  196. board_id: str = Path(..., description="Board identifier"),
  197. category_id: Optional[str] = Query(
  198. None, description="Filter by category ID"
  199. ),
  200. service: VehiclesService = Depends(get_vehicles_service)
  201. ):
  202. """
  203. Get all features with defaults for a specific vehicle/version/board.
  204. Args:
  205. vehicle_id: The vehicle identifier
  206. version_id: The version identifier
  207. board_id: The board identifier
  208. category_id: Optional filter by category
  209. Returns:
  210. List of features with default settings for the board
  211. """
  212. features = service.get_features(
  213. vehicle_id, version_id, board_id, category_id
  214. )
  215. return features
  216. @router.get(
  217. "/{vehicle_id}/versions/{version_id}/boards/{board_id}/"
  218. "features/{feature_id}",
  219. response_model=FeatureOut,
  220. responses={
  221. 404: {"description": "Feature not found"}
  222. }
  223. )
  224. async def get_feature(
  225. vehicle_id: str = Path(..., description="Vehicle identifier"),
  226. version_id: str = Path(..., description="Version identifier"),
  227. board_id: str = Path(..., description="Board identifier"),
  228. feature_id: str = Path(..., description="Feature identifier"),
  229. service: VehiclesService = Depends(get_vehicles_service)
  230. ):
  231. """
  232. Get details of a specific feature for a vehicle/version/board.
  233. Args:
  234. vehicle_id: The vehicle identifier
  235. version_id: The version identifier
  236. board_id: The board identifier
  237. feature_id: The feature identifier
  238. Returns:
  239. Feature details with default settings
  240. """
  241. feature = service.get_feature(
  242. vehicle_id, version_id, board_id, feature_id
  243. )
  244. if not feature:
  245. raise HTTPException(
  246. status_code=404,
  247. detail=f"Feature '{feature_id}' not found"
  248. )
  249. return feature