blob: 8cf051b9d6de6470bd0971c7b937e1b93f02c7e0 [file] [log] [blame]
Mitja Nikolaus1280ef42018-08-21 16:20:07 +02001"""REST API for accessing crash reports."""
2from drf_yasg import openapi
3from drf_yasg.utils import swagger_auto_schema
Dirk Vogte1784882016-10-13 16:09:38 +02004from django.shortcuts import get_object_or_404
Mitja Nikolaus1280ef42018-08-21 16:20:07 +02005from django.utils.decorators import method_decorator
6from rest_framework import status, generics
7from rest_framework.response import Response
8from rest_framework.exceptions import NotFound, ValidationError
9
Dirk Vogtc9e10ab2016-10-12 13:58:15 +020010from crashreports.permissions import HasRightsOrIsDeviceOwnerDeviceCreation
Dirk Vogtf2a33422016-10-11 17:17:26 +020011from crashreports.serializers import CrashReportSerializer
Mitja Nikolaus1280ef42018-08-21 16:20:07 +020012from crashreports.models import Crashreport
13from crashreports.response_descriptions import default_desc
Dirk Vogtf2a33422016-10-11 17:17:26 +020014
Dirk Vogtf2a33422016-10-11 17:17:26 +020015
Mitja Nikolaus1280ef42018-08-21 16:20:07 +020016class CreateCrashreportResponseSchema(CrashReportSerializer):
17 """Response schema for successful crash report creation."""
18
19 class Meta: # noqa: D106
20 model = Crashreport
21 fields = ["device_local_id"]
22
23
24@method_decorator(
25 name="get",
26 decorator=swagger_auto_schema(operation_description="List crash reports"),
27)
28@method_decorator(
29 name="post",
30 decorator=swagger_auto_schema(
31 operation_description="Create a crash report",
32 request_body=CrashReportSerializer,
33 responses=dict(
34 [
35 default_desc(ValidationError),
36 (
37 status.HTTP_404_NOT_FOUND,
38 openapi.Response(
39 "No device with the given uuid could be found."
40 ),
41 ),
42 (
43 status.HTTP_201_CREATED,
44 openapi.Response(
45 "The crash report has been successfully created.",
46 CreateCrashreportResponseSchema,
47 ),
48 ),
49 ]
50 ),
51 ),
52)
Dirk Vogte1784882016-10-13 16:09:38 +020053class ListCreateView(generics.ListCreateAPIView):
Mitja Nikolaus1280ef42018-08-21 16:20:07 +020054 """Endpoint for listing crash reports and creating new crash reports."""
55
Dirk Vogtf2a33422016-10-11 17:17:26 +020056 queryset = Crashreport.objects.all()
57 paginate_by = 20
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020058 permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,)
Dirk Vogtf2a33422016-10-11 17:17:26 +020059 serializer_class = CrashReportSerializer
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020060 filter_fields = ("device", "build_fingerprint", "radio_version")
Dirk Vogt83107df2017-05-02 12:04:19 +020061
Dirk Vogte1784882016-10-13 16:09:38 +020062 def dispatch(self, *args, **kwargs):
Mitja Nikolaus1280ef42018-08-21 16:20:07 +020063 """Dispatch an incoming HTTP request to the right method.
64
65 The method is overridden in order to replace the 'device__uuid'
66 parameter value with the 'uuid' value from the parameters.
67 """
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020068 if "uuid" in kwargs:
Dirk Vogte1784882016-10-13 16:09:38 +020069 self.queryset = Crashreport.objects.filter(
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020070 device__uuid=kwargs["uuid"]
71 )
Dirk Vogte1784882016-10-13 16:09:38 +020072 return generics.ListCreateAPIView.dispatch(self, *args, **kwargs)
73
Dirk Vogteda80d32016-11-21 11:45:50 +010074 def perform_create(self, serializer):
Mitja Nikolaus1280ef42018-08-21 16:20:07 +020075 """Create a crash report instance in the database.
76
77 The method is overridden in order to create a response containing only
78 the device_local_id.
79 """
Dirk Vogteda80d32016-11-21 11:45:50 +010080 serializer.save()
81 return Response(
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020082 {"device_local_id": serializer.data["device_local_id"]},
83 status.HTTP_200_OK,
84 )
Dirk Vogteda80d32016-11-21 11:45:50 +010085
Dirk Vogte1784882016-10-13 16:09:38 +020086
Mitja Nikolaus1280ef42018-08-21 16:20:07 +020087@method_decorator(
88 name="get",
89 decorator=swagger_auto_schema(
90 operation_description="Get a crash report",
91 responses=dict([default_desc(NotFound)]),
92 ),
93)
94@method_decorator(
95 name="put",
96 decorator=swagger_auto_schema(
97 operation_description="Update a crash report",
98 responses=dict([default_desc(NotFound), default_desc(ValidationError)]),
99 ),
100)
101@method_decorator(
102 name="patch",
103 decorator=swagger_auto_schema(
104 operation_description="Partially update a crash report",
105 responses=dict([default_desc(NotFound), default_desc(ValidationError)]),
106 ),
107)
108@method_decorator(
109 name="delete",
110 decorator=swagger_auto_schema(
111 operation_description="Delete a crash report",
112 responses=dict([default_desc(NotFound)]),
113 ),
114)
Dirk Vogte1784882016-10-13 16:09:38 +0200115class RetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
Mitja Nikolaus1280ef42018-08-21 16:20:07 +0200116 """Endpoint for retrieving, updating and deleting crash reports."""
117
118 # pylint: disable=too-many-ancestors
119
Dirk Vogte1784882016-10-13 16:09:38 +0200120 queryset = Crashreport.objects.all()
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +0200121 permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,)
Dirk Vogte1784882016-10-13 16:09:38 +0200122 serializer_class = CrashReportSerializer
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +0200123 multiple_lookup_fields = {"id", "device__uuid", "device_local_id"}
Dirk Vogte1784882016-10-13 16:09:38 +0200124
125 def get_object(self):
Mitja Nikolaus1280ef42018-08-21 16:20:07 +0200126 """Retrieve a crash report."""
Dirk Vogte1784882016-10-13 16:09:38 +0200127 queryset = self.get_queryset()
Mitja Nikolaus1280ef42018-08-21 16:20:07 +0200128 query_filter = {}
Dirk Vogte1784882016-10-13 16:09:38 +0200129 for field in self.multiple_lookup_fields:
130 if field in self.kwargs:
Mitja Nikolaus1280ef42018-08-21 16:20:07 +0200131 query_filter[field] = self.kwargs[field]
132 obj = get_object_or_404(queryset, **query_filter)
Dirk Vogte1784882016-10-13 16:09:38 +0200133 self.check_object_permissions(self.request, obj)
134 return obj