diff --git a/src/c3nav/access/admin.py b/src/c3nav/access/admin.py index 0fed57aa..88c827ba 100644 --- a/src/c3nav/access/admin.py +++ b/src/c3nav/access/admin.py @@ -29,7 +29,7 @@ admin.site.register(User, UserAdmin) class AccessTokenInline(admin.TabularInline): model = AccessToken show_change_link = True - readonly_fields = ('author', 'permissions', 'description', 'creation_date', 'expires', 'expired') + readonly_fields = ('author', 'permissions', 'description', 'creation_date', 'activated', 'expires', 'expired') def has_add_permission(self, request): return False @@ -55,9 +55,9 @@ class AccessTokenInstanceInline(admin.TabularInline): @admin.register(AccessToken) class AccessTokenAdmin(admin.ModelAdmin): inlines = (AccessTokenInstanceInline,) - list_display = ('__str__', 'user', 'permissions', 'author', 'creation_date', 'expires', 'expired') - fields = ('user', 'permissions', 'author', 'creation_date', 'expires', 'expired') - readonly_fields = ('user', 'creation_date', 'expired') + list_display = ('__str__', 'user', 'permissions', 'author', 'creation_date', 'activated', 'expires', 'expired') + fields = ('user', 'permissions', 'author', 'creation_date', 'activated', 'expires', 'expired') + readonly_fields = ('user', 'creation_date', 'activated', 'expired') def has_add_permission(self, request): return False diff --git a/src/c3nav/access/middleware.py b/src/c3nav/access/middleware.py new file mode 100644 index 00000000..d2069065 --- /dev/null +++ b/src/c3nav/access/middleware.py @@ -0,0 +1,50 @@ +import re +from datetime import timedelta + +from django.db import transaction +from django.db.models import Q +from django.utils import timezone + +from c3nav.access.models import AccessTokenInstance + + +class AccessTokenMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + request.c3nav_access_instance = None + request.c3nav_access_token = None + request.c3nav_new_access_token = False + + access_cookie = request.COOKIES.get('c3nav_access') + if access_cookie and re.match(r'^[0-9]+:[a-zA-Z0-9]+$', access_cookie): + pk, secret = access_cookie.split(':') + queryset = AccessTokenInstance.objects.filter(Q(access_token__id=int(pk), secret=secret), + Q(expires__isnull=True) | Q(expires__gt=timezone.now()), + Q(access_token__expired=False), + Q(access_token__expires__isnull=True) | + Q(access_token__expires__gt=timezone.now())) + access_instance = queryset.select_related('access_token').first() + if access_instance: + request.c3nav_access_instance = access_instance + request.c3nav_access_token = access_instance.access_token + request.c3nav_access_token.instances.filter(creation_date__lt=access_instance.creation_date).delete() + + response = self.get_response(request) + + if request.c3nav_access_token is not None: + with transaction.atomic(): + cookie_value = request.c3nav_access_token.new_instance() + response.set_cookie('c3nav_access', cookie_value, expires=timezone.now() + timedelta(days=30)) + + if request.c3nav_new_access_token: + request.c3nav_access_token.activated = True + request.c3nav_access_token.save() + + if request.c3nav_access_instance: + access_token = request.c3nav_access_instance.access_token + access_token.expired = True + access_token.save() + + return response diff --git a/src/c3nav/access/views.py b/src/c3nav/access/views.py index ba1673d1..90a172e6 100644 --- a/src/c3nav/access/views.py +++ b/src/c3nav/access/views.py @@ -69,8 +69,9 @@ def prove(request): def activate_token(request, pk, secret): - token = get_object_or_404(AccessToken, expired=False, id=pk, secret=secret) # noqa - + token = get_object_or_404(AccessToken, expired=False, activated=False, id=pk, secret=secret) + request.c3nav_access_token = token + request.c3nav_new_access_token = True return render(request, 'access/activate.html', context={ 'success': True, }) diff --git a/src/c3nav/settings.py b/src/c3nav/settings.py index d77432f0..e79c8722 100644 --- a/src/c3nav/settings.py +++ b/src/c3nav/settings.py @@ -151,7 +151,7 @@ INSTALLED_APPS = [ 'c3nav.editor', ] -MIDDLEWARE_CLASSES = [ +MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', @@ -161,6 +161,7 @@ MIDDLEWARE_CLASSES = [ 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'c3nav.access.middleware.AccessTokenMiddleware', ] try: @@ -168,7 +169,7 @@ try: except ImportError: pass else: - MIDDLEWARE_CLASSES += [ + MIDDLEWARE += [ 'htmlmin.middleware.HtmlMinifyMiddleware', 'htmlmin.middleware.MarkRequestMiddleware', ]