redeem token after logging in
This commit is contained in:
parent
040e2b2843
commit
803f9ee121
3 changed files with 40 additions and 13 deletions
|
@ -2,7 +2,7 @@ import pickle
|
|||
import uuid
|
||||
from collections import namedtuple
|
||||
from datetime import timedelta
|
||||
from typing import Iterable
|
||||
from typing import Sequence
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
@ -10,6 +10,7 @@ from django.db import models, transaction
|
|||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
|
||||
from c3nav.mapdata.models import MapUpdate
|
||||
from c3nav.mapdata.models.base import SerializableMixin, TitledMixin
|
||||
|
@ -57,19 +58,22 @@ class AccessPermissionToken(models.Model):
|
|||
data = models.BinaryField()
|
||||
|
||||
@property
|
||||
def restrictions(self) -> Iterable[AccessPermissionTokenItem]:
|
||||
def restrictions(self) -> Sequence[AccessPermissionTokenItem]:
|
||||
return pickle.loads(self.data)
|
||||
|
||||
@restrictions.setter
|
||||
def restrictions(self, value: Iterable[AccessPermissionTokenItem]):
|
||||
def restrictions(self, value: Sequence[AccessPermissionTokenItem]):
|
||||
self.data = pickle.dumps(value)
|
||||
|
||||
class RedeemError(Exception):
|
||||
pass
|
||||
|
||||
def redeem(self, user=None):
|
||||
if self.redeemed_by_id or (user is None and self.redeemed):
|
||||
raise TypeError('Already redeemed.')
|
||||
raise self.RedeemError('Already redeemed.')
|
||||
|
||||
if timezone.now()+timedelta(minutes=300 if self.redeemed else 0) > self.valid_until:
|
||||
raise TypeError('No longer valid.')
|
||||
if timezone.now() > self.valid_until + timedelta(minutes=5 if self.redeemed else 0):
|
||||
raise self.RedeemError('No longer valid.')
|
||||
|
||||
self.redeemed = True
|
||||
if user:
|
||||
|
@ -90,6 +94,10 @@ class AccessPermissionToken(models.Model):
|
|||
def bump(self):
|
||||
self.valid_until = default_valid_until()
|
||||
|
||||
@property
|
||||
def redeem_success_message(self):
|
||||
return ungettext_lazy('Area successfully unlocked.', 'Areas successfully unlocked.', len(self.restrictions))
|
||||
|
||||
|
||||
class AccessPermission(models.Model):
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
|
|
|
@ -9,15 +9,15 @@
|
|||
{% include 'site/fragment_messages.html' %}
|
||||
|
||||
{% if back_url %}
|
||||
<p><a href="{{ back_url }}">« {% trans 'back' %}</a></p>
|
||||
<p><a href="{{ back_url }}?{{ request.META.QUERY_STRING }}">« {% trans 'back' %}</a></p>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{{ request.path_info }}?{{ request.GET.urlencode }}">
|
||||
<form method="post" action="{{ request.path_info }}?{{ request.META.QUERY_STRING }}">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<button type="submit">{{ title }}</button>
|
||||
{% if bottom_link_url %}
|
||||
<a href="{{ bottom_link_url }}?{{ request.GET.urlencode }}">{{ bottom_link_text }}</a>
|
||||
<a href="{{ bottom_link_url }}?{{ request.META.QUERY_STRING }}">{{ bottom_link_text }}</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,6 @@ from django.contrib import messages
|
|||
from django.contrib.auth import login, logout
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm, UserCreationForm
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db import transaction
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
|
@ -132,6 +131,25 @@ def close_response(request):
|
|||
return redirect(redirect_path)
|
||||
|
||||
|
||||
def redeem_token_after_login(request):
|
||||
token = request.session.pop('redeem_token_on_login')
|
||||
if not token:
|
||||
return
|
||||
|
||||
try:
|
||||
token = AccessPermissionToken.objects.get(id=token)
|
||||
except AccessPermissionToken.DoesNotExist:
|
||||
return
|
||||
|
||||
try:
|
||||
token.redeem(request.user)
|
||||
except AccessPermissionToken.RedeemError:
|
||||
messages.error(request, _('Areas could not be unlocked because the token has expired.'))
|
||||
return
|
||||
|
||||
messages.success(request, token.redeem_success_message)
|
||||
|
||||
|
||||
@never_cache
|
||||
def login_view(request):
|
||||
if request.user.is_authenticated:
|
||||
|
@ -141,6 +159,7 @@ def login_view(request):
|
|||
form = AuthenticationForm(request, data=request.POST)
|
||||
if form.is_valid():
|
||||
login(request, form.user_cache)
|
||||
redeem_token_after_login(request)
|
||||
return close_response(request)
|
||||
else:
|
||||
form = AuthenticationForm(request)
|
||||
|
@ -169,6 +188,7 @@ def register_view(request):
|
|||
if form.is_valid():
|
||||
user = form.save()
|
||||
login(request, user)
|
||||
redeem_token_after_login(request)
|
||||
return close_response(request)
|
||||
else:
|
||||
form = UserCreationForm()
|
||||
|
@ -214,7 +234,6 @@ def account_view(request):
|
|||
|
||||
|
||||
@never_cache
|
||||
@login_required(login_url='site.login')
|
||||
def access_redeem_view(request, token):
|
||||
with transaction.atomic():
|
||||
try:
|
||||
|
@ -232,8 +251,8 @@ def access_redeem_view(request, token):
|
|||
|
||||
if not request.user.is_authenticated:
|
||||
messages.info(request, _('You need to log in to unlock areas.'))
|
||||
request.session['redeem_token_on_login'] = token.id
|
||||
return redirect_to_login(request.get_full_path(), 'site.login')
|
||||
request.session['redeem_token_on_login'] = str(token.id)
|
||||
return redirect('site.login')
|
||||
|
||||
token.redeemed_by = request.user
|
||||
token.save()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue