First preparations for Django >= 4.x

- Slight reformatting in some parts; Non-functional changes
- ugettext(_lazy) no longer available in Django > 4, changing to
  gettext(_lazy)
- Since django-openid-auth doesn't work with Django > 4 yet, we need to
  pin this project to Django < 4 until that issue is solved
This commit is contained in:
Oliver Falk
2021-12-10 09:21:49 +01:00
parent 0ccd3fa7c1
commit 0c3686beef
7 changed files with 147 additions and 135 deletions

View File

@@ -6,7 +6,7 @@ Configuration overrides for settings.py
import os import os
import sys import sys
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.messages import constants as message_constants from django.contrib.messages import constants as message_constants
from ivatar.settings import BASE_DIR from ivatar.settings import BASE_DIR

View File

@@ -1,10 +1,11 @@
''' # -*- coding: utf-8 -*-
"""
Classes for our ivatar.ivataraccount.forms Classes for our ivatar.ivataraccount.forms
''' """
from urllib.parse import urlsplit, urlunsplit from urllib.parse import urlsplit, urlunsplit
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from ipware import get_client_ip from ipware import get_client_ip
@@ -20,93 +21,97 @@ MAX_NUM_UNCONFIRMED_EMAILS_DEFAULT = 5
class AddEmailForm(forms.Form): class AddEmailForm(forms.Form):
''' """
Form to handle adding email addresses Form to handle adding email addresses
''' """
email = forms.EmailField( email = forms.EmailField(
label=_('Email'), label=_("Email"),
min_length=MIN_LENGTH_EMAIL, min_length=MIN_LENGTH_EMAIL,
max_length=MAX_LENGTH_EMAIL, max_length=MAX_LENGTH_EMAIL,
) )
def clean_email(self): def clean_email(self):
''' """
Enforce lowercase email Enforce lowercase email
''' """
# TODO: Domain restriction as in libravatar? # TODO: Domain restriction as in libravatar?
return self.cleaned_data['email'].lower() return self.cleaned_data["email"].lower()
def save(self, request): def save(self, request):
''' """
Save the model, ensuring some safety Save the model, ensuring some safety
''' """
user = request.user user = request.user
# Enforce the maximum number of unconfirmed emails a user can have # Enforce the maximum number of unconfirmed emails a user can have
num_unconfirmed = user.unconfirmedemail_set.count() num_unconfirmed = user.unconfirmedemail_set.count()
max_num_unconfirmed_emails = getattr( max_num_unconfirmed_emails = getattr(
settings, settings, "MAX_NUM_UNCONFIRMED_EMAILS", MAX_NUM_UNCONFIRMED_EMAILS_DEFAULT
'MAX_NUM_UNCONFIRMED_EMAILS', )
MAX_NUM_UNCONFIRMED_EMAILS_DEFAULT)
if num_unconfirmed >= max_num_unconfirmed_emails: if num_unconfirmed >= max_num_unconfirmed_emails:
self.add_error(None, _('Too many unconfirmed mail addresses!')) self.add_error(None, _("Too many unconfirmed mail addresses!"))
return False return False
# Check whether or not a confirmation email has been # Check whether or not a confirmation email has been
# sent by this user already # sent by this user already
if UnconfirmedEmail.objects.filter( # pylint: disable=no-member if UnconfirmedEmail.objects.filter( # pylint: disable=no-member
user=user, email=self.cleaned_data['email']).exists(): user=user, email=self.cleaned_data["email"]
self.add_error( ).exists():
'email', self.add_error("email", _("Address already added, currently unconfirmed"))
_('Address already added, currently unconfirmed'))
return False return False
# Check whether or not the email is already confirmed (by someone) # Check whether or not the email is already confirmed (by someone)
check_mail = ConfirmedEmail.objects.filter( check_mail = ConfirmedEmail.objects.filter(email=self.cleaned_data["email"])
email=self.cleaned_data['email'])
if check_mail.exists(): if check_mail.exists():
msg = _('Address already confirmed (by someone else)') msg = _("Address already confirmed (by someone else)")
if check_mail.first().user == request.user: if check_mail.first().user == request.user:
msg = _('Address already confirmed (by you)') msg = _("Address already confirmed (by you)")
self.add_error('email', msg) self.add_error("email", msg)
return False return False
unconfirmed = UnconfirmedEmail() unconfirmed = UnconfirmedEmail()
unconfirmed.email = self.cleaned_data['email'] unconfirmed.email = self.cleaned_data["email"]
unconfirmed.user = user unconfirmed.user = user
unconfirmed.save() unconfirmed.save()
unconfirmed.send_confirmation_mail(url=request.build_absolute_uri('/')[:-1]) unconfirmed.send_confirmation_mail(url=request.build_absolute_uri("/")[:-1])
return True return True
class UploadPhotoForm(forms.Form): class UploadPhotoForm(forms.Form):
''' """
Form handling photo upload Form handling photo upload
''' """
photo = forms.FileField( photo = forms.FileField(
label=_('Photo'), label=_("Photo"),
error_messages={'required': _('You must choose an image to upload.')}) error_messages={"required": _("You must choose an image to upload.")},
)
not_porn = forms.BooleanField( not_porn = forms.BooleanField(
label=_('suitable for all ages (i.e. no offensive content)'), label=_("suitable for all ages (i.e. no offensive content)"),
required=True, required=True,
error_messages={ error_messages={
'required': "required": _(
_('We only host "G-rated" images and so this field must be checked.') 'We only host "G-rated" images and so this field must be checked.'
}) )
},
)
can_distribute = forms.BooleanField( can_distribute = forms.BooleanField(
label=_('can be freely copied'), label=_("can be freely copied"),
required=True, required=True,
error_messages={ error_messages={
'required': "required": _(
_('This field must be checked since we need to be able to distribute photos to third parties.') "This field must be checked since we need to be able to distribute photos to third parties."
}) )
},
)
@staticmethod @staticmethod
def save(request, data): def save(request, data):
''' """
Save the model and assign it to the current user Save the model and assign it to the current user
''' """
# Link this file to the user's profile # Link this file to the user's profile
photo = Photo() photo = Photo()
photo.user = request.user photo.user = request.user
@@ -119,47 +124,48 @@ class UploadPhotoForm(forms.Form):
class AddOpenIDForm(forms.Form): class AddOpenIDForm(forms.Form):
''' """
Form to handle adding OpenID Form to handle adding OpenID
''' """
openid = forms.URLField( openid = forms.URLField(
label=_('OpenID'), label=_("OpenID"),
min_length=MIN_LENGTH_URL, min_length=MIN_LENGTH_URL,
max_length=MAX_LENGTH_URL, max_length=MAX_LENGTH_URL,
initial='http://' initial="http://",
) )
def clean_openid(self): def clean_openid(self):
''' """
Enforce restrictions Enforce restrictions
''' """
# Lowercase hostname port of the URL # Lowercase hostname port of the URL
url = urlsplit(self.cleaned_data['openid']) url = urlsplit(self.cleaned_data["openid"])
data = urlunsplit( data = urlunsplit(
(url.scheme.lower(), url.netloc.lower(), url.path, (url.scheme.lower(), url.netloc.lower(), url.path, url.query, url.fragment)
url.query, url.fragment)) )
# TODO: Domain restriction as in libravatar? # TODO: Domain restriction as in libravatar?
return data return data
def save(self, user): def save(self, user):
''' """
Save the model, ensuring some safety Save the model, ensuring some safety
''' """
if ConfirmedOpenId.objects.filter( # pylint: disable=no-member if ConfirmedOpenId.objects.filter( # pylint: disable=no-member
openid=self.cleaned_data['openid']).exists(): openid=self.cleaned_data["openid"]
self.add_error('openid', _('OpenID already added and confirmed!')) ).exists():
self.add_error("openid", _("OpenID already added and confirmed!"))
return False return False
if UnconfirmedOpenId.objects.filter( # pylint: disable=no-member if UnconfirmedOpenId.objects.filter( # pylint: disable=no-member
openid=self.cleaned_data['openid']).exists(): openid=self.cleaned_data["openid"]
self.add_error( ).exists():
'openid', self.add_error("openid", _("OpenID already added, but not confirmed yet!"))
_('OpenID already added, but not confirmed yet!'))
return False return False
unconfirmed = UnconfirmedOpenId() unconfirmed = UnconfirmedOpenId()
unconfirmed.openid = self.cleaned_data['openid'] unconfirmed.openid = self.cleaned_data["openid"]
unconfirmed.user = user unconfirmed.user = user
unconfirmed.save() unconfirmed.save()
@@ -167,40 +173,50 @@ class AddOpenIDForm(forms.Form):
class UpdatePreferenceForm(forms.ModelForm): class UpdatePreferenceForm(forms.ModelForm):
''' """
Form for updating user preferences Form for updating user preferences
''' """
class Meta: # pylint: disable=too-few-public-methods class Meta: # pylint: disable=too-few-public-methods
''' """
Meta class for UpdatePreferenceForm Meta class for UpdatePreferenceForm
''' """
model = UserPreference model = UserPreference
fields = ['theme'] fields = ["theme"]
class UploadLibravatarExportForm(forms.Form): class UploadLibravatarExportForm(forms.Form):
''' """
Form handling libravatar user export upload Form handling libravatar user export upload
''' """
export_file = forms.FileField( export_file = forms.FileField(
label=_('Export file'), label=_("Export file"),
error_messages={'required': _('You must choose an export file to upload.')}) error_messages={"required": _("You must choose an export file to upload.")},
)
not_porn = forms.BooleanField( not_porn = forms.BooleanField(
label=_('suitable for all ages (i.e. no offensive content)'), label=_("suitable for all ages (i.e. no offensive content)"),
required=True, required=True,
error_messages={ error_messages={
'required': "required": _(
_('We only host "G-rated" images and so this field must be checked.') 'We only host "G-rated" images and so this field must be checked.'
}) )
},
)
can_distribute = forms.BooleanField( can_distribute = forms.BooleanField(
label=_('can be freely copied'), label=_("can be freely copied"),
required=True, required=True,
error_messages={ error_messages={
'required': "required": _(
_('This field must be checked since we need to be able to\ "This field must be checked since we need to be able to\
distribute photos to third parties.') distribute photos to third parties."
}) )
},
)
class DeleteAccountForm(forms.Form): class DeleteAccountForm(forms.Form):
password = forms.CharField(label=_('Password'), required=False, widget=forms.PasswordInput()) password = forms.CharField(
label=_("Password"), required=False, widget=forms.PasswordInput()
)

View File

@@ -19,7 +19,7 @@ from django.db import models
from django.utils import timezone from django.utils import timezone
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.urls import reverse_lazy, reverse from django.urls import reverse_lazy, reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.mail import send_mail from django.core.mail import send_mail
from django.template.loader import render_to_string from django.template.loader import render_to_string

View File

@@ -27,7 +27,7 @@ from django.contrib.auth.views import LoginView
from django.contrib.auth.views import ( from django.contrib.auth.views import (
PasswordResetView as PasswordResetViewOriginal, PasswordResetView as PasswordResetViewOriginal,
) )
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse_lazy, reverse from django.urls import reverse_lazy, reverse
from django.shortcuts import render from django.shortcuts import render

View File

@@ -1,8 +1,9 @@
''' # -*- coding: utf-8 -*-
"""
Classes for our ivatar.tools.forms Classes for our ivatar.tools.forms
''' """
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
@@ -12,45 +13,40 @@ from ivatar.settings import MIN_LENGTH_EMAIL, MAX_LENGTH_EMAIL
class CheckDomainForm(forms.Form): class CheckDomainForm(forms.Form):
''' """
Form handling domain check Form handling domain check
''' """
domain = forms.CharField( domain = forms.CharField(
label=_('Domain'), label=_("Domain"),
required=True, required=True,
error_messages={ error_messages={"required": _("Cannot check without a domain name.")},
'required':
_('Cannot check without a domain name.')
}
) )
class CheckForm(forms.Form): class CheckForm(forms.Form):
''' """
Form handling check Form handling check
''' """
mail = forms.EmailField( mail = forms.EmailField(
label=_('E-Mail'), label=_("E-Mail"),
required=False, required=False,
min_length=MIN_LENGTH_EMAIL, min_length=MIN_LENGTH_EMAIL,
max_length=MAX_LENGTH_EMAIL, max_length=MAX_LENGTH_EMAIL,
error_messages={ error_messages={"required": _("Cannot check without a domain name.")},
'required': )
_('Cannot check without a domain name.')
})
openid = forms.CharField( openid = forms.CharField(
label=_('OpenID'), label=_("OpenID"),
required=False, required=False,
min_length=MIN_LENGTH_URL, min_length=MIN_LENGTH_URL,
max_length=MAX_LENGTH_URL, max_length=MAX_LENGTH_URL,
error_messages={ error_messages={"required": _("Cannot check without an openid name.")},
'required': )
_('Cannot check without an openid name.')
})
size = forms.IntegerField( size = forms.IntegerField(
label=_('Size'), label=_("Size"),
initial=80, initial=80,
min_value=5, min_value=5,
max_value=AVATAR_MAX_SIZE, max_value=AVATAR_MAX_SIZE,
@@ -58,24 +54,24 @@ class CheckForm(forms.Form):
) )
default_opt = forms.ChoiceField( default_opt = forms.ChoiceField(
label=_('Default'), label=_("Default"),
required=False, required=False,
widget=forms.RadioSelect, widget=forms.RadioSelect,
choices=[ choices=[
('retro', _('Retro style (similar to GitHub)')), ("retro", _("Retro style (similar to GitHub)")),
('robohash', _('Roboter style')), ("robohash", _("Roboter style")),
('pagan', _('Retro adventure character')), ("pagan", _("Retro adventure character")),
('wavatar', _('Wavatar style')), ("wavatar", _("Wavatar style")),
('monsterid', _('Monster style')), ("monsterid", _("Monster style")),
('identicon', _('Identicon style')), ("identicon", _("Identicon style")),
('mm', _('Mystery man')), ("mm", _("Mystery man")),
('mmng', _('Mystery man NextGen')), ("mmng", _("Mystery man NextGen")),
('none', _('None')), ("none", _("None")),
], ],
) )
default_url = forms.URLField( default_url = forms.URLField(
label=_('Default URL'), label=_("Default URL"),
min_length=1, min_length=1,
max_length=MAX_LENGTH_URL, max_length=MAX_LENGTH_URL,
required=False, required=False,
@@ -83,28 +79,28 @@ class CheckForm(forms.Form):
def clean(self): def clean(self):
self.cleaned_data = super().clean() self.cleaned_data = super().clean()
mail = self.cleaned_data.get('mail') mail = self.cleaned_data.get("mail")
openid = self.cleaned_data.get('openid') openid = self.cleaned_data.get("openid")
default_url = self.cleaned_data.get('default_url') default_url = self.cleaned_data.get("default_url")
default_opt = self.cleaned_data.get('default_opt') default_opt = self.cleaned_data.get("default_opt")
if default_url and default_opt and default_opt != 'none': if default_url and default_opt and default_opt != "none":
if not 'default_url' in self._errors: if "default_url" not in self._errors:
self._errors['default_url'] = ErrorList() self._errors["default_url"] = ErrorList()
if not 'default_opt' in self._errors: if "default_opt" not in self._errors:
self._errors['default_opt'] = ErrorList() self._errors["default_opt"] = ErrorList()
errstring = _('Only default URL OR default keyword may be specified') errstring = _("Only default URL OR default keyword may be specified")
self._errors['default_url'].append(errstring) self._errors["default_url"].append(errstring)
self._errors['default_opt'].append(errstring) self._errors["default_opt"].append(errstring)
if not mail and not openid: if not mail and not openid:
raise ValidationError(_('Either OpenID or mail must be specified')) raise ValidationError(_("Either OpenID or mail must be specified"))
return self.cleaned_data return self.cleaned_data
def clean_openid(self): def clean_openid(self):
data = self.cleaned_data['openid'] data = self.cleaned_data["openid"]
return data.lower() return data.lower()
def clean_mail(self): def clean_mail(self):
data = self.cleaned_data['mail'] data = self.cleaned_data["mail"]
print(data) print(data)
return data.lower() return data.lower()

View File

@@ -13,7 +13,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.http import HttpResponseNotFound, JsonResponse from django.http import HttpResponseNotFound, JsonResponse
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.cache import cache, caches from django.core.cache import cache, caches
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.db.models import Q from django.db.models import Q
from django.contrib.auth.models import User from django.contrib.auth.models import User

View File

@@ -1,7 +1,7 @@
autopep8 autopep8
bcrypt bcrypt
defusedxml defusedxml
Django Django < 4.0
django-anymail[mailgun] django-anymail[mailgun]
django-auth-ldap django-auth-ldap
django-bootstrap4 django-bootstrap4