views.py 12.1 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 .forms import FieldsForm
19
from .models import Event, Registration, RegistrationInformationField
Thom Wiggers's avatar
Thom Wiggers committed
20
21
22
23
24
25


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

27
28
    if (not request.user.is_superuser and event.organiser is not None and
            not request.user.has_perm('events.override_organiser')):
29
30
31
32
33
34
        committees = request.user.member.get_committees().filter(
            pk=event.organiser.pk).count()

        if committees == 0:
            raise PermissionDenied

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


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
@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
70
71
72
73
74
75
76
77
@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 = (
78
79
        ['name', 'email', 'paid', 'present',
         'status', 'phone number'] +
80
        [field.name for field in extra_fields] +
81
        ['date', 'date cancelled'])
Thom Wiggers's avatar
Thom Wiggers committed
82
83

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

            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
100
            cancelled = timezone.localtime(registration.date_cancelled)
101
102

        elif registration.queue_position():
103
            status = pgettext_lazy('registration status', 'waiting')
Thom Wiggers's avatar
Thom Wiggers committed
104
105
        data = {
            'name': name,
106
107
108
109
110
111
            '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
112
113
114
115
            'email': (registration.member.user.email
                      if registration.member
                      else ''),
            'status': status,
116
            'date cancelled': cancelled,
Thom Wiggers's avatar
Thom Wiggers committed
117
        }
118
119
120
        if event.price > 0:
            data['paid'] = _('Yes') if registration.paid else ''

Thom Wiggers's avatar
Thom Wiggers committed
121
122
123
124
125
126
127
128
        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()

129
130
131
132
133
134
135
    rows = sorted(rows,
                  key=lambda row:
                  (row['status'] == pgettext_lazy('registration status',
                                                  'late cancellation'),
                   row['date']),
                  reverse=True,
                  )
136

137
138
    for row in rows:
        writer.writerow(row)
Thom Wiggers's avatar
Thom Wiggers committed
139
140
141
142

    response['Content-Disposition'] = (
        'attachment; filename="{}.csv"'.format(slugify(event.title)))
    return response
Luuk Scholten's avatar
Luuk Scholten committed
143
144
145
146
147
148
149
150
151
152
153


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
    })
154
155
156
157
158
159
160


def event(request, event_id):
    event = get_object_or_404(
        Event.objects.filter(published=True),
        pk=event_id
    )
161
162
    registrations = event.registration_set.filter(
        date_cancelled=None)[:event.max_participants]
163
164
165
166
167
168
169
170

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

    if event.max_participants:
171
        perc = 100.0 * len(registrations) / event.max_participants
172
173
174
175
176
177
178
179
        context['registration_percentage'] = perc

    try:
        registration = Registration.objects.get(
            event=event,
            member=request.user.member
        )
        context['registration'] = registration
180
    except (Registration.DoesNotExist, AttributeError):
181
182
183
        pass

    return render(request, 'events/event.html', context)
184
185


186
187
def _send_queue_mail(event):
    if (event.max_participants is not None and
188
        Registration.objects
189
190
191
192
193
194
195
196
197
198
199
200
201
                    .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

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

        with translation.override(first_waiting_member.language):
            subject = _("[THALIA] Notification about your "
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
202
                        "registration for '{}'").format(
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
                event.title)
            text_message = text_template.render({
                'event': event,
                'reg': first_waiting,
                '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)
    if request.POST:
        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
227
                        field['value'] is None):
228
229
230
231
232
233
234
235
236
237
238
239
240
                    field['value'] = 0
                field['field'].set_value_for(reg,
                                             field['value'])

    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
241
        messages.success(request, _("Registration successful."))
242
243
244
245
246
247
248
249
250
251
252
        if event.has_fields():
            return _show_registration_fields(request, event, reg, 'register')
        else:
            reg.save()
    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
253
            messages.success(request, _("Registration successful."))
254
255
256
257
258
259
260
261
            if event.has_fields():
                return _show_registration_fields(request, event, reg,
                                                 'register')
            else:
                reg.save()
    elif not reg.member.can_attend_events:
        messages.error(request, _("You may not register"))
    else:
262
263
264
265
266
267
268
        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."))
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300

    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:
        # 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()

        _send_queue_mail(event)

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

    return redirect(event)


301
302
303
304
305
306
307
@login_required
def registration(request, event_id, action=None):
    event = get_object_or_404(
        Event.objects.filter(published=True),
        pk=event_id
    )

308
    if (event.status != Event.REGISTRATION_NOT_NEEDED and
309
310
            request.user.member.current_membership is not None and
            request.user.member.can_attend_events):
311
        try:
312
            reg = Registration.objects.get(
313
314
315
316
                event=event,
                member=request.user.member
            )
        except Registration.DoesNotExist:
317
318
            reg = None

319
        if request.method.lower() == 'post':
320
321
322
323
            if action == 'register' and (
                event.status == Event.REGISTRATION_OPEN or
                event.status == Event.REGISTRATION_OPEN_NO_CANCEL
            ):
324
                return _registration_register(request, event, reg)
325
326
327
            elif (action == 'update' and
                  (event.status == Event.REGISTRATION_OPEN or
                   event.status == Event.REGISTRATION_OPEN_NO_CANCEL)):
328
                return _registration_update(request, event, reg)
329
            elif action == 'cancel':
330
                return _registration_cancel(request, event, reg)
331

332
    return redirect(event)
333
334
335
336
337
338


@staff_member_required
@permission_required('events.change_event')
def all_present(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
339
340
341
342
343
344
345
346
347

    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])

348
349
    event.registration_set.filter(pk__in=registrations_query).update(
        present=True, paid=True)
350

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