Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 1 | """REST API for accessing crash reports.""" |
| 2 | from drf_yasg import openapi |
| 3 | from drf_yasg.utils import swagger_auto_schema |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 4 | from django.shortcuts import get_object_or_404 |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 5 | from django.utils.decorators import method_decorator |
| 6 | from rest_framework import status, generics |
| 7 | from rest_framework.response import Response |
| 8 | from rest_framework.exceptions import NotFound, ValidationError |
| 9 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 10 | from crashreports.permissions import HasRightsOrIsDeviceOwnerDeviceCreation |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 11 | from crashreports.serializers import CrashReportSerializer |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 12 | from crashreports.models import Crashreport |
| 13 | from crashreports.response_descriptions import default_desc |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 14 | |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 15 | |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 16 | class 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 Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 53 | class ListCreateView(generics.ListCreateAPIView): |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 54 | """Endpoint for listing crash reports and creating new crash reports.""" |
| 55 | |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 56 | queryset = Crashreport.objects.all() |
| 57 | paginate_by = 20 |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame] | 58 | permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 59 | serializer_class = CrashReportSerializer |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame] | 60 | filter_fields = ("device", "build_fingerprint", "radio_version") |
Dirk Vogt | 83107df | 2017-05-02 12:04:19 +0200 | [diff] [blame] | 61 | |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 62 | def dispatch(self, *args, **kwargs): |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 63 | """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 Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame] | 68 | if "uuid" in kwargs: |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 69 | self.queryset = Crashreport.objects.filter( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame] | 70 | device__uuid=kwargs["uuid"] |
| 71 | ) |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 72 | return generics.ListCreateAPIView.dispatch(self, *args, **kwargs) |
| 73 | |
Dirk Vogt | eda80d3 | 2016-11-21 11:45:50 +0100 | [diff] [blame] | 74 | def perform_create(self, serializer): |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 75 | """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 Vogt | eda80d3 | 2016-11-21 11:45:50 +0100 | [diff] [blame] | 80 | serializer.save() |
| 81 | return Response( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame] | 82 | {"device_local_id": serializer.data["device_local_id"]}, |
| 83 | status.HTTP_200_OK, |
| 84 | ) |
Dirk Vogt | eda80d3 | 2016-11-21 11:45:50 +0100 | [diff] [blame] | 85 | |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 86 | |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 87 | @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 Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 115 | class RetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView): |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 116 | """Endpoint for retrieving, updating and deleting crash reports.""" |
| 117 | |
| 118 | # pylint: disable=too-many-ancestors |
| 119 | |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 120 | queryset = Crashreport.objects.all() |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame] | 121 | permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,) |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 122 | serializer_class = CrashReportSerializer |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame] | 123 | multiple_lookup_fields = {"id", "device__uuid", "device_local_id"} |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 124 | |
| 125 | def get_object(self): |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 126 | """Retrieve a crash report.""" |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 127 | queryset = self.get_queryset() |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 128 | query_filter = {} |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 129 | for field in self.multiple_lookup_fields: |
| 130 | if field in self.kwargs: |
Mitja Nikolaus | 1280ef4 | 2018-08-21 16:20:07 +0200 | [diff] [blame] | 131 | query_filter[field] = self.kwargs[field] |
| 132 | obj = get_object_or_404(queryset, **query_filter) |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 133 | self.check_object_permissions(self.request, obj) |
| 134 | return obj |