blob: 08f5681fb902c4eb5d917a84a0560e547d45a9ca [file] [log] [blame]
Mitja Nikolause9208082018-07-30 14:22:09 +02001"""REST API for accessing devices."""
2
3from django.contrib.auth.models import Permission
4from django.utils.decorators import method_decorator
5from drf_yasg import openapi
6from drf_yasg.utils import swagger_auto_schema
7from rest_framework import generics, status
8from rest_framework.exceptions import NotFound, ValidationError
9from rest_framework.authtoken.models import Token
10from rest_framework.decorators import api_view, permission_classes
11from rest_framework.permissions import AllowAny
12from rest_framework.response import Response
13
14from crashreports.models import Device, User
Mitja Nikolaus4d759da2018-08-28 15:31:29 +020015from crashreports.permissions import (
16 HasRightsOrIsDeviceOwnerDeviceCreation,
17 SWAGGER_SECURITY_REQUIREMENTS_ALL,
18)
Franz-Xaver Geigerd9943352018-02-27 14:26:41 +010019from crashreports.serializers import DeviceSerializer, DeviceCreateSerializer
Mitja Nikolause9208082018-07-30 14:22:09 +020020from crashreports.response_descriptions import default_desc
Dirk Vogt7160b5e2016-10-12 17:04:40 +020021
Mitja Nikolause9208082018-07-30 14:22:09 +020022
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020023@method_decorator(
24 name="get",
Mitja Nikolaus4d759da2018-08-28 15:31:29 +020025 decorator=swagger_auto_schema(
26 operation_description="List devices",
27 security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
28 ),
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020029)
30@method_decorator(
31 name="post",
32 decorator=swagger_auto_schema(
33 operation_description="Create a device",
Mitja Nikolaus4d759da2018-08-28 15:31:29 +020034 security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020035 responses=dict([default_desc(ValidationError)]),
36 ),
37)
Dirk Vogtf2a33422016-10-11 17:17:26 +020038class ListCreateDevices(generics.ListCreateAPIView):
Mitja Nikolause9208082018-07-30 14:22:09 +020039 """Endpoint for listing devices and creating new devices."""
40
Dirk Vogtf2a33422016-10-11 17:17:26 +020041 queryset = Device.objects.all()
42 paginate_by = 20
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020043 permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,)
Dirk Vogtf2a33422016-10-11 17:17:26 +020044 serializer_class = DeviceSerializer
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020045 filter_fields = ("uuid", "board_date", "chipset")
Dirk Vogtf2a33422016-10-11 17:17:26 +020046
Dirk Vogt7160b5e2016-10-12 17:04:40 +020047
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020048@method_decorator(
49 name="get",
50 decorator=swagger_auto_schema(
51 operation_description="Get a device",
Mitja Nikolaus4d759da2018-08-28 15:31:29 +020052 security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020053 responses=dict([default_desc(NotFound)]),
54 ),
55)
56@method_decorator(
57 name="put",
58 decorator=swagger_auto_schema(
59 operation_description="Update a device",
Mitja Nikolaus4d759da2018-08-28 15:31:29 +020060 security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020061 responses=dict([default_desc(NotFound), default_desc(ValidationError)]),
62 ),
63)
64@method_decorator(
65 name="patch",
66 decorator=swagger_auto_schema(
67 operation_description="Make a partial update for a device",
Mitja Nikolaus4d759da2018-08-28 15:31:29 +020068 security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020069 responses=dict([default_desc(NotFound), default_desc(ValidationError)]),
70 ),
71)
72@method_decorator(
73 name="delete",
74 decorator=swagger_auto_schema(
75 operation_description="Delete a device",
Mitja Nikolaus4d759da2018-08-28 15:31:29 +020076 security=SWAGGER_SECURITY_REQUIREMENTS_ALL,
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020077 responses=dict([default_desc(NotFound)]),
78 ),
79)
Dirk Vogtf2a33422016-10-11 17:17:26 +020080class RetrieveUpdateDestroyDevice(generics.RetrieveUpdateDestroyAPIView):
Mitja Nikolause9208082018-07-30 14:22:09 +020081 """Endpoint for retrieving, updating, patching and deleting devices."""
82
83 # pylint: disable=too-many-ancestors
84
Dirk Vogtf2a33422016-10-11 17:17:26 +020085 queryset = Device.objects.all()
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020086 permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation,)
Dirk Vogtf2a33422016-10-11 17:17:26 +020087 serializer_class = DeviceSerializer
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020088 lookup_field = "uuid"
Dirk Vogtf2a33422016-10-11 17:17:26 +020089
Dirk Vogt7160b5e2016-10-12 17:04:40 +020090
Mitja Nikolause9208082018-07-30 14:22:09 +020091class DeviceRegisterResponseSchema(DeviceSerializer):
92 """Response schema for successful device registration."""
93
94 class Meta: # noqa: D106
95 model = Device
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +020096 fields = ["uuid", "token"]
Mitja Nikolause9208082018-07-30 14:22:09 +020097
98
99@swagger_auto_schema(
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +0200100 method="post",
Mitja Nikolause9208082018-07-30 14:22:09 +0200101 request_body=DeviceCreateSerializer,
Mitja Nikolaus4d759da2018-08-28 15:31:29 +0200102 security=[],
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +0200103 responses=dict(
104 [
105 default_desc(ValidationError),
106 (
107 status.HTTP_200_OK,
108 openapi.Response(
109 "The device has been successfully registered.",
110 DeviceRegisterResponseSchema,
111 ),
112 ),
113 ]
114 ),
115)
116@api_view(http_method_names=["POST"])
Dirk Vogtf2a33422016-10-11 17:17:26 +0200117@permission_classes((AllowAny,))
118def register_device(request):
Mitja Nikolause9208082018-07-30 14:22:09 +0200119 """Register a new device.
120
121 This endpoint will generate a django user for the new device. The device is
122 identified by a uuid, and authenticated with a token.
Dirk Vogt7160b5e2016-10-12 17:04:40 +0200123 We generate the uuid here as this makes it easier to deal with collisions.
Dirk Vogtf2a33422016-10-11 17:17:26 +0200124 """
Franz-Xaver Geigerd9943352018-02-27 14:26:41 +0100125 serializer = DeviceCreateSerializer(data=request.data)
126 serializer.is_valid(raise_exception=True)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200127 device = Device()
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +0200128 user = User.objects.create_user("device_" + str(device.uuid), "", None)
129 permission = Permission.objects.get(name="Can add crashreport")
Dirk Vogtf2a33422016-10-11 17:17:26 +0200130 user.user_permissions.add(permission)
131 user.save()
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +0200132 device.board_date = serializer.validated_data["board_date"]
133 device.chipset = serializer.validated_data["chipset"]
Dirk Vogtf2a33422016-10-11 17:17:26 +0200134 device.user = user
Dirk Vogt7160b5e2016-10-12 17:04:40 +0200135 device.token = Token.objects.create(user=user).key
Dirk Vogtf2a33422016-10-11 17:17:26 +0200136 device.save()
Mitja Nikolauscb50f2c2018-08-24 13:54:48 +0200137 return Response({"uuid": device.uuid, "token": device.token})