diff --git a/src/pretix/api/urls.py b/src/pretix/api/urls.py
index 0a8fce1e2b..56be1365c5 100644
--- a/src/pretix/api/urls.py
+++ b/src/pretix/api/urls.py
@@ -67,5 +67,8 @@ urlpatterns = [
url(r"^oauth/authorize$", oauth.AuthorizationView.as_view(), name="authorize"),
url(r"^oauth/token$", oauth.TokenView.as_view(), name="token"),
url(r"^oauth/revoke_token$", oauth.RevokeTokenView.as_view(), name="revoke-token"),
- url(r"^device/initialize", device.InitializeView.as_view(), name="device.initialize"),
+ url(r"^device/initialize$", device.InitializeView.as_view(), name="device.initialize"),
+ url(r"^device/update$", device.UpdateView.as_view(), name="device.update"),
+ url(r"^device/roll$", device.RollKeyView.as_view(), name="device.roll"),
+ url(r"^device/revoke$", device.RevokeKeyView.as_view(), name="device.revoke"),
]
diff --git a/src/pretix/api/views/device.py b/src/pretix/api/views/device.py
index 3a51ae3e70..b8fefdc20d 100644
--- a/src/pretix/api/views/device.py
+++ b/src/pretix/api/views/device.py
@@ -6,6 +6,7 @@ from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from rest_framework.views import APIView
+from pretix.api.auth.device import DeviceTokenAuthentication
from pretix.base.models import Device
from pretix.base.models.devices import generate_api_token
@@ -20,6 +21,13 @@ class InitializationRequestSerializer(serializers.Serializer):
software_version = serializers.CharField(max_length=190)
+class UpdateRequestSerializer(serializers.Serializer):
+ hardware_brand = serializers.CharField(max_length=190)
+ hardware_model = serializers.CharField(max_length=190)
+ software_brand = serializers.CharField(max_length=190)
+ software_version = serializers.CharField(max_length=190)
+
+
class DeviceSerializer(serializers.ModelSerializer):
organizer = serializers.SlugRelatedField(slug_field='slug', read_only=True)
@@ -55,5 +63,51 @@ class InitializeView(APIView):
device.api_token = generate_api_token()
device.save()
+ device.log_action('pretix.device.initialized', data=serializer.validated_data, auth=device)
+
+ serializer = DeviceSerializer(device)
+ return Response(serializer.data)
+
+
+class UpdateView(APIView):
+ authentication_classes = (DeviceTokenAuthentication,)
+
+ def post(self, request, format=None):
+ serializer = UpdateRequestSerializer(data=request.data)
+ serializer.is_valid(raise_exception=True)
+ device = request.auth
+ device.hardware_brand = serializer.validated_data.get('hardware_brand')
+ device.hardware_model = serializer.validated_data.get('hardware_model')
+ device.software_brand = serializer.validated_data.get('software_brand')
+ device.software_version = serializer.validated_data.get('software_version')
+ device.save()
+ device.log_action('pretix.device.updated', data=serializer.validated_data, auth=device)
+
+ serializer = DeviceSerializer(device)
+ return Response(serializer.data)
+
+
+class RollKeyView(APIView):
+ authentication_classes = (DeviceTokenAuthentication,)
+
+ def post(self, request, format=None):
+ device = request.auth
+ device.api_token = generate_api_token()
+ device.save()
+ device.log_action('pretix.device.keyroll', auth=device)
+
+ serializer = DeviceSerializer(device)
+ return Response(serializer.data)
+
+
+class RevokeKeyView(APIView):
+ authentication_classes = (DeviceTokenAuthentication,)
+
+ def post(self, request, format=None):
+ device = request.auth
+ device.api_token = None
+ device.save()
+ device.log_action('pretix.device.keyroll', auth=device)
+
serializer = DeviceSerializer(device)
return Response(serializer.data)
diff --git a/src/pretix/api/views/order.py b/src/pretix/api/views/order.py
index 14ecef8528..e18eebb1ad 100644
--- a/src/pretix/api/views/order.py
+++ b/src/pretix/api/views/order.py
@@ -25,7 +25,7 @@ from pretix.api.serializers.order import (
OrderRefundSerializer, OrderSerializer,
)
from pretix.base.models import (
- Invoice, Order, OrderPayment, OrderPosition, OrderRefund, Quota,
+ Device, Invoice, Order, OrderPayment, OrderPosition, OrderRefund, Quota,
TeamAPIToken,
)
from pretix.base.payment import PaymentException
@@ -177,6 +177,7 @@ class OrderViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
order,
user=request.user if request.user.is_authenticated else None,
api_token=request.auth if isinstance(request.auth, TeamAPIToken) else None,
+ device=request.auth if isinstance(request.auth, Device) else None,
oauth_application=request.auth.application if isinstance(request.auth, OAuthAccessToken) else None,
send_mail=send_mail
)
@@ -191,7 +192,7 @@ class OrderViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
approve_order(
order,
user=request.user if request.user.is_authenticated else None,
- auth=request.auth if isinstance(request.auth, (TeamAPIToken, OAuthAccessToken)) else None,
+ auth=request.auth if isinstance(request.auth, (Device, TeamAPIToken, OAuthAccessToken)) else None,
send_mail=send_mail,
)
except Quota.QuotaExceededException as e:
@@ -210,7 +211,7 @@ class OrderViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
deny_order(
order,
user=request.user if request.user.is_authenticated else None,
- auth=request.auth if isinstance(request.auth, (TeamAPIToken, OAuthAccessToken)) else None,
+ auth=request.auth if isinstance(request.auth, (Device, TeamAPIToken, OAuthAccessToken)) else None,
send_mail=send_mail,
comment=comment,
)
@@ -267,7 +268,7 @@ class OrderViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
mark_order_refunded(
order,
user=request.user if request.user.is_authenticated else None,
- api_token=(request.auth if isinstance(request.auth, TeamAPIToken) else None),
+ auth=(request.auth if isinstance(request.auth, (TeamAPIToken, OAuthAccessToken, Device)) else None),
)
return self.retrieve(request, [], **kwargs)
diff --git a/src/pretix/base/migrations/0099_auto_20180912_1035.py b/src/pretix/base/migrations/0099_auto_20180912_1035.py
index fea4153cea..8094d39c20 100644
--- a/src/pretix/base/migrations/0099_auto_20180912_1035.py
+++ b/src/pretix/base/migrations/0099_auto_20180912_1035.py
@@ -37,4 +37,9 @@ class Migration(migrations.Migration):
name='device',
unique_together={('organizer', 'device_id')},
),
+ migrations.AddField(
+ model_name='logentry',
+ name='device',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='pretixbase.Device'),
+ ),
]
diff --git a/src/pretix/base/models/base.py b/src/pretix/base/models/base.py
index 98abf70924..c4b783b08c 100644
--- a/src/pretix/base/models/base.py
+++ b/src/pretix/base/models/base.py
@@ -47,6 +47,7 @@ class LoggingMixin:
"""
from .log import LogEntry
from .event import Event
+ from .devices import Device
from pretix.api.models import OAuthAccessToken, OAuthApplication
from .organizer import TeamAPIToken
from ..notifications import get_all_notification_types
@@ -67,6 +68,8 @@ class LoggingMixin:
kwargs['oauth_application'] = auth
elif isinstance(auth, TeamAPIToken):
kwargs['api_token'] = auth
+ elif isinstance(auth, Device):
+ kwargs['device'] = auth
elif isinstance(api_token, TeamAPIToken):
kwargs['api_token'] = api_token
@@ -96,4 +99,4 @@ class LoggedModel(models.Model, LoggingMixin):
return LogEntry.objects.filter(
content_type=ContentType.objects.get_for_model(type(self)), object_id=self.pk
- ).select_related('user', 'event', 'oauth_application', 'api_token')
+ ).select_related('user', 'event', 'oauth_application', 'api_token', 'device')
diff --git a/src/pretix/base/models/log.py b/src/pretix/base/models/log.py
index fb5de7d2fd..2f86753ac2 100644
--- a/src/pretix/base/models/log.py
+++ b/src/pretix/base/models/log.py
@@ -41,6 +41,7 @@ class LogEntry(models.Model):
datetime = models.DateTimeField(auto_now_add=True, db_index=True)
user = models.ForeignKey('User', null=True, blank=True, on_delete=models.PROTECT)
api_token = models.ForeignKey('TeamAPIToken', null=True, blank=True, on_delete=models.PROTECT)
+ device = models.ForeignKey('Device', null=True, blank=True, on_delete=models.PROTECT)
oauth_application = models.ForeignKey('pretixapi.OAuthApplication', null=True, blank=True, on_delete=models.PROTECT)
event = models.ForeignKey('Event', null=True, blank=True, on_delete=models.SET_NULL)
action_type = models.CharField(max_length=255)
diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py
index e67a4ea2cb..bfa15dc2ee 100644
--- a/src/pretix/base/services/orders.py
+++ b/src/pretix/base/services/orders.py
@@ -21,7 +21,7 @@ from pretix.base.i18n import (
LazyCurrencyNumber, LazyDate, LazyLocaleException, LazyNumber, language,
)
from pretix.base.models import (
- CartPosition, Event, Item, ItemVariation, Order, OrderPayment,
+ CartPosition, Device, Event, Item, ItemVariation, Order, OrderPayment,
OrderPosition, Quota, User, Voucher,
)
from pretix.base.models.event import SubEvent
@@ -307,7 +307,7 @@ def deny_order(order, comment='', user=None, send_mail: bool=True, auth=None):
@transaction.atomic
-def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, oauth_application=None):
+def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device=None, oauth_application=None):
"""
Mark this order as canceled
:param order: The order to change
@@ -319,6 +319,8 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, oauth_
user = User.objects.get(pk=user)
if isinstance(api_token, int):
api_token = TeamAPIToken.objects.get(pk=api_token)
+ if isinstance(device, int):
+ device = Device.objects.get(pk=device)
if isinstance(oauth_application, int):
oauth_application = OAuthApplication.objects.get(pk=oauth_application)
with order.event.lock():
@@ -327,7 +329,7 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, oauth_
order.status = Order.STATUS_CANCELED
order.save()
- order.log_action('pretix.event.order.canceled', user=user, auth=api_token or oauth_application)
+ order.log_action('pretix.event.order.canceled', user=user, auth=api_token or oauth_application or device)
i = order.invoices.filter(is_cancellation=False).last()
if i:
generate_cancellation(i)
diff --git a/src/pretix/control/templates/pretixcontrol/event/index.html b/src/pretix/control/templates/pretixcontrol/event/index.html
index 2f71270283..c77932eac3 100644
--- a/src/pretix/control/templates/pretixcontrol/event/index.html
+++ b/src/pretix/control/templates/pretixcontrol/event/index.html
@@ -167,6 +167,9 @@
{{ log.oauth_application.name }}
{% endif %}
+ {% elif log.device %}
+
+ {{ log.device.name }}
{% elif log.api_token %}
{{ log.api_token.name }}
diff --git a/src/pretix/control/templates/pretixcontrol/event/logs.html b/src/pretix/control/templates/pretixcontrol/event/logs.html
index 3ad186eaaf..e95ab7dc2e 100644
--- a/src/pretix/control/templates/pretixcontrol/event/logs.html
+++ b/src/pretix/control/templates/pretixcontrol/event/logs.html
@@ -54,6 +54,9 @@
{{ log.oauth_application.name }}
{% endif %}
+ {% elif log.device %}
+
+ {{ log.device.name }}
{% elif log.api_token %}
{{ log.api_token.name }}
diff --git a/src/pretix/control/templates/pretixcontrol/includes/logs.html b/src/pretix/control/templates/pretixcontrol/includes/logs.html
index aa2c4ad339..3bdffd840c 100644
--- a/src/pretix/control/templates/pretixcontrol/includes/logs.html
+++ b/src/pretix/control/templates/pretixcontrol/includes/logs.html
@@ -19,6 +19,9 @@
{{ log.oauth_application.name }}
{% endif %}
+ {% elif log.device %}
+
+ {{ log.device.name }}
{% elif log.api_token %}
{{ log.api_token.name }}
diff --git a/src/pretix/control/templates/pretixcontrol/organizers/devices.html b/src/pretix/control/templates/pretixcontrol/organizers/devices.html
index 234ac3d7cd..4d4c4d0ac0 100644
--- a/src/pretix/control/templates/pretixcontrol/organizers/devices.html
+++ b/src/pretix/control/templates/pretixcontrol/organizers/devices.html
@@ -41,7 +41,9 @@
{{ d.device_id }}