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 sys
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 ivatar.settings import BASE_DIR

View File

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

View File

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

View File

@@ -13,7 +13,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.http import HttpResponseNotFound, JsonResponse
from django.core.exceptions import ObjectDoesNotExist
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.db.models import Q
from django.contrib.auth.models import User

View File

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