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