Ejemplo n.º 1
0
class AreaViewSet(utils.MultiSerializerViewSetMixin, viewsets.ModelViewSet):
    permission_classes = (require_scopes(SCOPE_PRV_API), )
    queryset = models.Area.objects.prefetch_related("polygons").all()
    filter_backends = (filters.OrderingFilter, )
    ordering_fields = ("label", )
    ordering = "label"
    lookup_field = "id"
    serializer_class = AreaResponseSerializer
    serializers_mapping = {
        "list": {
            "response": AreaResponseSerializer
        },
        "retrieve": {
            "response": AreaResponseSerializer
        },
        "create": {
            "request": AreaRequestSerializer,
            "response": utils.EmptyResponseSerializer,
        },
        "update": {
            "request": AreaRequestSerializer,
            "response": utils.EmptyResponseSerializer,
        },
    }

    def create(self, *args, **kwargs):
        return super()._create(*args, **kwargs)

    def update(self, *args, **kwargs):
        return super()._update(*args, **kwargs)
Ejemplo n.º 2
0
class AreaViewSet(viewsets.ReadOnlyModelViewSet):
    permission_classes = (require_scopes(SCOPE_AGENCY_API), )
    queryset = models.Area.objects.prefetch_related("polygons").all()
    lookup_field = "id"
    serializer_class = AreaSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        provider_id = getattr(self.request.user, "provider_id", None)
        if provider_id:
            queryset = queryset.filter(providers__id=provider_id)
        else:
            queryset = queryset.none()

        return queryset
Ejemplo n.º 3
0
class DeviceViewSet(utils.MultiSerializerViewSetMixin,
                    viewsets.ReadOnlyModelViewSet):
    permission_classes = (require_scopes(SCOPE_PRV_API), )
    lookup_field = "id"
    serializer_class = DeviceSerializer
    pagination_class = utils.LimitOffsetPagination
    filter_backends = (filters.DjangoFilterBackend, )

    filterset_class = DeviceFilter
    queryset = models.Device.objects.select_related("provider").all()
    serializers_mapping = {
        "list": {
            "response": DeviceSerializer
        },
        "retrieve": {
            "response": RetrieveDeviceSerializer
        },
    }
Ejemplo n.º 4
0
class ProviderApiViewSet(viewsets.ViewSet):
    permission_classes = [require_scopes(SCOPE_PRV_API)]

    @decorators.action(detail=False, methods=["get"])
    def status_changes(self, request, *args, **kwargs):
        start_time = request.query_params.get("start_time")
        end_time = request.query_params.get("end_time")
        # Only forward events that were first retrieved though providers'
        # `status_changes' endpoint
        event_types = enums.PROVIDER_REASON_TO_AGENCY_EVENT.values()
        events = models.EventRecord.objects.select_related(
            "device__provider").filter(event_type__in=event_types)
        if start_time:
            start_time = utils.from_mds_timestamp(int(start_time))
            events = events.filter(timestamp__gte=start_time)
        if end_time:
            end_time = utils.from_mds_timestamp(int(end_time))
            events = events.filter(timestamp__lte=end_time)
        paginator = CustomPagination()
        page = paginator.paginate_queryset(events.order_by("timestamp"),
                                           request)
        data = DeviceStatusChangesSerializer(page, many=True).data
        return paginator.get_paginated_response(data)
Ejemplo n.º 5
0
class PolygonViewSet(utils.MultiSerializerViewSetMixin, viewsets.ModelViewSet):
    permission_classes = (require_scopes(SCOPE_PRV_API), )
    queryset = models.Polygon.objects.prefetch_related("areas").all()
    filter_backends = (filters.OrderingFilter, )
    ordering_fields = ("label", )
    ordering = "label"
    lookup_field = "id"
    serializer_class = PolygonResponseSerializer
    serializers_mapping = {
        "list": {
            "response": PolygonResponseSerializer
        },
        "retrieve": {
            "response": PolygonResponseSerializer
        },
        "create": {
            "request": PolygonRequestSerializer,
            "response": utils.EmptyResponseSerializer,
        },
        "update": {
            "request": PolygonRequestSerializer,
            "response": utils.EmptyResponseSerializer,
        },
        "import_polygons": {
            "request": PolygonsImportRequestSerializer,
            "response": utils.EmptyResponseSerializer,
        },
    }

    def create(self, *args, **kwargs):
        return super()._create(*args, **kwargs)

    def update(self, *args, **kwargs):
        return super()._update(*args, **kwargs)

    @action(methods=["post"], url_path="import", detail=False)
    def import_polygons(self, request, pk=None):
        polygons = request.data.get("polygons", None)

        if not isinstance(polygons, list):
            return Response(status=400)

        try:
            polygons_to_create = []
            for polygon in polygons:
                geom = polygon.get("geom", None)
                if geom and geom["type"] == "Polygon":

                    areas = []
                    for area_label in polygon.get("areas", []):
                        defaults = {
                            "color": "#%06x" % random.randint(0, 0xFFFFFF)
                        }
                        # Create new Area if doesn't exist (based on label)
                        area = models.Area.objects.get_or_create(
                            label=area_label, defaults=defaults)[0]
                        areas.append(area)
                    poly = models.Polygon(label=polygon.get("label", ""),
                                          geom=str(geom))
                    poly.areas.set([a.id for a in areas])
                    polygons_to_create.append(poly)
            models.Polygon.objects.bulk_create(polygons_to_create)
        except IntegrityError as ex:
            return Response(exception=ex, status=500)

        return Response({"message": "ok"})
Ejemplo n.º 6
0
class DeviceViewSet(
        apis_utils.MultiSerializerViewSetMixin,
        mixins.ListModelMixin,
        mixins.RetrieveModelMixin,
        mixins.CreateModelMixin,
        viewsets.GenericViewSet,
):

    queryset = models.Device.objects.with_latest_events()
    permission_classes = (require_scopes(SCOPE_AGENCY_API), )
    lookup_field = "id"
    serializer_class = DeviceSerializer
    serializers_mapping = {
        "list": {
            "response": DeviceSerializer
        },
        "retrieve": {
            "response": DeviceSerializer
        },
        "create": {
            "request": DeviceRegisterSerializer,
            "response": apis_utils.EmptyResponseSerializer,
        },
        "event": {
            "request": DeviceEventSerializer,
            "response": DeviceEventResponseSerializer,
        },
        "telemetry": {
            "request": DeviceTelemetryInputSerializer,
            "response": apis_utils.EmptyResponseSerializer,
        },
    }

    def list(self, *args, **kwargs):
        return super().list(*args, **kwargs)

    def retrieve(self, *args, **kwargs):
        return super().retrieve(*args, **kwargs)

    def create(self, *args, **kwargs):
        return self._create(*args, **kwargs)

    @action(detail=True, methods=["post", "options"])
    def event(self, request, id):
        """Endpoint to receive an event from a provider."""
        provider_id = request.user.provider_id
        device = models.Device.objects.filter(provider_id=provider_id,
                                              id=id).last()
        if not device:
            return Response(data={}, status=404)

        provider = models.Provider.objects.get(pk=provider_id)
        request_serializer = self.get_serializer(
            data=request.data,
            context={
                "device": device,
                "request_or_response": "request",
                "provider": provider,
            },
        )
        request_serializer.is_valid(raise_exception=True)
        instance = request_serializer.save()
        response_serializer = self.get_serializer(
            instance=instance, context={"request_or_response": "response"})
        return Response(response_serializer.data,
                        status=status.HTTP_201_CREATED)

    @action(detail=False, methods=["post", "options"])
    def telemetry(self, request):
        """Endpoint to receive a telemetry from a provider."""
        context = self.get_serializer_context(
        )  # adds the request to the context
        context["request_or_response"] = "request"
        provider_id = request.user.provider_id
        context["provider"] = models.Provider.objects.get(pk=provider_id)
        serializer = self.get_serializer(data=request.data, context=context)
        serializer.is_valid(raise_exception=True)
        instance = serializer.save()
        response_serializer = self.get_serializer(
            instance=instance, context={"request_or_response": "response"})
        return Response(response_serializer.data,
                        status=status.HTTP_201_CREATED)

    def get_queryset(self):
        queryset = super().get_queryset()
        provider_id = getattr(self.request.user, "provider_id", None)
        if provider_id:
            queryset = queryset.filter(provider_id=provider_id)
        else:
            queryset = queryset.none()

        return queryset
Ejemplo n.º 7
0
class LongLivedTokenView(GenericAPIView):
    """Implements an endpoint to generate long lived (JWT) tokens.

    This is an alternate authentication method to Oauth2.
    An authorized user can generate such tokens and then transmit
    it to the token owner for future use with our API.
    """

    permission_classes = (require_scopes(SCOPE_PRV_API),)

    class RequestSerializer(serializers.Serializer):
        app_owner = serializers.UUIDField(
            help_text="The owner for which the token is generated."
        )
        token_duration = serializers.IntegerField(
            help_text="Token duration in seconds."
        )

    class RevokeRequestSerializer(serializers.Serializer):
        access_token = serializers.CharField()

    class RevokeResponseSerializer(utils.EmptyResponseSerializer):
        revocation_date = serializers.DateTimeField()

    class ResponseSerializer(serializers.Serializer):
        access_token = serializers.CharField()
        token_type = serializers.ChoiceField(choices=["bearer"])
        expires_in = serializers.IntegerField()

    def post(self, request, *args, **kwargs):
        serializer = self.RequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        try:
            token = public_api.get_long_lived_token(
                validated_data["app_owner"], validated_data["token_duration"]
            )
        except public_api.NoApplicationForOwner:
            raise exceptions.ValidationError(
                {
                    "app_owner": _("No application known for owner %s")
                    % validated_data["app_owner"]
                }
            )
        serializer = self.ResponseSerializer(
            instance={
                "access_token": token,
                "token_type": "bearer",
                "expires_in": validated_data["token_duration"],
            }
        )
        return Response(serializer.data, status=200)

    def delete(self, request, *args, **kwargs):
        serializer = self.RevokeRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        try:
            revocation_date = public_api.revoke_long_lived_token(
                serializer.validated_data["access_token"]
            )
        except public_api.UnknownToken:
            raise exceptions.ValidationError(
                {
                    "token": _("No access token known for %s")
                    % validated_data["access_token"]
                }
            )

        return Response(
            self.RevokeResponseSerializer({"revocation_date": revocation_date}).data,
            status=200,
        )
Ejemplo n.º 8
0
class AppCreationView(GenericAPIView):
    """ Implements an endpoint to create Oauth2 application for providers
    """

    permission_classes = (require_scopes(SCOPE_PRV_API),)

    class CreationRequestSerializer(serializers.Serializer):
        app_name = serializers.CharField()
        scopes = serializers.ListField(
            child=serializers.CharField(
                help_text="Scope of the application separated by a comma."
            )
        )
        app_owner = serializers.UUIDField(
            help_text="The owner for which the application is generated."
        )

    class CreationResponseSerializer(serializers.Serializer):
        client_id = serializers.CharField(help_text="Newly created Oauth app Client ID")
        client_secret = serializers.CharField(
            help_text="Newly created Oauth app Client Secret"
        )

    class RevocationRequestSerializer(serializers.Serializer):
        app_owner = serializers.UUIDField(
            help_text="The owner for which the application will be revoked."
        )
        delete = serializers.BooleanField(
            required=False,
            help_text="Indicate if the application should be removed or just revoked",
            default=False,
        )

    class RevokationResponseSerializer(utils.EmptyResponseSerializer):
        pass

    def post(self, request, *args, **kwargs):
        serializer = self.CreationRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        application = public_api.create_application(
            name=validated_data["app_name"],
            scopes=validated_data["scopes"],
            owner=validated_data["app_owner"],
        )

        serializer = self.CreationResponseSerializer(
            instance={
                "client_id": application["client_id"],
                "client_secret": application["client_secret"],
            }
        )

        return Response(serializer.data, status=200)

    def delete(self, request, *args, **kwargs):
        serializer = self.RevocationRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        try:
            if validated_data["delete"]:
                public_api.delete_application(validated_data["app_owner"])
            else:
                public_api.revoke_application(validated_data["app_owner"])
        except public_api.NoApplicationForOwner:
            raise exceptions.ValidationError(
                {
                    "app_owner": _("No application known for owner %s")
                    % validated_data["app_owner"]
                }
            )

        return Response(self.RevokationResponseSerializer().data, status=200)
Ejemplo n.º 9
0
class ProviderViewSet(viewsets.ModelViewSet):
    permission_classes = (require_scopes(SCOPE_PRV_API), )
    queryset = models.Provider.objects.with_device_categories()
    lookup_field = "id"
    serializer_class = ProviderSerializer