commit 0cf77a4ab0d138cf043dfdf2ddb2c27d9824ea80 Author: Jens Kleineheismann Date: Wed Jan 17 19:10:55 2018 +0100 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c52877 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.pyc +*.mo + +.idea/ +django_dav_events.egg-info/ + +env/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..8bc380f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +recursive-include dav_events/console_scripts/Resources *.py +recursive-include dav_events/static * +recursive-include dav_events/templates * diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..f8b912d --- /dev/null +++ b/README.rst @@ -0,0 +1,78 @@ +ABOUT +===== +This is the DAV Events django project. + + +REQUIREMENTS +============ +- Python 2.7 +- Django +- Several additional django related python packages + +For production use you surly want a real web server that supports WSGI +(e.g. Apache httpd with mod_wsgi) and a real Database like PostgreSQL. + + +INSTALLATION +============ + +1. Python Environment +--------------------- + It is strongly recommended to create a separated python environment + for your django project. But it is not exactly necessary. + + The creation of a separated python environment is very easy with the + virtualenv tool (a python package). + + If you decide to not use virtualenv, proceed with step 2. + + - Create the python environment in a directory called ./env/python: + + ``virtualenv --prompt="(dav)" ./env/python`` + + - If you use a posix compatible shell (like bash, the linux default shell), + you have to enter the environment with the following command: + + ``source ./env/python/bin/activate`` + + Your shell prompt should show the prefix '(dav)' now. + + Do not leave the environment (nor exit the shell) until the whole + installation is done. + After that you can call the command ``deactivate`` to leave. + + If you have left the environment and want to reenter it (e.g. to execute + a python command) use the previous ``source ...`` command. + +2. Install files +---------------- + + * ``pip install -e .`` + * ``django-dav-events-admin setup ./env/django`` + + The django project directory ('./env/django' within the previous example) + will be called project root for now on. + +3. Create the database schema / Populate the database +----------------------------------------------------- + Change into the *project root* (where the file ``manage.py`` lives) + and run + + * ``python manage.py makemigrations`` + * ``python manage.py migrate`` + +4. Start test server +-------------------- + While you still are in the *project root* directory, run + + ``python manage.py runserver`` + + Now you should be able to connect to the test server via + + http://localhost:8000 + + +LICENCE +======= +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted. diff --git a/dav_events/__init__.py b/dav_events/__init__.py new file mode 100644 index 0000000..5b92057 --- /dev/null +++ b/dav_events/__init__.py @@ -0,0 +1 @@ +default_app_config = 'dav_events.apps.AppConfig' diff --git a/dav_events/admin.py b/dav_events/admin.py new file mode 100644 index 0000000..7327c1d --- /dev/null +++ b/dav_events/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +from .models import Event + + +class EventAdmin(admin.ModelAdmin): + pass + +admin.site.register(Event, EventAdmin) diff --git a/dav_events/apps.py b/dav_events/apps.py new file mode 100644 index 0000000..922574a --- /dev/null +++ b/dav_events/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig as _AppConfig + + +class AppConfig(_AppConfig): + name = 'dav_events' + verbose_name = u'DAV Veranstaltungen' diff --git a/dav_events/choices.py b/dav_events/choices.py new file mode 100644 index 0000000..f9555ae --- /dev/null +++ b/dav_events/choices.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +from django.utils.translation import ugettext_lazy as _ + + +class ChoiceSet(object): + def __init__(self, choices): + self._codes = list() + self._labels = dict() + for code, label in choices: + self._codes.append(code) + self._labels[code] = label + + def __len__(self): + return len(self._codes) + + def __getitem__(self, key): + code = self._codes[key] + return code, self._labels[code] + + def __iter__(self): + for code in self._codes: + yield code, self._labels[code] + + def __contains__(self, item): + code, label = item + if code in self._codes: + return True + else: + return False + + def get_label(self, code): + return self._labels[code] + + +ACCOMMODATION_CHOICES = ChoiceSet([ + ('NONE', _(u'Keine (tägliche Anreise)')), + ('biwi', _(u'Biwak')), + ('camp', _(u'Zelt')), + ('hut', _(u'Alpenvereinshütte')), + ('hotel', _(u'Hotel/Pension/Hostel')), + ('OTHER', _(u'Andere Unterkunft (zusätzliches Feld)')), +]) + +COUNTRY_CHOICES = ChoiceSet([ + ('DE', _(u'Deutschland')), + ('AU', _(u'Österreich')), + ('CH', _(u'Schweiz')), + ('FR', _(u'Frankreich')), + ('IT', _(u'Italien')), +]) + +DEADLINE_CHOICES = ChoiceSet([ + ('month', _(u'Einen Monat vorher')), + ('quarter', _(u'Drei Monate vorher')), + ('OTHER', _(u'Anderes oder kein Datum (zusätzliches Feld)')), +]) + +LEVEL_CHOICES = ChoiceSet([ + ('beginner', _(u'Anfänger')), + ('advanced', _(u'Fortgeschrittene')), +]) + +MEALS_CHOICES = ChoiceSet([ + ('NONE', _(u'Keine Angabe')), + ('self', _(u'Selbstverpflegung')), + ('hp', _(u'Halbpension')), + ('vp', _(u'Vollpension')), + ('OTHER', _(u'Andere Verpflegung (zusätzliches Feld)')), +]) + +MEETING_POINT_CHOICES = ChoiceSet([ + ('NONE', _(u'Keine Angabe')), + ('dav', _(u'DAV Sektionszentrum')), + ('hbf', _(u'Hauptbahnhof Karlsruhe, vor der Buchhandlung')), + ('hbf_south', _(u'Hauptbahnhof Karlsruhe, Südausgang')), + ('battert', _(u'Battertparkplatz, Ebersteinburg')), + ('OTHER', _(u'Anderer Treffpunkt (zusätzliches Feld)')), +]) + +MODE_CHOICES = ChoiceSet([ + ('joint', _(u'gemeinschaftliche Tour')), + ('supervised', _(u'begleitete Tour')), + ('guided', _(u'geführte Tour')), + ('training', _(u'Kurs')), +]) + +SPORT_CHOICES = ChoiceSet([ + ('W', _(u'Wanderung')), + ('S', _(u'Skitour')), + ('M', _(u'Mountainbike')), + ('K', _(u'Klettern')), + ('B', _(u'Bergsteigen')), +]) + +TERRAIN_CHOICES = ChoiceSet([ + ('gym', _(u'Kletterhalle')), + ('crag', _(u'Klettergarten')), + ('submountains', _(u'Mittelgebirge')), + ('alpine', _(u'Alpin')), +]) + +TRANSPORT_CHOICES = ChoiceSet([ + ('NONE', _(u'Keine Angabe')), + ('train', _(u'Bahn')), + ('bus', _(u'Bus')), + ('car', _(u'Fahrgemeinschaften')), + ('self', _(u'Eigenverantwortlich')), + ('OTHER', _(u'Anderes Verkehrsmittel (zusätzliches Feld)')), +]) diff --git a/dav_events/config.py b/dav_events/config.py new file mode 100644 index 0000000..37a6b54 --- /dev/null +++ b/dav_events/config.py @@ -0,0 +1,14 @@ +COMMON_CHAR_FIELD_LENGTH = 250 + +TITLE_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH + +TRAINER_NAME_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH +PHONE_NUMBER_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH + +LOCATION_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH +TRANSPORT_OTHER_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH +MEETING_POINT_OTHER_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH +BASECAMP_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH +ACCOMMODATION_OTHER_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH +MEALS_OTHER_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH +ADDITIONAL_COSTS_MAX_LENGTH = COMMON_CHAR_FIELD_LENGTH \ No newline at end of file diff --git a/dav_events/console_scripts/Resources/django.main.additional_settings.py b/dav_events/console_scripts/Resources/django.main.additional_settings.py new file mode 100644 index 0000000..51f661d --- /dev/null +++ b/dav_events/console_scripts/Resources/django.main.additional_settings.py @@ -0,0 +1,107 @@ + +## +## Additional settings for django-alte-maschinen +## + +BASE_VAR_DIR = os.path.join(BASE_DIR, 'var') +BASE_SHARE_DIR = os.path.join(BASE_DIR, 'common') + +INSTALLED_APPS += [ + 'bootstrap3', + 'datetimewidget', + 'django_extensions', + # Our main app + 'dav_events', +] + +DATABASES['default'] = { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_VAR_DIR, 'db', 'devel.sqlite3'), +} + +STATIC_ROOT = os.path.join(BASE_VAR_DIR, 'www', 'static') + +LANGUAGE_CODE = 'de' + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'default': { + 'format': '%(asctime)s - %(name)s - %(levelname)s: %(message)s' + }, + 'verbose': { + 'format': '%(asctime)s -- %(processName)s[%(process)d]:%(threadName)s[%(thread)d] -- %(name)s -- %(module)s...%(funcName)s() -- %(pathname)s:%(lineno)d -- %(levelname)s: %(message)s' + }, + }, + 'filters': { + 'require_debug_true': { + '()': 'django.utils.log.RequireDebugTrue', + }, + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, + }, + 'handlers': { + 'console': { + 'level': 'DEBUG', + 'filters': ['require_debug_true'], + 'class': 'logging.StreamHandler', + }, + 'null': { + 'class': 'logging.NullHandler', + }, + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + }, + 'default_log': { + 'level': 'INFO', + 'class': 'logging.FileHandler', + 'filename': os.path.join(BASE_VAR_DIR, 'log', 'default.log'), + 'formatter': 'default', + }, + 'error_log': { + 'level': 'ERROR', + 'class': 'logging.FileHandler', + 'filename': os.path.join(BASE_VAR_DIR, 'log', 'error.log'), + 'formatter': 'default', + }, + 'debug_log': { + 'level': 'DEBUG', + 'filters': ['require_debug_true'], + 'class': 'logging.FileHandler', + 'filename': os.path.join(BASE_VAR_DIR, 'log', 'debug.log'), + 'formatter': 'verbose', + }, + 'django_log': { + 'level': 'INFO', + 'filters': ['require_debug_true'], + 'class': 'logging.FileHandler', + 'filename': os.path.join(BASE_VAR_DIR, 'log', 'django.log'), + 'formatter': 'default', + }, + }, + 'loggers': { + 'django': { + 'level': 'INFO', + 'handlers': ['console', 'django_log'], + 'propagate': False, + }, + 'django.request': { + 'level': 'DEBUG', + 'handlers': ['mail_admins'], + 'propagate': True, + }, + 'django.security': { + 'level': 'DEBUG', + 'handlers': ['mail_admins'], + 'propagate': True, + }, + }, + 'root': { + 'level': 'DEBUG', + 'handlers': ['console', 'default_log', 'error_log', 'debug_log'], + }, +} diff --git a/dav_events/console_scripts/Resources/django.main.urls.py b/dav_events/console_scripts/Resources/django.main.urls.py new file mode 100644 index 0000000..26adf37 --- /dev/null +++ b/dav_events/console_scripts/Resources/django.main.urls.py @@ -0,0 +1,7 @@ +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), +] diff --git a/dav_events/console_scripts/__init__.py b/dav_events/console_scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dav_events/console_scripts/admin.py b/dav_events/console_scripts/admin.py new file mode 100644 index 0000000..4a8ae74 --- /dev/null +++ b/dav_events/console_scripts/admin.py @@ -0,0 +1,98 @@ +import argparse +import os +import pkg_resources +import posix +import sys + +VERSION = '0.1' + + +class AdminCommand(object): + def _setup_argparser(self): + kwargs = { + 'description': 'Tool to manage the DAV Events django project installation.', + 'epilog': 'Off Belay.', + } + parser = argparse.ArgumentParser(**kwargs) + + parser.add_argument('-V', '--version', action='version', + version='%(prog)s ' + VERSION) + + subparsers = parser.add_subparsers(dest='subcmd', metavar='CMD', + title='subcommands', + description="Use '%(prog)s CMD -h' to show help for a subcommand") + subparser = subparsers.add_parser('setup', help='Setup the installation.') + subparser.add_argument('path', metavar='PATH', + help='A directory, where the project files will be installed.') + + return parser + + def _parse_args(self, argv=None): + if argv is None: + argv = sys.argv[1:] + if not argv: + argv = ['--help'] + + return self._argparser.parse_args(argv) + + def _subcmd_setup(self, cmd_args): + django_project_name = 'main' + django_project_path = cmd_args.path + + sys.stdout.write('Setup installation in \'{path}\'...\n'.format(path=django_project_path)) + + 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)) + return posix.EX_USAGE + else: + os.makedirs(django_project_path) + + sys.stdout.write('Creating django project...\n') + django_cmd = 'django-admin startproject {name} "{path}"'.format(name=django_project_name, + path=django_project_path) + 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'), + ] + + for d in dirs: + sys.stdout.write(' - %s\n' % d) + os.makedirs(d) + + 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') + 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') + with open(output_file, 'w') as f: + f.write(pkg_resources.resource_string(__package__, input_file)) + + return posix.EX_OK + + def __init__(self): + self._argparser = self._setup_argparser() + + def __call__(self, argv=None): + cmd_args = self._parse_args(argv) + subcmd = cmd_args.subcmd + method_name = '_subcmd_{}'.format(subcmd) + method = getattr(self, method_name) + exitval = method(cmd_args) + return exitval + + +def main(): + cmd = AdminCommand() + exitval = cmd() + sys.exit(exitval) diff --git a/dav_events/converters.py b/dav_events/converters.py new file mode 100644 index 0000000..161392e --- /dev/null +++ b/dav_events/converters.py @@ -0,0 +1,93 @@ +import datetime +import logging +import re + +from django.http import QueryDict + +from . import models + +logger = logging.getLogger(__name__) + + +class SessionDict(QueryDict): + _re_iso8601 = re.compile(r'^ISO8601:(?P' + r'(?P\d{4})' + r'-(?P(0[1-9])|(1[012]))' + r'-(?P(0[1-9])|([12][0-9])|(3[01]))' + r')?(?P.)?' + r'(?P