diff --git a/doc/admin/config.rst b/doc/admin/config.rst index 8b9f4f5286..e89fa23dff 100644 --- a/doc/admin/config.rst +++ b/doc/admin/config.rst @@ -60,6 +60,9 @@ Example:: ``password_reset`` Enables or disables password reset. Defaults to ``on``. +``long_sessions`` + Enables or disables the "keep me logged in" button. Defaults to ``on``. + ``ecb_rates`` By default, pretix periodically downloads a XML file from the European Central Bank to retrieve exchange rates that are used to print tax amounts in the customer currency on invoices for some currencies. Set to ``off`` to diff --git a/src/pretix/base/forms/auth.py b/src/pretix/base/forms/auth.py index c38fa3e39a..8162d3173f 100644 --- a/src/pretix/base/forms/auth.py +++ b/src/pretix/base/forms/auth.py @@ -1,4 +1,5 @@ from django import forms +from django.conf import settings from django.contrib.auth import authenticate from django.contrib.auth.password_validation import ( password_validators_help_texts, validate_password, @@ -15,6 +16,7 @@ class LoginForm(forms.Form): """ email = forms.EmailField(label=_("E-mail"), max_length=254) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) + keep_logged_in = forms.BooleanField(label=_("Keep me logged in"), required=False) error_messages = { 'invalid_login': _("Please enter a correct email address and password."), @@ -29,6 +31,8 @@ class LoginForm(forms.Form): self.request = request self.user_cache = None super().__init__(*args, **kwargs) + if not settings.PRETIX_LONG_SESSIONS: + del self.fields['keep_logged_in'] def clean(self): email = self.cleaned_data.get('email') @@ -90,6 +94,12 @@ class RegistrationForm(forms.Form): }), required=True ) + keep_logged_in = forms.BooleanField(label=_("Keep me logged in"), required=False) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if not settings.PRETIX_LONG_SESSIONS: + del self.fields['keep_logged_in'] def clean(self): password1 = self.cleaned_data.get('password', '') diff --git a/src/pretix/control/middleware.py b/src/pretix/control/middleware.py index 2870a2f224..c1b5caa20f 100644 --- a/src/pretix/control/middleware.py +++ b/src/pretix/control/middleware.py @@ -1,8 +1,9 @@ -from urllib.parse import urljoin, urlparse +import time +from urllib.parse import quote, urljoin, urlparse from django.conf import settings -from django.contrib.auth import REDIRECT_FIELD_NAME -from django.core.urlresolvers import get_script_prefix, resolve +from django.contrib.auth import REDIRECT_FIELD_NAME, logout +from django.core.urlresolvers import get_script_prefix, resolve, reverse from django.http import Http404 from django.shortcuts import redirect, resolve_url from django.utils.deprecation import MiddlewareMixin @@ -28,6 +29,24 @@ class PermissionMiddleware(MiddlewareMixin): "auth.invite", ) + def _login_redirect(self, request): + # Taken from django/contrib/auth/decorators.py + path = request.build_absolute_uri() + # urlparse chokes on lazy objects in Python 3, force to str + resolved_login_url = force_str( + resolve_url(settings.LOGIN_URL_CONTROL)) + # If the login url is the same scheme and net location then just + # use the path as the "next" url. + login_scheme, login_netloc = urlparse(resolved_login_url)[:2] + current_scheme, current_netloc = urlparse(path)[:2] + if ((not login_scheme or login_scheme == current_scheme) and + (not login_netloc or login_netloc == current_netloc)): + path = request.get_full_path() + from django.contrib.auth.views import redirect_to_login + + return redirect_to_login( + path, resolved_login_url, REDIRECT_FIELD_NAME) + def process_request(self, request): url = resolve(request.path_info) url_name = url.url_name @@ -42,22 +61,18 @@ class PermissionMiddleware(MiddlewareMixin): if url_name in self.EXCEPTIONS: return if not request.user.is_authenticated: - # Taken from django/contrib/auth/decorators.py - path = request.build_absolute_uri() - # urlparse chokes on lazy objects in Python 3, force to str - resolved_login_url = force_str( - resolve_url(settings.LOGIN_URL_CONTROL)) - # If the login url is the same scheme and net location then just - # use the path as the "next" url. - login_scheme, login_netloc = urlparse(resolved_login_url)[:2] - current_scheme, current_netloc = urlparse(path)[:2] - if ((not login_scheme or login_scheme == current_scheme) and - (not login_netloc or login_netloc == current_netloc)): - path = request.get_full_path() - from django.contrib.auth.views import redirect_to_login + return self._login_redirect(request) - return redirect_to_login( - path, resolved_login_url, REDIRECT_FIELD_NAME) + if not settings.PRETIX_LONG_SESSIONS or not request.session.get('pretix_auth_long_session', False): + last_used = request.session.get('pretix_auth_last_used', 0) or time.time() + if time.time() - request.session.get('pretix_auth_login_time', 0) > settings.PRETIX_SESSION_TIMEOUT_ABSOLUTE: + logout(request) + request.session['pretix_auth_login_time'] = 0 + return self._login_redirect(request) + if time.time() - last_used > settings.PRETIX_SESSION_TIMEOUT_RELATIVE and url_name != 'user.reauth': + return redirect(reverse('control:user.reauth') + '?next=' + quote(request.get_full_path())) + + request.session['pretix_auth_last_used'] = int(time.time()) if 'event' in url.kwargs and 'organizer' in url.kwargs: request.event = Event.objects.filter( diff --git a/src/pretix/control/templates/pretixcontrol/auth/login.html b/src/pretix/control/templates/pretixcontrol/auth/login.html index b8e17be4f3..75f5518e2c 100644 --- a/src/pretix/control/templates/pretixcontrol/auth/login.html +++ b/src/pretix/control/templates/pretixcontrol/auth/login.html @@ -8,24 +8,23 @@ {% csrf_token %} {% bootstrap_field form.email %} {% bootstrap_field form.password %} + {% if form.keep_logged_in %} + {% bootstrap_field form.keep_logged_in %} + {% endif %}
- - {% if can_register %} - - {% endif %} + {% endif %} + {% endblock %} diff --git a/src/pretix/control/templates/pretixcontrol/auth/register.html b/src/pretix/control/templates/pretixcontrol/auth/register.html index 3fdaac8ecc..4d2e0646bf 100644 --- a/src/pretix/control/templates/pretixcontrol/auth/register.html +++ b/src/pretix/control/templates/pretixcontrol/auth/register.html @@ -10,6 +10,9 @@ {% bootstrap_field form.email %} {% bootstrap_field form.password %} {% bootstrap_field form.password_repeat %} + {% if form.keep_logged_in %} + {% bootstrap_field form.keep_logged_in %} + {% endif %}