forked from CGM_Public/pretix_original
Allow to create devices through the API (#1785)
This commit is contained in:
220
doc/api/resources/devices.rst
Normal file
220
doc/api/resources/devices.rst
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
.. spelling:: fullname
|
||||||
|
|
||||||
|
.. _`rest-devices`:
|
||||||
|
|
||||||
|
Devices
|
||||||
|
=======
|
||||||
|
|
||||||
|
See also :ref:`rest-deviceauth`.
|
||||||
|
|
||||||
|
Device resource
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The device resource contains the following public fields:
|
||||||
|
|
||||||
|
.. rst-class:: rest-resource-table
|
||||||
|
|
||||||
|
===================================== ========================== =======================================================
|
||||||
|
Field Type Description
|
||||||
|
===================================== ========================== =======================================================
|
||||||
|
device_id integer Internal ID of the device within this organizer
|
||||||
|
unique_serial string Unique identifier of this device
|
||||||
|
name string Device name
|
||||||
|
all_events boolean Whether this device has access to all events
|
||||||
|
limit_events list List of event slugs this device has access to
|
||||||
|
hardware_brand string Device hardware manufacturer (read-only)
|
||||||
|
hardware_model string Device hardware model (read-only)
|
||||||
|
software_brand string Device software product (read-only)
|
||||||
|
software_version string Device software version (read-only)
|
||||||
|
created datetime Creation time
|
||||||
|
initialized datetime Time of initialization (or ``null``)
|
||||||
|
initialization_token string Token for initialization
|
||||||
|
revoked boolean Whether this device no longer has access
|
||||||
|
===================================== ========================== =======================================================
|
||||||
|
|
||||||
|
Device endpoints
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. http:get:: /api/v1/organizers/(organizer)/devices/
|
||||||
|
|
||||||
|
Returns a list of all devices within a given organizer.
|
||||||
|
|
||||||
|
**Example request**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
GET /api/v1/organizers/bigevents/devices/ HTTP/1.1
|
||||||
|
Host: pretix.eu
|
||||||
|
Accept: application/json, text/javascript
|
||||||
|
|
||||||
|
**Example response**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Vary: Accept
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"next": null,
|
||||||
|
"previous": null,
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"device_id": 1,
|
||||||
|
"unique_serial": "UOS3GNZ27O39V3QS",
|
||||||
|
"initialization_token": "frkso3m2w58zuw70",
|
||||||
|
"all_events": false,
|
||||||
|
"limit_events": [
|
||||||
|
"museum"
|
||||||
|
],
|
||||||
|
"revoked": false,
|
||||||
|
"name": "Scanner",
|
||||||
|
"created": "2020-09-18T14:17:40.971519Z",
|
||||||
|
"initialized": "2020-09-18T14:17:44.190021Z",
|
||||||
|
"hardware_brand": "Zebra",
|
||||||
|
"hardware_model": "TC25",
|
||||||
|
"software_brand": "pretixSCAN",
|
||||||
|
"software_version": "1.5.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
:query integer page: The page number in case of a multi-page result set, default is 1
|
||||||
|
:param organizer: The ``slug`` field of the organizer to fetch
|
||||||
|
:statuscode 200: no error
|
||||||
|
:statuscode 401: Authentication failure
|
||||||
|
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||||
|
|
||||||
|
.. http:get:: /api/v1/organizers/(organizer)/devices/(device_id)/
|
||||||
|
|
||||||
|
Returns information on one device, identified by its ID.
|
||||||
|
|
||||||
|
**Example request**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
GET /api/v1/organizers/bigevents/devices/1/ HTTP/1.1
|
||||||
|
Host: pretix.eu
|
||||||
|
Accept: application/json, text/javascript
|
||||||
|
|
||||||
|
**Example response**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Vary: Accept
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"device_id": 1,
|
||||||
|
"unique_serial": "UOS3GNZ27O39V3QS",
|
||||||
|
"initialization_token": "frkso3m2w58zuw70",
|
||||||
|
"all_events": false,
|
||||||
|
"limit_events": [
|
||||||
|
"museum"
|
||||||
|
],
|
||||||
|
"revoked": false,
|
||||||
|
"name": "Scanner",
|
||||||
|
"created": "2020-09-18T14:17:40.971519Z",
|
||||||
|
"initialized": "2020-09-18T14:17:44.190021Z",
|
||||||
|
"hardware_brand": "Zebra",
|
||||||
|
"hardware_model": "TC25",
|
||||||
|
"software_brand": "pretixSCAN",
|
||||||
|
"software_version": "1.5.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
:param organizer: The ``slug`` field of the organizer to fetch
|
||||||
|
:param device_id: The ``device_id`` field of the device to fetch
|
||||||
|
:statuscode 200: no error
|
||||||
|
:statuscode 401: Authentication failure
|
||||||
|
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.
|
||||||
|
|
||||||
|
.. http:post:: /api/v1/organizers/(organizer)/devices/
|
||||||
|
|
||||||
|
Creates a new device
|
||||||
|
|
||||||
|
**Example request**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
POST /api/v1/organizers/bigevents/devices/ HTTP/1.1
|
||||||
|
Host: pretix.eu
|
||||||
|
Accept: application/json, text/javascript
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Scanner",
|
||||||
|
"all_events": true,
|
||||||
|
"limit_events": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
**Example response**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
HTTP/1.1 201 Created
|
||||||
|
Vary: Accept
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"device_id": 1,
|
||||||
|
"unique_serial": "UOS3GNZ27O39V3QS",
|
||||||
|
"initialization_token": "frkso3m2w58zuw70",
|
||||||
|
"all_events": true,
|
||||||
|
"limit_events": [],
|
||||||
|
"revoked": false,
|
||||||
|
"name": "Scanner",
|
||||||
|
"created": "2020-09-18T14:17:40.971519Z",
|
||||||
|
"initialized": null
|
||||||
|
"hardware_brand": null,
|
||||||
|
"hardware_model": null,
|
||||||
|
"software_brand": null,
|
||||||
|
"software_version": null
|
||||||
|
}
|
||||||
|
|
||||||
|
:param organizer: The ``slug`` field of the organizer to create a device for
|
||||||
|
:statuscode 201: no error
|
||||||
|
:statuscode 400: The device could not be created due to invalid submitted data.
|
||||||
|
:statuscode 401: Authentication failure
|
||||||
|
:statuscode 403: The requested organizer does not exist **or** you have no permission to create this resource.
|
||||||
|
|
||||||
|
.. http:patch:: /api/v1/organizers/(organizer)/devices/(device_id)/
|
||||||
|
|
||||||
|
Update a device.
|
||||||
|
|
||||||
|
**Example request**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
PATCH /api/v1/organizers/bigevents/devices/1/ HTTP/1.1
|
||||||
|
Host: pretix.eu
|
||||||
|
Accept: application/json, text/javascript
|
||||||
|
Content-Type: application/json
|
||||||
|
Content-Length: 94
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
**Example response**:
|
||||||
|
|
||||||
|
.. sourcecode:: http
|
||||||
|
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Vary: Accept
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Foo",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
:param organizer: The ``slug`` field of the organizer to modify
|
||||||
|
:param device_id: The ``device_id`` field of the deviec to modify
|
||||||
|
:statuscode 200: no error
|
||||||
|
:statuscode 400: The device could not be modified due to invalid submitted data
|
||||||
|
:statuscode 401: Authentication failure
|
||||||
|
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ Resources and endpoints
|
|||||||
giftcards
|
giftcards
|
||||||
carts
|
carts
|
||||||
teams
|
teams
|
||||||
|
devices
|
||||||
webhooks
|
webhooks
|
||||||
seatingplans
|
seatingplans
|
||||||
billing_invoices
|
billing_invoices
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ from pretix.api.serializers.i18n import I18nAwareModelSerializer
|
|||||||
from pretix.api.serializers.order import CompatibleJSONField
|
from pretix.api.serializers.order import CompatibleJSONField
|
||||||
from pretix.base.auth import get_auth_backends
|
from pretix.base.auth import get_auth_backends
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite, User,
|
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
|
||||||
|
User,
|
||||||
)
|
)
|
||||||
from pretix.base.models.seating import SeatingPlanLayoutValidator
|
from pretix.base.models.seating import SeatingPlanLayoutValidator
|
||||||
from pretix.base.services.mail import SendMailException, mail
|
from pretix.base.services.mail import SendMailException, mail
|
||||||
@@ -66,9 +67,6 @@ class EventSlugField(serializers.SlugRelatedField):
|
|||||||
class TeamSerializer(serializers.ModelSerializer):
|
class TeamSerializer(serializers.ModelSerializer):
|
||||||
limit_events = EventSlugField(slug_field='slug', many=True)
|
limit_events = EventSlugField(slug_field='slug', many=True)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Team
|
model = Team
|
||||||
fields = (
|
fields = (
|
||||||
@@ -86,6 +84,28 @@ class TeamSerializer(serializers.ModelSerializer):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceSerializer(serializers.ModelSerializer):
|
||||||
|
limit_events = EventSlugField(slug_field='slug', many=True)
|
||||||
|
device_id = serializers.IntegerField(read_only=True)
|
||||||
|
unique_serial = serializers.CharField(read_only=True)
|
||||||
|
hardware_brand = serializers.CharField(read_only=True)
|
||||||
|
hardware_model = serializers.CharField(read_only=True)
|
||||||
|
software_brand = serializers.CharField(read_only=True)
|
||||||
|
software_version = serializers.CharField(read_only=True)
|
||||||
|
created = serializers.DateTimeField(read_only=True)
|
||||||
|
revoked = serializers.BooleanField(read_only=True)
|
||||||
|
initialized = serializers.DateTimeField(read_only=True)
|
||||||
|
initialization_token = serializers.DateTimeField(read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Device
|
||||||
|
fields = (
|
||||||
|
'device_id', 'unique_serial', 'initialization_token', 'all_events', 'limit_events',
|
||||||
|
'revoked', 'name', 'created', 'initialized', 'hardware_brand', 'hardware_model',
|
||||||
|
'software_brand', 'software_version'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TeamInviteSerializer(serializers.ModelSerializer):
|
class TeamInviteSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TeamInvite
|
model = TeamInvite
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ orga_router.register(r'webhooks', webhooks.WebHookViewSet)
|
|||||||
orga_router.register(r'seatingplans', organizer.SeatingPlanViewSet)
|
orga_router.register(r'seatingplans', organizer.SeatingPlanViewSet)
|
||||||
orga_router.register(r'giftcards', organizer.GiftCardViewSet)
|
orga_router.register(r'giftcards', organizer.GiftCardViewSet)
|
||||||
orga_router.register(r'teams', organizer.TeamViewSet)
|
orga_router.register(r'teams', organizer.TeamViewSet)
|
||||||
|
orga_router.register(r'devices', organizer.DeviceViewSet)
|
||||||
|
|
||||||
team_router = routers.DefaultRouter()
|
team_router = routers.DefaultRouter()
|
||||||
team_router.register(r'members', organizer.TeamMemberViewSet)
|
team_router.register(r'members', organizer.TeamMemberViewSet)
|
||||||
|
|||||||
@@ -6,20 +6,22 @@ from django.shortcuts import get_object_or_404
|
|||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from rest_framework import filters, serializers, status, viewsets
|
from rest_framework import filters, mixins, serializers, status, viewsets
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
|
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
|
||||||
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin
|
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.viewsets import GenericViewSet
|
||||||
|
|
||||||
from pretix.api.models import OAuthAccessToken
|
from pretix.api.models import OAuthAccessToken
|
||||||
from pretix.api.serializers.organizer import (
|
from pretix.api.serializers.organizer import (
|
||||||
GiftCardSerializer, OrganizerSerializer, SeatingPlanSerializer,
|
DeviceSerializer, GiftCardSerializer, OrganizerSerializer,
|
||||||
TeamAPITokenSerializer, TeamInviteSerializer, TeamMemberSerializer,
|
SeatingPlanSerializer, TeamAPITokenSerializer, TeamInviteSerializer,
|
||||||
TeamSerializer,
|
TeamMemberSerializer, TeamSerializer,
|
||||||
)
|
)
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite, User,
|
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
|
||||||
|
User,
|
||||||
)
|
)
|
||||||
from pretix.helpers.dicts import merge_dicts
|
from pretix.helpers.dicts import merge_dicts
|
||||||
|
|
||||||
@@ -353,3 +355,44 @@ class TeamAPITokenViewSet(CreateModelMixin, DestroyModelMixin, viewsets.ReadOnly
|
|||||||
serializer = self.get_serializer_class()(instance)
|
serializer = self.get_serializer_class()(instance)
|
||||||
headers = self.get_success_headers(serializer.data)
|
headers = self.get_success_headers(serializer.data)
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK, headers=headers)
|
return Response(serializer.data, status=status.HTTP_200_OK, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceViewSet(mixins.CreateModelMixin,
|
||||||
|
mixins.RetrieveModelMixin,
|
||||||
|
mixins.UpdateModelMixin,
|
||||||
|
mixins.ListModelMixin,
|
||||||
|
GenericViewSet):
|
||||||
|
serializer_class = DeviceSerializer
|
||||||
|
queryset = Device.objects.none()
|
||||||
|
permission = 'can_change_organizer_settings'
|
||||||
|
write_permission = 'can_change_organizer_settings'
|
||||||
|
lookup_field = 'device_id'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.request.organizer.devices.order_by('pk')
|
||||||
|
|
||||||
|
def get_serializer_context(self):
|
||||||
|
ctx = super().get_serializer_context()
|
||||||
|
ctx['organizer'] = self.request.organizer
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
@transaction.atomic()
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
inst = serializer.save(organizer=self.request.organizer)
|
||||||
|
inst.log_action(
|
||||||
|
'pretix.device.created',
|
||||||
|
user=self.request.user,
|
||||||
|
auth=self.request.auth,
|
||||||
|
data=merge_dicts(self.request.data, {'id': inst.pk})
|
||||||
|
)
|
||||||
|
|
||||||
|
@transaction.atomic()
|
||||||
|
def perform_update(self, serializer):
|
||||||
|
inst = serializer.save()
|
||||||
|
inst.log_action(
|
||||||
|
'pretix.device.changed',
|
||||||
|
user=self.request.user,
|
||||||
|
auth=self.request.auth,
|
||||||
|
data=self.request.data
|
||||||
|
)
|
||||||
|
return inst
|
||||||
|
|||||||
@@ -144,6 +144,11 @@ org_permission_sub_urls = [
|
|||||||
('get', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
('get', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||||
('put', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
('put', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||||
('patch', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
('patch', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||||
|
('get', 'can_change_organizer_settings', 'devices/', 200),
|
||||||
|
('post', 'can_change_organizer_settings', 'devices/', 400),
|
||||||
|
('get', 'can_change_organizer_settings', 'devices/1/', 404),
|
||||||
|
('put', 'can_change_organizer_settings', 'devices/1/', 404),
|
||||||
|
('patch', 'can_change_organizer_settings', 'devices/1/', 404),
|
||||||
('get', 'can_change_teams', 'teams/', 200),
|
('get', 'can_change_teams', 'teams/', 200),
|
||||||
('post', 'can_change_teams', 'teams/', 400),
|
('post', 'can_change_teams', 'teams/', 400),
|
||||||
('get', 'can_change_teams', 'teams/{team_id}/', 200),
|
('get', 'can_change_teams', 'teams/{team_id}/', 200),
|
||||||
|
|||||||
Reference in New Issue
Block a user