devices.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. """
  2. Superadmin endpoints for device management.
  3. """
  4. from typing import Annotated
  5. from fastapi import APIRouter, Depends, HTTPException, Query, status
  6. from sqlalchemy.ext.asyncio import AsyncSession
  7. from app.api.deps import get_current_superadmin
  8. from app.core.database import get_db
  9. from app.models.user import User
  10. from app.schemas.device import (
  11. DeviceCreate,
  12. DeviceListResponse,
  13. DeviceResponse,
  14. DeviceUpdate,
  15. )
  16. from app.services import device_service
  17. router = APIRouter()
  18. @router.get("", response_model=DeviceListResponse)
  19. async def list_devices(
  20. db: Annotated[AsyncSession, Depends(get_db)],
  21. current_user: Annotated[User, Depends(get_current_superadmin)],
  22. skip: int = Query(0, ge=0, description="Number of records to skip"),
  23. limit: int = Query(100, ge=1, le=1000, description="Max records to return"),
  24. organization_id: int | None = Query(
  25. None, description="Filter by organization"
  26. ),
  27. status: str | None = Query(None, description="Filter by status"),
  28. search: str | None = Query(
  29. None,
  30. min_length=2,
  31. description="Universal search: MAC, simple_id, organization name/email",
  32. ),
  33. ):
  34. """
  35. List all devices (superadmin only).
  36. Returns paginated list of devices with optional filters.
  37. Search parameter searches across:
  38. - MAC address
  39. - Simple ID (#1, #2, etc)
  40. - Organization name
  41. - Organization contact email
  42. """
  43. devices, total = await device_service.list_devices(
  44. db,
  45. skip=skip,
  46. limit=limit,
  47. organization_id=organization_id,
  48. status=status,
  49. search=search,
  50. )
  51. return DeviceListResponse(
  52. devices=devices,
  53. total=total,
  54. )
  55. @router.get("/{device_id}", response_model=DeviceResponse)
  56. async def get_device(
  57. device_id: int,
  58. db: Annotated[AsyncSession, Depends(get_db)],
  59. current_user: Annotated[User, Depends(get_current_superadmin)],
  60. ):
  61. """
  62. Get device by ID (superadmin only).
  63. """
  64. device = await device_service.get_device(db, device_id)
  65. if not device:
  66. raise HTTPException(
  67. status_code=status.HTTP_404_NOT_FOUND,
  68. detail="Device not found",
  69. )
  70. return device
  71. @router.post(
  72. "", response_model=DeviceResponse, status_code=status.HTTP_201_CREATED
  73. )
  74. async def create_device(
  75. data: DeviceCreate,
  76. db: Annotated[AsyncSession, Depends(get_db)],
  77. current_user: Annotated[User, Depends(get_current_superadmin)],
  78. ):
  79. """
  80. Register a new device (superadmin only).
  81. Devices are assigned a unique simple_id (Receiver #1, #2, etc).
  82. """
  83. try:
  84. device = await device_service.create_device(db, data)
  85. except ValueError as e:
  86. raise HTTPException(
  87. status_code=status.HTTP_400_BAD_REQUEST,
  88. detail=str(e),
  89. )
  90. return device
  91. @router.patch("/{device_id}", response_model=DeviceResponse)
  92. async def update_device(
  93. device_id: int,
  94. data: DeviceUpdate,
  95. db: Annotated[AsyncSession, Depends(get_db)],
  96. current_user: Annotated[User, Depends(get_current_superadmin)],
  97. ):
  98. """
  99. Update device (superadmin only).
  100. Can update device organization assignment, status, and configuration.
  101. """
  102. device = await device_service.update_device(db, device_id, data)
  103. if not device:
  104. raise HTTPException(
  105. status_code=status.HTTP_404_NOT_FOUND,
  106. detail="Device not found",
  107. )
  108. return device
  109. @router.delete("/{device_id}", status_code=status.HTTP_204_NO_CONTENT)
  110. async def delete_device(
  111. device_id: int,
  112. db: Annotated[AsyncSession, Depends(get_db)],
  113. current_user: Annotated[User, Depends(get_current_superadmin)],
  114. ):
  115. """
  116. Delete device (superadmin only).
  117. Warning: This permanently deletes the device.
  118. """
  119. deleted = await device_service.delete_device(db, device_id)
  120. if not deleted:
  121. raise HTTPException(
  122. status_code=status.HTTP_404_NOT_FOUND,
  123. detail="Device not found",
  124. )