diff --git a/src/pretix/control/logdisplay.py b/src/pretix/control/logdisplay.py
index 0df4d9b88..3d6ad6ce6 100644
--- a/src/pretix/control/logdisplay.py
+++ b/src/pretix/control/logdisplay.py
@@ -274,6 +274,12 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
'pretix.subevent.quota.added': pgettext_lazy('subevent', 'A quota has been added to the event date.'),
'pretix.subevent.quota.changed': pgettext_lazy('subevent', 'A quota has been changed on the event date.'),
'pretix.subevent.quota.deleted': pgettext_lazy('subevent', 'A quota has been removed from the event date.'),
+ 'pretix.device.created': _('The device has been created.'),
+ 'pretix.device.changed': _('The device has been changed.'),
+ 'pretix.device.revoked': _('Access of the device has been revoked.'),
+ 'pretix.device.initialized': _('The device has been initialized.'),
+ 'pretix.device.keyroll': _('The access token of the device has been regenerated.'),
+ 'pretix.device.updated': _('The device has notified the server of an hardware or software update.'),
}
data = json.loads(logentry.data)
diff --git a/src/pretix/control/templates/pretixcontrol/organizers/device_edit.html b/src/pretix/control/templates/pretixcontrol/organizers/device_edit.html
index ab5899456..86c07984e 100644
--- a/src/pretix/control/templates/pretixcontrol/organizers/device_edit.html
+++ b/src/pretix/control/templates/pretixcontrol/organizers/device_edit.html
@@ -8,6 +8,10 @@
{% endif %}
{% endblock %}
diff --git a/src/pretix/control/templates/pretixcontrol/organizers/device_revoke.html b/src/pretix/control/templates/pretixcontrol/organizers/device_revoke.html
new file mode 100644
index 000000000..621c4ae30
--- /dev/null
+++ b/src/pretix/control/templates/pretixcontrol/organizers/device_revoke.html
@@ -0,0 +1,21 @@
+{% extends "pretixcontrol/organizers/base.html" %}
+{% load i18n %}
+{% load bootstrap3 %}
+{% block inner %}
+ {% trans "Revoke device access:" %} {{ device.name }}
+
+{% endblock %}
diff --git a/src/pretix/control/templates/pretixcontrol/organizers/devices.html b/src/pretix/control/templates/pretixcontrol/organizers/devices.html
index 4d4c4d0ac..edf95fb29 100644
--- a/src/pretix/control/templates/pretixcontrol/organizers/devices.html
+++ b/src/pretix/control/templates/pretixcontrol/organizers/devices.html
@@ -81,6 +81,10 @@
{% trans "Connect" %}
+ {% elif d.api_token %}
+
+ {% trans "Revoke access" %}
{% endif %}
diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py
index 6ec60df4c..4137e8fa0 100644
--- a/src/pretix/control/urls.py
+++ b/src/pretix/control/urls.py
@@ -71,10 +71,12 @@ urlpatterns = [
url(r'^organizer/(?P[^/]+)/devices$', organizer.DeviceListView.as_view(), name='organizer.devices'),
url(r'^organizer/(?P[^/]+)/device/add$', organizer.DeviceCreateView.as_view(),
name='organizer.device.add'),
- url(r'^organizer/(?P[^/]+)/device/(?P[^/]+)/edit', organizer.DeviceUpdateView.as_view(),
+ url(r'^organizer/(?P[^/]+)/device/(?P[^/]+)/edit$', organizer.DeviceUpdateView.as_view(),
name='organizer.device.edit'),
- url(r'^organizer/(?P[^/]+)/device/(?P[^/]+)/connect', organizer.DeviceConnectView.as_view(),
+ url(r'^organizer/(?P[^/]+)/device/(?P[^/]+)/connect$', organizer.DeviceConnectView.as_view(),
name='organizer.device.connect'),
+ url(r'^organizer/(?P[^/]+)/device/(?P[^/]+)/revoke$', organizer.DeviceRevokeView.as_view(),
+ name='organizer.device.revoke'),
url(r'^organizer/(?P[^/]+)/teams$', organizer.TeamListView.as_view(), name='organizer.teams'),
url(r'^organizer/(?P[^/]+)/team/add$', organizer.TeamCreateView.as_view(), name='organizer.team.add'),
url(r'^organizer/(?P[^/]+)/team/(?P[^/]+)/$', organizer.TeamMemberView.as_view(),
diff --git a/src/pretix/control/views/organizer.py b/src/pretix/control/views/organizer.py
index 0a41947d1..c547b7872 100644
--- a/src/pretix/control/views/organizer.py
+++ b/src/pretix/control/views/organizer.py
@@ -662,7 +662,6 @@ class DeviceConnectView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
template_name = 'pretixcontrol/organizers/device_connect.html'
permission = 'can_change_organizer_settings'
context_object_name = 'device'
- form_class = DeviceForm
def get_object(self, queryset=None):
return get_object_or_404(Device, organizer=self.request.organizer, pk=self.kwargs.get('device'))
@@ -688,3 +687,32 @@ class DeviceConnectView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
'token': self.object.initialization_token,
})
return ctx
+
+
+class DeviceRevokeView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
+ model = Device
+ template_name = 'pretixcontrol/organizers/device_revoke.html'
+ permission = 'can_change_organizer_settings'
+ context_object_name = 'device'
+
+ def get_object(self, queryset=None):
+ return get_object_or_404(Device, organizer=self.request.organizer, pk=self.kwargs.get('device'))
+
+ def get(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ if not self.object.api_token:
+ messages.success(request, _('This device currently does not have access.'))
+ return redirect(reverse('control:organizer.devices', kwargs={
+ 'organizer': self.request.organizer.slug,
+ }))
+ return super().get(request, *args, **kwargs)
+
+ def post(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ self.object.api_token = None
+ self.object.save()
+ self.object.log_action('pretix.device.revoked', user=self.request.user)
+ messages.success(request, _('Access for this device has been revoked.'))
+ return redirect(reverse('control:organizer.devices', kwargs={
+ 'organizer': self.request.organizer.slug,
+ }))