viewsets.py 6.23 KB
Newer Older
1
2
3
from datetime import datetime

from django.utils import timezone
4
from rest_framework import viewsets, filters
5
from rest_framework.decorators import list_route, detail_route
6
from rest_framework.exceptions import ParseError, PermissionDenied, NotFound
7
from rest_framework.generics import get_object_or_404
8
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin
9
10
11
12
13
from rest_framework.permissions import (
    IsAuthenticated,
    IsAdminUser,
    IsAuthenticatedOrReadOnly
)
14
from rest_framework.response import Response
15
from rest_framework.viewsets import GenericViewSet
16

17
from events import services
18
from events.api.permissions import UnpublishedEventPermissions
Luuk Scholten's avatar
Luuk Scholten committed
19
20
21
22
from events.api.serializers import (
    EventCalenderJSSerializer,
    UnpublishedEventSerializer,
    EventRetrieveSerializer,
23
    EventListSerializer,
24
25
    RegistrationListSerializer, RegistrationSerializer)
from events.exceptions import RegistrationError
26
from events.models import Event, Registration
27
28


29
30
31
32
33
34
35
36
37
38
39
40
41
def _extract_date_range(request):
    try:
        start = timezone.make_aware(
            datetime.strptime(request.query_params['start'], '%Y-%m-%d')
        )
        end = timezone.make_aware(
            datetime.strptime(request.query_params['end'], '%Y-%m-%d')
        )
    except:
        raise ParseError(detail='start or end query parameters invalid')
    return end, start


42
class EventViewset(viewsets.ReadOnlyModelViewSet):
43
    queryset = Event.objects.filter(end__gte=timezone.now(),
44
                                    published=True)
45
    permission_classes = [IsAuthenticated]
46
47
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = ('start', 'end')
48

49
50
51
52
53
54
55
    def get_serializer_class(self):
        if self.action == 'list':
            return EventListSerializer
        if self.action == 'retrieve':
            return EventRetrieveSerializer
        return EventCalenderJSSerializer

56
57
58
    def get_serializer_context(self):
        return super().get_serializer_context()

59
    @detail_route(methods=['get', 'post'])
60
    def registrations(self, request, pk):
61
        event = get_object_or_404(Event, pk=pk)
62
63
64
65

        if request.method.lower() == 'post':
            try:
                registration = services.create_registration(
66
                    request.member, event)
67
68
69
70
71
72
73
74
                serializer = RegistrationSerializer(
                    instance=registration,
                    context={'request': request}
                )
                return Response(status=201, data=serializer.data)
            except RegistrationError as e:
                raise PermissionDenied(detail=e)

75
76
        status = request.query_params.get('status', None)

77
78
        # Make sure you can only access other registrations when you have
        # the permissions to do so
79
        if not services.is_organiser(request.member, event):
80
81
            status = 'registered'

82
83
84
85
86
87
88
89
90
91
        queryset = Registration.objects.filter(event=pk)
        if status is not None:
            if status == 'queued':
                queryset = Registration.objects.filter(
                    event=pk, date_cancelled=None)[event.max_participants:]
            elif status == 'cancelled':
                queryset = Registration.objects.filter(
                    event=pk, date_cancelled__not=None)
            elif status == 'registered':
                queryset = Registration.objects.filter(
92
                    event=pk, date_cancelled=None)[:event.max_participants]
93

94
95
        serializer = RegistrationListSerializer(queryset, many=True,
                                                context={'request': request})
96
97
98

        return Response(serializer.data)

99
    @list_route(permission_classes=(IsAuthenticatedOrReadOnly,))
100
    def calendarjs(self, request):
101
        end, start = _extract_date_range(request)
102

103
        queryset = Event.objects.filter(
104
105
106
107
108
            end__gte=start,
            start__lte=end,
            published=True
        )

109
110
        serializer = EventCalenderJSSerializer(
                queryset, many=True, context={'member': request.member})
111
        return Response(serializer.data)
112
113
114
115
116

    @list_route(permission_classes=(IsAdminUser, UnpublishedEventPermissions,))
    def unpublished(self, request):
        end, start = _extract_date_range(request)

117
        queryset = Event.objects.filter(
118
119
120
121
122
            end__gte=start,
            start__lte=end,
            published=False
        )

123
124
        serializer = UnpublishedEventSerializer(
                queryset, many=True, context={'member': request.member})
125
        return Response(serializer.data)
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140


class RegistrationViewSet(GenericViewSet, RetrieveModelMixin,
                          UpdateModelMixin):
    queryset = Registration.objects.all()
    serializer_class = RegistrationSerializer
    permission_classes = [IsAuthenticated]

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['request'] = self.request
        return context

    def get_object(self):
        instance = super().get_object()
141
142
        if (instance.member.pk != self.request.member.pk and
                not services.is_organiser(self.request.member,
143
144
145
146
147
148
149
150
151
152
153
154
155
156
                                          instance.event)):
            raise NotFound()

        return instance

    # Always set instance so that OPTIONS call will show the info fields too
    def get_serializer(self, *args, **kwargs):
        if len(args) == 0 and "instance" not in kwargs:
            kwargs["instance"] = self.get_object()
        return super().get_serializer(*args, **kwargs)

    def perform_update(self, serializer):
        super().perform_update(serializer)
        registration = serializer.instance
157
        services.update_registration(registration.member,
158
159
160
                                     registration.event,
                                     serializer.field_values())
        serializer.information_fields = services.registration_fields(
161
            registration.member, registration.event)
162
163
164
165
166

    def destroy(self, request, pk=None, **kwargs):
        registration = self.get_object()
        try:
            services.cancel_registration(request,
167
                                         registration.member,
168
169
170
171
                                         registration.event)
            return Response(status=204)
        except RegistrationError as e:
            raise PermissionDenied(detail=e)