From 2a175aa43d387ea560ad3a87b52a2294eba995a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Sun, 10 Dec 2017 03:49:21 +0100 Subject: [PATCH] create and show access qr code --- .../control/templates/control/access.html | 9 ++++ .../control/templates/control/access_qr.html | 25 +++++++++ src/c3nav/control/templates/control/base.html | 7 ++- src/c3nav/control/urls.py | 4 +- src/c3nav/control/views.py | 54 ++++++++++++++++++- src/c3nav/mapdata/models/access.py | 3 ++ 6 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 src/c3nav/control/templates/control/access.html create mode 100644 src/c3nav/control/templates/control/access_qr.html 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)