blob: 40a1adb4cdb410128511df3160afa2f895df9a41 [file] [log] [blame]
"""REST API for accessing crash reports."""
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from django.utils.decorators import method_decorator
from rest_framework import status, generics
from rest_framework.response import Response
from rest_framework.exceptions import NotFound, ValidationError
from crashreports.permissions import (
HasRightsOrIsDeviceOwnerDeviceCreation,
SWAGGER_SECURITY_REQUIREMENTS_ALL,
)
from crashreports.serializers import CrashReportSerializer
from crashreports.utils import get_object_by_lookup_fields
from crashreports.models import Crashreport
from crashreports.response_descriptions import default_desc
class CreateCrashreportResponseSchema(CrashReportSerializer):
"""Response schema for successful crash report creation."""
class Meta: # noqa: D106
model = Crashreport
fields = ["device_local_id"]
@method_decorator(
name="get",
decorator=swagger_auto_schema(
operation_description="List crash reports",
security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
),
)
@method_decorator(
name="post",
decorator=swagger_auto_schema(
operation_description="Create a crash report",
security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
request_body=CrashReportSerializer,
responses=dict(
[
default_desc(ValidationError),
(
status.HTTP_404_NOT_FOUND,
openapi.Response(
"No device with the given uuid could be found."
),
),
(
status.HTTP_201_CREATED,
openapi.Response(
"The crash report has been successfully created.",
CreateCrashreportResponseSchema,
),
),
]
),
),
)
class ListCreateView(generics.ListCreateAPIView):
"""Endpoint for listing crash reports and creating new crash reports."""
queryset = Crashreport.objects.all()
paginate_by = 20
permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,)
serializer_class = CrashReportSerializer
filter_fields = ("device", "build_fingerprint", "radio_version")
def dispatch(self, request, *args, **kwargs):
"""Dispatch an incoming HTTP request to the right method.
The method is overridden in order to replace the 'device__uuid'
parameter value with the 'uuid' value from the parameters.
"""
if "uuid" in kwargs:
self.queryset = Crashreport.objects.filter(
device__uuid=kwargs["uuid"]
)
return generics.ListCreateAPIView.dispatch(
self, request, *args, **kwargs
)
def perform_create(self, serializer):
"""Create a crash report instance in the database.
The method is overridden in order to create a response containing only
the device_local_id.
"""
serializer.save()
return Response(
{"device_local_id": serializer.data["device_local_id"]},
status.HTTP_200_OK,
)
@method_decorator(
name="get",
decorator=swagger_auto_schema(
operation_description="Get a crash report",
security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
responses=dict([default_desc(NotFound)]),
),
)
@method_decorator(
name="put",
decorator=swagger_auto_schema(
operation_description="Update a crash report",
security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
responses=dict([default_desc(NotFound), default_desc(ValidationError)]),
),
)
@method_decorator(
name="patch",
decorator=swagger_auto_schema(
operation_description="Partially update a crash report",
security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
responses=dict([default_desc(NotFound), default_desc(ValidationError)]),
),
)
@method_decorator(
name="delete",
decorator=swagger_auto_schema(
operation_description="Delete a crash report",
security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
responses=dict([default_desc(NotFound)]),
),
)
class RetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
"""Endpoint for retrieving, updating and deleting crash reports."""
# pylint: disable=too-many-ancestors
queryset = Crashreport.objects.all()
permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,)
serializer_class = CrashReportSerializer
multiple_lookup_fields = {"id", "device__uuid", "device_local_id"}
def get_object(self):
"""Retrieve a crash report."""
return get_object_by_lookup_fields(self, self.multiple_lookup_fields)