forked from CGM_Public/pretix_original
Add endpoints to update, roll and revoke devices
This commit is contained in:
@@ -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"),
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -167,6 +167,9 @@
|
||||
<br><span class="fa fa-plug fa-fw"></span>
|
||||
{{ log.oauth_application.name }}
|
||||
{% endif %}
|
||||
{% elif log.device %}
|
||||
<span class="fa fa-mobile fa-fw"></span>
|
||||
{{ log.device.name }}
|
||||
{% elif log.api_token %}
|
||||
<span class="fa fa-key fa-fw"></span>
|
||||
{{ log.api_token.name }}
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
<br><span class="fa fa-plug fa-fw"></span>
|
||||
{{ log.oauth_application.name }}
|
||||
{% endif %}
|
||||
{% elif log.device %}
|
||||
<span class="fa fa-mobile fa-fw"></span>
|
||||
{{ log.device.name }}
|
||||
{% elif log.api_token %}
|
||||
<span class="fa fa-key fa-fw"></span>
|
||||
{{ log.api_token.name }}
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
<span class="fa fa-plug fa-fw"></span>
|
||||
{{ log.oauth_application.name }}
|
||||
{% endif %}
|
||||
{% elif log.device %}
|
||||
<span class="fa fa-mobile fa-fw"></span>
|
||||
{{ log.device.name }}
|
||||
{% elif log.api_token %}
|
||||
<span class="fa fa-key fa-fw"></span>
|
||||
{{ log.api_token.name }}
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
{{ d.device_id }}
|
||||
</td>
|
||||
<td>
|
||||
{% if d.initialized and not d.api_token %}<del>{% endif %}
|
||||
{{ d.name }}
|
||||
{% if d.initialized and not d.api_token %}</del>{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ d.hardware_brand|default_if_none:"" }} {{ d.hardware_model|default_if_none:"" }}
|
||||
@@ -55,6 +57,9 @@
|
||||
{% else %}
|
||||
<em>{% trans "Not yet initialized" %}</em>
|
||||
{% endif %}
|
||||
{% if d.initialized and not d.api_token %}
|
||||
<span class="label label-danger">{% trans "Revoked" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if d.all_events %}
|
||||
|
||||
@@ -254,7 +254,8 @@ def event_index(request, organizer, event):
|
||||
|
||||
can_change_orders = request.user.has_event_permission(request.organizer, request.event, 'can_change_orders',
|
||||
request=request)
|
||||
qs = request.event.logentry_set.all().select_related('user', 'content_type', 'api_token', 'oauth_application').order_by('-datetime')
|
||||
qs = request.event.logentry_set.all().select_related('user', 'content_type', 'api_token', 'oauth_application',
|
||||
'device').order_by('-datetime')
|
||||
qs = qs.exclude(action_type__in=OVERVIEW_BLACKLIST)
|
||||
if not request.user.has_event_permission(request.organizer, request.event, 'can_view_orders', request=request):
|
||||
qs = qs.exclude(content_type=ContentType.objects.get_for_model(Order))
|
||||
|
||||
@@ -875,7 +875,7 @@ class EventLog(EventPermissionRequiredMixin, ListView):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.request.event.logentry_set.all().select_related(
|
||||
'user', 'content_type', 'api_token', 'oauth_application'
|
||||
'user', 'content_type', 'api_token', 'oauth_application', 'device'
|
||||
).order_by('-datetime')
|
||||
qs = qs.exclude(action_type__in=OVERVIEW_BLACKLIST)
|
||||
if not self.request.user.has_event_permission(self.request.organizer, self.request.event, 'can_view_orders',
|
||||
|
||||
@@ -5,6 +5,7 @@ from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.mixins import CreateModelMixin
|
||||
from rest_framework.response import Response
|
||||
|
||||
from pretix.base.models import Device
|
||||
from pretix.base.models.organizer import TeamAPIToken
|
||||
|
||||
from .models import BankImportJob, BankTransaction
|
||||
@@ -68,7 +69,7 @@ class BankImportJobViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
return serializer.save()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
perm_holder = (request.auth if isinstance(request.auth, TeamAPIToken) else request.user)
|
||||
perm_holder = (request.auth if isinstance(request.auth, (Device, TeamAPIToken)) else request.user)
|
||||
if not perm_holder.has_organizer_permission(request.organizer, 'can_change_orders'):
|
||||
raise PermissionDenied('Invalid set of permissions')
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
|
||||
Reference in New Issue
Block a user