diff --git a/dav_events/admin.py b/dav_events/admin.py
index eb98b30..7a434ab 100644
--- a/dav_events/admin.py
+++ b/dav_events/admin.py
@@ -1,6 +1,6 @@
from django.contrib import admin
-from .models import EventStatus, EventFlag, Event, OneClickAction
+from .models import EventStatus, EventFlag, Event, OneClickAction, Participant
@admin.register(EventStatus)
@@ -13,11 +13,20 @@ class EventFlagInline(admin.TabularInline):
extra = 1
+class EventParticipantInline(admin.TabularInline):
+ model = Participant
+ extra = 1
+
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
- inlines = [EventFlagInline]
+ inlines = [EventFlagInline, EventParticipantInline]
@admin.register(OneClickAction)
class OneClickActionAdmin(admin.ModelAdmin):
pass
+
+
+@admin.register(Participant)
+class ParticipantAdmin(admin.ModelAdmin):
+ pass
diff --git a/dav_events/forms/__init__.py b/dav_events/forms/__init__.py
index f995b85..a13db64 100644
--- a/dav_events/forms/__init__.py
+++ b/dav_events/forms/__init__.py
@@ -1,2 +1,3 @@
from . import generic
from . import events
+from . import participant
diff --git a/dav_events/forms/participant.py b/dav_events/forms/participant.py
new file mode 100644
index 0000000..92dd23c
--- /dev/null
+++ b/dav_events/forms/participant.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from django import forms
+
+from ..models import Participant
+
+
+class ParticipantForm(forms.ModelForm):
+ class Meta:
+ model = Participant
+ exclude = ['event', 'created_at', 'position', 'purge_at']
+ widgets = {
+ 'emergency_contact': forms.Textarea(attrs={'rows': 4}),
+ 'experience': forms.Textarea(attrs={'rows': 5}),
+ 'note': forms.Textarea(attrs={'rows': 5}),
+ }
diff --git a/dav_events/migrations/0030_auto_20190603_1014.py b/dav_events/migrations/0030_auto_20190603_1014.py
new file mode 100644
index 0000000..c157c0c
--- /dev/null
+++ b/dav_events/migrations/0030_auto_20190603_1014.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-06-03 10:14
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dav_events', '0029_event_registration_closed'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Participant',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('position', models.IntegerField(verbose_name='Listennummer')),
+ ('personal_names', models.CharField(max_length=1024, verbose_name='Vorname(n)')),
+ ('family_names', models.CharField(max_length=1024, verbose_name='Familienname')),
+ ('address', models.CharField(help_text='Straße, Hausnummer', max_length=1024, verbose_name='Anschrift')),
+ ('postal_code', models.CharField(max_length=254, verbose_name='Postleitzahl')),
+ ('city', models.CharField(max_length=1024, verbose_name='Ort')),
+ ('email_address', models.EmailField(max_length=254, verbose_name='E-Mail-Adresse')),
+ ('phone_number', models.CharField(max_length=254, verbose_name='Telefonnummer')),
+ ('dav_number', models.CharField(max_length=62, verbose_name='DAV Mitgliednummer')),
+ ('emergency_contact', models.TextField(blank=True, verbose_name='Notfall-Kontakt')),
+ ('experience', models.TextField(blank=True, verbose_name='Erfahrung')),
+ ('note', models.TextField(blank=True, verbose_name='Anmerkung')),
+ ('paid', models.BooleanField(default=False, verbose_name='Teilnehmerbeitrag bezahlt')),
+ ('purge_at', models.DateTimeField()),
+ ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participants', to='dav_events.Event')),
+ ],
+ options={
+ 'verbose_name': 'Teilnehmer',
+ 'verbose_name_plural': 'Teilnehmer',
+ 'ordering': ['event', 'position'],
+ },
+ ),
+ migrations.AlterUniqueTogether(
+ name='participant',
+ unique_together=set([('event', 'position')]),
+ ),
+ ]
diff --git a/dav_events/models/__init__.py b/dav_events/models/__init__.py
index e8f44d2..9645797 100644
--- a/dav_events/models/__init__.py
+++ b/dav_events/models/__init__.py
@@ -2,3 +2,4 @@ from .event import Event
from .eventflag import EventFlag
from .eventstatus import EventStatus
from .oneclickaction import OneClickAction
+from .participant import Participant
diff --git a/dav_events/models/participant.py b/dav_events/models/participant.py
new file mode 100644
index 0000000..aa8283b
--- /dev/null
+++ b/dav_events/models/participant.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+import datetime
+from django.db import models
+from django.utils import timezone
+from django.utils.encoding import python_2_unicode_compatible
+from django.utils.translation import ugettext_lazy as _
+
+midnight = datetime.time(00, 00, 00)
+one_day = datetime.timedelta(1)
+
+
+@python_2_unicode_compatible
+class Participant(models.Model):
+ event = models.ForeignKey('Event', related_name='participants')
+ created_at = models.DateTimeField(auto_now_add=True)
+
+ position = models.IntegerField(verbose_name='Listennummer')
+
+ personal_names = models.CharField(max_length=1024,
+ verbose_name=_('Vorname(n)'))
+ family_names = models.CharField(max_length=1024,
+ verbose_name=_('Familienname'))
+ address = models.CharField(max_length=1024,
+ verbose_name=_('Anschrift'),
+ help_text=_('Straße, Hausnummer'))
+ postal_code = models.CharField(max_length=254,
+ verbose_name=_('Postleitzahl'))
+ city = models.CharField(max_length=1024,
+ verbose_name=_('Ort'))
+ email_address = models.EmailField(verbose_name=_('E-Mail-Adresse'))
+ phone_number = models.CharField(max_length=254,
+ verbose_name=_('Telefonnummer'))
+ dav_number = models.CharField(max_length=62,
+ #validators=[DAVNumberValidator],
+ verbose_name=_('DAV Mitgliednummer'))
+ emergency_contact = models.TextField(blank=True,
+ verbose_name=_('Notfall-Kontakt'))
+ experience = models.TextField(blank=True,
+ verbose_name=_('Erfahrung'))
+ note = models.TextField(blank=True,
+ verbose_name=_('Anmerkung'))
+
+ paid = models.BooleanField('Teilnehmerbeitrag bezahlt', default=False)
+
+ purge_at = models.DateTimeField()
+
+ class Meta:
+ unique_together = (('event', 'position'), )
+ verbose_name = _('Teilnehmer')
+ verbose_name_plural = _('Teilnehmer')
+ ordering = ['event', 'position']
+
+ def __str__(self):
+ return '{position}. {name}'.format(
+ position=self.position,
+ name=self.get_full_name(),
+ )
+
+ def get_full_name(self):
+ return '{} {}'.format(self.personal_names, self.family_names)
+
+ def save(self, **kwargs):
+ if not self.purge_at and self.event:
+ self.purge_at = self.__class__.calc_purge_at(self.event)
+
+ super(Participant, self).save(**kwargs)
+
+ @staticmethod
+ def calc_purge_at(event):
+ if event.alt_last_day:
+ last_day = event.alt_last_day
+ elif event.last_day:
+ last_day = event.last_day
+ elif event.alt_first_day:
+ last_day = event.alt_first_day
+ else:
+ last_day = event.first_day
+ return timezone.make_aware(datetime.datetime.combine(last_day + one_day * 7, midnight))
diff --git a/dav_events/templates/dav_events/event_registrations.html b/dav_events/templates/dav_events/event_registrations.html
index 9a572b2..ff9b036 100644
--- a/dav_events/templates/dav_events/event_registrations.html
+++ b/dav_events/templates/dav_events/event_registrations.html
@@ -220,22 +220,117 @@
Teilnehmer (Designstudie - Das funktioniert alles noch nicht!)
+
+
+
+
+ {% for registration in registrations %}
+
+ {% empty %}
+ Keine unbestätigten Anmeldungen vorhanden
+ {% endfor %}
+
+
+
@@ -245,7 +340,7 @@
diff --git a/dav_events/views/events.py b/dav_events/views/events.py
index 6f4c785..fda013c 100644
--- a/dav_events/views/events.py
+++ b/dav_events/views/events.py
@@ -5,7 +5,7 @@ import os
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
-from django.core.exceptions import PermissionDenied, SuspiciousOperation
+from django.core.exceptions import PermissionDenied, SuspiciousOperation, FieldDoesNotExist
from django.db.models import Q
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404
@@ -169,58 +169,130 @@ class EventRegistrationsView(EventPermissionMixin, generic.DetailView):
self.enforce_permission(obj)
return obj
+ def get_form_kwargs(self):
+ kwargs = {}
+ if self.request.method in ('POST', 'PUT'):
+ kwargs.update({
+ 'data': self.request.POST,
+ 'files': self.request.FILES,
+ })
+ return kwargs
+
+ def get_create_participant_form(self):
+ event = self.get_object()
+ form = forms.participant.ParticipantForm(**self.get_form_kwargs())
+ form.instance.event = event
+ form.instance.position = event.participants.count() + 1
+ return form
+
def get_context_data(self, **kwargs):
context = super(EventRegistrationsView, self).get_context_data(**kwargs)
- obj = context.get('event')
- context['has_permission_update'] = self.has_permission('update', obj)
- context['is_published_any'] = obj.workflow.has_reached_status('published*')
- context['is_done'] = obj.workflow.has_reached_status('expired')
+ event = context.get('event')
+ context['has_permission_update'] = self.has_permission('update', event)
+ context['is_published_any'] = event.workflow.has_reached_status('published*')
+ context['is_done'] = event.workflow.has_reached_status('expired')
- class MockParticipant(object):
- def __init__(self, id, name):
- self.id = id
- self.name = name
-
- @property
- def position(self):
- return self.id
-
- def get_full_name(self):
- return self.name
-
- participants = [MockParticipant(1, 'Erika Musterfrau'), MockParticipant(2, 'Max Mustermann')]
+ participants = event.participants.all()
context['participants'] = participants
-
+ if hasattr(event, 'registrations'):
+ # registrations = event.registrations.filter(answered=False)
+ registrations = event.registrations.all()
+ context['registrations'] = registrations
+ if 'create_participant_form' not in context:
+ context['create_participant_form'] = self.get_create_participant_form()
return context
- def _send_mails(self, event, request):
- editor = request.user
+ def _notify_publisher(self, event, editor):
recipients = get_users_by_role('publisher')
for recipient in recipients:
if recipient.email:
email = emails.EventRegistrationClosedMail(recipient=recipient, event=event, editor=editor)
email.send()
+ def _close_registration(self, request, event):
+ logger.info('Close registration: %s', event)
+ event.registration_closed = True
+ event.save(implicit_update=True)
+ self._notify_publisher(event, request.user)
+ messages.success(request, _(u'Die Anmeldung wurde geschlossen'))
+
+ def _reopen_registration(self, request, event):
+ logger.info('Reopen registration: %s', event)
+ event.registration_closed = False
+ event.save(implicit_update=True)
+ messages.success(request, _(u'Die Anmeldung wurde geöffnet'))
+
+ def _kill_deadline(self, request, event):
+ logger.info('Delete deadline: %s', event)
+ event.deadline = None
+ event.registration_closed = False
+ event.save(implicit_update=True)
+ messages.success(request, _(u'Der Anmeldeschluss wurde gelöscht'))
+
+ def _accept_registration(self, request, registration):
+ event = registration.event
+
+ position = event.participants.count() + 1
+
+ data = {
+ 'event': event,
+ 'position': position,
+ 'personal_names': registration.personal_names,
+ 'family_names': registration.family_names,
+ 'address': registration.address,
+ 'postal_code': registration.postal_code,
+ 'city': registration.city,
+ 'email_address': registration.email_address,
+ 'phone_number': registration.phone_number,
+ 'dav_number': registration.dav_number,
+ 'emergency_contact': registration.emergency_contact,
+ 'experience': registration.experience,
+ 'note': registration.note,
+ 'purge_at': registration.purge_at,
+ }
+ participant = models.Participant.objects.create(**data)
+ registration.answered = True
+ registration.save()
+ messages.success(request, _(u'Teilnehmer hinzugefügt: {}'.format(participant.get_full_name())))
+
+ def _reject_registration(self, registration):
+ registration.answered = True
+ registration.save()
+
def post(self, request, *args, **kwargs):
event = self.get_object()
+ self.object = event
+
action = request.POST.get('action')
if action == 'close-registration':
- logger.info('Close registration: %s', event)
- event.registration_closed = True
- event.save(implicit_update=True)
- self._send_mails(event, request)
- messages.success(request, _(u'Die Anmeldung wurde geschlossen'))
+ self._close_registration(request, event)
elif action == 'open-registration':
- logger.info('Reopen registration: %s', event)
- event.registration_closed = False
- event.save(implicit_update=True)
- messages.success(request, _(u'Die Anmeldung wurde geöffnet'))
+ self._reopen_registration(request, event)
elif action == 'kill-deadline':
- logger.info('Delete deadline: %s', event)
- event.deadline = None
- event.registration_closed = False
- event.save(implicit_update=True)
- messages.success(request, _(u'Der Anmeldeschluss wurde gelöscht'))
+ self._kill_deadline(request, event)
+ elif action == 'accept_registration':
+ if hasattr(event, 'registrations'):
+ registration_id = request.POST.get('registration')
+ registration = event.registrations.get(id=registration_id)
+ self._accept_registration(request, registration)
+ else:
+ raise FieldDoesNotExist('Event has no registrations')
+ elif action == 'reject_registration':
+ if hasattr(event, 'registrations'):
+ registration_id = request.POST.get('registration')
+ registration = event.registrations.get(id=registration_id)
+ self._reject_registration(registration)
+ else:
+ raise FieldDoesNotExist('Event has no registrations')
+ else:
+ form = self.get_create_participant_form()
+ if form.is_valid():
+ form.save()
+ participant = form.instance
+ messages.success(request, _(u'Teilnehmer hinzugefügt: {}'.format(participant.get_full_name())))
+ else:
+ messages.error(request, _(u'irgendwas ging schief.'))
+ return self.render_to_response(self.get_context_data(create_participant_form=form))
return HttpResponseRedirect(reverse('dav_events:registrations', kwargs={'pk': event.pk}))
@method_decorator(login_required)
diff --git a/dav_registration/forms.py b/dav_registration/forms.py
index 202e02c..504874b 100644
--- a/dav_registration/forms.py
+++ b/dav_registration/forms.py
@@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
class RegistrationForm(forms.ModelForm):
class Meta:
model = Registration
- exclude = ['event', 'created_at', 'privacy_policy', 'purge_at']
+ exclude = ['event', 'created_at', 'privacy_policy', 'purge_at', 'answered']
widgets = {
'emergency_contact': forms.Textarea(attrs={'rows': 4}),
'experience': forms.Textarea(attrs={'rows': 5}),
diff --git a/dav_registration/migrations/0003_auto_20190603_1425.py b/dav_registration/migrations/0003_auto_20190603_1425.py
new file mode 100644
index 0000000..e36f545
--- /dev/null
+++ b/dav_registration/migrations/0003_auto_20190603_1425.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-06-03 14:25
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dav_registration', '0002_auto_20190401_1310'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='registration',
+ name='answered',
+ field=models.BooleanField(default=False, verbose_name='Durch Tourleitung beantwortet'),
+ ),
+ migrations.AlterField(
+ model_name='registration',
+ name='purge_at',
+ field=models.DateTimeField(verbose_name='Zeitpunkt der Datenlöschung'),
+ ),
+ ]
diff --git a/dav_registration/models.py b/dav_registration/models.py
index 18bad94..c0842ca 100644
--- a/dav_registration/models.py
+++ b/dav_registration/models.py
@@ -69,7 +69,9 @@ class Registration(models.Model):
verbose_name=_('Erklärung zur Datenspeicherung'))
privacy_policy_accepted = models.BooleanField(default=False,
verbose_name=_('Einwilligung zur Datenspeicherung'))
- purge_at = models.DateTimeField()
+ purge_at = models.DateTimeField(_('Zeitpunkt der Datenlöschung'))
+
+ answered = models.BooleanField(_('Durch Tourleitung beantwortet'), default=False)
@staticmethod
def pk2hexstr(pk):
@@ -105,6 +107,25 @@ class Registration(models.Model):
def get_full_name(self):
return '{} {}'.format(self.personal_names, self.family_names)
+ def get_info(self):
+ text = """{fullname}
+{address}, {postal_code} {city}
+
+Erfahrung:
+{experience}
+
+Anmerkung:
+{note}
+"""
+ return text.format(
+ fullname=self.get_full_name(),
+ address=self.address,
+ postal_code=self.postal_code,
+ city=self.city,
+ experience=self.experience,
+ note=self.note,
+ )
+
def save(self, **kwargs):
creating = False
if not self.id: