from rest_framework import decorators, mixins, permissions, response, status, views, viewsets from apps.core.errors import error_response from apps.live_monitoring.models import Camera from apps.live_monitoring.serializers import CameraSerializer from apps.live_monitoring.services import StreamAccessService from apps.rbac.permissions import ActionPermission class CameraViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = Camera.objects.filter(active=True) serializer_class = CameraSerializer permission_classes = [ActionPermission] code_map = {"list": "processing.view", "retrieve": "processing.view", "access": "processing.view"} @decorators.action(detail=True, methods=["post"]) def access(self, request, pk=None): camera = self.get_object() service = StreamAccessService() if not service.can_access(request.user, camera): return response.Response( error_response("STREAM_FORBIDDEN", "You do not have access to this stream."), status=status.HTTP_403_FORBIDDEN, ) token, expires_at = service.issue_token(camera) access_url = request.build_absolute_uri(f"/api/v1/live-monitoring/streams/verify/?token={token}") return response.Response({"token": token, "expires_at": expires_at, "access_url": access_url}) class VerifyStreamView(views.APIView): permission_classes = [permissions.AllowAny] def get(self, request): token = request.query_params.get("token") payload = StreamAccessService().verify_token(token) if not payload: return response.Response( error_response("INVALID_TOKEN", "Invalid or expired stream token."), status=status.HTTP_403_FORBIDDEN, ) try: camera = Camera.objects.get(pk=payload["camera"], active=True) except Camera.DoesNotExist: return response.Response( error_response("CAMERA_NOT_FOUND", "Camera not found."), status=status.HTTP_404_NOT_FOUND, ) return response.Response({"stream_url": camera.stream_url})