views.py 11.6 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.mail import EmailMessage
8
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
9
from django.shortcuts import get_object_or_404, redirect, render
10
11
12
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
13
from django.utils.text import slugify
14
15
16
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
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
26
27
28
29
30
31
32
33
34


@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
35
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
@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
61
62
63
64
65
66
67
68
@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 = (
69
70
        ['name', 'email', 'paid', 'present',
         'status', 'phone number'] +
71
        [field.name for field in extra_fields] +
72
        ['date', 'date cancelled'])
Thom Wiggers's avatar
Thom Wiggers committed
73
74

    rows = []
75
76
    if event.price == 0:
        header_fields.remove('paid')
Thom Wiggers's avatar
Thom Wiggers committed
77
78
79
80
81
    for i, registration in enumerate(registrations):
        if registration.member:
            name = registration.member.get_full_name()
        else:
            name = registration.name
82
        status = pgettext_lazy('registration status', 'registered')
Thom Wiggers's avatar
Thom Wiggers committed
83
84
        cancelled = None
        if registration.date_cancelled:
85
86
87
88
89
90

            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
91
            cancelled = timezone.localtime(registration.date_cancelled)
92
93

        elif registration.queue_position():
94
            status = pgettext_lazy('registration status', 'waiting')
Thom Wiggers's avatar
Thom Wiggers committed
95
96
        data = {
            'name': name,
97
98
99
100
101
102
            '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
103
104
105
106
            'email': (registration.member.user.email
                      if registration.member
                      else ''),
            'status': status,
107
            'date cancelled': cancelled,
Thom Wiggers's avatar
Thom Wiggers committed
108
        }
109
110
111
        if event.price > 0:
            data['paid'] = _('Yes') if registration.paid else ''

Thom Wiggers's avatar
Thom Wiggers committed
112
113
114
115
116
117
118
119
        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()

120
121
122
123
124
125
126
    rows = sorted(rows,
                  key=lambda row:
                  (row['status'] == pgettext_lazy('registration status',
                                                  'late cancellation'),
                   row['date']),
                  reverse=True,
                  )
127

128
129
    for row in rows:
        writer.writerow(row)
Thom Wiggers's avatar
Thom Wiggers committed
130
131
132
133

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


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
    })
145
146
147
148
149
150
151


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

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

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

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

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


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

184
    if (event.status != Event.REGISTRATION_NOT_NEEDED and
185
186
            request.user.member.current_membership is not None and
            request.user.member.can_attend_events):
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
            elif not obj.member.can_attend_events:
                error_message = _("You may not register")
219
220
221
222
            else:
                error_message = _("You were already registered.")

            if error_message is None:
223
                success_message = _("Registration successful.")
224
225
226
227
228
        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)):
229
            show_fields = True
230
231
            success_message = _("Registration successfully updated.")
        elif action == 'cancel':
232
233
            if (obj is not None and
                    obj.date_cancelled is None):
234
                if (event.max_participants is not None and
235
236
237
                        (Registration.objects
                            .filter(event=event,
                                    date_cancelled=None).count()) >=
238
                        event.max_participants):
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
                    # 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]
                        )
263

264
265
266
267
268
                # 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()
269
                success_message = _("Registration successfully cancelled.")
270
271
272
273
            else:
                error_message = _("You were not registered for this event.")

        if show_fields:
274
275
276
            if request.POST:
                form = FieldsForm(request.POST, registration=obj)
                if form.is_valid():
277
                    obj.save()
278
279
                    form_field_values = form.field_values()
                    for field in form_field_values:
280
                        if (field['field'].type ==
281
282
                                RegistrationInformationField.INTEGER_FIELD and
                                field['value'] is None):
283
                            field['value'] = 0
284
285
286
287
288
289
290
291
292
293
294
295
                        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()
296

297
298
299
        if waiting_list_notification is not None:
            waiting_list_notification.send()

300
    return redirect(event)
301
302
303
304
305
306


@staff_member_required
@permission_required('events.change_event')
def all_present(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
307
308
309
310
311
312
313
314
315
316
317

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

    registrations_query.update(present=True, paid=True)

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