Commit b622cdc6 authored by Luuk Scholten's avatar Luuk Scholten
Browse files

Merge branch 'feature/events-member-views' into 'master'

Events member views

Closes #54 and #61

Ik vind dat ie heel ver af is. Kunnen jullie al eens een kijkje nemen?

~~Moet echt alleen nog even die Google API Key checken, maar dat kan woensdag. En de extra velden worden in de backend echt belabberd weergeven, dus dat is ook nog een dingetje.~~ Zie #111 

See merge request !107
parents 899d3401 d0d9e74b
......@@ -9,3 +9,4 @@ django-tinymce==2.3.0
pytz
rcssmin
djangorestframework==3.4.4
django-ical==1.4
# -*- coding: utf-8 -*-
from django import forms
from django.urls import reverse
from activemembers.models import Committee
from django.contrib import admin
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils import timezone
from django.utils.http import is_safe_url
from django.utils.html import format_html
from django.utils.http import is_safe_url
from django.utils.translation import ugettext_lazy as _
from utils.translation import TranslatedModelAdmin
from activemembers.models import Committee
from members.models import Member
from utils.translation import TranslatedModelAdmin
from . import forms
from . import models
......@@ -32,17 +32,8 @@ class DoNextModelAdmin(TranslatedModelAdmin):
return _do_next(request, res)
class RegistrationInformationFieldForm(forms.ModelForm):
order = forms.IntegerField(label=_('order'), initial=0)
class Meta:
fields = '__all__'
model = models.RegistrationInformationField
class RegistrationInformationFieldInline(admin.StackedInline):
form = RegistrationInformationFieldForm
form = forms.RegistrationInformationFieldForm
extra = 0
model = models.RegistrationInformationField
ordering = ('_order',)
......
......@@ -10,7 +10,7 @@ class CalenderJSSerializer(serializers.ModelSerializer):
fields = (
'start', 'end', 'all_day', 'is_birthday',
'url', 'title', 'description',
'background_color', 'text_color', 'target_blank'
'backgroundColor', 'textColor', 'blank'
)
start = serializers.SerializerMethodField('_start')
......@@ -20,9 +20,9 @@ class CalenderJSSerializer(serializers.ModelSerializer):
url = serializers.SerializerMethodField('_url')
title = serializers.SerializerMethodField('_title')
description = serializers.SerializerMethodField('_description')
background_color = serializers.SerializerMethodField('_background_color')
text_color = serializers.SerializerMethodField('_text_color')
target_blank = serializers.SerializerMethodField('_target_blank')
backgroundColor = serializers.SerializerMethodField('_background_color')
textColor = serializers.SerializerMethodField('_text_color')
blank = serializers.SerializerMethodField('_target_blank')
def _start(self, instance):
return timezone.localtime(instance.start)
......@@ -60,4 +60,4 @@ class EventSerializer(CalenderJSSerializer):
model = Event
def _url(self, instance):
return reverse('#')
return reverse('events:event', kwargs={'event_id': instance.id})
from datetime import datetime, timedelta
from django.urls import reverse
from django.utils.translation import activate
from django_ical.views import ICalFeed
from events.models import Event
from django.utils.translation import ugettext as _
class EventFeed(ICalFeed):
def __init__(self, lang='en'):
super().__init__()
self.lang = lang
def product_id(self):
return '-//thalia.nu//EventCalendar//' + self.lang.upper()
def file_name(self):
return "thalia_{}.ics".format(self.lang)
def title(self):
activate(self.lang)
return _('Study Association Thalia event calendar')
def items(self):
return Event.objects.filter(published=True).order_by('-start')
def item_title(self, item):
return item.title
def item_description(self, item):
return item.description
def item_start_datetime(self, item):
return item.start
def item_end_datetime(self, item):
return item.end
def item_link(self, item):
return reverse('events:event', kwargs={'event_id': item.id})
def item_location(self, item):
return "{} - {}".format(item.location, item.map_location)
class DeprecationFeed(ICalFeed):
def product_id(self):
return '-//thalia.nu//DEPRECATED'
def items(self):
return range(7)
def item_start_datetime(self, item):
today = datetime.now().replace(hour=13, minute=37, second=0)
delta = timedelta(days=item)
return today + delta
def item_end_datetime(self, item):
today = datetime.now().replace(hour=15, minute=37, second=0)
delta = timedelta(days=item)
return today + delta
def item_title(self, item):
return (
'Oude Thalia Feed, gebruik https://thalia.nu' +
reverse('events:ical-nl')
)
def item_link(self, item):
return reverse('events:ical-nl') + '?item={}'.format(item)
from django import forms
from django.utils.translation import ugettext_lazy as _
from .models import RegistrationInformationField
class RegistrationInformationFieldForm(forms.ModelForm):
order = forms.IntegerField(label=_('order'), initial=0)
class Meta:
fields = '__all__'
model = RegistrationInformationField
widgets = {
'type': forms.Select,
}
class FieldsForm(forms.Form):
def __init__(self, *args, **kwargs):
registration = kwargs.pop('registration')
super(FieldsForm, self).__init__(*args, **kwargs)
self.information_fields = registration.registration_information()
for information_field in self.information_fields:
field = information_field['field']
key = "info_field_{}".format(field.id)
if field.type == RegistrationInformationField.BOOLEAN_FIELD:
self.fields[key] = forms.BooleanField(
required=False
)
elif field.type == RegistrationInformationField.INTEGER_FIELD:
self.fields[key] = forms.IntegerField()
elif field.type == RegistrationInformationField.TEXT_FIELD:
self.fields[key] = forms.CharField()
self.fields[key].label = field.name
self.fields[key].help_text = field.description
self.fields[key].initial = information_field['value']
if not field.type == RegistrationInformationField.BOOLEAN_FIELD:
self.fields[key].required = field.required
def field_values(self):
for information_field in self.information_fields:
key = "info_field_{}".format(information_field['field'].id)
field = {
"field": information_field["field"],
"value": self.cleaned_data[key]
}
yield field
......@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-14 21:48+0200\n"
"PO-Revision-Date: 2016-09-14 21:45+0200\n"
"POT-Creation-Date: 2016-09-28 21:27+0200\n"
"PO-Revision-Date: 2016-09-28 21:28+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: nl\n"
......@@ -16,178 +16,184 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.8\n"
"X-Generator: Poedit 1.8.7.1\n"
#: admin.py:36
#: admin.py:37
msgid "order"
msgstr "volgorde"
#: admin.py:71
#: admin.py:72
msgid "Edit"
msgstr "Aanpassen"
#: admin.py:81
#: admin.py:82
msgid "Number of participants"
msgstr "Aantal deelnemers"
#: admin.py:85
#: admin.py:86
msgid "Publish selected events"
msgstr "Publiceer geselecteerde evenementen"
#: admin.py:89
#: admin.py:90
msgid "Unpublish selected events"
msgstr "Publicatie van geselecteerde evenementen ongedaan maken"
#: models.py:12
#: feeds.py:23
msgid "Study Association Thalia event calendar"
msgstr "Studievereniginig Thalia evenementenkalender"
#: models.py:13
msgid "No registration required"
msgstr "Geen registratie vereist"
#: models.py:14 templates/events/admin/details.html:47
#: models.py:17 templates/events/admin/details.html:47
msgid "title"
msgstr "titel"
#: models.py:16 models.py:157
#: models.py:21 models.py:167
msgid "description"
msgstr "beschrijving"
#: models.py:18
#: models.py:23
msgid "start time"
msgstr "starttijd"
#: models.py:20
#: models.py:25
msgid "end time"
msgstr "eindtijd"
#: models.py:26 templates/events/admin/details.html:51
#: models.py:31 templates/events/admin/details.html:51
msgid "organiser"
msgstr "organisator"
#: models.py:30
#: models.py:35
msgid "registration start"
msgstr "start registratie"
#: models.py:36
#: models.py:41
msgid "registration end"
msgstr "einde registratie"
#: models.py:42
#: models.py:47
msgid "cancel deadline"
msgstr "afmelddeadline"
#: models.py:47 templates/events/admin/details.html:55
#: models.py:54 templates/events/admin/details.html:55
#: templates/events/event.html:21
msgid "location"
msgstr "locatie"
#: models.py:50
#: models.py:59
msgid "location for minimap"
msgstr "locatie voor minimap"
#: models.py:52
#: models.py:61
msgid "Location of Huygens: Heyendaalseweg 135, Nijmegen. Not shown as text!!"
msgstr ""
"Locatie van ’t Huygens: Heyendaalseweg 135, Nijmegen. Dit veld wordt niet "
"getoond als tekst!!"
#: models.py:57 templates/events/admin/details.html:57
#: models.py:66 templates/events/admin/details.html:57
#: templates/events/event.html:26
msgid "price"
msgstr "prijs"
#: models.py:65 templates/events/admin/details.html:59
#: models.py:74 templates/events/admin/details.html:59
msgid "cost"
msgstr "kosten"
#: models.py:69
#: models.py:78
msgid "Actual cost of event."
msgstr "werkelijke kosten van het evenement"
#: models.py:74
#: models.py:83
msgid "maximum number of participants"
msgstr "maximum aantal deelnemers"
#: models.py:80
#: models.py:90
msgid "message when there is no registration"
msgstr "bericht dat getoond wordt wanneer er geen registratie nodig is"
#: models.py:84
#: models.py:94
msgid "Default: "
msgstr "Standaard: "
#: models.py:88
#: models.py:98
msgid "published"
msgstr "gepubliceerd"
#: models.py:98
#: models.py:108
msgid "Can't have an event travel back in time"
msgstr "Een evenement kan niet terugreizen in de tijd"
#: models.py:103
#: models.py:113
msgid "Doesn't make sense to have this if you require registrations."
msgstr "Het is niet logisch om dit te hebben als je registratie vereist."
#: models.py:108
#: models.py:118
msgid "If registration is required, you need a start of registration"
msgstr ""
"Als registratie vereist is, dan heb je een starttijd voor de registratie "
"nodig"
#: models.py:113
#: models.py:123
msgid "If registration is required, you need an end of registration"
msgstr ""
"Als registratie vereist is, dan heb je een eindtijd voor de registratie nodig"
#: models.py:117
#: models.py:127
msgid "Registration start should be before registration end"
msgstr "De starttijd voor de registratie moet voor de eindtijd liggen"
#: models.py:139
#: models.py:149
msgid "checkbox"
msgstr "checkbox"
#: models.py:140
#: models.py:150
msgid "text field"
msgstr "tekstveld"
#: models.py:141
#: models.py:151
msgid "integer field"
msgstr "integerveld"
#: models.py:146
#: models.py:156
msgid "field type"
msgstr "veldtype"
#: models.py:152
#: models.py:162
msgid "field name"
msgstr "veldnaam"
#: models.py:194 templates/events/admin/registrations_table.html:6
#: models.py:204 templates/events/admin/registrations_table.html:6
msgid "name"
msgstr "naam"
#: models.py:196
#: models.py:206
msgid "Use this for non-members"
msgstr "Gebruikt dit voor niet-leden"
#: models.py:201
#: models.py:211
msgid "registration date"
msgstr "registratiedatum"
#: models.py:202
#: models.py:212
msgid "cancellation date"
msgstr "afmelddatum"
#: models.py:207 templates/events/admin/registrations_table.html:11
#: models.py:217 templates/events/admin/registrations_table.html:11
msgid "present"
msgstr "aanwezig"
#: models.py:211 templates/events/admin/registrations_table.html:12
#: models.py:221 templates/events/admin/registrations_table.html:12
msgid "paid"
msgstr "betaald"
#: models.py:224 models.py:225
#: models.py:253 models.py:254
msgid "Either specify a member or a name"
msgstr "Geef een lid of een naam op"
#: models.py:247
#: models.py:276
msgid "last changed"
msgstr "laatst aangepast"
......@@ -255,6 +261,96 @@ msgstr "toevoegen"
msgid "Nobody %(verb)s yet"
msgstr "Niemand heeft zich %(verb)s"
#: templates/events/event.html:13
msgid "from"
msgstr "van"
#: templates/events/event.html:17
msgid "until"
msgstr "tot"
#: templates/events/event.html:32
msgid "registration deadline"
msgstr "aanmelddeadline"
#: templates/events/event.html:36
msgid "cancellation deadline"
msgstr "afmelddeadline"
#: templates/events/event.html:40
msgid "number of registrations"
msgstr "aantal aanmeldingen"
#: templates/events/event.html:42
#, python-format
msgid "%(counter)s registration"
msgid_plural "%(counter)s registrations"
msgstr[0] "%(counter)s aanmelding"
msgstr[1] "%(counter)s aanmeldingen"
#: templates/events/event.html:48
msgid "max"
msgstr "max"
#: templates/events/event.html:59
msgid "registration status"
msgstr "aanmeldstatus"
#: templates/events/event.html:62
msgid "You are registered"
msgstr "Je bent aangemeld"
#: templates/events/event.html:64
#, python-format
msgid "Waiting list position %(pos)s"
msgstr "Wachtlijst positie %(pos)s"
#: templates/events/event.html:68
msgid "Your registration is cancelled after the cancellation deadline"
msgstr "Je bent afgemeld na de afmelddeadline"
#: templates/events/event.html:70
msgid "Your registration is cancelled"
msgstr "Je bent afgemeld"
#: templates/events/event.html:155
msgid "You have to log in before you can register for this event."
msgstr "Je moet inloggen voordat je jezelf kunt aanmelden."
#: templates/events/event.html:241
msgid "cohort"
msgstr "jaarlaag"
#: templates/events/index.html:13
msgid "Calendar"
msgstr "Agenda"
#: templates/events/index.html:49 templates/events/index.html:51
#: templates/events/index.html:57
msgid "hide birthdays"
msgstr "Verberg verjaardagen"
#: templates/events/index.html:49 templates/events/index.html:52
msgid "show birthdays"
msgstr "Toon verjaardagen"
#: templates/events/index.html:69
msgid "list"
msgstr "Lijst"
#~ msgid "From"
#~ msgstr "Vanaf"
#, fuzzy
#~| msgid "location"
#~ msgid "Location"
#~ msgstr "locatie"
#, fuzzy
#~| msgid "price"
#~ msgid "Price"
#~ msgstr "prijs"
#~ msgid "Present"
#~ msgstr "Aanwezig"
......
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-10-09 21:52
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('events', '0006_auto_20160921_2201'),
]
operations = [
migrations.AddField(
model_name='registrationinformationfield',
name='required',
field=models.BooleanField(default=True, verbose_name='required'),
preserve_default=False,
),
migrations.AlterField(
model_name='registrationinformationfield',
name='type',
field=models.CharField(choices=[('boolean', 'Checkbox'), ('text', 'Text'), ('integer', 'Integer')], max_length=10, verbose_name='field type'),
),
]
......@@ -2,6 +2,7 @@ from django.core import validators
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _, string_concat
from utils.translation import MultilingualField, ModelTranslateMeta
......@@ -10,6 +11,13 @@ from utils.translation import MultilingualField, ModelTranslateMeta
class Event(models.Model, metaclass=ModelTranslateMeta):
"""Represents events"""
REGISTRATION_NOT_NEEDED = -1
REGISTRATION_NOT_YET_OPEN = 0
REGISTRATION_OPEN = 1
REGISTRATION_OPEN_NO_CANCEL = 2
REGISTRATION_CLOSED = 3
REGISTRATION_CLOSED_CANCEL_ONLY = 4
DEFAULT_NO_REGISTRATION_MESSAGE = _('No registration required')
title = MultilingualField(
......@@ -100,15 +108,42 @@ class Event(models.Model, metaclass=ModelTranslateMeta):
published = models.BooleanField(_("published"), default=False)
def after_cancel_deadline(self):
return self.cancel_deadline <= timezone.now()
def registration_required(self):
return bool(self.registration_start) or bool(self.registration_end)
def has_fields(self):
return self.registrationinformationfield_set.count() > 0
def reached_participants_limit(self):
return self.max_participants <= self.registration_set.count()
@property
def status(self):
now = timezone.now()
if bool(self.registration_start) or bool(self.registration_end):
if now <= self.registration_start:
return Event.REGISTRATION_NOT_YET_OPEN
elif self.registration_end <= now < self.cancel_deadline:
return Event.REGISTRATION_CLOSED_CANCEL_ONLY
elif self.cancel_deadline <= now < self.registration_end:
return Event.REGISTRATION_OPEN_NO_CANCEL
elif now >= self.registration_end and now >= self.cancel_deadline:
return Event.REGISTRATION_CLOSED
else:
return Event.REGISTRATION_OPEN
else:
return Event.REGISTRATION_NOT_NEEDED
def clean(self):
super().clean()
errors = {}