BIG UPD: migrate to python 3.10 and django 3.2
All checks were successful
buildbot/tox Build done.

This commit is contained in:
2022-06-07 16:07:08 +02:00
parent edd4050935
commit 8610e2a557
36 changed files with 192 additions and 91 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@
/env/ /env/
/tmp/ /tmp/
/.eggs/
*.pyc *.pyc
*.mo *.mo
/.coverage /.coverage

View File

@@ -10,7 +10,7 @@ disable=missing-docstring,
missing-module-docstring, missing-module-docstring,
missing-class-docstring, missing-class-docstring,
missing-function-docstring, missing-function-docstring,
useless-object-inheritance, consider-using-f-string,
[BASIC] [BASIC]
@@ -18,10 +18,17 @@ good-names=_,
c, c,
d, d,
e, e,
f,
i, i,
j, j,
k, k,
r,
t,
[FORMAT] [FORMAT]
max-line-length=120 max-line-length=120
[SIMILARITIES]
ignore-comments=no

View File

@@ -1,6 +1,6 @@
REQUIREMENTS REQUIREMENTS
============ ============
- Python 2.7 - Python 3
- Python package virtualenv (in most cases this is distributed or installed together with python) - Python package virtualenv (in most cases this is distributed or installed together with python)
- Django (will be installed automatically) - Django (will be installed automatically)
- Several additional django related python packages (will be installed automatically) - Several additional django related python packages (will be installed automatically)

View File

@@ -9,7 +9,6 @@ logger = logging.getLogger(__name__)
class LoginForm(auth_forms.AuthenticationForm): class LoginForm(auth_forms.AuthenticationForm):
username = auth_forms.UsernameField( username = auth_forms.UsernameField(
max_length=254,
label=_(u'E-Mail-Adresse'), label=_(u'E-Mail-Adresse'),
widget=forms.TextInput(attrs={'autofocus': True}), widget=forms.TextInput(attrs={'autofocus': True}),
) )
@@ -64,7 +63,6 @@ class SetPasswordForm(forms.Form):
class CreateAndSendPasswordForm(forms.Form): class CreateAndSendPasswordForm(forms.Form):
username = auth_forms.UsernameField( username = auth_forms.UsernameField(
max_length=254,
label=_(u'E-Mail-Adresse'), label=_(u'E-Mail-Adresse'),
widget=forms.TextInput(attrs={'autofocus': True}), widget=forms.TextInput(attrs={'autofocus': True}),
) )

View File

@@ -3,7 +3,7 @@ from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
class SeleniumAuthMixin(object): class SeleniumAuthMixin:
def login(self, driver, username, password): def login(self, driver, username, password):
driver.get(self.complete_url(reverse('dav_auth:login'))) driver.get(self.complete_url(reverse('dav_auth:login')))
username_field = self.wait_on_presence(driver, (By.ID, 'id_username')) username_field = self.wait_on_presence(driver, (By.ID, 'id_username'))

View File

@@ -11,7 +11,6 @@ from ..forms import LoginForm, SetPasswordForm, CreateAndSendPasswordForm
TEST_USERNAME = 'root@localhost' TEST_USERNAME = 'root@localhost'
TEST_PASSWORD = u'me||ön 21ABll' TEST_PASSWORD = u'me||ön 21ABll'
TEST_EMAIL = TEST_USERNAME TEST_EMAIL = TEST_USERNAME
USERNAME_MAX_LENGTH = 254
class LoginFormTestCase(FormsTestCase): class LoginFormTestCase(FormsTestCase):
@@ -24,11 +23,6 @@ class LoginFormTestCase(FormsTestCase):
model = get_user_model() model = get_user_model()
self.user = model.objects.create_user(username=TEST_USERNAME, password=TEST_PASSWORD, email=TEST_EMAIL) self.user = model.objects.create_user(username=TEST_USERNAME, password=TEST_PASSWORD, email=TEST_EMAIL)
def test_length(self):
form = self.form_class()
self.assertEqual(form.fields['username'].max_length, USERNAME_MAX_LENGTH)
self.assertEqual(form.fields['password'].max_length, None)
def test_labels(self): def test_labels(self):
form = self.form_class() form = self.form_class()
self.assertEqual(form.fields['username'].label, ugettext(u'E-Mail-Adresse')) self.assertEqual(form.fields['username'].label, ugettext(u'E-Mail-Adresse'))
@@ -53,13 +47,6 @@ class LoginFormTestCase(FormsTestCase):
] ]
super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets) super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets)
def test_username_too_long(self):
data_sets = [
FormDataSet({'username': 'u' * USERNAME_MAX_LENGTH + 'u', 'password': self.test_password},
expected_errors=[('username', 'max_length')]),
]
super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets)
def test_invalid_username(self): def test_invalid_username(self):
data_sets = [ data_sets = [
FormDataSet({'username': self.test_username[::-1], 'password': self.test_password}, FormDataSet({'username': self.test_username[::-1], 'password': self.test_password},
@@ -202,13 +189,8 @@ class CreateAndSendPasswordFormTestCase(FormsTestCase):
) )
invalid_data_sets = ( invalid_data_sets = (
FormDataSet({'username': ''}, expected_errors=[('username', 'required')]), FormDataSet({'username': ''}, expected_errors=[('username', 'required')]),
FormDataSet({'username': 'u' * USERNAME_MAX_LENGTH + 'u'}, expected_errors=[('username', 'max_length')]),
) )
def test_length(self):
form = self.form_class()
self.assertEqual(form.fields['username'].max_length, USERNAME_MAX_LENGTH)
def test_labels(self): def test_labels(self):
form = self.form_class() form = self.form_class()
self.assertEqual(form.fields['username'].label, ugettext(u'E-Mail-Adresse')) self.assertEqual(form.fields['username'].label, ugettext(u'E-Mail-Adresse'))

View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from unittest import skip
from django.contrib.auth import get_user_model
from django.test import TestCase, Client
class ModelsTestCase(TestCase):
@skip('I do not know, why the user.save() does not raise an exception')
def test_username_length(self):
max_length = 150 # Hard coded in django.contrib.auth.models.AbstractUser
username_ok = 'u' * max_length
username_too_long = username_ok + 'u'
user_model = get_user_model()
user = user_model(username=username_too_long,
first_name='A',
last_name='User',
email='a.user@example.com')
user.save()
def test_last_login(self):
user_model = get_user_model()
user = user_model(username='auser',
first_name='A',
last_name='User',
email='a.user@example.com')
user.save()
self.assertEqual(user.last_login, None)
c = Client()
c.force_login(user)
self.assertNotEqual(user.last_login, None)

View File

@@ -40,7 +40,7 @@ class TestCase(SeleniumAuthMixin, SeleniumTestCase):
c = self.selenium c = self.selenium
c.get(self.complete_url('/')) c.get(self.complete_url('/'))
try: try:
link = c.find_element_by_css_selector('#login-widget a') c.find_element_by_css_selector('#login-widget a')
except NoSuchElementException as e: # pragma: no cover except NoSuchElementException as e: # pragma: no cover
self.fail(str(e)) self.fail(str(e))
@@ -65,4 +65,3 @@ class TestCase(SeleniumAuthMixin, SeleniumTestCase):
self.assertEqual(field.get_attribute('required'), 'true') self.assertEqual(field.get_attribute('required'), 'true')
field = c.find_element_by_id('id_send_password_mail') field = c.find_element_by_id('id_send_password_mail')
self.assertEqual(field.get_attribute('required'), None) self.assertEqual(field.get_attribute('required'), None)

View File

@@ -35,7 +35,7 @@ class ViewsTestCase(TestCase):
cls.set_password_message = ugettext(u'Passwort gespeichert.') cls.set_password_message = ugettext(u'Passwort gespeichert.')
def setUp(self): def setUp(self):
super(TestCase, self).setUp() super(ViewsTestCase, self).setUp()
# Need a test user # Need a test user
self.test_username = TEST_USERNAME self.test_username = TEST_USERNAME
self.test_password = TEST_PASSWORD self.test_password = TEST_PASSWORD

View File

@@ -2,6 +2,8 @@ from django.conf.urls import url
from . import views from . import views
app_name = 'dav_auth'
urlpatterns = [ urlpatterns = [
url(r'^login$', views.LoginView.as_view(), name='login'), url(r'^login$', views.LoginView.as_view(), name='login'),
url(r'^logout$', views.LogoutView.as_view(), name='logout'), url(r'^logout$', views.LogoutView.as_view(), name='logout'),

View File

@@ -4,7 +4,7 @@ from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
class PasswordScoreValidator(object): class PasswordScoreValidator:
def _get_score(self, password, user=None): def _get_score(self, password, user=None):
score = 0 score = 0
char_counters = {} char_counters = {}
@@ -98,7 +98,7 @@ class PasswordScoreValidator(object):
return text return text
class CustomWordlistPasswordValidator(object): class CustomWordlistPasswordValidator:
context = 'the Sektion Karlsruhe' context = 'the Sektion Karlsruhe'
words = ( words = (
u'dav', u'dav',
@@ -132,7 +132,7 @@ class CustomWordlistPasswordValidator(object):
return text return text
class CharacterClassPasswordValidator(object): class CharacterClassPasswordValidator:
def _is_enough_lower(self, password): def _is_enough_lower(self, password):
lower = re.sub(r'[^a-z]', '', password) lower = re.sub(r'[^a-z]', '', password)
if len(lower) < self.minimum_lower: if len(lower) < self.minimum_lower:

View File

@@ -3,8 +3,8 @@
# Additional settings for django-dav # Additional settings for django-dav
# #
BASE_VAR_DIR = os.path.join(BASE_DIR, 'var') BASE_VAR_DIR = BASE_DIR / 'var'
BASE_SHARE_DIR = os.path.join(BASE_DIR, 'common') BASE_SHARE_DIR = BASE_DIR / 'common'
# Get modules config # Get modules config
from dav_base.config.modules import ModuleConfig from dav_base.config.modules import ModuleConfig
@@ -14,7 +14,7 @@ INSTALLED_APPS += [
'bootstrap3', 'bootstrap3',
'datetimewidget', 'datetimewidget',
'django_countries', 'django_countries',
'django_extensions', # 'django_extensions',
# Our main app # Our main app
'dav_base', 'dav_base',
] ]
@@ -45,11 +45,11 @@ TEMPLATES += [
# Add our local templates directory to the template engine configurations. # Add our local templates directory to the template engine configurations.
for config in TEMPLATES: for config in TEMPLATES:
config['DIRS'].append(os.path.join(BASE_SHARE_DIR, 'templates')) config['DIRS'].append(BASE_SHARE_DIR / 'templates')
DATABASES['default'] = { DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_VAR_DIR, 'db', 'devel.sqlite3'), 'NAME': BASE_VAR_DIR / 'db' / 'devel.sqlite3',
} }
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
@@ -76,7 +76,7 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
STATIC_ROOT = os.path.join(BASE_VAR_DIR, 'www', 'static') STATIC_ROOT = BASE_VAR_DIR / 'www' / 'static'
LANGUAGE_CODE = 'de' LANGUAGE_CODE = 'de'
TIME_ZONE = 'Europe/Berlin' TIME_ZONE = 'Europe/Berlin'
@@ -130,20 +130,20 @@ LOGGING = {
'default_log': { 'default_log': {
'level': 'INFO', 'level': 'INFO',
'class': 'logging.FileHandler', 'class': 'logging.FileHandler',
'filename': os.path.join(BASE_VAR_DIR, 'log', 'default.log'), 'filename': BASE_VAR_DIR / 'log' / 'default.log',
'formatter': 'default', 'formatter': 'default',
}, },
'error_log': { 'error_log': {
'level': 'ERROR', 'level': 'ERROR',
'class': 'logging.FileHandler', 'class': 'logging.FileHandler',
'filename': os.path.join(BASE_VAR_DIR, 'log', 'error.log'), 'filename': BASE_VAR_DIR / 'log' / 'error.log',
'formatter': 'default', 'formatter': 'default',
}, },
'debug_log': { 'debug_log': {
'level': 'DEBUG', 'level': 'DEBUG',
'filters': ['require_debug_true'], 'filters': ['require_debug_true'],
'class': 'logging.FileHandler', 'class': 'logging.FileHandler',
'filename': os.path.join(BASE_VAR_DIR, 'log', 'debug.log'), 'filename': BASE_VAR_DIR / 'log' / 'debug.log',
'formatter': 'verbose', 'formatter': 'verbose',
}, },
}, },

View File

@@ -1,6 +1,6 @@
{# This template is used by software tests #}{% load dav_base %} {# This template is used by software tests #}{% load dav_base %}
--{% include_if_exist './includes/include_missing.html' %}-- --{% include_if_exist './includes/include_missing3.html' %}--
--{% include_if_exist './includes/include_missing.html' default 'dav_base/tests/includes/include_default.html' %}-- --{% include_if_exist './includes/include_missing4.html' default 'dav_base/tests/includes/include_default.html' %}--
--{% include_if_exist './includes/include_optional.html' %}-- --{% include_if_exist './includes/include_optional.html' %}--
--{% include_if_exist './includes/include_optional.html' default 'dav_base/tests/includes/include_default.html' %}-- --{% include_if_exist './includes/include_optional.html' default 'dav_base/tests/includes/include_default.html' %}--
--{% include_if_exist './includes/include_with_missing_include.html' %}-- --{% include_if_exist './includes/include_with_missing_include.html' %}--

View File

@@ -1,2 +1,2 @@
{# This template is used by software tests #}{% load dav_base %} {# This template is used by software tests #}{% load dav_base %}
--{% include_if_exist './includes/include_missing.html' default './includes/include_missing.html' %}-- --{% include_if_exist './includes/include_missing1.html' default './includes/include_missing2.html' %}--

View File

@@ -1,2 +1,2 @@
{# This template is used by software tests #}{% load dav_base %} {# This template is used by software tests #}{% load dav_base %}
--{% include './include_missing.html' %}-- --{% include './include_missing5.html' %}--

View File

@@ -16,7 +16,7 @@ def do_include_if_exist(parser, token):
""" """
bits = token.split_contents() bits = token.split_contents()
if len(bits) < 2: if len(bits) < 2:
raise template.TemplateSyntaxError("%r tag takes at least two arguments:" raise template.TemplateSyntaxError("%r tag takes at least one argument:"
" the name of the template to be included" % bits[0]) " the name of the template to be included" % bits[0])
try: try:
@@ -27,6 +27,10 @@ def do_include_if_exist(parser, token):
token = template.base.Token(token.token_type, ' '.join(bits)) token = template.base.Token(token.token_type, ' '.join(bits))
token2 = template.base.Token(token.token_type, bits[0] + ' ' + default_template + ' '.join(bits[2:])) token2 = template.base.Token(token.token_type, bits[0] + ' ' + default_template + ' '.join(bits[2:]))
default_node = template.loader_tags.do_include(parser, token2) default_node = template.loader_tags.do_include(parser, token2)
# TODO: I belive, this ist not the correct way to do things.
# But without setting default_node.origin here the following AttributeError will be risen within the tests:
# AttributeError: 'IncludeNode' object has no attribute 'origin'
default_node.origin = template.Origin(name='<unknown_source>', template_name=None)
except ValueError: except ValueError:
default_node = template.defaulttags.CommentNode() default_node = template.defaulttags.CommentNode()
except IndexError: except IndexError:

View File

@@ -28,20 +28,20 @@ class TemplateTagsTestCase(SimpleTestCase):
def test_include_if_exist(self): def test_include_if_exist(self):
template_name = 'dav_base/tests/include_if_exist.html' template_name = 'dav_base/tests/include_if_exist.html'
template = get_template(template_name)
content = template.render() with self.settings(DEBUG=False):
expected_content = """ template = get_template(template_name)
content = template.render()
expected_content = """
---- ----
--DEFAULT INCLUDED HTML-- --DEFAULT INCLUDED HTML--
--OPTIONAL INCLUDED HTML-- --OPTIONAL INCLUDED HTML--
--OPTIONAL INCLUDED HTML-- --OPTIONAL INCLUDED HTML--
--
---- ----
--
""" """
self.assertEqual(content, expected_content) self.assertEqual(content, expected_content)
def test_include_if_exist_while_debug(self): def test_include_if_exist_while_debug(self):
template_name = 'dav_base/tests/include_if_exist.html' template_name = 'dav_base/tests/include_if_exist.html'

View File

@@ -2,6 +2,8 @@ from django.conf.urls import url
from . import views from . import views
app_name = 'dav_event_office'
urlpatterns = [ urlpatterns = [
url(r'^home$', views.HomeView.as_view(), name='root'), url(r'^home$', views.HomeView.as_view(), name='root'),
url(r'^participants$', views.ParticipantListView.as_view(), name='participant-list'), url(r'^participants$', views.ParticipantListView.as_view(), name='participant-list'),

View File

@@ -0,0 +1,44 @@
# Generated by Django 3.2.13 on 2022-06-07 11:45
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dav_events', '0041_auto_20210107_1220'),
]
operations = [
migrations.AlterField(
model_name='event',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='eventchange',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='eventflag',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='participant',
name='event',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='participants', to='dav_events.event'),
),
migrations.AlterField(
model_name='participant',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='trashedparticipant',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
]

View File

@@ -10,10 +10,9 @@ import unicodedata
from babel.dates import format_date from babel.dates import format_date
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.template.loader import get_template from django.template.loader import get_template
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import get_language, ugettext_lazy as _ from django.utils.translation import get_language, ugettext_lazy as _
from django_countries.fields import Country, CountryField from django_countries.fields import Country, CountryField
@@ -27,7 +26,6 @@ from .eventchange import EventChange
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class Event(models.Model): class Event(models.Model):
# Metadata # Metadata
owner = models.ForeignKey(settings.AUTH_USER_MODEL, owner = models.ForeignKey(settings.AUTH_USER_MODEL,

View File

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from . import get_ghost_user, get_system_user from . import get_ghost_user, get_system_user
@@ -12,7 +11,6 @@ def get_system_user_id():
return get_system_user().id return get_system_user().id
@python_2_unicode_compatible
class EventChange(models.Model): class EventChange(models.Model):
UPDATE = 'update' UPDATE = 'update'
RAISE_FLAG = 'set_flag' RAISE_FLAG = 'set_flag'
@@ -23,7 +21,7 @@ class EventChange(models.Model):
(LOWER_FLAG, 'Lower Flag'), (LOWER_FLAG, 'Lower Flag'),
) )
event = models.ForeignKey('dav_events.Event', related_name='changes') event = models.ForeignKey('dav_events.Event', related_name='changes', on_delete=models.CASCADE)
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(settings.AUTH_USER_MODEL, user = models.ForeignKey(settings.AUTH_USER_MODEL,
default=get_system_user_id, default=get_system_user_id,

View File

@@ -2,7 +2,6 @@ from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from . import get_ghost_user, get_system_user from . import get_ghost_user, get_system_user
@@ -11,9 +10,8 @@ def get_system_user_id():
return get_system_user().id return get_system_user().id
@python_2_unicode_compatible
class EventFlag(models.Model): class EventFlag(models.Model):
event = models.ForeignKey('dav_events.Event', related_name='flags') event = models.ForeignKey('dav_events.Event', related_name='flags', on_delete=models.CASCADE)
status = models.ForeignKey('dav_events.EventStatus', status = models.ForeignKey('dav_events.EventStatus',
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='+') related_name='+')

View File

@@ -1,6 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from ..validators import IdStringValidator from ..validators import IdStringValidator
@@ -22,7 +21,6 @@ BOOTSTRAP_CONTEXT_CHOICES = (
) )
@python_2_unicode_compatible
class EventStatus(models.Model): class EventStatus(models.Model):
code = models.CharField(primary_key=True, max_length=254, validators=[IdStringValidator]) code = models.CharField(primary_key=True, max_length=254, validators=[IdStringValidator])
severity = models.IntegerField(unique=True) severity = models.IntegerField(unique=True)

View File

@@ -3,10 +3,9 @@ from __future__ import unicode_literals
import logging import logging
import uuid import uuid
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext, ugettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _
from .event import Event from .event import Event
@@ -14,7 +13,6 @@ from .event import Event
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class OneClickAction(models.Model): class OneClickAction(models.Model):
COMMANDS = ( COMMANDS = (
('EVENT_LIST', 'login and go to event list (user id)'), ('EVENT_LIST', 'login and go to event list (user id)'),

View File

@@ -4,7 +4,6 @@ import datetime
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from dav_base.validators import DAVNumberValidator from dav_base.validators import DAVNumberValidator
@@ -12,7 +11,6 @@ from dav_base.validators import DAVNumberValidator
midnight = datetime.time(00, 00, 00) midnight = datetime.time(00, 00, 00)
@python_2_unicode_compatible
class AbstractParticipant(models.Model): class AbstractParticipant(models.Model):
personal_names = models.CharField(max_length=1024, personal_names = models.CharField(max_length=1024,
verbose_name=_('Vorname(n)')) verbose_name=_('Vorname(n)'))
@@ -158,9 +156,8 @@ class AbstractParticipant(models.Model):
return timezone.make_aware(datetime.datetime.combine(purge_date, midnight)) return timezone.make_aware(datetime.datetime.combine(purge_date, midnight))
@python_2_unicode_compatible
class Participant(AbstractParticipant): class Participant(AbstractParticipant):
event = models.ForeignKey('Event', related_name='participants') event = models.ForeignKey('Event', related_name='participants', on_delete=models.PROTECT)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
position = models.IntegerField(verbose_name='Listennummer') position = models.IntegerField(verbose_name='Listennummer')

View File

@@ -1,15 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from ..participant import AbstractParticipant from ..participant import AbstractParticipant
@python_2_unicode_compatible
class TrashedParticipant(AbstractParticipant): class TrashedParticipant(AbstractParticipant):
event = models.ForeignKey('Event', related_name='trashed_participants') event = models.ForeignKey('Event', related_name='trashed_participants', on_delete=models.CASCADE)
created_at = models.DateTimeField() created_at = models.DateTimeField()
trashed_at = models.DateTimeField(auto_now_add=True) trashed_at = models.DateTimeField(auto_now_add=True)
position = models.IntegerField(verbose_name='Listennummer') position = models.IntegerField(verbose_name='Listennummer')

View File

@@ -2,6 +2,8 @@ from django.conf.urls import url
from . import views from . import views
app_name = 'dav_events'
urlpatterns = [ urlpatterns = [
url(r'^home$', views.base.HomeView.as_view(), name='root'), url(r'^home$', views.base.HomeView.as_view(), name='root'),
url(r'^$', views.events.EventListView.as_view(), name='list'), url(r'^$', views.events.EventListView.as_view(), name='list'),

View File

@@ -754,14 +754,14 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
_(u'Du hast jemand anderen als Tourenleiter eingetragen.'), _(u'Du hast jemand anderen als Tourenleiter eingetragen.'),
_(u'Warum machst du sowas?') _(u'Warum machst du sowas?')
)) ))
elif owner.has_usable_password(): elif owner.last_login is None:
next_url = reverse('dav_events:list')
else:
login(self.request, owner) login(self.request, owner)
next_url = reverse('dav_auth:set_password') next_url = reverse('dav_auth:set_password')
messages.success(self.request, messages.success(self.request,
_(u'Neuen Benutzer angemeldet: %(username)s') % {'username': owner.username}) _(u'Neuen Benutzer angemeldet: %(username)s') % {'username': owner.username})
messages.warning(self.request, _(u'Bitte neues Passwort setzen!')) messages.warning(self.request, _(u'Bitte neues Passwort setzen!'))
else:
next_url = reverse('dav_events:list')
return HttpResponseRedirect(next_url) return HttpResponseRedirect(next_url)
def clean_session_data(self, session=None): def clean_session_data(self, session=None):

View File

@@ -0,0 +1,30 @@
# Generated by Django 3.2.13 on 2022-06-07 11:45
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dav_events', '0042_auto_20220607_1345'),
('dav_registration', '0010_registration_apply_reduced_fee'),
]
operations = [
migrations.AlterField(
model_name='registration',
name='event',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='registrations', to='dav_events.event'),
),
migrations.AlterField(
model_name='registration',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='registrationstatus',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
]

View File

@@ -6,7 +6,6 @@ from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from dav_base.validators import DAVNumberValidator from dav_base.validators import DAVNumberValidator
@@ -19,9 +18,8 @@ logger = logging.getLogger(__name__)
midnight = datetime.time(00, 00, 00) midnight = datetime.time(00, 00, 00)
@python_2_unicode_compatible
class Registration(models.Model): class Registration(models.Model):
event = models.ForeignKey(Event, related_name='registrations') event = models.ForeignKey(Event, related_name='registrations', on_delete=models.PROTECT)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
personal_names = models.CharField(max_length=1024, personal_names = models.CharField(max_length=1024,
@@ -219,11 +217,11 @@ Anmerkung:
return timezone.make_aware(datetime.datetime.combine(purge_date, midnight)) return timezone.make_aware(datetime.datetime.combine(purge_date, midnight))
@python_2_unicode_compatible
class RegistrationStatus(models.Model): class RegistrationStatus(models.Model):
registration = models.OneToOneField(Registration, on_delete=models.CASCADE, related_name='status') registration = models.OneToOneField(Registration, on_delete=models.CASCADE, related_name='status')
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
answered = models.BooleanField(_('Durch Tourleitung beantwortet'), default=False) answered = models.BooleanField(_('Durch Tourleitung beantwortet'), default=False)
# TODO: NullBooleanField is marked deprecated
accepted = models.NullBooleanField(_('Zusage erteilt')) accepted = models.NullBooleanField(_('Zusage erteilt'))
class Meta: class Meta:

View File

@@ -2,6 +2,8 @@ from django.conf.urls import url
from . import views from . import views
app_name = 'dav_registration'
urlpatterns = [ urlpatterns = [
url(r'^$', views.RootView.as_view(), name='root'), url(r'^$', views.RootView.as_view(), name='root'),
url(r'^finished', views.RegistrationSuccessView.as_view(), name='registered'), url(r'^finished', views.RegistrationSuccessView.as_view(), name='registered'),

View File

@@ -2,6 +2,8 @@ from django.conf.urls import url
from . import views from . import views
app_name = 'dav_submission'
urlpatterns = [ urlpatterns = [
url(r'^$', views.UploadView.as_view(), name='root'), url(r'^$', views.UploadView.as_view(), name='root'),
url(r'^danke', views.SuccessView.as_view(), name='success'), url(r'^danke', views.SuccessView.as_view(), name='success'),

View File

@@ -22,12 +22,7 @@ class SetupPythonEnvironment(MyCommand):
def run(self): def run(self):
python_bin = sys.executable if sys.executable else 'python' python_bin = sys.executable if sys.executable else 'python'
python_ver = sys.version_info.major python_ver = sys.version_info.major
if python_ver == 2: if python_ver == 3:
path = os.path.join('env', 'python2')
symlink_path = os.path.join('env', 'python')
venv_module = 'virtualenv'
prompt = '(py2-dav) '
elif python_ver == 3:
path = os.path.join('env', 'python3') path = os.path.join('env', 'python3')
symlink_path = os.path.join('env', 'python') symlink_path = os.path.join('env', 'python')
venv_module = 'venv' venv_module = 'venv'
@@ -97,7 +92,7 @@ class QuickSetup(MyCommand):
setup( setup(
name='django-dav-events', name='django-dav-events',
version='2.0', version='2.1',
description='A django based web application project to organize DAV Events.', description='A django based web application project to organize DAV Events.',
url='https://touren.alpenverein-karlsruhe.de', url='https://touren.alpenverein-karlsruhe.de',
author='Jens Kleineheismann', author='Jens Kleineheismann',
@@ -116,11 +111,12 @@ setup(
}, },
install_requires=[ install_requires=[
'babel', 'babel',
'django >= 1.11, < 2.0', #'django >= 1.11, < 2.0',
'django-extensions', 'django >= 1.11, < 3.3',
'django-bootstrap3 < 12', # 'django-extensions',
'django-countries < 6', 'django-bootstrap3',
'django-datetime-widget', 'django-countries',
'django-datetime-widget2',
'pytz', 'pytz',
'selenium', 'selenium',
'coverage', 'coverage',

5
tests/__main__.py Normal file
View File

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from test_suite import main
if __name__ == '__main__':
main()

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
@@ -80,3 +81,12 @@ class TestSuite(object):
def __call__(self): def __call__(self):
sys.exit(self.run()) sys.exit(self.run())
def main():
test_suite = TestSuite()
test_suite()
if __name__ == '__main__':
main()

View File

@@ -1,7 +1,7 @@
[tox] [tox]
envlist = py3,py2 envlist = py3
[testenv] [testenv]
commands = python --version commands = python --version
python -m coverage run setup.py test python -m coverage run tests/test_suite.py
coverage report --skip-covered coverage report --skip-covered