views.py 11.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 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
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
10
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
    if (event.status != Event.REGISTRATION_NOT_NEEDED and
186
187
            request.user.member.current_membership is not None and
            request.user.member.can_attend_events):
188
        try:
189
            obj = Registration.objects.get(
190
191
192
193
                event=event,
                member=request.user.member
            )
        except Registration.DoesNotExist:
194
            obj = None
195
196
197
198

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

207
208
209
210
211
212
213
214
215
216
217
            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
218
219
            elif not obj.member.can_attend_events:
                error_message = _("You may not register")
220
221
222
223
            else:
                error_message = _("You were already registered.")

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

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

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

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

299
    return redirect(event)
300
301
302
303
304
305
306
307
308
309
310
311


@staff_member_required
@permission_required('events.change_event')
def all_present(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
    registrations = event.registration_set.all()
    for registration in registrations:
        registration.present = True
        registration.paid = True
        registration.save()
    return HttpResponseRedirect('/events/admin/{}'.format(event_id))