diff --git a/src/c3nav/control/templates/control/access.html b/src/c3nav/control/templates/control/access.html
new file mode 100644
index 00000000..9746397f
--- /dev/null
+++ b/src/c3nav/control/templates/control/access.html
@@ -0,0 +1,9 @@
+{% extends 'control/base.html' %}
+{% load i18n %}
+
+{% block heading %}{% trans 'Access Permissions' %}{% endblock %}
+
+{% block subcontent %}
+ {% trans 'Generate QR Code' as button_label %}
+ {% include 'control/fragment_access_permissions_form.html' with button_label=button_label %}
+{% endblock %}
diff --git a/src/c3nav/control/templates/control/access_qr.html b/src/c3nav/control/templates/control/access_qr.html
new file mode 100644
index 00000000..aabd22fd
--- /dev/null
+++ b/src/c3nav/control/templates/control/access_qr.html
@@ -0,0 +1,25 @@
+{% extends 'control/base.html' %}
+{% load i18n %}
+
+{% block heading %}{% trans 'Access Permission QR Code' %}{% endblock %}
+
+{% block addattributes %} style="text-align: center;"{% endblock %}
+{% block menu %}{% endblock %}
+
+{% block subcontent %}
+
+ {% trans 'Scan this QR code to get access permissions:' %}
+
+
+
+
+
+ {{ absolute_url }}
+
+
+ « {% trans 'back' %}
+
+
+{% endblock %}
diff --git a/src/c3nav/control/templates/control/base.html b/src/c3nav/control/templates/control/base.html
index 30c2fd45..d9a0316b 100644
--- a/src/c3nav/control/templates/control/base.html
+++ b/src/c3nav/control/templates/control/base.html
@@ -6,15 +6,18 @@
{% block header_title_url %}{% url 'control.index' %}{% endblock %}
{% block content %}
-
+
{% include 'site/fragment_messages.html' %}
{% block heading %}{% endblock %}
+ {% block menu %}
+ {% endblock %}
{% block subcontent %}
{% endblock %}
diff --git a/src/c3nav/control/urls.py b/src/c3nav/control/urls.py
index dcb68f52..6255143f 100644
--- a/src/c3nav/control/urls.py
+++ b/src/c3nav/control/urls.py
@@ -1,9 +1,11 @@
from django.conf.urls import url
-from c3nav.control.views import main_index, user_detail, user_list
+from c3nav.control.views import grant_access, grant_access_qr, main_index, user_detail, user_list
urlpatterns = [
url(r'^users/$', user_list, name='control.users'),
url(r'^users/(?P\d+)/$', user_detail, name='control.users.detail'),
+ url(r'^access/$', grant_access, name='control.access'),
+ url(r'^access/qr/(?P[^/]+)', grant_access_qr, name='control.access.qr'),
url(r'^$', main_index, name='control.index'),
]
diff --git a/src/c3nav/control/views.py b/src/c3nav/control/views.py
index 1bbcad58..8437593b 100644
--- a/src/c3nav/control/views.py
+++ b/src/c3nav/control/views.py
@@ -5,13 +5,15 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
from django.core.paginator import Paginator
+from django.db import transaction
from django.db.models import Prefetch
from django.shortcuts import get_object_or_404, redirect, render
+from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from c3nav.control.forms import AccessPermissionForm, UserPermissionsForm
from c3nav.control.models import UserPermissions
-from c3nav.mapdata.models.access import AccessPermission
+from c3nav.mapdata.models.access import AccessPermission, AccessPermissionToken
def control_panel_view(func):
@@ -112,3 +114,53 @@ def user_detail(request, user):
})
return render(request, 'control/user.html', ctx)
+
+
+@login_required
+@control_panel_view
+def grant_access(request):
+ if request.method == 'POST' and request.POST.get('submit_access_permissions'):
+ form = AccessPermissionForm(request=request, data=request.POST)
+ if form.is_valid():
+ token = form.get_token()
+ token.save()
+ return redirect(reverse('control.access.qr', kwargs={'token': token.id}))
+ else:
+ form = AccessPermissionForm(request=request)
+
+ ctx = {
+ 'access_permission_form': form
+ }
+
+ return render(request, 'control/access.html', ctx)
+
+
+@login_required
+@control_panel_view
+def grant_access_qr(request, token):
+ with transaction.atomic():
+ token = AccessPermissionToken.objects.select_for_update().get(id=token, author=request.user)
+ if token.redeemed:
+ messages.success(_('Access successfully granted!'))
+ token = None
+ elif not token.unlimited:
+ try:
+ latest = AccessPermissionToken.objects.filter(author=request.user).latest('valid_until')
+ except AccessPermissionToken.DoesNotExist:
+ token = None
+ else:
+ if latest.id != token.id:
+ token = None
+ if token is None:
+ messages.error(_('You can only display your most recently created token.'))
+
+ if token is None:
+ redirect('control.access')
+
+ token.bump()
+ token.save()
+
+ return render(request, 'control/access_qr.html', {
+ 'token': token.id,
+ 'absolute_url': request.build_absolute_uri('/access/qr/%s' % token.id)
+ })
diff --git a/src/c3nav/mapdata/models/access.py b/src/c3nav/mapdata/models/access.py
index caba60db..5c7b112f 100644
--- a/src/c3nav/mapdata/models/access.py
+++ b/src/c3nav/mapdata/models/access.py
@@ -78,6 +78,9 @@ class AccessPermissionToken(models.Model):
if self.pk:
self.save()
+ def bump(self):
+ self.valid_until = default_valid_until()
+
class AccessPermission(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)