diff --git a/INSTALL.rst b/INSTALL.rst index bb3207e..ac03e22 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -10,11 +10,11 @@ For production use you surly want a real web server that supports WSGI QUICK INSTALLATION FOR THE IMPATIENT ==================================== -- python -m venv ./etc/python +- python -m venv ./env/python - source env/python/bin/activate - python -m pip install -r requirements.txt - python -m pip install -e . -- django-dav-events-admin setup ./env/django +- django-dav-admin setup ./env/django - python ./env/django/manage.py enable_module dav_auth - python ./env/django/manage.py enable_module dav_events - python ./env/django/manage.py enable_module dav_registration diff --git a/dav_auth/__init__.py b/dav_auth/__init__.py index 7c90b21..e69de29 100644 --- a/dav_auth/__init__.py +++ b/dav_auth/__init__.py @@ -1 +0,0 @@ -default_app_config = 'dav_auth.apps.AppConfig' # pylint: disable=invalid-name diff --git a/dav_auth/admin.py b/dav_auth/admin.py index 1e76950..1b2c014 100644 --- a/dav_auth/admin.py +++ b/dav_auth/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from django.contrib.auth.admin import GroupAdmin as _GroupAdmin from django.contrib.auth.models import Group from django.contrib.auth.models import Permission -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ admin.site.unregister(Group) diff --git a/dav_auth/forms.py b/dav_auth/forms.py index 6e51dfd..5c8e050 100644 --- a/dav_auth/forms.py +++ b/dav_auth/forms.py @@ -2,7 +2,7 @@ import logging from django import forms from django.contrib.auth import forms as auth_forms, password_validation -from django.utils.translation import ugettext, ugettext_lazy as _ +from django.utils.translation import gettext, gettext_lazy as _ logger = logging.getLogger(__name__) @@ -48,7 +48,7 @@ class SetPasswordForm(forms.Form): if password1 and password2: if password1 != password2: raise forms.ValidationError( - ugettext('Passwörter stimmen nicht überein'), + gettext('Passwörter stimmen nicht überein'), code='password_mismatch', ) return password2 diff --git a/dav_auth/module.json b/dav_auth/module.json index 2f1e776..dfc3a65 100644 --- a/dav_auth/module.json +++ b/dav_auth/module.json @@ -1,3 +1,4 @@ { - "url_prefix": "auth" + "url_prefix": "auth", + "app_config": ".apps.AppConfig" } \ No newline at end of file diff --git a/dav_auth/templates/dav_auth/includes/login_widget.html b/dav_auth/templates/dav_auth/includes/login_widget.html index b19180d..4309e8b 100644 --- a/dav_auth/templates/dav_auth/includes/login_widget.html +++ b/dav_auth/templates/dav_auth/includes/login_widget.html @@ -8,7 +8,13 @@
{% else %} diff --git a/dav_auth/tests/generic.py b/dav_auth/tests/generic.py index eede63a..ce38659 100644 --- a/dav_auth/tests/generic.py +++ b/dav_auth/tests/generic.py @@ -17,6 +17,10 @@ class SeleniumAuthMixin: return driver def logout(self, driver): - driver.get(self.complete_url(reverse('dav_auth:logout'))) + #driver.get(self.complete_url(reverse('dav_auth:logout'))) + dropdown_button = driver.find_element(By.ID, 'user_dropdown_button') + dropdown_button.click() + logout_button = driver.find_element(By.ID, 'id_logout_button') + logout_button.click() self.wait_on_presence(driver, (By.CSS_SELECTOR, "#messages .alert-success")) return driver diff --git a/dav_auth/tests/test_forms.py b/dav_auth/tests/test_forms.py index e317150..35076d9 100644 --- a/dav_auth/tests/test_forms.py +++ b/dav_auth/tests/test_forms.py @@ -2,7 +2,7 @@ from unittest import skip from django.contrib.auth import get_user_model from django.core import mail as django_mail -from django.utils.translation import ugettext +from django.utils.translation import gettext from dav_base.tests.generic import FormDataSet, FormsTestCase @@ -25,8 +25,8 @@ class LoginFormTestCase(FormsTestCase): def test_labels(self): form = self.form_class() - self.assertEqual(form.fields['username'].label, ugettext('E-Mail-Adresse')) - self.assertEqual(form.fields['password'].label, ugettext('Password')) + self.assertEqual(form.fields['username'].label, gettext('E-Mail-Adresse')) + self.assertEqual(form.fields['password'].label, gettext('Password')) def test_required(self): form = self.form_class() @@ -193,7 +193,7 @@ class CreateAndSendPasswordFormTestCase(FormsTestCase): def test_labels(self): form = self.form_class() - self.assertEqual(form.fields['username'].label, ugettext('E-Mail-Adresse')) + self.assertEqual(form.fields['username'].label, gettext('E-Mail-Adresse')) def test_required(self): form = self.form_class() diff --git a/dav_auth/tests/test_screenshots.py b/dav_auth/tests/test_screenshots.py index 9d30265..8e2acd6 100644 --- a/dav_auth/tests/test_screenshots.py +++ b/dav_auth/tests/test_screenshots.py @@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model from django.test import tag from django.urls import reverse -from django.utils.translation import ugettext +from django.utils.translation import gettext from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys @@ -105,7 +105,7 @@ class TestCase(ScreenshotTestCase): # Click on 'set password' -> save set password page user_menu = c.find_element(By.CSS_SELECTOR, '#login-widget ul') - link = user_menu.find_element(By.PARTIAL_LINK_TEXT, ugettext('Passwort ändern')) + link = user_menu.find_element(By.PARTIAL_LINK_TEXT, gettext('Passwort ändern')) link.click() password_field = self.wait_on_presence(c, (By.ID, 'id_new_password')) self.save_screenshot('empty_set_password_form', sequence=sequence_name) @@ -189,8 +189,10 @@ class TestCase(ScreenshotTestCase): dropdown_button = self.wait_on_presence(c, (By.ID, 'user_dropdown_button')) dropdown_button.click() user_menu = c.find_element(By.CSS_SELECTOR, '#login-widget ul') - link = user_menu.find_element(By.PARTIAL_LINK_TEXT, ugettext('Logout')) - link.click() + #link = user_menu.find_element(By.PARTIAL_LINK_TEXT, gettext('Logout')) + #link.click() + button = c.find_element(By.ID, 'id_logout_button') + button.click() self.wait_until_stale(c, user_menu) self.save_screenshot('logout_succeed', sequence=sequence_name) @@ -200,7 +202,7 @@ class TestCase(ScreenshotTestCase): self.wait_on_presence(c, (By.ID, 'id_username')) # Locate password recreate link, click it -> save password recreate form - link = c.find_element(By.PARTIAL_LINK_TEXT, ugettext('Passwort vergessen')) + link = c.find_element(By.PARTIAL_LINK_TEXT, gettext('Passwort vergessen')) link.click() username_field = self.wait_on_presence(c, (By.ID, 'id_username')) self.save_screenshot('empty_recreate_password_form', sequence=sequence_name) @@ -212,7 +214,7 @@ class TestCase(ScreenshotTestCase): self.save_screenshot('recreate_password_invalid_user', sequence=sequence_name) # Locate password recreate link, click it - link = c.find_element(By.PARTIAL_LINK_TEXT, ugettext('Passwort vergessen')) + link = c.find_element(By.PARTIAL_LINK_TEXT, gettext('Passwort vergessen')) link.click() username_field = self.wait_on_presence(c, (By.ID, 'id_username')) diff --git a/dav_auth/tests/test_templates.py b/dav_auth/tests/test_templates.py index b33ca12..73486c8 100644 --- a/dav_auth/tests/test_templates.py +++ b/dav_auth/tests/test_templates.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.contrib.auth import get_user_model from django.test import SimpleTestCase, tag -from django.utils.translation import ugettext +from django.utils.translation import gettext from django.urls import reverse from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By @@ -20,7 +20,7 @@ class TemplatesTestCase(SimpleTestCase): def test_recreate_link_in_login_form(self): login_url = reverse('dav_auth:login') recreate_url = reverse('dav_auth:recreate_password') - text = ugettext('Passwort vergessen?') + text = gettext('Passwort vergessen?') html = '{text}'.format(url=recreate_url, text=text) response = self.client.get(login_url) self.assertInHTML(html, response.content.decode('utf-8')) diff --git a/dav_auth/tests/test_urls.py b/dav_auth/tests/test_urls.py index 5acaf2f..5ad1538 100644 --- a/dav_auth/tests/test_urls.py +++ b/dav_auth/tests/test_urls.py @@ -6,7 +6,8 @@ from .. import views class TestCase(UrlsTestCase): urls = ( Url('/auth/login', 'dav_auth:login', views.LoginView.as_view()), - Url('/auth/logout', 'dav_auth:logout', views.LogoutView.as_view(), status_code=302), + Url('/auth/logout', 'dav_auth:logout', views.LogoutView.as_view(), status_code=302, + http_method='POST'), Url('/auth/password', 'dav_auth:set_password', views.SetPasswordView.as_view(), redirect='/auth/login?next=/auth/password'), Url('/auth/password/recreate', 'dav_auth:recreate_password', views.CreateAndSendPasswordView.as_view()), diff --git a/dav_auth/tests/test_views.py b/dav_auth/tests/test_views.py index 2e3a601..a086189 100644 --- a/dav_auth/tests/test_views.py +++ b/dav_auth/tests/test_views.py @@ -4,7 +4,7 @@ from django.contrib.auth import get_user_model from django.core import mail as django_mail from django.shortcuts import resolve_url from django.test import TestCase -from django.utils.translation import ugettext +from django.utils.translation import gettext from django.urls import reverse from ..forms import LoginForm, SetPasswordForm, CreateAndSendPasswordForm @@ -30,9 +30,9 @@ class ViewsTestCase(TestCase): cls.recreate_password_url = reverse('dav_auth:recreate_password') # Some messages - cls.wrong_credentials_message = ugettext('Benutzername oder Passwort falsch.') - cls.logout_message = ugettext('Benutzer abgemeldet.') - cls.set_password_message = ugettext('Passwort gespeichert.') + cls.wrong_credentials_message = gettext('Benutzername oder Passwort falsch.') + cls.logout_message = gettext('Benutzer abgemeldet.') + cls.set_password_message = gettext('Passwort gespeichert.') def setUp(self): super().setUp() @@ -61,7 +61,7 @@ class ViewsTestCase(TestCase): response = self.client.post(self.login_url, {'username': self.test_username, 'password': self.test_password}) self.assertEqual(response.status_code, 200) - self.assertFormError(response, 'form', None, self.wrong_credentials_message) + self.assertFormError(response.context['form'], None, self.wrong_credentials_message) self.assertFalse(response.context['user'].is_authenticated, 'User is logged in') def test_integrated_login_fail_with_wrong_credentials(self): @@ -69,12 +69,12 @@ class ViewsTestCase(TestCase): response = self.client.post(self.login_url, {'username': self.test_username, 'password': wrong_password}) self.assertEqual(response.status_code, 200) - self.assertFormError(response, 'form', None, self.wrong_credentials_message) + self.assertFormError(response.context['form'],None, self.wrong_credentials_message) self.assertFalse(response.context['user'].is_authenticated, 'User is logged in') def test_integrated_login_succeed(self): username = self.user.username - message = ugettext('Benutzer angemeldet: %(username)s') % {'username': username} + message = gettext('Benutzer angemeldet: %(username)s') % {'username': username} response = self.client.post(self.login_url, {'username': username, 'password': self.test_password}) self.assertEqual(response.status_code, 302) @@ -88,7 +88,7 @@ class ViewsTestCase(TestCase): def test_integrated_logout(self): self.client.login(username=self.test_username, password=self.test_password) - response = self.client.get(self.logout_url) + response = self.client.post(self.logout_url) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, self.logout_redirect_url) diff --git a/dav_auth/urls.py b/dav_auth/urls.py index 8d4bdf7..f627fab 100644 --- a/dav_auth/urls.py +++ b/dav_auth/urls.py @@ -1,12 +1,12 @@ -from django.conf.urls import url +from django.urls import re_path 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'), - url(r'^password$', views.SetPasswordView.as_view(), name='set_password'), - url(r'^password/recreate$', views.CreateAndSendPasswordView.as_view(), name='recreate_password'), + re_path(r'^login$', views.LoginView.as_view(), name='login'), + re_path(r'^logout$', views.LogoutView.as_view(), name='logout'), + re_path(r'^password$', views.SetPasswordView.as_view(), name='set_password'), + re_path(r'^password/recreate$', views.CreateAndSendPasswordView.as_view(), name='recreate_password'), ] diff --git a/dav_auth/views.py b/dav_auth/views.py index cf22504..bedb253 100644 --- a/dav_auth/views.py +++ b/dav_auth/views.py @@ -9,7 +9,7 @@ from django.http import HttpResponseRedirect from django.shortcuts import resolve_url from django.urls import reverse_lazy, reverse from django.utils.safestring import mark_safe -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.views import generic from . import emails @@ -48,9 +48,10 @@ class LoginView(auth_views.LoginView): class LogoutView(auth_views.LogoutView): - def get_next_page(self): - url = super().get_next_page() - if not url and app_config.settings.logout_redirect_url: + @property + def next_page(self): + url = None + if app_config.settings.logout_redirect_url: url = resolve_url(app_config.settings.logout_redirect_url) return url diff --git a/dav_base/__init__.py b/dav_base/__init__.py index c57740f..e69de29 100644 --- a/dav_base/__init__.py +++ b/dav_base/__init__.py @@ -1 +0,0 @@ -default_app_config = 'dav_base.apps.AppConfig' # pylint: disable=invalid-name diff --git a/dav_base/config/modules.py b/dav_base/config/modules.py index 6c82e87..ac0f7da 100644 --- a/dav_base/config/modules.py +++ b/dav_base/config/modules.py @@ -3,7 +3,7 @@ import os import pkg_resources from django.conf import settings -from django.conf.urls import url as django_conf_url, include +from django.urls import re_path, include DJANGO_MAIN_MODULE = 'main' MODULE_CONFIG_FILE_NAME = 'module_config.json' @@ -19,6 +19,7 @@ class ModuleMeta: def __init__(self, package_name): self._package_name = package_name + self._app_config = None self._additional_apps = [] self._url_prefix = None self._load_from_package() @@ -28,9 +29,19 @@ class ModuleMeta: return t @property - def app(self): + def package(self): return self._package_name + @property + def app(self): + if self._app_config: + app = self._app_config + if app.startswith('.'): + app = self._package_name + app + else: + app = self._package_name + return app + @property def additional_apps(self): return self._additional_apps @@ -50,7 +61,7 @@ class ModuleMeta: def url_conf_pattern(self): url_pattern = '^{}/'.format(self.url_prefix) url_conf = self._package_name + '.urls' - return django_conf_url(url_pattern, include(url_conf, self.url_namespace)) + return re_path(url_pattern, include(url_conf, self.url_namespace)) def _load_from_package(self): package_name = self._package_name @@ -61,6 +72,7 @@ class ModuleMeta: def load_from_dict(self, meta_dict): self._package_name = meta_dict.get('package', None) + self._app_config = meta_dict.get('app_config', None) self._additional_apps = meta_dict.get('additional_apps', []) self._url_prefix = meta_dict.get('url_prefix', None) @@ -68,6 +80,8 @@ class ModuleMeta: d = { 'package': self._package_name, } + if self._app_config: + d['app_config'] = self._app_config if self._additional_apps: d['additional_apps'] = self._additional_apps if self._url_prefix: 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 1bd7468..4bdde64 100644 --- a/dav_base/console_scripts/django_project_config/additional_settings.py +++ b/dav_base/console_scripts/django_project_config/additional_settings.py @@ -16,7 +16,7 @@ INSTALLED_APPS += [ 'django_countries', # 'django_extensions', # Our main app - 'dav_base', + 'dav_base.apps.AppConfig', ] # Add apps from our modules diff --git a/dav_base/console_scripts/django_project_config/urls.py b/dav_base/console_scripts/django_project_config/urls.py index d1e9a66..23dec90 100644 --- a/dav_base/console_scripts/django_project_config/urls.py +++ b/dav_base/console_scripts/django_project_config/urls.py @@ -1,5 +1,5 @@ from django.conf import settings -from django.conf.urls import url, include +from django.urls import re_path, include urlpatterns = [] @@ -8,5 +8,5 @@ for module_meta_obj in settings.MODULE_CONFIG.modules.values(): urlpatterns.append(module_meta_obj.url_conf_pattern) urlpatterns += [ - url(r'^', include('dav_base.urls')) + re_path(r'^', include('dav_base.urls')) ] diff --git a/dav_base/tests/generic.py b/dav_base/tests/generic.py index f631bdf..0320976 100644 --- a/dav_base/tests/generic.py +++ b/dav_base/tests/generic.py @@ -171,6 +171,8 @@ class Url: # pylint: disable=too-few-public-methods self.location = location self.name = name self.func = func + self.http_method = kwargs.get('http_method', "GET") + self.post_data = kwargs.get('post_data', {}) self.redirect = kwargs.get('redirect', False) self.status_code = kwargs.get('status_code', 200) self.follow = kwargs.get('follow', False) @@ -182,7 +184,12 @@ class UrlsTestCase(TestCase): def test_locations(self): for url in self.urls: if url.location: - response = self.client.get(url.location, follow=url.follow) + if url.http_method == "GET": + response = self.client.get(url.location, follow=url.follow) + elif url.http_method == "POST": + response = self.client.post(url.location, data=url.post_data, follow=url.follow) + else: # pragma: no cover + raise NotImplementedError("Method {} is not supported".format(url.http_method)) if url.redirect: self.assertRedirects(response, url.redirect) @@ -198,7 +205,13 @@ class UrlsTestCase(TestCase): def test_names(self): for url in self.urls: if url.name: - response = self.client.get(reverse(url.name), follow=url.follow) + location = reverse(url.name) + if url.http_method == "GET": + response = self.client.get(location, follow=url.follow) + elif url.http_method == "POST": + response = self.client.post(location, data=url.post_data, follow=url.follow) + else: # pragma: no cover + raise NotImplementedError("Method {} is not supported".format(url.http_method)) if url.redirect: self.assertRedirects(response, url.redirect) diff --git a/dav_base/urls.py b/dav_base/urls.py index 5286e4e..30251a5 100644 --- a/dav_base/urls.py +++ b/dav_base/urls.py @@ -1,11 +1,11 @@ -from django.conf.urls import url +from django.urls import re_path from django.contrib import admin from django.views import generic from . import views urlpatterns = [ - url(r'^$', views.RootView.as_view(), name='root'), - url(r'^css-demo$', generic.TemplateView.as_view(template_name='dav_base/css_demo.html'), name='css-demo'), - url(r'^djangoadmin/', admin.site.urls), + re_path(r'^$', views.RootView.as_view(), name='root'), + re_path(r'^css-demo$', generic.TemplateView.as_view(template_name='dav_base/css_demo.html'), name='css-demo'), + re_path(r'^djangoadmin/', admin.site.urls), ] diff --git a/dav_base/validators.py b/dav_base/validators.py index c7966ed..3b93187 100644 --- a/dav_base/validators.py +++ b/dav_base/validators.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from django.core.validators import RegexValidator -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ DAVNumberValidator = RegexValidator(r'^' diff --git a/dav_base/views.py b/dav_base/views.py index 76422ba..d07fd7c 100644 --- a/dav_base/views.py +++ b/dav_base/views.py @@ -15,7 +15,7 @@ class RootView(generic.TemplateView): root_url_name = '%s:%s' % (module_meta_obj.url_namespace, root_url_name) try: reverse(root_url_name) - root_urls.append((module_meta_obj.app, root_url_name)) + root_urls.append((module_meta_obj.package, root_url_name)) except NoReverseMatch: pass diff --git a/dav_event_office/__init__.py b/dav_event_office/__init__.py index 2136438..e69de29 100644 --- a/dav_event_office/__init__.py +++ b/dav_event_office/__init__.py @@ -1 +0,0 @@ -default_app_config = 'dav_event_office.apps.AppConfig' # pylint: disable=invalid-name diff --git a/dav_event_office/module.json b/dav_event_office/module.json index 5a4ef89..b851441 100644 --- a/dav_event_office/module.json +++ b/dav_event_office/module.json @@ -1,3 +1,4 @@ { - "url_prefix": "office/events" + "url_prefix": "office/events", + "app_config": ".apps.AppConfig" } \ No newline at end of file diff --git a/dav_event_office/urls.py b/dav_event_office/urls.py index 3def02d..6df768b 100644 --- a/dav_event_office/urls.py +++ b/dav_event_office/urls.py @@ -1,12 +1,12 @@ -from django.conf.urls import url +from django.urls import re_path 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'), - url(r'^$', views.EventListView.as_view(), name='event-list'), - url(r'^(?P