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

18
from thaliawebsite.templatetags import baseurl
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


@staff_member_required
@permission_required('events.change_event')
def admin_details(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
27

Thom Wiggers's avatar
Thom Wiggers committed
28
    if (not request.user.is_superuser and
29
            not request.user.has_perm('events.override_organiser')):
30
31
32
33
34
35
        committees = request.user.member.get_committees().filter(
            pk=event.organiser.pk).count()

        if committees == 0:
            raise PermissionDenied

Thom Wiggers's avatar
Thom Wiggers committed
36
37
38
39
40
41
42
43
44
    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
45
46


47
48
49
50
51
52
53
54
55
56
57
@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)
        obj = Registration.objects.get(event=event_id, pk=id)
58
59
60
        if action == 'present':
            checked = json.loads(request.POST.get("checked"))
            if checked is not None:
61
                obj.present = checked
62
63
64
65
66
67
                obj.save()
        elif action == 'payment':
            value = request.POST.get("value")
            if value is not None:
                obj.payment = value
                obj.save()
68
69
70
71
72
73
    except Registration.DoesNotExist:
        data['success'] = False

    return JsonResponse(data)


Thom Wiggers's avatar
Thom Wiggers committed
74
75
76
77
78
79
80
81
@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 = (
82
83
        ['name', 'email', 'paid', 'present',
         'status', 'phone number'] +
84
        [field.name for field in extra_fields] +
85
        ['date', 'date cancelled'])
Thom Wiggers's avatar
Thom Wiggers committed
86
87

    rows = []
88
89
    if event.price == 0:
        header_fields.remove('paid')
Thom Wiggers's avatar
Thom Wiggers committed
90
91
92
93
94
    for i, registration in enumerate(registrations):
        if registration.member:
            name = registration.member.get_full_name()
        else:
            name = registration.name
95
        status = pgettext_lazy('registration status', 'registered')
Thom Wiggers's avatar
Thom Wiggers committed
96
97
        cancelled = None
        if registration.date_cancelled:
98
99
100
101
102
103

            if registration.is_late_cancellation():
                status = pgettext_lazy('registration status',
                                       'late cancellation')
            else:
                status = pgettext_lazy('registration status', 'cancelled')
Thom Wiggers's avatar
Thom Wiggers committed
104
            cancelled = timezone.localtime(registration.date_cancelled)
105
106

        elif registration.queue_position():
107
            status = pgettext_lazy('registration status', 'waiting')
Thom Wiggers's avatar
Thom Wiggers committed
108
109
        data = {
            'name': name,
110
111
112
113
114
115
            'date': timezone.localtime(registration.date
                                       ).strftime("%Y-%m-%d %H:%m"),
            'present': _('Yes') if registration.present else '',
            'phone number': (registration.member.phone_number
                             if registration.member
                             else ''),
Thom Wiggers's avatar
Thom Wiggers committed
116
117
118
119
            'email': (registration.member.user.email
                      if registration.member
                      else ''),
            'status': status,
120
            'date cancelled': cancelled,
Thom Wiggers's avatar
Thom Wiggers committed
121
        }
122
        if event.price > 0:
123
            if registration.payment == 'cash_payment':
124
                data['paid'] = _('Cash')
125
            elif registration.payment == 'pin_payment':
126
                data['paid'] = _('Pin')
127
            else:
128
                data['paid'] = _('No')
129

Thom Wiggers's avatar
Thom Wiggers committed
130
131
132
133
134
135
136
137
        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()

138
139
140
141
142
143
144
    rows = sorted(rows,
                  key=lambda row:
                  (row['status'] == pgettext_lazy('registration status',
                                                  'late cancellation'),
                   row['date']),
                  reverse=True,
                  )
145

146
147
    for row in rows:
        writer.writerow(row)
Thom Wiggers's avatar
Thom Wiggers committed
148
149
150
151

    response['Content-Disposition'] = (
        'attachment; filename="{}.csv"'.format(slugify(event.title)))
    return response
Luuk Scholten's avatar
Luuk Scholten committed
152
153


154
155
156
157
158
159
160
161
162
@staff_member_required
@permission_required('events.change_event')
def export_email(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
    registrations = event.registration_set.filter(
        date_cancelled=None).prefetch_related('member__user')
    registrations = registrations[:event.max_participants]
    addresses = [r.member.user.email for r in registrations if r.member]
    no_addresses = [r.name for r in registrations if not r.member]
163
164
165
    return render(request, 'events/admin/email_export.html',
                  {'event': event, 'addresses': addresses,
                   'no_addresses': no_addresses})
166
167


Luuk Scholten's avatar
Luuk Scholten committed
168
169
170
171
172
173
174
175
176
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
    })
177
178
179
180
181
182
183


def event(request, event_id):
    event = get_object_or_404(
        Event.objects.filter(published=True),
        pk=event_id
    )
184
185
    registrations = event.registration_set.filter(
        date_cancelled=None)[:event.max_participants]
186
187
188
189
190
191
192
193

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

    if event.max_participants:
194
        perc = 100.0 * len(registrations) / event.max_participants
195
196
        context['registration_percentage'] = perc

197
    registration = None
198
199
200
201
202
203
    try:
        registration = Registration.objects.get(
            event=event,
            member=request.user.member
        )
        context['registration'] = registration
204
    except (Registration.DoesNotExist, AttributeError):
205
206
        pass

207
208
209
210
211
212
213
214
215
216
    context['user_registration_allowed'] = (
        request.user.is_authenticated and request.user.member is not None and
        request.user.member.current_membership is not None and
        request.user.member.can_attend_events)
    context['can_create_event_registration'] = (
        (registration is None or registration.date_cancelled is not None) and
        (event.status == event.REGISTRATION_OPEN or
         event.status == event.REGISTRATION_OPEN_NO_CANCEL))
    context['can_cancel_event_registration'] = (
        registration is not None and registration.date_cancelled is None and
217
218
        event.status != event.REGISTRATION_NOT_NEEDED and
        event.status != event.REGISTRATION_NOT_YET_OPEN)
219
220
221
222
    context['can_update_event_registration'] = (
        event.status == event.REGISTRATION_OPEN or
        event.status == event.REGISTRATION_OPEN_NO_CANCEL)

223
    return render(request, 'events/event.html', context)
224
225


226
def _send_queue_mail(request, event):
227
    if (event.max_participants is not None and
228
        Registration.objects
229
230
231
232
233
234
235
236
237
                    .filter(event=event, date_cancelled=None)
                    .count() > event.max_participants):
        # 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

238
239
240
        if not first_waiting_member:
            return

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

243
244
        base_url = baseurl.baseurl({'request': request})

245
246
        with translation.override(first_waiting_member.language):
            subject = _("[THALIA] Notification about your "
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
247
                        "registration for '{}'").format(
248
249
250
251
                event.title)
            text_message = text_template.render({
                'event': event,
                'reg': first_waiting,
252
                'base_url': base_url,
253
254
255
256
257
258
259
260
261
262
263
264
                'member': first_waiting_member
            })

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


def _show_registration_fields(request, event, reg, action):
    form = FieldsForm(registration=reg)
265
266
    # check length, since request is always post, length > 1 means that
    # there are more posted fields than just the CSRF token
267
    if request.method == 'POST' and len(request.POST) > 1:
268
269
270
271
272
273
274
        form = FieldsForm(request.POST, registration=reg)
        if form.is_valid():
            reg.save()
            form_field_values = form.field_values()
            for field in form_field_values:
                if (field['field'].type ==
                        RegistrationInformationField.INTEGER_FIELD and
275
                        field['value'] is None):
276
277
278
279
                    field['value'] = 0
                field['field'].set_value_for(reg,
                                             field['value'])

280
281
            return redirect(event)

282
283
284
285
286
287
288
289
290
    return render(request, 'events/event_fields.html',
                  {'event': event, 'form': form, 'action': action})


def _registration_register(request, event, reg):
    if reg is None:
        reg = Registration()
        reg.event = event
        reg.member = request.user.member
291
        messages.success(request, _("Registration successful."))
292
        reg.save()
293
294
295
296
297
298
299
300
301
        if event.has_fields():
            return _show_registration_fields(request, event, reg, 'register')
    elif reg.date_cancelled is not None:
        if reg.is_late_cancellation():
            messages.error(request, _("You cannot re-register anymore since "
                                      "you've cancelled after the deadline."))
        else:
            reg.date = timezone.now()
            reg.date_cancelled = None
302
            messages.success(request, _("Registration successful."))
303
            reg.save()
304
305
306
            if event.has_fields():
                return _show_registration_fields(request, event, reg,
                                                 'register')
307
308
    elif event.has_fields():
        return _show_registration_fields(request, event, reg, 'register')
309
310
311
    elif not reg.member.can_attend_events:
        messages.error(request, _("You may not register"))
    else:
312
313
314
315
316
317
318
        storage = messages.get_messages(request)
        was_success = False
        for message in storage:
            was_success = message.message == _("Registration successful.")
        storage.used = False
        if not was_success:
            messages.error(request, _("You were already registered."))
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

    return redirect(event)


def _registration_update(request, event, reg):
    if not event.has_fields():
        return redirect(event)
    if reg is None:
        messages.error(request, _("You are not registered for this event."))
        return redirect(event)

    return _show_registration_fields(request, event, reg, 'update')


def _registration_cancel(request, event, reg):
    if reg is None or reg.date_cancelled is not None:
        messages.error(request, _("You are not registered for this event."))
    else:
337
        if reg.queue_position() == 0:
338
            _send_queue_mail(request, event)
339

340
341
342
343
344
345
346
347
348
349
350
351
        # 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.
        reg.date_cancelled = timezone.now()
        reg.save()

        messages.success(request, _("Registration successfully cancelled."))

    return redirect(event)


352
353
354
355
356
357
358
@login_required
def registration(request, event_id, action=None):
    event = get_object_or_404(
        Event.objects.filter(published=True),
        pk=event_id
    )

359
    if (event.status != Event.REGISTRATION_NOT_NEEDED and
360
361
            request.user.member.current_membership is not None and
            request.user.member.can_attend_events):
362
        try:
363
            reg = Registration.objects.get(
364
365
366
367
                event=event,
                member=request.user.member
            )
        except Registration.DoesNotExist:
368
369
            reg = None

370
        if request.method.lower() == 'post':
371
372
373
374
            if action == 'register' and (
                event.status == Event.REGISTRATION_OPEN or
                event.status == Event.REGISTRATION_OPEN_NO_CANCEL
            ):
375
                return _registration_register(request, event, reg)
376
377
378
            elif (action == 'update' and
                  (event.status == Event.REGISTRATION_OPEN or
                   event.status == Event.REGISTRATION_OPEN_NO_CANCEL)):
379
                return _registration_update(request, event, reg)
380
            elif action == 'cancel':
381
                return _registration_cancel(request, event, reg)
382

383
    return redirect(event)
384
385
386
387
388
389


@staff_member_required
@permission_required('events.change_event')
def all_present(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
390
391
392
393
394
395
396
397
398

    if event.max_participants is None:
        registrations_query = event.registration_set.filter(
            date_cancelled=None)
    else:
        registrations_query = (event.registration_set
                               .filter(date_cancelled=None)
                               .order_by('date')[:event.max_participants])

399
    event.registration_set.filter(pk__in=registrations_query).update(
400
        present=True, payment='cash_payment')
401

402
    return HttpResponseRedirect('/events/admin/{}'.format(event_id))