Refactor: split code into several django apps (we call them modules).

This commit is contained in:
2018-12-13 14:47:58 +01:00
parent c23dc33d4e
commit 0d5a8c65e3
81 changed files with 739 additions and 332 deletions

1
dav_auth/__init__.py Normal file
View File

@@ -0,0 +1 @@
default_app_config = 'dav_auth.apps.AppConfig'

12
dav_auth/apps.py Normal file
View File

@@ -0,0 +1,12 @@
from dav_base.config.apps import AppConfig as _AppConfig, DefaultSetting
DEFAULT_SETTINGS = (
DefaultSetting('login_redirect_url', 'root'),
DefaultSetting('logout_redirect_url', 'root'),
)
class AppConfig(_AppConfig):
name = 'dav_auth'
verbose_name = u'DAV Benutzerverwaltung'
default_settings = DEFAULT_SETTINGS

View File

@@ -0,0 +1,2 @@
# LOGIN_REDIRECT_URL = 'root'
# LOGOUT_REDIRECT_URL = 'root'

25
dav_auth/emails.py Normal file
View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from dav_base.emails import AbstractMail
class PasswordSetEmail(AbstractMail):
_subject = u'Zugangsdaten'
_template_name = 'dav_auth/emails/password_set.txt'
def __init__(self, user, password):
self._user = user
self._password = password
def _get_recipients(self):
r = u'{fullname} <{email}>'.format(fullname=self._user.get_full_name(),
email=self._user.email)
return [r]
def _get_context_data(self, extra_context=None):
context = super(PasswordSetEmail, self)._get_context_data(extra_context=extra_context)
context.update({
'fullname': self._user.get_full_name(),
'username': self._user.username,
'password': self._password
})
return context

3
dav_auth/module.json Normal file
View File

@@ -0,0 +1,3 @@
{
"url_prefix": "auth"
}

View File

@@ -0,0 +1 @@
{% extends "dav_base/base.html" %}

View File

@@ -3,4 +3,4 @@ Hallo {{ fullname }},
Benutzername: {{ username }}
Passwort: {{ password }}
URL: {{ base_url }}{% url 'dav_events:home' %}
URL: {{ base_url }}{% url 'root' %}

View File

@@ -1,4 +1,4 @@
{% extends "dav_events/base.html" %}
{% extends "dav_auth/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
@@ -15,13 +15,13 @@
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<div class="pull-right"><a href="{% url 'dav_events:reset_password' %}">{% trans 'Passwort vergessen?' %}</a></div>
<div class="pull-right"><a href="{% url 'dav_auth:reset_password' %}">{% trans 'Passwort vergessen?' %}</a></div>
{% buttons %}
<button type="submit" class="btn btn-success">
{% bootstrap_icon 'log-in' %}&thinsp;
{% trans 'Login' %}
</button>
<a class="btn btn-danger" href="{% url 'dav_events:home' %}">
<a class="btn btn-danger" href="{% url 'root' %}">
{% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %}
</a>

View File

@@ -1,4 +1,4 @@
{% extends "dav_events/base.html" %}
{% extends "dav_auth/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
@@ -20,7 +20,7 @@
{% bootstrap_icon 'saved' %}&thinsp;
{% trans 'Neues Passwort per E-Mail zusenden' %}
</button>
<a class="btn btn-danger" href="{% url 'dav_events:home' %}">
<a class="btn btn-danger" href="{% url 'root' %}">
{% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %}
</a>

View File

@@ -1,4 +1,4 @@
{% extends "dav_events/base.html" %}
{% extends "dav_auth/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
@@ -20,7 +20,7 @@
{% bootstrap_icon 'saved' %}&thinsp;
{% trans 'Neues Passwort setzen' %}
</button>
<a class="btn btn-danger" href="{% url 'dav_events:home' %}">
<a class="btn btn-danger" href="{% url 'root' %}">
{% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %}
</a>

View File

@@ -7,12 +7,12 @@
{{ user }}&ensp;<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="user_dropdown_button">
<li><a href="{% url 'dav_events:set_password' %}">{% trans 'Passwort ändern' %}</a></li>
<li><a href="{% url 'dav_events:logout' %}">{% trans 'Logout' %}</a></li>
<li><a href="{% url 'dav_auth:set_password' %}">{% trans 'Passwort ändern' %}</a></li>
<li><a href="{% url 'dav_auth:logout' %}">{% trans 'Logout' %}</a></li>
</ul>
</div>
{% else %}
<a class="btn btn-default btn-sm" href="{% url 'dav_events:login' %}">
<a class="btn btn-default btn-sm" href="{% url 'dav_auth:login' %}">
{% bootstrap_icon 'log-in' %}&nbsp;
{% trans 'Login' %}
</a>

10
dav_auth/urls.py Normal file
View File

@@ -0,0 +1,10 @@
from django.conf.urls import url
from . import views
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/reset$', views.ResetPasswordView.as_view(), name='reset_password'),
]

View File

@@ -1,24 +1,28 @@
import logging
from django.apps import apps
from django.contrib import messages
from django.contrib.auth import views as auth_views, get_user_model
from django.shortcuts import resolve_url
from django.urls import reverse_lazy
from django.utils.translation import ugettext as _
from django.views import generic
from .. import emails
from .. import forms
from . import emails
from . import forms
app_config = apps.get_containing_app_config(__package__)
logger = logging.getLogger(__name__)
class LoginView(auth_views.LoginView):
form_class = forms.auth.LoginForm
next_page = reverse_lazy('dav_events:event_list')
template_name = 'dav_events/auth/login_form.html'
form_class = forms.LoginForm
template_name = 'dav_auth/forms/login.html'
def get_success_url(self):
url = self.get_redirect_url()
return url or self.next_page
def get_redirect_url(self):
url = super(LoginView, self).get_redirect_url()
if not url and app_config.settings.login_redirect_url:
url = resolve_url(app_config.settings.login_redirect_url)
return url
def form_valid(self, form):
r = super(LoginView, self).form_valid(form)
@@ -27,7 +31,11 @@ class LoginView(auth_views.LoginView):
class LogoutView(auth_views.LogoutView):
next_page = reverse_lazy('dav_events:home')
def get_next_page(self):
url = super(LogoutView, self).get_next_page()
if not url and app_config.settings.logout_redirect_url:
url = resolve_url(app_config.settings.logout_redirect_url)
return url
def dispatch(self, request, *args, **kwargs):
r = super(LogoutView, self).dispatch(request, *args, **kwargs)
@@ -36,9 +44,11 @@ class LogoutView(auth_views.LogoutView):
class SetPasswordView(auth_views.PasswordChangeView):
form_class = forms.auth.SetPasswordForm
template_name = 'dav_events/auth/set_password_form.html'
success_url = reverse_lazy('dav_events:event_list')
form_class = forms.SetPasswordForm
template_name = 'dav_auth/forms/set_password.html'
def get_success_url(self):
return resolve_url(app_config.settings.login_redirect_url)
def form_valid(self, form):
r = super(SetPasswordView, self).form_valid(form)
@@ -50,9 +60,9 @@ class SetPasswordView(auth_views.PasswordChangeView):
class ResetPasswordView(generic.FormView):
form_class = forms.auth.ResetPasswordForm
template_name = 'dav_events/auth/reset_password_form.html'
success_url = reverse_lazy('dav_events:login')
form_class = forms.ResetPasswordForm
template_name = 'dav_auth/forms/reset_password.html'
success_url = reverse_lazy('dav_auth:login')
def form_valid(self, form):
username = form.cleaned_data.get('username')

1
dav_base/__init__.py Normal file
View File

@@ -0,0 +1 @@
default_app_config = 'dav_base.apps.AppConfig'

13
dav_base/apps.py Normal file
View File

@@ -0,0 +1,13 @@
from .config.apps import AppConfig as _AppConfig, DefaultSetting
DEFAULT_SETTINGS = (
DefaultSetting('email_sender', None),
DefaultSetting('email_base_url', None),
DefaultSetting('email_subject_prefix', ''),
)
class AppConfig(_AppConfig):
name = 'dav_base'
verbose_name = u'DAV Base App'
default_settings = DEFAULT_SETTINGS

View File

@@ -0,0 +1,2 @@
from . import apps
from . import modules

71
dav_base/config/apps.py Normal file
View File

@@ -0,0 +1,71 @@
import importlib
import logging
import re
from django.apps import AppConfig as _AppConfig
from django.core.exceptions import ImproperlyConfigured
logger = logging.getLogger(__name__)
class DefaultSetting(object):
def __init__(self, name, value, key_name=None, validator=None):
self.name = name
self.value = value
if key_name is None:
self.key_name = self.name.upper()
else:
self.key_name = key_name
self.validator = validator
def validate(self, value):
if hasattr(self, 'validator') and self.validator is not None:
if callable(self.validator):
if not self.validator(value):
raise ImproperlyConfigured("Validator callback {clb} returned False".format(clb=self.validator))
else:
if not re.search(self.validator, value):
raise ImproperlyConfigured("Does not match /{re}/".format(re=self.validator))
class AppSettings(object):
def __init__(self, app_name, defaults):
settings_name = 'main.settings-' + app_name
try:
settings_module = importlib.import_module(settings_name)
except ImportError:
settings_module = None
for default in defaults:
if hasattr(settings_module, default.key_name):
value = getattr(settings_module, default.key_name)
try:
default.validate(value)
except ImproperlyConfigured as e:
msg = 'Invalid value of {key} in {module}: {cause}'.format(key=default.key_name,
module=settings_name,
cause=e.message)
raise ImproperlyConfigured(msg)
setattr(self, default.name, value)
elif isinstance(default.value, ImproperlyConfigured):
raise default.value
else:
try:
is_impconf = issubclass(default.value, ImproperlyConfigured)
except TypeError:
is_impconf = False
if is_impconf:
msg = '{key} must be defined in {module}'.format(key=default.key_name,
module=settings_name)
raise default.value(msg)
else:
setattr(self, default.name, default.value)
class AppConfig(_AppConfig):
default_settings = ()
def __init__(self, app_name, app_module):
super(AppConfig, self).__init__(app_name, app_module)
self.settings = AppSettings(app_name, self.default_settings)

132
dav_base/config/modules.py Normal file
View File

@@ -0,0 +1,132 @@
import json
import os
import pkg_resources
from django.conf import settings
from django.conf.urls import url as django_conf_url, include
DJANGO_MAIN_MODULE = 'main'
MODULE_CONFIG_FILE_NAME = 'module_config.json'
class ModuleConfigError(Exception):
pass
class ModuleMeta(object):
_json_file = 'module.json'
_root_url_name = 'root'
def __init__(self, package_name):
self._package_name = package_name
self._additional_apps = []
self._url_prefix = None
self._load_from_package()
def __str__(self):
t = '- {}'.format(self._package_name)
return t
@property
def app(self):
return self._package_name
@property
def additional_apps(self):
return self._additional_apps
@property
def url_conf_pattern(self):
url_pattern = '^'
if self._url_prefix is None:
url_pattern += self._package_name
else:
url_pattern += self._url_prefix
url_pattern += '/'
url_conf = self._package_name + '.urls'
return django_conf_url(url_pattern, include(url_conf, self.url_namespace))
@property
def url_namespace(self):
return self._package_name.replace('.', '_')
def _load_from_package(self):
package_name = self._package_name
json_text = pkg_resources.resource_string(package_name, self._json_file)
meta_dict = json.loads(json_text)
meta_dict['package'] = package_name
self.load_from_dict(meta_dict)
def load_from_dict(self, meta_dict):
self._package_name = meta_dict.get('package', None)
self._additional_apps = meta_dict.get('additional_apps', [])
self._url_prefix = meta_dict.get('url_prefix', None)
def dump_as_dict(self):
d = {
'package': self._package_name,
}
if self._additional_apps:
d['additional_apps'] = self._additional_apps
if self._url_prefix:
d['url_prefix'] = self._url_prefix
return d
class ModuleConfig(object):
_lazy_load = True
def __init__(self, config_file_path=None, django_base_dir=None):
if config_file_path is None:
if django_base_dir is None:
django_base_dir = settings.BASE_DIR
config_file_path = os.path.join(django_base_dir, DJANGO_MAIN_MODULE, MODULE_CONFIG_FILE_NAME)
self._config_file_path = config_file_path
self._modules = dict()
self._loaded = False
if not self._lazy_load:
self._load()
def _lazy_init(self):
if not self._loaded:
self._load()
def _load(self):
path = self._config_file_path
self._modules = dict()
with open(path, 'r') as f:
data = json.load(f)
if 'modules' in data:
for meta_dict in data['modules']:
module_name = meta_dict['package']
self._modules[module_name] = ModuleMeta(module_name)
self._modules[module_name].load_from_dict(meta_dict)
self._loaded = True
@property
def modules(self):
self._lazy_init()
return self._modules
def save(self):
path = self._config_file_path
if os.path.exists(path):
self._lazy_init()
else:
self._loaded = True
data = {
'modules': [],
}
for meta_obj in self._modules.values():
data['modules'].append(meta_obj.dump_as_dict())
with open(path, 'w') as f:
json.dump(data, f, indent=4)

View File

View File

@@ -4,13 +4,15 @@ import pkg_resources
import posix
import sys
from dav_base.config.modules import DJANGO_MAIN_MODULE, ModuleConfig
VERSION = '0.1'
class AdminCommand(object):
def _setup_argparser(self):
kwargs = {
'description': 'Tool to manage the DAV Events django project installation.',
'description': 'Tool to manage the DAV django project installation.',
'epilog': 'Off Belay.',
}
parser = argparse.ArgumentParser(**kwargs)
@@ -36,30 +38,31 @@ class AdminCommand(object):
return self._argparser.parse_args(argv)
def _subcmd_setup(self, cmd_args):
django_project_name = 'main'
django_project_path = cmd_args.path
django_main_module = DJANGO_MAIN_MODULE
django_base_dir = cmd_args.path
sys.stdout.write('Setup installation in \'{path}\'...\n'.format(path=django_project_path))
sys.stdout.write('Setup installation in \'{path}\'...\n'.format(path=django_base_dir))
if os.path.exists(django_project_path):
if not os.path.isdir(django_project_path):
sys.stderr.write('{path}: Not a directory.\n'.format(path=django_project_path))
if os.path.exists(django_base_dir):
if not os.path.isdir(django_base_dir):
sys.stderr.write('{path}: Not a directory.\n'.format(path=django_base_dir))
return posix.EX_USAGE
else:
os.makedirs(django_project_path)
os.makedirs(django_base_dir)
sys.stdout.write('Creating django project...\n')
django_cmd = 'django-admin startproject {name} "{path}"'.format(name=django_project_name,
path=django_project_path)
django_cmd = 'django-admin startproject {name} "{path}"'.format(name=django_main_module,
path=django_base_dir)
exitval = os.system(django_cmd)
if exitval != posix.EX_OK:
return exitval
sys.stdout.write('Creating directories...\n')
dirs = [
os.path.join(django_project_path, 'var', 'db'),
os.path.join(django_project_path, 'var', 'log'),
os.path.join(django_project_path, 'var', 'www', 'static'),
os.path.join(django_base_dir, 'common', 'templates'),
os.path.join(django_base_dir, 'var', 'db'),
os.path.join(django_base_dir, 'var', 'log'),
os.path.join(django_base_dir, 'var', 'www', 'static'),
]
for d in dirs:
@@ -68,18 +71,21 @@ class AdminCommand(object):
sys.stdout.write('Configure django project...\n')
input_file = os.path.join('Resources', 'django.main.additional_settings.py')
output_file = os.path.join(django_project_path, django_project_name, 'settings.py')
config = ModuleConfig(django_base_dir=django_base_dir)
config.save()
input_file = os.path.join('django_project_config', 'additional_settings.py')
output_file = os.path.join(django_base_dir, django_main_module, 'settings.py')
with open(output_file, 'a') as f:
f.write(pkg_resources.resource_string(__package__, input_file))
input_file = os.path.join('Resources', 'django.main.urls.py')
output_file = os.path.join(django_project_path, django_project_name, 'urls.py')
input_file = os.path.join('django_project_config', 'urls.py')
output_file = os.path.join(django_base_dir, django_main_module, 'urls.py')
with open(output_file, 'w') as f:
f.write(pkg_resources.resource_string(__package__, input_file))
input_file = os.path.join('Resources', 'django.main.settings-dav_events.py')
output_file = os.path.join(django_project_path, django_project_name, 'settings-dav_events.py')
input_file = os.path.join('django_project_config', 'settings-dav_base.py')
output_file = os.path.join(django_base_dir, django_main_module, 'settings-dav_base.py')
with open(output_file, 'w') as f:
f.write(pkg_resources.resource_string(__package__, input_file))

View File

@@ -1,20 +1,33 @@
#
# Additional settings for django-dav-events
# Additional settings for django-dav
#
BASE_VAR_DIR = os.path.join(BASE_DIR, 'var')
BASE_SHARE_DIR = os.path.join(BASE_DIR, 'common')
# Get modules config
from dav_base.config.modules import ModuleConfig
MODULE_CONFIG = ModuleConfig()
INSTALLED_APPS += [
'bootstrap3',
'datetimewidget',
'django_countries',
'django_extensions',
# Our main app
'dav_events',
'dav_base',
]
# Add apps from our modules
for module_meta_obj in MODULE_CONFIG.modules.values():
if module_meta_obj.app:
INSTALLED_APPS.append(module_meta_obj.app)
if module_meta_obj.additional_apps:
for app in module_meta_obj.additional_apps:
INSTALLED_APPS.append(app)
# Add a template engine without html auto escape for rendering plain text templates.
TEMPLATES += [
{
'NAME': 'PLAINTEXT',
@@ -30,6 +43,10 @@ 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'))
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_VAR_DIR, 'db', 'devel.sqlite3'),
@@ -39,7 +56,7 @@ STATIC_ROOT = os.path.join(BASE_VAR_DIR, 'www', 'static')
LANGUAGE_CODE = 'de'
LOGIN_URL = 'dav_events:login'
LOGIN_URL = 'dav_auth:login'
BOOTSTRAP3 = {
'set_placeholder': False,

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# E-Mails
EMAIL_SENDER = 'DAV heinzel <heinzel@alpenverein-karlsruhe.de>'
EMAIL_BASE_URL = 'http://localhost:8000'
EMAIL_SUBJECT_PREFIX = u'[DAV heinzel]'

View File

@@ -0,0 +1,12 @@
from django.conf import settings
from django.conf.urls import url, include
urlpatterns = []
for module_meta_obj in settings.MODULE_CONFIG.modules.values():
if module_meta_obj.url_conf_pattern:
urlpatterns.append(module_meta_obj.url_conf_pattern)
urlpatterns = [
url(r'^', include('dav_base.urls'))
]

59
dav_base/emails.py Normal file
View File

@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
import logging
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
from django.core.mail import EmailMessage
from django.template.loader import get_template
app_config = apps.get_containing_app_config(__package__)
logger = logging.getLogger(__name__)
class AbstractMail(object):
_subject = u''
_template_name = None
def _get_sender(self):
#app_config = apps.get_containing_app_config(__package__)
return app_config.settings.email_sender
def _get_subject(self, subject_fmt=None, **kwargs):
if subject_fmt is None:
subject_fmt = self._subject
#app_config = apps.get_containing_app_config(__package__)
if app_config.settings.email_subject_prefix:
subject_fmt = u'%s %s' % (app_config.settings.email_subject_prefix, subject_fmt)
subject = subject_fmt.format(**kwargs)
return subject
def _get_template(self):
if not self._template_name:
raise ImproperlyConfigured('%s._template_name ist not set.', self.__class__.__name__)
return get_template(self._template_name, using='PLAINTEXT')
def _get_context_data(self, extra_context=None):
#app_config = apps.get_containing_app_config(__package__)
context = {
'base_url': app_config.settings.email_base_url,
}
if extra_context:
context.update(extra_context)
return context
def _get_body(self, context=None):
template = self._get_template()
context = self._get_context_data(extra_context=context)
return template.render(context)
def _get_recipients(self):
raise NotImplementedError()
def send(self):
subject = self._get_subject()
body = self._get_body()
sender = self._get_sender()
recipients = self._get_recipients()
email = EmailMessage(subject=subject, body=body, from_email=sender, to=recipients)
logger.info(u'Send %s to %s', self.__class__.__name__, recipients)
email.send()

View File

View File

View File

@@ -0,0 +1,18 @@
from django.conf import settings
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Disable a modular app from django-dav installation.'
def add_arguments(self, parser):
parser.add_argument('module')
def handle(self, *args, **options):
module_name = options['module']
config = settings.MODULE_CONFIG
del config.modules[module_name]
config.save()
self.stdout.write(self.style.SUCCESS('Module \'{}\' disabled.'.format(module_name)))

View File

@@ -0,0 +1,37 @@
import os
import pkg_resources
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from dav_base.config.modules import DJANGO_MAIN_MODULE, ModuleMeta
class Command(BaseCommand):
help = 'Enable a modular app in django-dav installation.'
def add_arguments(self, parser):
parser.add_argument('module', help='the name of the module')
def handle(self, *args, **options):
django_base_dir = settings.BASE_DIR
django_main_module = DJANGO_MAIN_MODULE
module_name = options['module']
config = settings.MODULE_CONFIG
if module_name in config.modules.keys():
raise CommandError('Module \'{}\' is already enabled'.format(module_name))
settings_file_name = 'settings-{}.py'.format(module_name)
input_file = os.path.join('django_project_config', settings_file_name)
if pkg_resources.resource_exists(module_name, input_file):
output_file = os.path.join(django_base_dir, django_main_module, settings_file_name)
if not os.path.exists(output_file):
with open(output_file, 'w') as f:
f.write(pkg_resources.resource_string(module_name, input_file))
module_meta_obj = ModuleMeta(module_name)
config.modules[module_name] = module_meta_obj
config.save()
self.stdout.write(self.style.SUCCESS('Module \'{}\' enabled.'.format(module_name)))

View File

@@ -0,0 +1,17 @@
from django.conf import settings
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'List enabled modular apps in django-dav installation.'
def add_arguments(self, parser):
pass
def handle(self, *args, **options):
paragraphs = []
config = settings.MODULE_CONFIG
for obj in config.modules.values():
paragraphs.append(str(obj))
output = '\n'.join(paragraphs)
self.stdout.write(output)

View File

View File

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,4 +1,4 @@
{% extends "error_base.html" %}
{% extends "dav_base/error_base.html" %}
{% block error-code %}400{% endblock %}
{% block error-title %}Bad Request{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "error_base.html" %}
{% extends "dav_base/error_base.html" %}
{% block error-code %}403{% endblock %}
{% block error-title %}Forbidden{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "error_base.html" %}
{% extends "dav_base/error_base.html" %}
{% block error-code %}404{% endblock %}
{% block error-title %}Not Found{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "error_base.html" %}
{% extends "dav_base/error_base.html" %}
{% block error-code %}500{% endblock %}
{% block error-title %}Internal Server Error{% endblock %}

View File

@@ -0,0 +1,72 @@
<!DOCTYPE html>
{% load static %}
{% load i18n %}
{% load bootstrap3 %}
{% load dav_base %}
<html lang="{{ LANGUAGE_CODE|default:'de' }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% block head-media %}
<link type="image/x-icon" href="{% static 'dav_base/img/dav-favicon.ico' %}" rel="shortcut icon" />
<link type="text/css" href="{% static 'dav_base/bootstrap/css/bootstrap.min.css' %}" rel="stylesheet" />
<link type="text/css" href="{% static 'dav_base/css/dataTables.bootstrap.min.css' %}" rel="stylesheet" />
<link type="text/css" href="{% static 'dav_base/css/local.css' %}" rel="stylesheet" />
<script type="text/javascript" src="{% static 'dav_base/js/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'dav_base/js/jquery.dataTables.min.js' %}"></script>
<script type="text/javascript" src="{% static 'dav_base/bootstrap/js/bootstrap.min.js' %}"></script>
{{ form.media }}
{% endblock head-media %}
{% block head-additional %}
{% endblock head-additional %}
<title>
{% block head-title %}Alpenverein Karlsruhe{% endblock head-title %}
</title>
</head>
<body>
<div id="page">
<div id="page-header">
<h2>
<a href="{% url 'root' %}">
<img width="217" height="30" src="{% static 'dav_base/img/brand.png' %}" />{% block project-name %}{% include_if_exist 'project_name.html' %}{% endblock project-name %}
</a>
</h2>
<div id="login-widget">{% include_if_exist 'dav_auth/includes/login_widget.html' %}</div>
</div>
<div id="messages">
{% block messages %}
<div class="container-fluid">
{% bootstrap_messages %}
</div>
{% endblock messages %}
</div>
<div id="page-body">
{% block modals %}
{% endblock modals %}
{% block page-body %}
<div class="container-fluid">
{% block page-container-fluid %}
{% endblock page-container-fluid %}
</div>
<div class="container">
{% block page-container %}
{% endblock page-container %}
</div>
{% endblock page-body %}
</div>
<div id="page-footer">
<div class="signum">{% block signum %}<a href="mailto:heinzel@alpenverein-karlsruhe.de">heinzel@alpenverein-karlsruhe.de</a>{% endblock signum %}</div>
<a href="http://alpenverein-karlsruhe.de" target="_blank">&copy; Sektion Karlsruhe im Deutschen Alpenverein (DAV) e.V.</a> &ensp;&bull;&ensp;
<a href="http://alpenverein-karlsruhe.de/impressum">{% trans 'Impressum' %}</a>
</div>
</div>
</body>
</html>

View File

@@ -1,4 +1,4 @@
{% extends "dav_events/base.html" %}
{% extends "dav_base/base.html" %}
{% load bootstrap3 %}
{% block head-title %}{% block error-code %}{% endblock %} {% block error-title %}Error{% endblock %} - {{ block.super }}{% endblock head-title %}

View File

@@ -0,0 +1,27 @@
{% extends "dav_base/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
{% block page-container %}
<div class="jumbotron">
<h1>Hallo,</h1>
<p>
du bist auf dem Entwicklungs- und Testserver der
<a href="http://alpenverein-karlsruhe.de">Sektion Karlsruhe des Deutschen Alpenvereins (DAV) e.V.</a> gelandet.
</p>
<p>
Wenn du Fragen hast, kannst du dich an
<a href="mailto:heinzel@alpenverein-karlsruhe.de">heinzel@alpenverein-karlsruhe.de</a> wenden.
</p>
<p>&nbsp;</p>
{% if root_urls %}
<h3>Module:</h3>
<div class="list-group">
{% for root_url in root_urls %}
<a class="list-group-item list-group-item-warning"
href="{% url root_url.1 %}"><span class="glyphicon glyphicon-arrow-right"></span> {{ root_url.0 }}</a>
{% endfor %}
</div>
{% endif %}
</div>
{% endblock page-container %}

View File

View File

View File

@@ -0,0 +1,53 @@
from django import template
register = template.Library()
@register.tag('include_if_exist')
def do_include_if_exist(parser, token):
"""
Used to include a template, that maybe does not exist.
include_if_exist support an optional keyword 'default', which must be followed by the name of a default template.
The default template will be included, if the first template does not exist.
If also the default template does not exist, the behaviour is the same as for the original (builtin) include tag.
If no default template is given and the first template does not exist an empty string will be returned.
"""
bits = token.split_contents()
if len(bits) < 2:
raise template.TemplateSyntaxError("%r tag takes at least two arguments:"
" the name of the template to be included" % bits[0])
try:
pos = bits.index('default')
del bits[pos]
default_template = bits[pos]
del bits[pos]
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)
except ValueError:
default_node = template.defaulttags.CommentNode()
except IndexError:
raise template.TemplateSyntaxError("'default' keyword in %r tag requires another arguments:"
" the name of the default template" % bits[0])
try:
include_node = template.loader_tags.do_include(parser, token)
except template.TemplateDoesNotExist:
return default_node
orig_render = include_node.render
orig_template = include_node.template
def wrapped_render(context, *args, **kwargs):
try:
t = orig_template.resolve(context)
if not callable(getattr(t, 'render', None)):
t = context.template.engine.find_template(t)
return orig_render(context, *args, **kwargs)
except template.TemplateDoesNotExist:
return default_node.render(context, *args, **kwargs)
include_node.render = wrapped_render
return include_node

9
dav_base/urls.py Normal file
View File

@@ -0,0 +1,9 @@
from django.conf.urls import url
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^$', views.RootView.as_view(), name='root'),
url(r'^djangoadmin/', admin.site.urls),
]

23
dav_base/views.py Normal file
View File

@@ -0,0 +1,23 @@
from django.conf import settings
from django.urls import reverse, NoReverseMatch
from django.views import generic
class RootView(generic.TemplateView):
template_name = 'dav_base/root.html'
def get_context_data(self, **kwargs):
c = super(RootView, self).get_context_data(**kwargs)
root_urls = []
for module_meta_obj in settings.MODULE_CONFIG.modules.values():
root_url_name = 'root'
if module_meta_obj.url_namespace:
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))
except NoReverseMatch:
pass
c['root_urls'] = root_urls
return c

View File

@@ -1,13 +1,11 @@
from django.core.exceptions import ImproperlyConfigured
from dav_base.config.apps import AppConfig as _AppConfig, DefaultSetting
from . import signals
from .config import AppConfig as _AppConfig, DefaultSetting
DEFAULT_SETTINGS = (
DefaultSetting('enable_email_notifications', False),
DefaultSetting('email_sender', None),
DefaultSetting('email_base_url', None),
DefaultSetting('email_subject_prefix', ''),
DefaultSetting('group_manage_all', None),
DefaultSetting('group_manage_w', None),
DefaultSetting('group_manage_s', None),

View File

@@ -1,8 +1,5 @@
import importlib
import logging
import re
from django.apps import AppConfig as _AppConfig
from django.core.exceptions import ImproperlyConfigured
logger = logging.getLogger(__name__)
@@ -84,67 +81,3 @@ class FieldInitial(object):
return result
return None
class DefaultSetting(object):
def __init__(self, name, value, key_name=None, validator=None):
self.name = name
self.value = value
if key_name is None:
self.key_name = self.name.upper()
else:
self.key_name = key_name
self.validator = validator
def validate(self, value):
if hasattr(self, 'validator') and self.validator is not None:
if callable(self.validator):
if not self.validator(value):
raise ImproperlyConfigured("Validator callback {clb} returned False".format(clb=self.validator))
else:
if not re.search(self.validator, value):
raise ImproperlyConfigured("Does not match /{re}/".format(re=self.validator))
class AppSettings(object):
def __init__(self, app_name, defaults):
settings_name = 'main.settings-' + app_name
try:
settings_module = importlib.import_module(settings_name)
except ImportError:
settings_module = None
for default in defaults:
if hasattr(settings_module, default.key_name):
value = getattr(settings_module, default.key_name)
try:
default.validate(value)
except ImproperlyConfigured as e:
msg = 'Invalid value of {key} in {module}: {cause}'.format(key=default.key_name,
module=settings_name,
cause=e.message)
raise ImproperlyConfigured(msg)
setattr(self, default.name, value)
elif isinstance(default.value, ImproperlyConfigured):
raise default.value
else:
try:
is_impconf = issubclass(default.value, ImproperlyConfigured)
except TypeError:
is_impconf = False
if is_impconf:
msg = '{key} must be defined in {module}'.format(key=default.key_name,
module=settings_name)
raise default.value(msg)
else:
setattr(self, default.name, default.value)
class AppConfig(_AppConfig):
default_settings = ()
def __init__(self, app_name, app_module):
super(AppConfig, self).__init__(app_name, app_module)
self.settings = AppSettings(app_name, self.default_settings)

View File

@@ -1,7 +0,0 @@
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^', include('dav_events.urls', namespace='dav_events')),
url(r'^admin/', admin.site.urls),
]

View File

@@ -4,9 +4,6 @@ from dav_events.config import FieldInitial
# E-Mails
ENABLE_EMAIL_NOTIFICATIONS = False
EMAIL_SENDER = 'DAV Veranstaltungsheinzel <heinzel@alpenverein-karlsruhe.de>'
EMAIL_BASE_URL = 'http://localhost:8000'
EMAIL_SUBJECT_PREFIX = u'[DAV Veranstaltungen]'
# Authorization Roles / Groups
GROUP_MANAGE_ALL = 'Tourenreferenten'

View File

@@ -1,61 +1,5 @@
# -*- coding: utf-8 -*-
import logging
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
from django.core.mail import EmailMessage
from django.template.loader import get_template
logger = logging.getLogger(__name__)
class AbstractMail(object):
_subject = u''
_template_name = None
def _get_sender(self):
app_config = apps.get_containing_app_config(__package__)
return app_config.settings.email_sender
def _get_subject(self, subject_fmt=None, **kwargs):
if subject_fmt is None:
subject_fmt = self._subject
app_config = apps.get_containing_app_config(__package__)
if app_config.settings.email_subject_prefix:
subject_fmt = u'%s %s' % (app_config.settings.email_subject_prefix, subject_fmt)
subject = subject_fmt.format(**kwargs)
return subject
def _get_template(self):
if not self._template_name:
raise ImproperlyConfigured('%s._template_name ist not set.', self.__class__.__name__)
return get_template(self._template_name, using='PLAINTEXT')
def _get_context_data(self, extra_context=None):
app_config = apps.get_containing_app_config(__package__)
context = {
'base_url': app_config.settings.email_base_url,
}
if extra_context:
context.update(extra_context)
return context
def _get_body(self, context=None):
template = self._get_template()
context = self._get_context_data(extra_context=context)
return template.render(context)
def _get_recipients(self):
raise NotImplementedError()
def send(self):
subject = self._get_subject()
body = self._get_body()
sender = self._get_sender()
recipients = self._get_recipients()
emo = EmailMessage(subject=subject, body=body, from_email=sender, to=recipients)
logger.info(u'Send %s to %s', self.__class__.__name__, recipients)
emo.send()
from dav_base.emails import AbstractMail
class AbstractEventMail(AbstractMail):
@@ -149,26 +93,3 @@ class EventToPublishMail(AbstractEventMail):
context['editor'] = self._editor
context['confirm_publication_url'] = self._confirm_publication_action.get_absolute_url()
return context
class PasswordSetEmail(AbstractMail):
_subject = u'Zugangsdaten'
_template_name = 'dav_events/emails/password_set.txt'
def __init__(self, user, password):
self._user = user
self._password = password
def _get_recipients(self):
r = u'{fullname} <{email}>'.format(fullname=self._user.get_full_name(),
email=self._user.email)
return [r]
def _get_context_data(self, extra_context=None):
context = super(PasswordSetEmail, self)._get_context_data(extra_context=extra_context)
context.update({
'fullname': self._user.get_full_name(),
'username': self._user.username,
'password': self._password
})
return context

View File

@@ -1,3 +1,2 @@
from . import generic
from . import auth
from . import events

View File

@@ -254,7 +254,7 @@ class Event(models.Model):
date=self.get_formated_date())
def get_absolute_url(self):
return reverse('dav_events:event_detail', kwargs={'pk': self.pk})
return reverse('dav_events:detail', kwargs={'pk': self.pk})
def save(self, implicit_update=False, **kwargs):
creating = False

View File

@@ -132,7 +132,7 @@ class OneClickAction(models.Model):
try:
user_id = self.parameters
user = get_user_model().objects.get(id=user_id)
url = reverse('dav_events:event_list')
url = reverse('dav_events:list')
result['location'] = url
result['login'] = user
except Exception as e:

3
dav_events/module.json Normal file
View File

@@ -0,0 +1,3 @@
{
"url_prefix": "events"
}

View File

@@ -1,71 +1,3 @@
<!DOCTYPE html>
{% load static %}
{% load i18n %}
{% load bootstrap3 %}
<html lang="{{ LANGUAGE_CODE|default:'de' }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% block head-media %}
<link type="image/x-icon" href="{% static 'dav_events/img/dav-favicon.ico' %}" rel="shortcut icon" />
<link type="text/css" href="{% static 'dav_events/bootstrap/css/bootstrap.min.css' %}" rel="stylesheet" />
<link type="text/css" href="{% static 'dav_events/css/dataTables.bootstrap.min.css' %}" rel="stylesheet" />
<link type="text/css" href="{% static 'dav_events/css/local.css' %}" rel="stylesheet" />
{% extends "dav_base/base.html" %}
<script type="text/javascript" src="{% static 'dav_events/js/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'dav_events/js/jquery.dataTables.min.js' %}"></script>
<script type="text/javascript" src="{% static 'dav_events/bootstrap/js/bootstrap.min.js' %}"></script>
{{ form.media }}
{% endblock head-media %}
{% block head-additional %}
{% endblock head-additional %}
<title>
{% block head-title %}Veranstaltungsheinzel - Alpenverein Karlsruhe{% endblock head-title %}
</title>
</head>
<body>
<div id="page">
<div id="page-header">
<h2>
<a href="{% url 'dav_events:home' %}">
<img width="217" height="30" src="{% static 'dav_events/img/brand.png' %}" />Veranstaltungsheinzel
</a>
</h2>
<div id="login-widget">{% include 'dav_events/includes/login_widget.html' %}</div>
</div>
<div id="messages">
{% block messages %}
<div class="container-fluid">
{% bootstrap_messages %}
</div>
{% endblock messages %}
</div>
<div id="page-body">
{% block modals %}
{% endblock modals %}
{% block page-body %}
<div class="container-fluid">
{% block page-container-fluid %}
{% endblock page-container-fluid %}
</div>
<div class="container">
{% block page-container %}
{% endblock page-container %}
</div>
{% endblock page-body %}
</div>
<div id="page-footer">
<div class="signum"><a href="mailto:heinzel@alpenverein-karlsruhe.de">heinzel@alpenverein-karlsruhe.de</a></div>
<a href="http://alpenverein-karlsruhe.de" target="_blank">&copy; Sektion Karlsruhe im Deutschen Alpenverein (DAV) e.V.</a> &ensp;&bull;&ensp;
<a href="http://alpenverein-karlsruhe.de/impressum">{% trans 'Impressum' %}</a>
</div>
</div>
</body>
</html>
{% block head-title %}Touren und Kurse - {{ block.super }}{% endblock %}

View File

@@ -23,7 +23,7 @@
</p>
</div>
<div class="modal-footer">
<a class="btn btn-success" href="{% url 'dav_events:event_confirmstatus' event.pk 'submitted' %}">
<a class="btn btn-success" href="{% url 'dav_events:confirmstatus' event.pk 'submitted' %}">
{% bootstrap_icon 'ok' %}&thinsp;
{% trans 'Ja, alles klar!' %}
</a>
@@ -51,7 +51,7 @@
</p>
</div>
<div class="modal-footer">
<a class="btn btn-success" href="{% url 'dav_events:event_confirmstatus' event.pk 'accepted' %}">
<a class="btn btn-success" href="{% url 'dav_events:confirmstatus' event.pk 'accepted' %}">
{% bootstrap_icon 'ok' %}&thinsp;
{% trans 'Ja, passt schon!' %}
</a>
@@ -84,7 +84,7 @@
</p>
</div>
<div class="modal-footer">
<a class="btn btn-success" href="{% if event.planned_publication_date %}{% url 'dav_events:event_confirmstatus' event.pk 'publishing' %}{% else %}{% url 'dav_events:event_confirmstatus' event.pk 'published' %}{% endif %}">
<a class="btn btn-success" href="{% if event.planned_publication_date %}{% url 'dav_events:confirmstatus' event.pk 'publishing' %}{% else %}{% url 'dav_events:confirmstatus' event.pk 'published' %}{% endif %}">
{% bootstrap_icon 'ok' %}&thinsp;
{% trans 'Ja' %}
</a>
@@ -135,7 +135,7 @@
</a>
{% endif %}
<a class="btn btn-primary"
href="{% url 'dav_events:event_create' %}?copy={{ event.pk }}"
href="{% url 'dav_events:create' %}?copy={{ event.pk }}"
title="{% trans 'Diese Veranstaltung als Vorlage für eine neue Veranstaltung benutzen' %}">
{% bootstrap_icon 'duplicate' %}&thinsp;
{% trans 'Kopieren' %}
@@ -144,15 +144,15 @@
<ul class="nav nav-tabs" role="tablist">
<li>
<a class="btn"
href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
</li>
<li class="active">
<a class="btn"
href="{% url 'dav_events:event_detail' event.pk %}">{% trans 'Details' %}</a>
href="{% url 'dav_events:detail' event.pk %}">{% trans 'Details' %}</a>
</li>
<li class="{% if not has_permission_update %}disabled{% endif %}">
<a class="btn {% if has_permission_update %}btn-warning{% else %}disabled{% endif %}"
href="{% url 'dav_events:event_update' event.pk %}">{% trans 'Ändern' %}</a>
href="{% url 'dav_events:update' event.pk %}">{% trans 'Ändern' %}</a>
</li>
</ul>
</div>

View File

@@ -6,18 +6,18 @@
<div class="action-tabs">
<div class="pull-right">
<a class="btn btn-primary"
href="{% url 'dav_events:event_create' %}">
href="{% url 'dav_events:create' %}">
{% bootstrap_icon 'plus' %}
{% trans 'Neue Veranstaltung anlegen' %}
</a>
</div>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
<a href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
</li>
<li class="{% if not has_permission_export %}disabled{% endif %}">
<a class="btn {% if not has_permission_export %}disabled{% endif %}"
href="{% url 'dav_events:event_list_export' %}">{% trans 'Veranstaltungsliste herunterladen' %}</a>
href="{% url 'dav_events:list_export' %}">{% trans 'Veranstaltungsliste herunterladen' %}</a>
</li>
</ul>
</div>
@@ -45,11 +45,11 @@
<tr>
<td data-order="{{ event.get_number|slice:':1' }}{{ event.get_number|slice:'-2:' }}{{ event.get_number|slice:'1:-2'|cut:'/' }}"
data-search="{{ event.get_number }} ({{ event.get_sport_display }})">
<a href="{% url 'dav_events:event_detail' event.pk %}">{{ event.get_number }}</a><br />
<a href="{% url 'dav_events:detail' event.pk %}">{{ event.get_number }}</a><br />
<small>({{ event.get_sport_display }})</small>
</td>
<td>
<a href="{% url 'dav_events:event_detail' event.pk %}">{{ event.title }}</a>
<a href="{% url 'dav_events:detail' event.pk %}">{{ event.title }}</a>
</td>
<td>
{{ event.get_trainer_full_name }}

View File

@@ -6,17 +6,17 @@
<div class="action-tabs">
<div class="pull-right">
<a class="btn btn-primary"
href="{% url 'dav_events:event_create' %}">
href="{% url 'dav_events:create' %}">
{% bootstrap_icon 'plus' %}
{% trans 'Neue Veranstaltung anlegen' %}
</a>
</div>
<ul class="nav nav-tabs" role="tablist">
<li>
<a href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
<a href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
</li>
<li class="active">
<a href="{% url 'dav_events:event_list_export' %}">{% trans 'Veranstaltungsliste herunterladen' %}</a>
<a href="{% url 'dav_events:list_export' %}">{% trans 'Veranstaltungsliste herunterladen' %}</a>
</li>
</ul>
</div>
@@ -29,7 +29,7 @@
{% bootstrap_icon 'download-alt' %}&thinsp;
{% trans 'Herunterladen' %}
</button>
<a class="btn btn-danger" href="{% url 'dav_events:event_list' %}">
<a class="btn btn-danger" href="{% url 'dav_events:list' %}">
{% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %}
</a>

View File

@@ -8,13 +8,13 @@
<div class="action-tabs">
<ul class="nav nav-tabs" role="tablist">
<li>
<a href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
<a href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
</li>
<li>
<a href="{% url 'dav_events:event_detail' event.pk %}">{% trans 'Details' %}</a>
<a href="{% url 'dav_events:detail' event.pk %}">{% trans 'Details' %}</a>
</li>
<li class="active">
<a href="{% url 'dav_events:event_update' event.pk %}">{% trans 'Ändern' %}</a>
<a href="{% url 'dav_events:update' event.pk %}">{% trans 'Ändern' %}</a>
</li>
</ul>
</div>
@@ -50,7 +50,7 @@
{% bootstrap_icon 'hdd' %}&thinsp;
{% trans 'Speichern' %}
</button>
<a class="btn btn-danger" href="{% url 'dav_events:event_detail' event.pk %}">
<a class="btn btn-danger" href="{% url 'dav_events:detail' event.pk %}">
{% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %}
</a>

View File

@@ -18,7 +18,7 @@
Du wirst dann per E-Mail auf dem laufenden gehalten.
</p>
<p>
<a class="btn btn-primary" href="{% url 'dav_events:event_create' %}">Los geht's!</a>
<a class="btn btn-primary" href="{% url 'dav_events:create' %}">Los geht's!</a>
</p>
</div>
<div class="well">
@@ -30,7 +30,7 @@
Tourenreferenten und Redakteure können hier Veranstaltungen freigeben und Programmlisten herunterladen.
</p>
<p>
<a class="btn btn-primary" href="{% url 'dav_events:event_list' %}">Weiter</a>
<a class="btn btn-primary" href="{% url 'dav_events:list' %}">Weiter</a>
</p>
</div>
{% endblock page-container-fluid %}

View File

@@ -3,18 +3,14 @@ from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.base.HomeView.as_view(), name='home'),
url(r'^user/login$', views.auth.LoginView.as_view(), name='login'),
url(r'^user/logout$', views.auth.LogoutView.as_view(), name='logout'),
url(r'^user/password$', views.auth.SetPasswordView.as_view(), name='set_password'),
url(r'^user/password/reset$', views.auth.ResetPasswordView.as_view(), name='reset_password'),
url(r'^events$', views.events.EventListView.as_view(), name='event_list'),
url(r'^events/export$', views.events.EventListExportView.as_view(), name='event_list_export'),
url(r'^events/create$', views.events.EventCreateView.as_view(), name='event_create'),
url(r'^events/(?P<pk>\d+)/confirm/(?P<status>[a-z0-9][a-z0-9]*)',
views.events.EventConfirmStatusView.as_view(), name='event_confirmstatus'),
url(r'^events/(?P<pk>\d+)/edit', views.events.EventUpdateView.as_view(), name='event_update'),
url(r'^events/(?P<pk>\d+)/', views.events.EventDetailView.as_view(), name='event_detail'),
url(r'^home$', views.base.HomeView.as_view(), name='root'),
url(r'^$', views.events.EventListView.as_view(), name='list'),
url(r'^export$', views.events.EventListExportView.as_view(), name='list_export'),
url(r'^create$', views.events.EventCreateView.as_view(), name='create'),
url(r'^(?P<pk>\d+)/confirm/(?P<status>[a-z0-9][a-z0-9]*)',
views.events.EventConfirmStatusView.as_view(), name='confirmstatus'),
url(r'^(?P<pk>\d+)/edit', views.events.EventUpdateView.as_view(), name='update'),
url(r'^(?P<pk>\d+)/', views.events.EventDetailView.as_view(), name='detail'),
url(r'^action/(?P<pk>[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})/',
views.actions.OneClickActionRunView.as_view(), name='action_run'),
]

View File

@@ -1,4 +1,3 @@
from . import base
from . import auth
from . import events
from . import actions

View File

@@ -20,7 +20,6 @@ from .. import models
from ..utils import has_role
from ..workflow import workflow
app_config = apps.get_containing_app_config(__package__)
logger = logging.getLogger(__name__)
@@ -259,7 +258,7 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
form_class = forms.events.EventCreateForm
template_dir = os.path.join('dav_events', 'event_create')
default_template_name = 'default.html'
abort_url = reverse_lazy('dav_events:home')
abort_url = reverse_lazy('dav_events:root')
def get_template_names(self):
form = self.get_form()
@@ -317,7 +316,7 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
owner = event.owner
self.clean_session_data()
if self.request.user.is_authenticated:
next_url = reverse('dav_events:event_list')
next_url = reverse('dav_events:list')
if self.request.user != event.owner:
messages.warning(self.request,
u'%s %s' % (
@@ -325,10 +324,10 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
_(u'Warum machst du sowas?')
))
elif owner.has_usable_password():
next_url = reverse('dav_events:event_list')
next_url = reverse('dav_events:list')
else:
login(self.request, owner)
next_url = reverse('dav_events:set_password')
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!'))

View File

@@ -4,6 +4,7 @@ from django.apps import apps
from django.utils import timezone
from . import emails
from .utils import get_users_by_role
logger = logging.getLogger(__name__)
@@ -143,7 +144,6 @@ class BasicWorkflow(object):
recipients = [event.owner]
if event.is_flagged('submitted'):
# If the event is already submitted, add managers to the recipients.
from .utils import get_users_by_role
recipients += get_users_by_role('manage_all')
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
if event.is_flagged('accepted'):
@@ -174,7 +174,6 @@ class BasicWorkflow(object):
# Inform managers that they have to accept the event.
# Also create OneClickActions for all of them and add the link to the mail,
# so they can accept the event with a click into the mail.
from .utils import get_users_by_role
recipients = get_users_by_role('manage_all')
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
OneClickAction = app_config.get_model('OneClickAction')
@@ -195,7 +194,6 @@ class BasicWorkflow(object):
# Inform publishers that they have to publish the event.
# Also create OneClickActions for all of them and add the link to the mail,
# so they can confirm the publication with a click into the mail.
from .utils import get_users_by_role
recipients = get_users_by_role('publish_incremental')
OneClickAction = app_config.get_model('OneClickAction')
for recipient in recipients:

View File

@@ -45,7 +45,7 @@ if sys.version_info.major != 2:
setup(
name='django-dav-events',
version='0.2',
version='1.0',
description='A django based web application project to submit DAV Events.',
url='https://www.heinzelwelt.de',
maintainer='Jens Kleineheismann',
@@ -57,7 +57,7 @@ setup(
include_package_data=True,
entry_points={
'console_scripts': [
'django-dav-events-admin = dav_events.console_scripts.admin:main',
'django-dav-admin = dav_base.console_scripts.admin:main',
],
},
install_requires=[