views.py 10.5 KB
Newer Older
Thom Wiggers's avatar
Thom Wiggers committed
1
import csv
2
import json
Thom Wiggers's avatar
Thom Wiggers committed
3 4
from datetime import timedelta

5
from django.contrib import messages
Thom Wiggers's avatar
Thom Wiggers committed
6
from django.contrib.admin.views.decorators import staff_member_required
7
from django.contrib.auth.decorators import login_required, permission_required
8
from django.core.mail import EmailMessage
9 10
from django.http import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
11 12 13
from django.template import Context
from django.template.loader import get_template
from django.utils import timezone, translation
Thom Wiggers's avatar
Thom Wiggers committed
14
from django.utils.text import slugify
15 16 17
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import pgettext_lazy
from django.views.decorators.http import require_http_methods
Thom Wiggers's avatar
Thom Wiggers committed
18

19
from .forms import FieldsForm
20
from .models import Event, Registration, RegistrationInformationField
Thom Wiggers's avatar
Thom Wiggers committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35


@staff_member_required
@permission_required('events.change_event')
def admin_details(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
    n = event.max_participants
    registrations = list(event.registration_set.filter(date_cancelled=None))
    cancellations = event.registration_set.exclude(date_cancelled=None)
    return render(request, 'events/admin/details.html', {
        'event': event,
        'registrations': registrations[:n],
        'waiting': registrations[n:] if n else [],
        'cancellations': cancellations,
    })
Thom Wiggers's avatar
Thom Wiggers committed
36 37


38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
@staff_member_required
@permission_required('events.change_event')
@require_http_methods(["POST"])
def admin_change_registration(request, event_id, action=None):
    data = {
        'success': True
    }

    try:
        id = request.POST.get("id", -1)
        checked = json.loads(request.POST.get("checked"))
        obj = Registration.objects.get(event=event_id, pk=id)
        if checked is not None:
            if action == 'present':
                obj.present = checked
            elif action == 'paid':
                obj.paid = checked
            obj.save()
    except Registration.DoesNotExist:
        data['success'] = False

    return JsonResponse(data)


Thom Wiggers's avatar
Thom Wiggers committed
62 63 64 65 66 67 68 69
@staff_member_required
@permission_required('events.change_event')
def export(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
    extra_fields = event.registrationinformationfield_set.all()
    registrations = event.registration_set.all()

    header_fields = (
70 71 72 73
        ['name', 'paid', 'present', 'email',
         'phone number'] +
        [field.name for field in extra_fields] +
        ['status', 'date', 'date cancelled'])
Thom Wiggers's avatar
Thom Wiggers committed
74 75 76

    rows = []
    capacity = event.max_participants
77 78
    if event.price == 0:
        header_fields.remove('paid')
Thom Wiggers's avatar
Thom Wiggers committed
79 80 81 82 83
    for i, registration in enumerate(registrations):
        if registration.member:
            name = registration.member.get_full_name()
        else:
            name = registration.name
84
        status = pgettext_lazy('registration status', 'registered')
Thom Wiggers's avatar
Thom Wiggers committed
85 86 87 88
        cancelled = None
        if registration.date_cancelled:
            if capacity is not None:
                capacity += 1
89
            status = pgettext_lazy('registration status', 'cancelled')
Thom Wiggers's avatar
Thom Wiggers committed
90 91
            cancelled = timezone.localtime(registration.date_cancelled)
        elif capacity and i >= capacity:
92
            status = pgettext_lazy('registration status', 'waiting')
Thom Wiggers's avatar
Thom Wiggers committed
93 94
        data = {
            'name': name,
95 96 97 98 99 100 101
            'date': timezone.localtime(registration.date
                                       ).strftime("%Y-%m-%d %H:%m"),
            'dateobj': registration.date,
            'present': _('Yes') if registration.present else '',
            'phone number': (registration.member.phone_number
                             if registration.member
                             else ''),
Thom Wiggers's avatar
Thom Wiggers committed
102 103 104 105
            'email': (registration.member.user.email
                      if registration.member
                      else ''),
            'status': status,
106
            'date cancelled': cancelled,
Thom Wiggers's avatar
Thom Wiggers committed
107
        }
108 109 110
        if event.price > 0:
            data['paid'] = _('Yes') if registration.paid else ''

Thom Wiggers's avatar
Thom Wiggers committed
111 112 113 114 115 116 117 118 119 120
        data.update({field['field'].name: field['value'] for field in
                     registration.registration_information()})
        rows.append(data)

    response = HttpResponse(content_type='text/csv')
    writer = csv.DictWriter(response, header_fields)
    writer.writeheader()

    def order(item):
        if item['status'] == 'cancelled':
121
            return item['dateobj'] + timedelta(days=10000)
Thom Wiggers's avatar
Thom Wiggers committed
122
        elif item['status'] == 'registered':
123
            return item['dateobj'] - timedelta(days=10000)
Thom Wiggers's avatar
Thom Wiggers committed
124
        else:
125
            return item['dateobj']
126

Thom Wiggers's avatar
Thom Wiggers committed
127
    for row in sorted(rows, key=order):
128 129 130
        r = row.copy()
        del r['dateobj']
        writer.writerow(r)
Thom Wiggers's avatar
Thom Wiggers committed
131 132 133 134

    response['Content-Disposition'] = (
        'attachment; filename="{}.csv"'.format(slugify(event.title)))
    return response
Luuk Scholten's avatar
Luuk Scholten committed
135 136 137 138 139 140 141 142 143 144 145


def index(request):
    upcoming_activity = Event.objects.filter(
        published=True,
        end__gte=timezone.now()
    ).order_by('end').first()

    return render(request, 'events/index.html', {
        'upcoming_activity': upcoming_activity
    })
146 147 148 149 150 151 152


def event(request, event_id):
    event = get_object_or_404(
        Event.objects.filter(published=True),
        pk=event_id
    )
153 154
    registrations = event.registration_set.filter(
        date_cancelled=None)[:event.max_participants]
155 156 157 158 159 160 161 162

    context = {
        'event': event,
        'registrations': registrations,
        'user': request.user,
    }

    if event.max_participants:
163
        perc = 100.0 * len(registrations) / event.max_participants
164 165 166 167 168 169 170 171
        context['registration_percentage'] = perc

    try:
        registration = Registration.objects.get(
            event=event,
            member=request.user.member
        )
        context['registration'] = registration
172
    except (Registration.DoesNotExist, AttributeError):
173 174 175
        pass

    return render(request, 'events/event.html', context)
176 177 178 179 180 181 182 183 184


@login_required
def registration(request, event_id, action=None):
    event = get_object_or_404(
        Event.objects.filter(published=True),
        pk=event_id
    )

185 186
    if (event.status != Event.REGISTRATION_NOT_NEEDED and
            request.user.member.current_membership is not None):
187
        try:
188
            obj = Registration.objects.get(
189 190 191 192
                event=event,
                member=request.user.member
            )
        except Registration.DoesNotExist:
193
            obj = None
194 195 196 197

        success_message = None
        error_message = None
        show_fields = False
198
        waiting_list_notification = None
199 200 201 202
        if action == 'register' and (
            event.status == Event.REGISTRATION_OPEN or
            event.status == Event.REGISTRATION_OPEN_NO_CANCEL
        ):
203 204 205
            if event.has_fields():
                show_fields = True

206 207 208 209 210 211 212 213 214 215 216
            if obj is None:
                obj = Registration()
                obj.event = event
                obj.member = request.user.member
            elif obj.date_cancelled is not None:
                if obj.is_late_cancellation():
                    error_message = _("You cannot re-register anymore since "
                                      "you've cancelled after the deadline.")
                else:
                    obj.date = timezone.now()
                    obj.date_cancelled = None
217 218 219 220
            else:
                error_message = _("You were already registered.")

            if error_message is None:
221
                success_message = _("Registration successful.")
222 223 224 225 226
        elif (action == 'update' and
              event.has_fields() and
              obj is not None and
              (event.status == Event.REGISTRATION_OPEN or
               event.status == Event.REGISTRATION_OPEN_NO_CANCEL)):
227
            show_fields = True
228 229
            success_message = _("Registration successfully updated.")
        elif action == 'cancel':
230 231
            if (obj is not None and
                    obj.date_cancelled is None):
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
                # Prepare email to send to the first person on the waiting list
                first_waiting = (Registration.objects
                                 .filter(event=event, date_cancelled=None)
                                 .order_by('date')[event.max_participants])
                first_waiting_member = first_waiting.member

                text_template = get_template('events/email.txt')

                with translation.override(first_waiting_member.language):
                    subject = _("[THALIA] Notification about your "
                                "registration for '{}'").format(event.title)
                    text_message = text_template.render(Context({
                        'event': event,
                        'registration': first_waiting,
                        'member': first_waiting_member
                    }))

                    waiting_list_notification = EmailMessage(
                        subject,
                        text_message,
                        to=[first_waiting_member.user.email]
                    )

255 256 257 258 259
                # Note that this doesn't remove the values for the
                # information fields that the user entered upon registering.
                # But this is regarded as a feature, not a bug. Especially
                # since the values will still appear in the backend.
                obj.date_cancelled = timezone.now()
260
                success_message = _("Registration successfully cancelled.")
261 262 263 264
            else:
                error_message = _("You were not registered for this event.")

        if show_fields:
265 266 267
            if request.POST:
                form = FieldsForm(request.POST, registration=obj)
                if form.is_valid():
268
                    obj.save()
269 270
                    form_field_values = form.field_values()
                    for field in form_field_values:
271 272 273 274
                        if (field['field'].type ==
                                RegistrationInformationField.INTEGER_FIELD
                                and field['value'] is None):
                            field['value'] = 0
275 276 277 278 279 280 281 282 283 284 285 286
                        field['field'].set_value_for(obj,
                                                     field['value'])
            else:
                form = FieldsForm(registration=obj)
                context = {'event': event, 'form': form, 'action': action}
                return render(request, 'events/event_fields.html', context)

        if success_message is not None:
            messages.success(request, success_message)
        elif error_message is not None:
            messages.error(request, error_message)
        obj.save()
287

288 289 290
        if waiting_list_notification is not None:
            waiting_list_notification.send()

291
    return redirect(event)