Commit 2aec63a9 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg

Working basic registration

parent 302f4946
......@@ -11,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(
......@@ -101,9 +108,34 @@ class Event(models.Model, metaclass=ModelTranslateMeta):
published = models.BooleanField(_("published"), default=False)
def after_deadline(self):
return self.registration_end < 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()
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 = {}
......@@ -127,6 +159,11 @@ class Event(models.Model, metaclass=ModelTranslateMeta):
{'registration_end': _(
"If registration is required, you need an end of "
"registration")})
if not self.cancel_deadline:
errors.update(
{'cancel_deadline': _(
"If registration is required, you need a deadline for "
"the cancellation")})
if self.registration_start and self.registration_end and (
self.registration_start >= self.registration_end):
message = _('Registration start should be before '
......@@ -237,7 +274,12 @@ class Registration(models.Model):
def is_late_cancellation(self):
return (self.date_cancelled and
self.date_cancelled > self.event.cancel_deadline)
self.date_cancelled > self.event.cancel_deadline and
self.event.registration_set.filter(
(Q(date_cancelled__gte=self.date_cancelled) |
Q(date_cancelled=None)) &
Q(date_lte=self.date)
) < self.event.max_participants)
def is_registered(self):
return self.date_cancelled is None
......@@ -248,7 +290,7 @@ class Registration(models.Model):
return max(self.event.registration_set.filter(
date_cancelled=None,
id__lte=self.id
date__lte=self.date
).count() - self.event.max_participants, 0)
def clean(self):
......
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{{ event.title }} — {% trans "Calendar"|capfirst %} — {{ block.super }}{% endblock %}
{% block body %}
<h1>{{ event.title }}</h1>
<p class="tcenter">{{ event.description }}</p>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
<button type="button" class="close"><span class="alert-icon-close"></span></button>
</div>
{% endfor %}
{% endif %}
<div class="clearfix row">
<div class="span6">
<table class="table borderless">
......@@ -45,7 +56,7 @@
{{ counter }} registrations
{% endblocktrans %}
{% if event.max_participants > 0 %}
<i>({{ event.max_participants }} {% trans "max"|capfirst %})</i>
<i>({{ event.max_participants }} {% trans "max" %})</i>
{% with prc=registration_percentage %}
<div class="progress progress-style1">
<div class="bar trans-enabled" style="width: {{ prc }}%;" data-width="{{ prc }}%"></div>
......@@ -116,30 +127,31 @@
<tr>
<td></td>
<td>
</td>
<td>
{# <?php if($show_button): ?>#}
{##}
{# <form class="form-inline pull-left" method="post" action="<?php echo $this->action('/register'); ?>">#}
{# <?php echo $form->hidden('activity_id', $activity->id); ?>#}
{# <?php echo $form->hidden('intent', $intent); ?>#}
{# <?php if($afterDeadline): ?>#}
{# <?php echo $form->submit('submit', $button_text, ['class' => 'btn btn-style1', 'onclick' => 'return confirm(\'' . $confirmText . '\');']); ?>#}
{# <?php else: ?>#}
{# <?php echo $form->submit('submit', $button_text, ['class' => 'btn btn-style1']); ?>#}
{# <?php endif; ?>#}
{# <?php echo $csrf_token; ?>#}
{# </form>#}
{##}
{# <?php endif; ?>#}
{# <?php if($registered && ($registration_status === ActivityModel::REGISTRATION_OPEN || $registration_status === ActivityModel::REGISTRATION_CLOSED_REGISTER_ONLY) && $registration->isRegisteredExcludeCoolDown() && count($activity->getExtraFields()) > 0):?>#}
{# <form class="form-inline pull-left" method="post" action="<?php echo $this->action('/register'); ?>">#}
{# <?php echo $form->hidden('activity_id', $activity->id);?>#}
{# <?php echo $form->hidden('intent', 'prompt_update_screen');?>#}
{# <?php echo $form->submit('submit', 'Bijwerken', ['class' => 'btn btn-style1']); ?>#}
{# <?php echo $csrf_token; ?>#}
{# </form>#}
{# <?php endif; ?>#}
{% if request.user.is_authenticated %}
{% if event.status == event.REGISTRATION_OPEN or event.status == event.REGISTRATION_CLOSED_CANCEL_ONLY %}
{% if registration is None or registration.date_cancelled is not None %}
{% if event.status == event.REGISTRATION_OPEN %}
<a class="btn btn-style1" href="{% url 'events:registration' event.id 'register' %}">
{% if event.reached_participants_limit %}
{% trans "Put me on the waiting list" %}
{% else %}
{% trans "Register" %}
{% endif %}
</a>
{% endif %}
{% elif registration is not None and registration.date_cancelled is None %}
{# TODO: Specific message to accept costs when cancelling after the deadline, unless member is on the waiting list #}
<a class="btn btn-style1" href="{% url 'events:registration' event.id 'cancel' %}" onclick="return confirm('{% trans "Are you sure you want to cancel your registration?" %}');">{% trans "Cancel registration" %}</a>
{% endif %}
{% endif %}
{% if event.status == event.REGISTRATION_OPEN or event.status == event.REGISTRATION_OPEN_NO_CANCEL %}
{% if registration is not None and registration.date_cancelled is None and event.has_fields %}
<a class="btn btn-style1" href="{% url 'events:registration' event.id 'update' %}">{% trans "Update information" %}</a>
{% endif %}
{% endif %}
{% else %}
<a class="btn btn-style1" href="{% url 'login' %}?next={{ request.path }}">{% trans "Login" %}</a>
{% endif %}
</td>
</tr>
<tr>
......@@ -147,35 +159,21 @@
</td>
<td>
<em>
{% if not request.user.is_authenticated %}
{% if not request.user.is_authenticated %}
{% trans "You have to log in before you can register for this event." %}
{% elif event.status == event.REGISTRATION_NOT_YET_OPEN %}
{% blocktrans with datetime=event.registration_start %}Registration will open {{ datetime }}{% endblocktrans %}
{% elif event.status == event.REGISTRATION_OPEN_NO_CANCEL %}
{% blocktrans with costs=event.costs %}Cancellation isn't possible anymore without having to pay the full costs of {{ costs }}{% endblocktrans %}
{% elif event.status == event.REGISTRATION_CLOSED or event.status == event.REGISTRATION_CLOSED_CANCEL_ONLY %}
{% blocktrans %}Registration is not possible anymore.{% endblocktrans %}
{% elif status == event.REGISTRATION_NOT_NEEDED %}
{% if event.no_registration_message %}
{{ event.no_registration_message }}
{% else %}
{% trans "No registration required" %}
{% endif %}
{# Todo implement aanmeldtekst #}
{# <?php if (!$user->isLoggedIn()):?>#}
{# <?php elseif($registered && $registration->isInCoolDown()): ?>#}
{# <script>#}
{# window.onload = function () {#}
{# startTimer("<?= (new \DateTime($registration->canceled))->format("Y/m/d H:i:s");?>", document.querySelector('#events_cool_down_timer'));#}
{# };#}
{# </script>#}
{# <span id="events_cool_down_text" title="Binnen de aangegeven hoeveelheid tijd kun je je afmelding annuleren door je opnieuw aan te melden. In dat geval raak je je oude plek niet kwijt.">Je hebt nog <span id="events_cool_down_timer" >een onbekende hoeveelheid tijd</span> om je afmelding ongedaan te maken.</span>#}
{# <?php elseif($registration_status === ActivityModel::REGISTRATION_NOT_NEEDED): ?>#}
{# <?php if($activity->registration_not_needed_message !== null) : ?>#}
{# <?php echo $activity->registration_not_needed_message; ?>#}
{# <?php else: ?>#}
{# Aanmelden hoeft niet#}
{# <?php endif; ?>#}
{# <?php elseif($registration_status === ActivityModel::REGISTRATION_NOT_YET_OPEN): ?>#}
{# Aanmelden kan vanaf <?php echo $activity->formatDate('begin_registration'); ?>#}
{# <?php elseif($registration && $registration->isRegisteredExcludeCoolDown() && ($registration_status === ActivityModel::REGISTRATION_CLOSED || $registration_status === ActivityModel::REGISTRATION_CLOSED_REGISTER_ONLY)): ?>#}
{# <?php // You are registered, but you can either: do nothing, or only register, so no cancelling ?>#}
{# Afmelden kan niet meer, tenzij je de boete betaalt <?php echo $costText; ?>.#}
{# <?php elseif(!($registered && $registration->isRegisteredExcludeCoolDown()) && ($registration_status === ActivityModel::REGISTRATION_CLOSED || $registration_status === ActivityModel::REGISTRATION_CLOSED_CANCEL_ONLY)): ?>#}
{# <?php // You are not registered, but you can either: do nothing, or only cancel, so no registering ?>#}
{# Aanmelden kan niet meer#}
{# <?php endif; ?>#}
{% endif %}
</em>
</td>
</tr>
......@@ -204,7 +202,7 @@
{% if user.is_authenticated and registrations|length > 0 %}
<div class="member-directory">
<h1 class="midhead">Aanmeldingen</h1>
<h1 class="midhead">{% trans "Registrations" %}</h1>
<ul class="member-directory row">
{% for registration in registrations %}
<li class="post member-item span3 has-overlay{% if forloop.counter0|divisibleby:4 %} first-child{% endif %}">
......
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{{ event.title }} — {% trans "Calendar"|capfirst %} — {{ block.super }}{% endblock %}
{% block body %}
<h1>{{ event.title }}</h1>
{% endblock %}
\ No newline at end of file
......@@ -2,6 +2,8 @@
{% load i18n static compress %}}
{% get_current_language as LANGUAGE_CODE %}
{% block title %}{% trans "Calendar"|capfirst %} — {{ block.super }}{% endblock %}
{% block css_head %}
{{ block.super }}
{% compress css %}
......
......@@ -10,7 +10,9 @@ from . import views
urlpatterns = [
url(r'admin/(?P<event_id>\d+)/$', views.admin_details, name='admin-details'),
url(r'admin/(?P<event_id>\d+)/export/$', views.export, name='export'),
url(r'^(?P<event_id>\d+)$', views.event, name='event'),
url(r'^(?P<event_id>\d+)/$', views.event, name='event'),
url(r'^(?P<event_id>\d+)/registration/(?P<action>[-\w]+)/$',
views.registration, name='registration'),
url(r'^$', views.index, name='index'),
url(r'^ical/nl.ics', EventFeed(lang='nl'), name='ical-nl'),
url(r'^ical/en.ics', EventFeed(), name='ical-en'),
......
......@@ -2,11 +2,13 @@ import csv
from datetime import timedelta
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.decorators import permission_required, login_required
from django.utils import timezone
from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
from .models import Event, Registration
......@@ -79,6 +81,7 @@ def export(request, event_id):
return item['date'] - timedelta(days=10000)
else:
return item['date']
for row in sorted(rows, key=order):
writer.writerow(row)
......@@ -112,7 +115,7 @@ def event(request, event_id):
}
if event.max_participants:
perc = 100.0*len(registrations)/event.max_participants
perc = 100.0 * len(registrations) / event.max_participants
context['registration_percentage'] = perc
try:
......@@ -121,7 +124,86 @@ def event(request, event_id):
member=request.user.member
)
context['registration'] = registration
except:
except Registration.DoesNotExist:
pass
return render(request, 'events/event.html', context)
@login_required
def registration(request, event_id, action=None):
event = get_object_or_404(
Event.objects.filter(published=True),
pk=event_id
)
if event.registration_required():
try:
registration = Registration.objects.get(
event=event,
member=request.user.member
)
except Registration.DoesNotExist:
registration = None
success_message = None
error_message = None
show_fields = False
if action == 'register':
if event.has_fields():
show_fields = True
if registration is None:
registration = Registration()
registration.event = event
registration.member = request.user.member
elif registration.date_cancelled is not None:
registration.date = timezone.now()
registration.date_cancelled = None
else:
error_message = _("You were already registered.")
if error_message is None:
success_message = _("Registration successful")
elif (action == 'update' and event.has_fields() and
registration is not None):
show_fields = True
elif action == 'cancel':
if (registration is not None and
registration.date_cancelled is None):
registration.date_cancelled = timezone.now()
success_message = _("Registration successfully cancelled")
else:
error_message = _("You were not registered for this event.")
if show_fields:
# saved = False
#
# if request.POST:
# form = AddExamForm(request.POST, request.FILES)
# if form.is_valid():
# saved = True
# obj = form.save(commit=False)
# obj.uploader = request.user
# obj.uploader_date = datetime.now()
# obj.save()
#
# form = AddExamForm()
# form.exam_date = datetime.now()
# else:
# obj = Exam()
# if id is not None:
# obj.course = Course.objects.get(id=id)
# form = AddExamForm(instance=obj)
# form.exam_date = datetime.now()
context = {'event': event}
return render(request, 'events/event_fields.html', context)
else:
if success_message is not None:
messages.success(request, success_message)
elif error_message is not None:
messages.error(request, error_message)
registration.save()
return redirect(event)
......@@ -67,7 +67,7 @@
{% if not user.is_authenticated %}
<div class="btn-group open" id="account-menu">
<a class="btn btn-default" href="{% url 'login' %}"><i class="fa fa-user"></i>{% trans "Login" %}</a>
<a class="btn btn-default" href="{% url 'login' %}?next={{ request.path }}"><i class="fa fa-user"></i>{% trans "Login" %}</a>
</div>
{% else %}
<div class="btn-group" id="account-menu">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment