Refactor: split code into several django apps (we call them modules).
This commit is contained in:
1
dav_auth/__init__.py
Normal file
1
dav_auth/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
default_app_config = 'dav_auth.apps.AppConfig'
|
||||||
12
dav_auth/apps.py
Normal file
12
dav_auth/apps.py
Normal 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
|
||||||
2
dav_auth/django_project_config/settings-dav_auth.py
Normal file
2
dav_auth/django_project_config/settings-dav_auth.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# LOGIN_REDIRECT_URL = 'root'
|
||||||
|
# LOGOUT_REDIRECT_URL = 'root'
|
||||||
25
dav_auth/emails.py
Normal file
25
dav_auth/emails.py
Normal 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
3
dav_auth/module.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"url_prefix": "auth"
|
||||||
|
}
|
||||||
1
dav_auth/templates/dav_auth/base.html
Normal file
1
dav_auth/templates/dav_auth/base.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{% extends "dav_base/base.html" %}
|
||||||
@@ -3,4 +3,4 @@ Hallo {{ fullname }},
|
|||||||
Benutzername: {{ username }}
|
Benutzername: {{ username }}
|
||||||
Passwort: {{ password }}
|
Passwort: {{ password }}
|
||||||
|
|
||||||
URL: {{ base_url }}{% url 'dav_events:home' %}
|
URL: {{ base_url }}{% url 'root' %}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "dav_events/base.html" %}
|
{% extends "dav_auth/base.html" %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
@@ -15,13 +15,13 @@
|
|||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% bootstrap_form form %}
|
{% 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 %}
|
{% buttons %}
|
||||||
<button type="submit" class="btn btn-success">
|
<button type="submit" class="btn btn-success">
|
||||||
{% bootstrap_icon 'log-in' %} 
|
{% bootstrap_icon 'log-in' %} 
|
||||||
{% trans 'Login' %}
|
{% trans 'Login' %}
|
||||||
</button>
|
</button>
|
||||||
<a class="btn btn-danger" href="{% url 'dav_events:home' %}">
|
<a class="btn btn-danger" href="{% url 'root' %}">
|
||||||
{% bootstrap_icon 'remove' %} 
|
{% bootstrap_icon 'remove' %} 
|
||||||
{% trans 'Abbrechen' %}
|
{% trans 'Abbrechen' %}
|
||||||
</a>
|
</a>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "dav_events/base.html" %}
|
{% extends "dav_auth/base.html" %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
{% bootstrap_icon 'saved' %} 
|
{% bootstrap_icon 'saved' %} 
|
||||||
{% trans 'Neues Passwort per E-Mail zusenden' %}
|
{% trans 'Neues Passwort per E-Mail zusenden' %}
|
||||||
</button>
|
</button>
|
||||||
<a class="btn btn-danger" href="{% url 'dav_events:home' %}">
|
<a class="btn btn-danger" href="{% url 'root' %}">
|
||||||
{% bootstrap_icon 'remove' %} 
|
{% bootstrap_icon 'remove' %} 
|
||||||
{% trans 'Abbrechen' %}
|
{% trans 'Abbrechen' %}
|
||||||
</a>
|
</a>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "dav_events/base.html" %}
|
{% extends "dav_auth/base.html" %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
{% bootstrap_icon 'saved' %} 
|
{% bootstrap_icon 'saved' %} 
|
||||||
{% trans 'Neues Passwort setzen' %}
|
{% trans 'Neues Passwort setzen' %}
|
||||||
</button>
|
</button>
|
||||||
<a class="btn btn-danger" href="{% url 'dav_events:home' %}">
|
<a class="btn btn-danger" href="{% url 'root' %}">
|
||||||
{% bootstrap_icon 'remove' %} 
|
{% bootstrap_icon 'remove' %} 
|
||||||
{% trans 'Abbrechen' %}
|
{% trans 'Abbrechen' %}
|
||||||
</a>
|
</a>
|
||||||
@@ -7,12 +7,12 @@
|
|||||||
{{ user }} <span class="caret"></span>
|
{{ user }} <span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="user_dropdown_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_auth:set_password' %}">{% trans 'Passwort ändern' %}</a></li>
|
||||||
<li><a href="{% url 'dav_events:logout' %}">{% trans 'Logout' %}</a></li>
|
<li><a href="{% url 'dav_auth:logout' %}">{% trans 'Logout' %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% 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' %}
|
{% bootstrap_icon 'log-in' %}
|
||||||
{% trans 'Login' %}
|
{% trans 'Login' %}
|
||||||
</a>
|
</a>
|
||||||
10
dav_auth/urls.py
Normal file
10
dav_auth/urls.py
Normal 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'),
|
||||||
|
]
|
||||||
@@ -1,24 +1,28 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from django.apps import apps
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import views as auth_views, get_user_model
|
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.urls import reverse_lazy
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
|
||||||
from .. import emails
|
from . import emails
|
||||||
from .. import forms
|
from . import forms
|
||||||
|
|
||||||
|
app_config = apps.get_containing_app_config(__package__)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LoginView(auth_views.LoginView):
|
class LoginView(auth_views.LoginView):
|
||||||
form_class = forms.auth.LoginForm
|
form_class = forms.LoginForm
|
||||||
next_page = reverse_lazy('dav_events:event_list')
|
template_name = 'dav_auth/forms/login.html'
|
||||||
template_name = 'dav_events/auth/login_form.html'
|
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_redirect_url(self):
|
||||||
url = self.get_redirect_url()
|
url = super(LoginView, self).get_redirect_url()
|
||||||
return url or self.next_page
|
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):
|
def form_valid(self, form):
|
||||||
r = super(LoginView, self).form_valid(form)
|
r = super(LoginView, self).form_valid(form)
|
||||||
@@ -27,7 +31,11 @@ class LoginView(auth_views.LoginView):
|
|||||||
|
|
||||||
|
|
||||||
class LogoutView(auth_views.LogoutView):
|
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):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
r = super(LogoutView, self).dispatch(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):
|
class SetPasswordView(auth_views.PasswordChangeView):
|
||||||
form_class = forms.auth.SetPasswordForm
|
form_class = forms.SetPasswordForm
|
||||||
template_name = 'dav_events/auth/set_password_form.html'
|
template_name = 'dav_auth/forms/set_password.html'
|
||||||
success_url = reverse_lazy('dav_events:event_list')
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return resolve_url(app_config.settings.login_redirect_url)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
r = super(SetPasswordView, self).form_valid(form)
|
r = super(SetPasswordView, self).form_valid(form)
|
||||||
@@ -50,9 +60,9 @@ class SetPasswordView(auth_views.PasswordChangeView):
|
|||||||
|
|
||||||
|
|
||||||
class ResetPasswordView(generic.FormView):
|
class ResetPasswordView(generic.FormView):
|
||||||
form_class = forms.auth.ResetPasswordForm
|
form_class = forms.ResetPasswordForm
|
||||||
template_name = 'dav_events/auth/reset_password_form.html'
|
template_name = 'dav_auth/forms/reset_password.html'
|
||||||
success_url = reverse_lazy('dav_events:login')
|
success_url = reverse_lazy('dav_auth:login')
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
username = form.cleaned_data.get('username')
|
username = form.cleaned_data.get('username')
|
||||||
1
dav_base/__init__.py
Normal file
1
dav_base/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
default_app_config = 'dav_base.apps.AppConfig'
|
||||||
13
dav_base/apps.py
Normal file
13
dav_base/apps.py
Normal 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
|
||||||
2
dav_base/config/__init__.py
Normal file
2
dav_base/config/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import apps
|
||||||
|
from . import modules
|
||||||
71
dav_base/config/apps.py
Normal file
71
dav_base/config/apps.py
Normal 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
132
dav_base/config/modules.py
Normal 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)
|
||||||
0
dav_base/console_scripts/__init__.py
Normal file
0
dav_base/console_scripts/__init__.py
Normal file
@@ -4,13 +4,15 @@ import pkg_resources
|
|||||||
import posix
|
import posix
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dav_base.config.modules import DJANGO_MAIN_MODULE, ModuleConfig
|
||||||
|
|
||||||
VERSION = '0.1'
|
VERSION = '0.1'
|
||||||
|
|
||||||
|
|
||||||
class AdminCommand(object):
|
class AdminCommand(object):
|
||||||
def _setup_argparser(self):
|
def _setup_argparser(self):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'description': 'Tool to manage the DAV Events django project installation.',
|
'description': 'Tool to manage the DAV django project installation.',
|
||||||
'epilog': 'Off Belay.',
|
'epilog': 'Off Belay.',
|
||||||
}
|
}
|
||||||
parser = argparse.ArgumentParser(**kwargs)
|
parser = argparse.ArgumentParser(**kwargs)
|
||||||
@@ -36,30 +38,31 @@ class AdminCommand(object):
|
|||||||
return self._argparser.parse_args(argv)
|
return self._argparser.parse_args(argv)
|
||||||
|
|
||||||
def _subcmd_setup(self, cmd_args):
|
def _subcmd_setup(self, cmd_args):
|
||||||
django_project_name = 'main'
|
django_main_module = DJANGO_MAIN_MODULE
|
||||||
django_project_path = cmd_args.path
|
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 os.path.exists(django_base_dir):
|
||||||
if not os.path.isdir(django_project_path):
|
if not os.path.isdir(django_base_dir):
|
||||||
sys.stderr.write('{path}: Not a directory.\n'.format(path=django_project_path))
|
sys.stderr.write('{path}: Not a directory.\n'.format(path=django_base_dir))
|
||||||
return posix.EX_USAGE
|
return posix.EX_USAGE
|
||||||
else:
|
else:
|
||||||
os.makedirs(django_project_path)
|
os.makedirs(django_base_dir)
|
||||||
|
|
||||||
sys.stdout.write('Creating django project...\n')
|
sys.stdout.write('Creating django project...\n')
|
||||||
django_cmd = 'django-admin startproject {name} "{path}"'.format(name=django_project_name,
|
django_cmd = 'django-admin startproject {name} "{path}"'.format(name=django_main_module,
|
||||||
path=django_project_path)
|
path=django_base_dir)
|
||||||
exitval = os.system(django_cmd)
|
exitval = os.system(django_cmd)
|
||||||
if exitval != posix.EX_OK:
|
if exitval != posix.EX_OK:
|
||||||
return exitval
|
return exitval
|
||||||
|
|
||||||
sys.stdout.write('Creating directories...\n')
|
sys.stdout.write('Creating directories...\n')
|
||||||
dirs = [
|
dirs = [
|
||||||
os.path.join(django_project_path, 'var', 'db'),
|
os.path.join(django_base_dir, 'common', 'templates'),
|
||||||
os.path.join(django_project_path, 'var', 'log'),
|
os.path.join(django_base_dir, 'var', 'db'),
|
||||||
os.path.join(django_project_path, 'var', 'www', 'static'),
|
os.path.join(django_base_dir, 'var', 'log'),
|
||||||
|
os.path.join(django_base_dir, 'var', 'www', 'static'),
|
||||||
]
|
]
|
||||||
|
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
@@ -68,18 +71,21 @@ class AdminCommand(object):
|
|||||||
|
|
||||||
sys.stdout.write('Configure django project...\n')
|
sys.stdout.write('Configure django project...\n')
|
||||||
|
|
||||||
input_file = os.path.join('Resources', 'django.main.additional_settings.py')
|
config = ModuleConfig(django_base_dir=django_base_dir)
|
||||||
output_file = os.path.join(django_project_path, django_project_name, 'settings.py')
|
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:
|
with open(output_file, 'a') as f:
|
||||||
f.write(pkg_resources.resource_string(__package__, input_file))
|
f.write(pkg_resources.resource_string(__package__, input_file))
|
||||||
|
|
||||||
input_file = os.path.join('Resources', 'django.main.urls.py')
|
input_file = os.path.join('django_project_config', 'urls.py')
|
||||||
output_file = os.path.join(django_project_path, django_project_name, 'urls.py')
|
output_file = os.path.join(django_base_dir, django_main_module, 'urls.py')
|
||||||
with open(output_file, 'w') as f:
|
with open(output_file, 'w') as f:
|
||||||
f.write(pkg_resources.resource_string(__package__, input_file))
|
f.write(pkg_resources.resource_string(__package__, input_file))
|
||||||
|
|
||||||
input_file = os.path.join('Resources', 'django.main.settings-dav_events.py')
|
input_file = os.path.join('django_project_config', 'settings-dav_base.py')
|
||||||
output_file = os.path.join(django_project_path, django_project_name, 'settings-dav_events.py')
|
output_file = os.path.join(django_base_dir, django_main_module, 'settings-dav_base.py')
|
||||||
with open(output_file, 'w') as f:
|
with open(output_file, 'w') as f:
|
||||||
f.write(pkg_resources.resource_string(__package__, input_file))
|
f.write(pkg_resources.resource_string(__package__, input_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_VAR_DIR = os.path.join(BASE_DIR, 'var')
|
||||||
BASE_SHARE_DIR = os.path.join(BASE_DIR, 'common')
|
BASE_SHARE_DIR = os.path.join(BASE_DIR, 'common')
|
||||||
|
|
||||||
|
# Get modules config
|
||||||
|
from dav_base.config.modules import ModuleConfig
|
||||||
|
MODULE_CONFIG = ModuleConfig()
|
||||||
|
|
||||||
INSTALLED_APPS += [
|
INSTALLED_APPS += [
|
||||||
'bootstrap3',
|
'bootstrap3',
|
||||||
'datetimewidget',
|
'datetimewidget',
|
||||||
'django_countries',
|
'django_countries',
|
||||||
'django_extensions',
|
'django_extensions',
|
||||||
# Our main app
|
# 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 += [
|
TEMPLATES += [
|
||||||
{
|
{
|
||||||
'NAME': 'PLAINTEXT',
|
'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'] = {
|
DATABASES['default'] = {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': os.path.join(BASE_VAR_DIR, 'db', 'devel.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'
|
LANGUAGE_CODE = 'de'
|
||||||
|
|
||||||
LOGIN_URL = 'dav_events:login'
|
LOGIN_URL = 'dav_auth:login'
|
||||||
|
|
||||||
BOOTSTRAP3 = {
|
BOOTSTRAP3 = {
|
||||||
'set_placeholder': False,
|
'set_placeholder': False,
|
||||||
@@ -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]'
|
||||||
12
dav_base/console_scripts/django_project_config/urls.py
Normal file
12
dav_base/console_scripts/django_project_config/urls.py
Normal 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
59
dav_base/emails.py
Normal 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()
|
||||||
0
dav_base/management/__init__.py
Normal file
0
dav_base/management/__init__.py
Normal file
0
dav_base/management/commands/__init__.py
Normal file
0
dav_base/management/commands/__init__.py
Normal file
18
dav_base/management/commands/disable_module.py
Normal file
18
dav_base/management/commands/disable_module.py
Normal 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)))
|
||||||
37
dav_base/management/commands/enable_module.py
Normal file
37
dav_base/management/commands/enable_module.py
Normal 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)))
|
||||||
17
dav_base/management/commands/list_modules.py
Normal file
17
dav_base/management/commands/list_modules.py
Normal 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)
|
||||||
0
dav_base/migrations/__init__.py
Normal file
0
dav_base/migrations/__init__.py
Normal file
0
dav_base/models/__init__.py
Normal file
0
dav_base/models/__init__.py
Normal file
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
@@ -1,4 +1,4 @@
|
|||||||
{% extends "error_base.html" %}
|
{% extends "dav_base/error_base.html" %}
|
||||||
|
|
||||||
{% block error-code %}400{% endblock %}
|
{% block error-code %}400{% endblock %}
|
||||||
{% block error-title %}Bad Request{% endblock %}
|
{% block error-title %}Bad Request{% endblock %}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "error_base.html" %}
|
{% extends "dav_base/error_base.html" %}
|
||||||
|
|
||||||
{% block error-code %}403{% endblock %}
|
{% block error-code %}403{% endblock %}
|
||||||
{% block error-title %}Forbidden{% endblock %}
|
{% block error-title %}Forbidden{% endblock %}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "error_base.html" %}
|
{% extends "dav_base/error_base.html" %}
|
||||||
|
|
||||||
{% block error-code %}404{% endblock %}
|
{% block error-code %}404{% endblock %}
|
||||||
{% block error-title %}Not Found{% endblock %}
|
{% block error-title %}Not Found{% endblock %}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "error_base.html" %}
|
{% extends "dav_base/error_base.html" %}
|
||||||
|
|
||||||
{% block error-code %}500{% endblock %}
|
{% block error-code %}500{% endblock %}
|
||||||
{% block error-title %}Internal Server Error{% endblock %}
|
{% block error-title %}Internal Server Error{% endblock %}
|
||||||
72
dav_base/templates/dav_base/base.html
Normal file
72
dav_base/templates/dav_base/base.html
Normal 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">© Sektion Karlsruhe im Deutschen Alpenverein (DAV) e.V.</a>  • 
|
||||||
|
<a href="http://alpenverein-karlsruhe.de/impressum">{% trans 'Impressum' %}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "dav_events/base.html" %}
|
{% extends "dav_base/base.html" %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
{% block head-title %}{% block error-code %}{% endblock %} {% block error-title %}Error{% endblock %} - {{ block.super }}{% endblock head-title %}
|
{% block head-title %}{% block error-code %}{% endblock %} {% block error-title %}Error{% endblock %} - {{ block.super }}{% endblock head-title %}
|
||||||
27
dav_base/templates/dav_base/root.html
Normal file
27
dav_base/templates/dav_base/root.html
Normal 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> </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 %}
|
||||||
0
dav_base/templates/project_name.html
Normal file
0
dav_base/templates/project_name.html
Normal file
0
dav_base/templatetags/__init__.py
Normal file
0
dav_base/templatetags/__init__.py
Normal file
53
dav_base/templatetags/dav_base.py
Normal file
53
dav_base/templatetags/dav_base.py
Normal 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
9
dav_base/urls.py
Normal 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
23
dav_base/views.py
Normal 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
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
|
from dav_base.config.apps import AppConfig as _AppConfig, DefaultSetting
|
||||||
|
|
||||||
from . import signals
|
from . import signals
|
||||||
from .config import AppConfig as _AppConfig, DefaultSetting
|
|
||||||
|
|
||||||
DEFAULT_SETTINGS = (
|
DEFAULT_SETTINGS = (
|
||||||
DefaultSetting('enable_email_notifications', False),
|
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_all', None),
|
||||||
DefaultSetting('group_manage_w', None),
|
DefaultSetting('group_manage_w', None),
|
||||||
DefaultSetting('group_manage_s', None),
|
DefaultSetting('group_manage_s', None),
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import importlib
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from django.apps import AppConfig as _AppConfig
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -84,67 +81,3 @@ class FieldInitial(object):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
return None
|
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)
|
|
||||||
|
|||||||
@@ -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),
|
|
||||||
]
|
|
||||||
@@ -4,9 +4,6 @@ from dav_events.config import FieldInitial
|
|||||||
|
|
||||||
# E-Mails
|
# E-Mails
|
||||||
ENABLE_EMAIL_NOTIFICATIONS = False
|
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
|
# Authorization Roles / Groups
|
||||||
GROUP_MANAGE_ALL = 'Tourenreferenten'
|
GROUP_MANAGE_ALL = 'Tourenreferenten'
|
||||||
@@ -1,61 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import logging
|
from dav_base.emails import AbstractMail
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractEventMail(AbstractMail):
|
class AbstractEventMail(AbstractMail):
|
||||||
@@ -149,26 +93,3 @@ class EventToPublishMail(AbstractEventMail):
|
|||||||
context['editor'] = self._editor
|
context['editor'] = self._editor
|
||||||
context['confirm_publication_url'] = self._confirm_publication_action.get_absolute_url()
|
context['confirm_publication_url'] = self._confirm_publication_action.get_absolute_url()
|
||||||
return context
|
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
|
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
from . import generic
|
from . import generic
|
||||||
from . import auth
|
|
||||||
from . import events
|
from . import events
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ class Event(models.Model):
|
|||||||
date=self.get_formated_date())
|
date=self.get_formated_date())
|
||||||
|
|
||||||
def get_absolute_url(self):
|
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):
|
def save(self, implicit_update=False, **kwargs):
|
||||||
creating = False
|
creating = False
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class OneClickAction(models.Model):
|
|||||||
try:
|
try:
|
||||||
user_id = self.parameters
|
user_id = self.parameters
|
||||||
user = get_user_model().objects.get(id=user_id)
|
user = get_user_model().objects.get(id=user_id)
|
||||||
url = reverse('dav_events:event_list')
|
url = reverse('dav_events:list')
|
||||||
result['location'] = url
|
result['location'] = url
|
||||||
result['login'] = user
|
result['login'] = user
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
3
dav_events/module.json
Normal file
3
dav_events/module.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"url_prefix": "events"
|
||||||
|
}
|
||||||
@@ -1,71 +1,3 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "dav_base/base.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 %}
|
{% block head-title %}Touren und Kurse - {{ block.super }}{% endblock %}
|
||||||
<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" />
|
|
||||||
|
|
||||||
<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">© Sektion Karlsruhe im Deutschen Alpenverein (DAV) e.V.</a>  • 
|
|
||||||
<a href="http://alpenverein-karlsruhe.de/impressum">{% trans 'Impressum' %}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<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' %} 
|
{% bootstrap_icon 'ok' %} 
|
||||||
{% trans 'Ja, alles klar!' %}
|
{% trans 'Ja, alles klar!' %}
|
||||||
</a>
|
</a>
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<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' %} 
|
{% bootstrap_icon 'ok' %} 
|
||||||
{% trans 'Ja, passt schon!' %}
|
{% trans 'Ja, passt schon!' %}
|
||||||
</a>
|
</a>
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<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' %} 
|
{% bootstrap_icon 'ok' %} 
|
||||||
{% trans 'Ja' %}
|
{% trans 'Ja' %}
|
||||||
</a>
|
</a>
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="btn btn-primary"
|
<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' %}">
|
title="{% trans 'Diese Veranstaltung als Vorlage für eine neue Veranstaltung benutzen' %}">
|
||||||
{% bootstrap_icon 'duplicate' %} 
|
{% bootstrap_icon 'duplicate' %} 
|
||||||
{% trans 'Kopieren' %}
|
{% trans 'Kopieren' %}
|
||||||
@@ -144,15 +144,15 @@
|
|||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li>
|
<li>
|
||||||
<a class="btn"
|
<a class="btn"
|
||||||
href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a class="btn"
|
<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>
|
||||||
<li class="{% if not has_permission_update %}disabled{% endif %}">
|
<li class="{% if not has_permission_update %}disabled{% endif %}">
|
||||||
<a class="btn {% if has_permission_update %}btn-warning{% else %}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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,18 +6,18 @@
|
|||||||
<div class="action-tabs">
|
<div class="action-tabs">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a class="btn btn-primary"
|
<a class="btn btn-primary"
|
||||||
href="{% url 'dav_events:event_create' %}">
|
href="{% url 'dav_events:create' %}">
|
||||||
{% bootstrap_icon 'plus' %}
|
{% bootstrap_icon 'plus' %}
|
||||||
{% trans 'Neue Veranstaltung anlegen' %}
|
{% trans 'Neue Veranstaltung anlegen' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
<a href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{% if not has_permission_export %}disabled{% endif %}">
|
<li class="{% if not has_permission_export %}disabled{% endif %}">
|
||||||
<a class="btn {% 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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,11 +45,11 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td data-order="{{ event.get_number|slice:':1' }}{{ event.get_number|slice:'-2:' }}{{ event.get_number|slice:'1:-2'|cut:'/' }}"
|
<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 }})">
|
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>
|
<small>({{ event.get_sport_display }})</small>
|
||||||
</td>
|
</td>
|
||||||
<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>
|
||||||
<td>
|
<td>
|
||||||
{{ event.get_trainer_full_name }}
|
{{ event.get_trainer_full_name }}
|
||||||
|
|||||||
@@ -6,17 +6,17 @@
|
|||||||
<div class="action-tabs">
|
<div class="action-tabs">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a class="btn btn-primary"
|
<a class="btn btn-primary"
|
||||||
href="{% url 'dav_events:event_create' %}">
|
href="{% url 'dav_events:create' %}">
|
||||||
{% bootstrap_icon 'plus' %}
|
{% bootstrap_icon 'plus' %}
|
||||||
{% trans 'Neue Veranstaltung anlegen' %}
|
{% trans 'Neue Veranstaltung anlegen' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
<a href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="active">
|
<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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
{% bootstrap_icon 'download-alt' %} 
|
{% bootstrap_icon 'download-alt' %} 
|
||||||
{% trans 'Herunterladen' %}
|
{% trans 'Herunterladen' %}
|
||||||
</button>
|
</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' %} 
|
{% bootstrap_icon 'remove' %} 
|
||||||
{% trans 'Abbrechen' %}
|
{% trans 'Abbrechen' %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
<div class="action-tabs">
|
<div class="action-tabs">
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'dav_events:event_list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
<a href="{% url 'dav_events:list' %}">{% trans 'Veranstaltungsliste' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<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>
|
||||||
<li class="active">
|
<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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
{% bootstrap_icon 'hdd' %} 
|
{% bootstrap_icon 'hdd' %} 
|
||||||
{% trans 'Speichern' %}
|
{% trans 'Speichern' %}
|
||||||
</button>
|
</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' %} 
|
{% bootstrap_icon 'remove' %} 
|
||||||
{% trans 'Abbrechen' %}
|
{% trans 'Abbrechen' %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
Du wirst dann per E-Mail auf dem laufenden gehalten.
|
Du wirst dann per E-Mail auf dem laufenden gehalten.
|
||||||
</p>
|
</p>
|
||||||
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="well">
|
<div class="well">
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
Tourenreferenten und Redakteure können hier Veranstaltungen freigeben und Programmlisten herunterladen.
|
Tourenreferenten und Redakteure können hier Veranstaltungen freigeben und Programmlisten herunterladen.
|
||||||
</p>
|
</p>
|
||||||
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endblock page-container-fluid %}
|
{% endblock page-container-fluid %}
|
||||||
|
|||||||
@@ -3,18 +3,14 @@ from django.conf.urls import url
|
|||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', views.base.HomeView.as_view(), name='home'),
|
url(r'^home$', views.base.HomeView.as_view(), name='root'),
|
||||||
url(r'^user/login$', views.auth.LoginView.as_view(), name='login'),
|
url(r'^$', views.events.EventListView.as_view(), name='list'),
|
||||||
url(r'^user/logout$', views.auth.LogoutView.as_view(), name='logout'),
|
url(r'^export$', views.events.EventListExportView.as_view(), name='list_export'),
|
||||||
url(r'^user/password$', views.auth.SetPasswordView.as_view(), name='set_password'),
|
url(r'^create$', views.events.EventCreateView.as_view(), name='create'),
|
||||||
url(r'^user/password/reset$', views.auth.ResetPasswordView.as_view(), name='reset_password'),
|
url(r'^(?P<pk>\d+)/confirm/(?P<status>[a-z0-9][a-z0-9]*)',
|
||||||
url(r'^events$', views.events.EventListView.as_view(), name='event_list'),
|
views.events.EventConfirmStatusView.as_view(), name='confirmstatus'),
|
||||||
url(r'^events/export$', views.events.EventListExportView.as_view(), name='event_list_export'),
|
url(r'^(?P<pk>\d+)/edit', views.events.EventUpdateView.as_view(), name='update'),
|
||||||
url(r'^events/create$', views.events.EventCreateView.as_view(), name='event_create'),
|
url(r'^(?P<pk>\d+)/', views.events.EventDetailView.as_view(), name='detail'),
|
||||||
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'^action/(?P<pk>[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})/',
|
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'),
|
views.actions.OneClickActionRunView.as_view(), name='action_run'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from . import base
|
from . import base
|
||||||
from . import auth
|
|
||||||
from . import events
|
from . import events
|
||||||
from . import actions
|
from . import actions
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ from .. import models
|
|||||||
from ..utils import has_role
|
from ..utils import has_role
|
||||||
from ..workflow import workflow
|
from ..workflow import workflow
|
||||||
|
|
||||||
app_config = apps.get_containing_app_config(__package__)
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -259,7 +258,7 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
|
|||||||
form_class = forms.events.EventCreateForm
|
form_class = forms.events.EventCreateForm
|
||||||
template_dir = os.path.join('dav_events', 'event_create')
|
template_dir = os.path.join('dav_events', 'event_create')
|
||||||
default_template_name = 'default.html'
|
default_template_name = 'default.html'
|
||||||
abort_url = reverse_lazy('dav_events:home')
|
abort_url = reverse_lazy('dav_events:root')
|
||||||
|
|
||||||
def get_template_names(self):
|
def get_template_names(self):
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
@@ -317,7 +316,7 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
|
|||||||
owner = event.owner
|
owner = event.owner
|
||||||
self.clean_session_data()
|
self.clean_session_data()
|
||||||
if self.request.user.is_authenticated:
|
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:
|
if self.request.user != event.owner:
|
||||||
messages.warning(self.request,
|
messages.warning(self.request,
|
||||||
u'%s %s' % (
|
u'%s %s' % (
|
||||||
@@ -325,10 +324,10 @@ class EventCreateView(EventPermissionMixin, generic.FormView):
|
|||||||
_(u'Warum machst du sowas?')
|
_(u'Warum machst du sowas?')
|
||||||
))
|
))
|
||||||
elif owner.has_usable_password():
|
elif owner.has_usable_password():
|
||||||
next_url = reverse('dav_events:event_list')
|
next_url = reverse('dav_events:list')
|
||||||
else:
|
else:
|
||||||
login(self.request, owner)
|
login(self.request, owner)
|
||||||
next_url = reverse('dav_events:set_password')
|
next_url = reverse('dav_auth:set_password')
|
||||||
messages.success(self.request,
|
messages.success(self.request,
|
||||||
_(u'Neuen Benutzer angemeldet: %(username)s') % {'username': owner.username})
|
_(u'Neuen Benutzer angemeldet: %(username)s') % {'username': owner.username})
|
||||||
messages.warning(self.request, _(u'Bitte neues Passwort setzen!'))
|
messages.warning(self.request, _(u'Bitte neues Passwort setzen!'))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from django.apps import apps
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from . import emails
|
from . import emails
|
||||||
|
from .utils import get_users_by_role
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -143,7 +144,6 @@ class BasicWorkflow(object):
|
|||||||
recipients = [event.owner]
|
recipients = [event.owner]
|
||||||
if event.is_flagged('submitted'):
|
if event.is_flagged('submitted'):
|
||||||
# If the event is already submitted, add managers to the recipients.
|
# 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_all')
|
||||||
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
|
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
|
||||||
if event.is_flagged('accepted'):
|
if event.is_flagged('accepted'):
|
||||||
@@ -174,7 +174,6 @@ class BasicWorkflow(object):
|
|||||||
# Inform managers that they have to accept the event.
|
# Inform managers that they have to accept the event.
|
||||||
# Also create OneClickActions for all of them and add the link to the mail,
|
# 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.
|
# 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_all')
|
||||||
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
|
recipients += get_users_by_role('manage_{}'.format(event.sport.lower()))
|
||||||
OneClickAction = app_config.get_model('OneClickAction')
|
OneClickAction = app_config.get_model('OneClickAction')
|
||||||
@@ -195,7 +194,6 @@ class BasicWorkflow(object):
|
|||||||
# Inform publishers that they have to publish the event.
|
# Inform publishers that they have to publish the event.
|
||||||
# Also create OneClickActions for all of them and add the link to the mail,
|
# 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.
|
# 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')
|
recipients = get_users_by_role('publish_incremental')
|
||||||
OneClickAction = app_config.get_model('OneClickAction')
|
OneClickAction = app_config.get_model('OneClickAction')
|
||||||
for recipient in recipients:
|
for recipient in recipients:
|
||||||
|
|||||||
4
setup.py
4
setup.py
@@ -45,7 +45,7 @@ if sys.version_info.major != 2:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='django-dav-events',
|
name='django-dav-events',
|
||||||
version='0.2',
|
version='1.0',
|
||||||
description='A django based web application project to submit DAV Events.',
|
description='A django based web application project to submit DAV Events.',
|
||||||
url='https://www.heinzelwelt.de',
|
url='https://www.heinzelwelt.de',
|
||||||
maintainer='Jens Kleineheismann',
|
maintainer='Jens Kleineheismann',
|
||||||
@@ -57,7 +57,7 @@ setup(
|
|||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
'django-dav-events-admin = dav_events.console_scripts.admin:main',
|
'django-dav-admin = dav_base.console_scripts.admin:main',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
install_requires=[
|
install_requires=[
|
||||||
|
|||||||
Reference in New Issue
Block a user