diff --git a/.gitignore b/.gitignore index 35ee2b2..ef37281 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /env/ /tmp/ +/.eggs/ *.pyc *.mo /.coverage diff --git a/.pylintrc b/.pylintrc index 752daa2..225bd4d 100644 --- a/.pylintrc +++ b/.pylintrc @@ -10,7 +10,7 @@ disable=missing-docstring, missing-module-docstring, missing-class-docstring, missing-function-docstring, - useless-object-inheritance, + consider-using-f-string, [BASIC] @@ -18,10 +18,17 @@ good-names=_, c, d, e, + f, i, j, k, + r, + t, [FORMAT] max-line-length=120 + +[SIMILARITIES] + +ignore-comments=no diff --git a/INSTALL.rst b/INSTALL.rst index da4c2cb..f20a374 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -1,6 +1,6 @@ REQUIREMENTS ============ -- Python 2.7 +- Python 3 - Python package virtualenv (in most cases this is distributed or installed together with python) - Django (will be installed automatically) - Several additional django related python packages (will be installed automatically) diff --git a/dav_auth/forms.py b/dav_auth/forms.py index 8c1faa4..65b8f6b 100644 --- a/dav_auth/forms.py +++ b/dav_auth/forms.py @@ -9,7 +9,6 @@ logger = logging.getLogger(__name__) class LoginForm(auth_forms.AuthenticationForm): username = auth_forms.UsernameField( - max_length=254, label=_(u'E-Mail-Adresse'), widget=forms.TextInput(attrs={'autofocus': True}), ) @@ -64,7 +63,6 @@ class SetPasswordForm(forms.Form): class CreateAndSendPasswordForm(forms.Form): username = auth_forms.UsernameField( - max_length=254, label=_(u'E-Mail-Adresse'), widget=forms.TextInput(attrs={'autofocus': True}), ) diff --git a/dav_auth/tests/generic.py b/dav_auth/tests/generic.py index 202b9b6..ace764a 100644 --- a/dav_auth/tests/generic.py +++ b/dav_auth/tests/generic.py @@ -3,7 +3,7 @@ from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys -class SeleniumAuthMixin(object): +class SeleniumAuthMixin: def login(self, driver, username, password): driver.get(self.complete_url(reverse('dav_auth:login'))) username_field = self.wait_on_presence(driver, (By.ID, 'id_username')) diff --git a/dav_auth/tests/test_forms.py b/dav_auth/tests/test_forms.py index d02c9ba..44e52f5 100644 --- a/dav_auth/tests/test_forms.py +++ b/dav_auth/tests/test_forms.py @@ -11,7 +11,6 @@ from ..forms import LoginForm, SetPasswordForm, CreateAndSendPasswordForm TEST_USERNAME = 'root@localhost' TEST_PASSWORD = u'me||ön 21ABll' TEST_EMAIL = TEST_USERNAME -USERNAME_MAX_LENGTH = 254 class LoginFormTestCase(FormsTestCase): @@ -24,11 +23,6 @@ class LoginFormTestCase(FormsTestCase): model = get_user_model() 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): form = self.form_class() 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) - 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): data_sets = [ FormDataSet({'username': self.test_username[::-1], 'password': self.test_password}, @@ -202,13 +189,8 @@ class CreateAndSendPasswordFormTestCase(FormsTestCase): ) invalid_data_sets = ( 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): form = self.form_class() self.assertEqual(form.fields['username'].label, ugettext(u'E-Mail-Adresse')) diff --git a/dav_auth/tests/test_models.py b/dav_auth/tests/test_models.py new file mode 100644 index 0000000..81af0a2 --- /dev/null +++ b/dav_auth/tests/test_models.py @@ -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) diff --git a/dav_auth/tests/test_templates.py b/dav_auth/tests/test_templates.py index ebd1c66..592ae0f 100644 --- a/dav_auth/tests/test_templates.py +++ b/dav_auth/tests/test_templates.py @@ -40,7 +40,7 @@ class TestCase(SeleniumAuthMixin, SeleniumTestCase): c = self.selenium c.get(self.complete_url('/')) 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 self.fail(str(e)) @@ -65,4 +65,3 @@ class TestCase(SeleniumAuthMixin, SeleniumTestCase): self.assertEqual(field.get_attribute('required'), 'true') field = c.find_element_by_id('id_send_password_mail') self.assertEqual(field.get_attribute('required'), None) - diff --git a/dav_auth/tests/test_views.py b/dav_auth/tests/test_views.py index 28a1ee0..83f4b59 100644 --- a/dav_auth/tests/test_views.py +++ b/dav_auth/tests/test_views.py @@ -35,7 +35,7 @@ class ViewsTestCase(TestCase): cls.set_password_message = ugettext(u'Passwort gespeichert.') def setUp(self): - super(TestCase, self).setUp() + super(ViewsTestCase, self).setUp() # Need a test user self.test_username = TEST_USERNAME self.test_password = TEST_PASSWORD diff --git a/dav_auth/urls.py b/dav_auth/urls.py index dd3c1b5..8d4bdf7 100644 --- a/dav_auth/urls.py +++ b/dav_auth/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url from . import views +app_name = 'dav_auth' + urlpatterns = [ url(r'^login$', views.LoginView.as_view(), name='login'), url(r'^logout$', views.LogoutView.as_view(), name='logout'), diff --git a/dav_auth/validators.py b/dav_auth/validators.py index 481eea4..ec595ca 100644 --- a/dav_auth/validators.py +++ b/dav_auth/validators.py @@ -4,7 +4,7 @@ from django.core.exceptions import ValidationError from django.utils.translation import gettext as _ -class PasswordScoreValidator(object): +class PasswordScoreValidator: def _get_score(self, password, user=None): score = 0 char_counters = {} @@ -98,7 +98,7 @@ class PasswordScoreValidator(object): return text -class CustomWordlistPasswordValidator(object): +class CustomWordlistPasswordValidator: context = 'the Sektion Karlsruhe' words = ( u'dav', @@ -132,7 +132,7 @@ class CustomWordlistPasswordValidator(object): return text -class CharacterClassPasswordValidator(object): +class CharacterClassPasswordValidator: def _is_enough_lower(self, password): lower = re.sub(r'[^a-z]', '', password) if len(lower) < self.minimum_lower: diff --git a/dav_base/console_scripts/django_project_config/additional_settings.py b/dav_base/console_scripts/django_project_config/additional_settings.py index 470bb04..1bd7468 100644 --- a/dav_base/console_scripts/django_project_config/additional_settings.py +++ b/dav_base/console_scripts/django_project_config/additional_settings.py @@ -3,8 +3,8 @@ # Additional settings for django-dav # -BASE_VAR_DIR = os.path.join(BASE_DIR, 'var') -BASE_SHARE_DIR = os.path.join(BASE_DIR, 'common') +BASE_VAR_DIR = BASE_DIR / 'var' +BASE_SHARE_DIR = BASE_DIR / 'common' # Get modules config from dav_base.config.modules import ModuleConfig @@ -14,7 +14,7 @@ INSTALLED_APPS += [ 'bootstrap3', 'datetimewidget', 'django_countries', - 'django_extensions', + # 'django_extensions', # Our main app 'dav_base', ] @@ -45,11 +45,11 @@ TEMPLATES += [ # Add our local templates directory to the template engine configurations. for config in TEMPLATES: - config['DIRS'].append(os.path.join(BASE_SHARE_DIR, 'templates')) + config['DIRS'].append(BASE_SHARE_DIR / 'templates') DATABASES['default'] = { '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 = [ @@ -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' TIME_ZONE = 'Europe/Berlin' @@ -130,20 +130,20 @@ LOGGING = { 'default_log': { 'level': 'INFO', 'class': 'logging.FileHandler', - 'filename': os.path.join(BASE_VAR_DIR, 'log', 'default.log'), + 'filename': BASE_VAR_DIR / 'log' / 'default.log', 'formatter': 'default', }, 'error_log': { 'level': 'ERROR', 'class': 'logging.FileHandler', - 'filename': os.path.join(BASE_VAR_DIR, 'log', 'error.log'), + 'filename': BASE_VAR_DIR / 'log' / 'error.log', 'formatter': 'default', }, 'debug_log': { 'level': 'DEBUG', 'filters': ['require_debug_true'], 'class': 'logging.FileHandler', - 'filename': os.path.join(BASE_VAR_DIR, 'log', 'debug.log'), + 'filename': BASE_VAR_DIR / 'log' / 'debug.log', 'formatter': 'verbose', }, }, diff --git a/dav_base/templates/dav_base/tests/include_if_exist.html b/dav_base/templates/dav_base/tests/include_if_exist.html index 22eefd4..5971d6c 100644 --- a/dav_base/templates/dav_base/tests/include_if_exist.html +++ b/dav_base/templates/dav_base/tests/include_if_exist.html @@ -1,6 +1,6 @@ {# This template is used by software tests #}{% load dav_base %} ---{% include_if_exist './includes/include_missing.html' %}-- ---{% include_if_exist './includes/include_missing.html' default 'dav_base/tests/includes/include_default.html' %}-- +--{% include_if_exist './includes/include_missing3.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' default 'dav_base/tests/includes/include_default.html' %}-- --{% include_if_exist './includes/include_with_missing_include.html' %}-- diff --git a/dav_base/templates/dav_base/tests/include_if_exist_default_missing.html b/dav_base/templates/dav_base/tests/include_if_exist_default_missing.html index 62da605..98ee02c 100644 --- a/dav_base/templates/dav_base/tests/include_if_exist_default_missing.html +++ b/dav_base/templates/dav_base/tests/include_if_exist_default_missing.html @@ -1,2 +1,2 @@ {# 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' %}-- diff --git a/dav_base/templates/dav_base/tests/includes/include_with_missing_include.html b/dav_base/templates/dav_base/tests/includes/include_with_missing_include.html index 8694ad9..a6a44a1 100644 --- a/dav_base/templates/dav_base/tests/includes/include_with_missing_include.html +++ b/dav_base/templates/dav_base/tests/includes/include_with_missing_include.html @@ -1,2 +1,2 @@ {# This template is used by software tests #}{% load dav_base %} ---{% include './include_missing.html' %}-- +--{% include './include_missing5.html' %}-- diff --git a/dav_base/templatetags/dav_base.py b/dav_base/templatetags/dav_base.py index b8f9b3c..53d3eb0 100644 --- a/dav_base/templatetags/dav_base.py +++ b/dav_base/templatetags/dav_base.py @@ -16,7 +16,7 @@ def do_include_if_exist(parser, token): """ bits = token.split_contents() 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]) try: @@ -27,6 +27,10 @@ def do_include_if_exist(parser, token): token = template.base.Token(token.token_type, ' '.join(bits)) token2 = template.base.Token(token.token_type, bits[0] + ' ' + default_template + ' '.join(bits[2:])) 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='', template_name=None) except ValueError: default_node = template.defaulttags.CommentNode() except IndexError: diff --git a/dav_base/tests/test_templatetags.py b/dav_base/tests/test_templatetags.py index 1cba8a1..8ee4cdc 100644 --- a/dav_base/tests/test_templatetags.py +++ b/dav_base/tests/test_templatetags.py @@ -28,20 +28,20 @@ class TemplateTagsTestCase(SimpleTestCase): def test_include_if_exist(self): template_name = 'dav_base/tests/include_if_exist.html' - template = get_template(template_name) - content = template.render() - expected_content = """ + with self.settings(DEBUG=False): + template = get_template(template_name) + + content = template.render() + expected_content = """ ---- --DEFAULT 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): template_name = 'dav_base/tests/include_if_exist.html' diff --git a/dav_event_office/urls.py b/dav_event_office/urls.py index e2686c2..3def02d 100644 --- a/dav_event_office/urls.py +++ b/dav_event_office/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url from . import views +app_name = 'dav_event_office' + urlpatterns = [ url(r'^home$', views.HomeView.as_view(), name='root'), url(r'^participants$', views.ParticipantListView.as_view(), name='participant-list'), diff --git a/dav_events/migrations/0042_auto_20220607_1345.py b/dav_events/migrations/0042_auto_20220607_1345.py new file mode 100644 index 0000000..6599ac5 --- /dev/null +++ b/dav_events/migrations/0042_auto_20220607_1345.py @@ -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'), + ), + ] diff --git a/dav_events/models/event.py b/dav_events/models/event.py index 18c33d6..01fcc02 100644 --- a/dav_events/models/event.py +++ b/dav_events/models/event.py @@ -10,10 +10,9 @@ import unicodedata from babel.dates import format_date from django.conf import settings 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.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_countries.fields import Country, CountryField @@ -27,7 +26,6 @@ from .eventchange import EventChange logger = logging.getLogger(__name__) -@python_2_unicode_compatible class Event(models.Model): # Metadata owner = models.ForeignKey(settings.AUTH_USER_MODEL, diff --git a/dav_events/models/eventchange.py b/dav_events/models/eventchange.py index a1f3084..8991fbb 100644 --- a/dav_events/models/eventchange.py +++ b/dav_events/models/eventchange.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals from django.conf import settings from django.db import models from django.utils import timezone -from django.utils.encoding import python_2_unicode_compatible from . import get_ghost_user, get_system_user @@ -12,7 +11,6 @@ def get_system_user_id(): return get_system_user().id -@python_2_unicode_compatible class EventChange(models.Model): UPDATE = 'update' RAISE_FLAG = 'set_flag' @@ -23,7 +21,7 @@ class EventChange(models.Model): (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) user = models.ForeignKey(settings.AUTH_USER_MODEL, default=get_system_user_id, diff --git a/dav_events/models/eventflag.py b/dav_events/models/eventflag.py index 2fe4976..c825c91 100644 --- a/dav_events/models/eventflag.py +++ b/dav_events/models/eventflag.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals from django.conf import settings from django.db import models from django.utils import timezone -from django.utils.encoding import python_2_unicode_compatible from . import get_ghost_user, get_system_user @@ -11,9 +10,8 @@ def get_system_user_id(): return get_system_user().id -@python_2_unicode_compatible 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', on_delete=models.PROTECT, related_name='+') diff --git a/dav_events/models/eventstatus.py b/dav_events/models/eventstatus.py index af7f5ce..fd62e61 100644 --- a/dav_events/models/eventstatus.py +++ b/dav_events/models/eventstatus.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals from django.db import models -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from ..validators import IdStringValidator @@ -22,7 +21,6 @@ BOOTSTRAP_CONTEXT_CHOICES = ( ) -@python_2_unicode_compatible class EventStatus(models.Model): code = models.CharField(primary_key=True, max_length=254, validators=[IdStringValidator]) severity = models.IntegerField(unique=True) diff --git a/dav_events/models/oneclickaction.py b/dav_events/models/oneclickaction.py index 336babc..63d48bd 100644 --- a/dav_events/models/oneclickaction.py +++ b/dav_events/models/oneclickaction.py @@ -3,10 +3,9 @@ from __future__ import unicode_literals import logging import uuid 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.utils import timezone -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext, ugettext_lazy as _ from .event import Event @@ -14,7 +13,6 @@ from .event import Event logger = logging.getLogger(__name__) -@python_2_unicode_compatible class OneClickAction(models.Model): COMMANDS = ( ('EVENT_LIST', 'login and go to event list (user id)'), diff --git a/dav_events/models/participant.py b/dav_events/models/participant.py index da0b692..d664c35 100644 --- a/dav_events/models/participant.py +++ b/dav_events/models/participant.py @@ -4,7 +4,6 @@ import datetime from django.core.exceptions import ValidationError from django.db import models from django.utils import timezone -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from dav_base.validators import DAVNumberValidator @@ -12,7 +11,6 @@ from dav_base.validators import DAVNumberValidator midnight = datetime.time(00, 00, 00) -@python_2_unicode_compatible class AbstractParticipant(models.Model): personal_names = models.CharField(max_length=1024, verbose_name=_('Vorname(n)')) @@ -158,9 +156,8 @@ class AbstractParticipant(models.Model): return timezone.make_aware(datetime.datetime.combine(purge_date, midnight)) -@python_2_unicode_compatible 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) position = models.IntegerField(verbose_name='Listennummer') diff --git a/dav_events/models/trash/trashed_participant.py b/dav_events/models/trash/trashed_participant.py index 90609ac..916ca08 100644 --- a/dav_events/models/trash/trashed_participant.py +++ b/dav_events/models/trash/trashed_participant.py @@ -1,15 +1,13 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from ..participant import AbstractParticipant -@python_2_unicode_compatible 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() trashed_at = models.DateTimeField(auto_now_add=True) position = models.IntegerField(verbose_name='Listennummer') diff --git a/dav_events/urls.py b/dav_events/urls.py index 40cb2d7..bef399c 100644 --- a/dav_events/urls.py +++ b/dav_events/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url from . import views +app_name = 'dav_events' + urlpatterns = [ url(r'^home$', views.base.HomeView.as_view(), name='root'), url(r'^$', views.events.EventListView.as_view(), name='list'), diff --git a/dav_events/views/events.py b/dav_events/views/events.py index c6711c9..40f3f37 100644 --- a/dav_events/views/events.py +++ b/dav_events/views/events.py @@ -754,14 +754,14 @@ class EventCreateView(EventPermissionMixin, generic.FormView): _(u'Du hast jemand anderen als Tourenleiter eingetragen.'), _(u'Warum machst du sowas?') )) - elif owner.has_usable_password(): - next_url = reverse('dav_events:list') - else: + elif owner.last_login is None: login(self.request, owner) next_url = reverse('dav_auth:set_password') messages.success(self.request, _(u'Neuen Benutzer angemeldet: %(username)s') % {'username': owner.username}) messages.warning(self.request, _(u'Bitte neues Passwort setzen!')) + else: + next_url = reverse('dav_events:list') return HttpResponseRedirect(next_url) def clean_session_data(self, session=None): diff --git a/dav_registration/migrations/0011_auto_20220607_1345.py b/dav_registration/migrations/0011_auto_20220607_1345.py new file mode 100644 index 0000000..c07273e --- /dev/null +++ b/dav_registration/migrations/0011_auto_20220607_1345.py @@ -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'), + ), + ] diff --git a/dav_registration/models.py b/dav_registration/models.py index d5cc281..de35ad2 100644 --- a/dav_registration/models.py +++ b/dav_registration/models.py @@ -6,7 +6,6 @@ from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse from django.utils import timezone -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from dav_base.validators import DAVNumberValidator @@ -19,9 +18,8 @@ logger = logging.getLogger(__name__) midnight = datetime.time(00, 00, 00) -@python_2_unicode_compatible 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) personal_names = models.CharField(max_length=1024, @@ -219,11 +217,11 @@ Anmerkung: return timezone.make_aware(datetime.datetime.combine(purge_date, midnight)) -@python_2_unicode_compatible class RegistrationStatus(models.Model): registration = models.OneToOneField(Registration, on_delete=models.CASCADE, related_name='status') updated_at = models.DateTimeField(auto_now=True) answered = models.BooleanField(_('Durch Tourleitung beantwortet'), default=False) + # TODO: NullBooleanField is marked deprecated accepted = models.NullBooleanField(_('Zusage erteilt')) class Meta: diff --git a/dav_registration/urls.py b/dav_registration/urls.py index 62988b8..c0585d8 100644 --- a/dav_registration/urls.py +++ b/dav_registration/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url from . import views +app_name = 'dav_registration' + urlpatterns = [ url(r'^$', views.RootView.as_view(), name='root'), url(r'^finished', views.RegistrationSuccessView.as_view(), name='registered'), diff --git a/dav_submission/urls.py b/dav_submission/urls.py index c6ebfd9..b556c42 100644 --- a/dav_submission/urls.py +++ b/dav_submission/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url from . import views +app_name = 'dav_submission' + urlpatterns = [ url(r'^$', views.UploadView.as_view(), name='root'), url(r'^danke', views.SuccessView.as_view(), name='success'), diff --git a/setup.py b/setup.py index 37da236..1a64cef 100644 --- a/setup.py +++ b/setup.py @@ -22,12 +22,7 @@ class SetupPythonEnvironment(MyCommand): def run(self): python_bin = sys.executable if sys.executable else 'python' python_ver = sys.version_info.major - if python_ver == 2: - path = os.path.join('env', 'python2') - symlink_path = os.path.join('env', 'python') - venv_module = 'virtualenv' - prompt = '(py2-dav) ' - elif python_ver == 3: + if python_ver == 3: path = os.path.join('env', 'python3') symlink_path = os.path.join('env', 'python') venv_module = 'venv' @@ -97,7 +92,7 @@ class QuickSetup(MyCommand): setup( name='django-dav-events', - version='2.0', + version='2.1', description='A django based web application project to organize DAV Events.', url='https://touren.alpenverein-karlsruhe.de', author='Jens Kleineheismann', @@ -116,11 +111,12 @@ setup( }, install_requires=[ 'babel', - 'django >= 1.11, < 2.0', - 'django-extensions', - 'django-bootstrap3 < 12', - 'django-countries < 6', - 'django-datetime-widget', + #'django >= 1.11, < 2.0', + 'django >= 1.11, < 3.3', + # 'django-extensions', + 'django-bootstrap3', + 'django-countries', + 'django-datetime-widget2', 'pytz', 'selenium', 'coverage', diff --git a/tests/__main__.py b/tests/__main__.py new file mode 100644 index 0000000..a145d81 --- /dev/null +++ b/tests/__main__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +from test_suite import main + +if __name__ == '__main__': + main() diff --git a/tests/test_suite.py b/tests/test_suite.py index 78919ed..31bbca5 100644 --- a/tests/test_suite.py +++ b/tests/test_suite.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import unicode_literals import datetime @@ -80,3 +81,12 @@ class TestSuite(object): def __call__(self): sys.exit(self.run()) + + +def main(): + test_suite = TestSuite() + test_suite() + + +if __name__ == '__main__': + main() diff --git a/tox.ini b/tox.ini index f23d041..4c6403c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] -envlist = py3,py2 +envlist = py3 [testenv] commands = python --version - python -m coverage run setup.py test + python -m coverage run tests/test_suite.py coverage report --skip-covered