serializers.py 13.5 KB
Newer Older
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
1
from django.templatetags.static import static
2
from django.urls import reverse
3
from django.utils import timezone
4
from django.utils.html import strip_tags
5
from html import unescape
6
from rest_framework import serializers
7
from rest_framework.fields import empty
8

Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
9
from thaliawebsite.api.services import create_image_thumbnail_dict
10
11
12
from events import services
from events.exceptions import RegistrationError
from events.models import Event, Registration, RegistrationInformationField
13
from pizzas.models import PizzaEvent
14
from thaliawebsite.settings import settings
15
16
17
18
19
20
21


class CalenderJSSerializer(serializers.ModelSerializer):
    class Meta:
        fields = (
            'start', 'end', 'all_day', 'is_birthday',
            'url', 'title', 'description',
22
23
            'backgroundColor', 'textColor', 'blank',
            'registered'
24
25
26
27
28
29
30
31
32
        )

    start = serializers.SerializerMethodField('_start')
    end = serializers.SerializerMethodField('_end')
    all_day = serializers.SerializerMethodField('_all_day')
    is_birthday = serializers.SerializerMethodField('_is_birthday')
    url = serializers.SerializerMethodField('_url')
    title = serializers.SerializerMethodField('_title')
    description = serializers.SerializerMethodField('_description')
33
34
35
    backgroundColor = serializers.SerializerMethodField('_background_color')
    textColor = serializers.SerializerMethodField('_text_color')
    blank = serializers.SerializerMethodField('_target_blank')
36
    registered = serializers.SerializerMethodField('_registered')
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

    def _start(self, instance):
        return timezone.localtime(instance.start)

    def _end(self, instance):
        return timezone.localtime(instance.end)

    def _all_day(self, instance):
        return False

    def _is_birthday(self, instance):
        return False

    def _url(self, instance):
        raise NotImplementedError

    def _title(self, instance):
        return instance.title

    def _description(self, instance):
57
        return unescape(strip_tags(instance.description))
58
59
60
61
62
63
64
65
66
67

    def _background_color(self, instance):
        pass

    def _text_color(self, instance):
        pass

    def _target_blank(self, instance):
        return False

68
69
70
    def _registered(self, instance):
        return None

71

72
class EventCalenderJSSerializer(CalenderJSSerializer):
73
74
75
76
    class Meta(CalenderJSSerializer.Meta):
        model = Event

    def _url(self, instance):
77
        return reverse('events:event', kwargs={'pk': instance.id})
78
79
80

    def _registered(self, instance):
        try:
81
82
            return services.is_user_registered(self.context['member'],
                                               instance)
83
84
        except AttributeError:
            return None
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99


class UnpublishedEventSerializer(CalenderJSSerializer):
    class Meta(CalenderJSSerializer.Meta):
        model = Event

    def _background_color(self, instance):
        return "#888888"

    def _text_color(self, instance):
        return "white"

    def _url(self, instance):
        return reverse('events:admin-details', kwargs={
            'event_id': instance.id})
Gijs Hendriksen's avatar
Gijs Hendriksen committed
100
101


102
class EventRetrieveSerializer(serializers.ModelSerializer):
Gijs Hendriksen's avatar
Gijs Hendriksen committed
103
104
    class Meta:
        model = Event
105
106
107
108
109
        fields = ('pk', 'title', 'description', 'start', 'end', 'organiser',
                  'category', 'registration_start', 'registration_end',
                  'cancel_deadline', 'location', 'map_location', 'price',
                  'fine', 'max_participants', 'num_participants', 'status',
                  'user_registration', 'registration_allowed',
110
                  'no_registration_message', 'has_fields', 'is_pizza_event')
AuckeBos's avatar
AuckeBos committed
111

112
    description = serializers.SerializerMethodField('_description')
113
114
115
116
117
    user_registration = serializers.SerializerMethodField('_user_registration')
    num_participants = serializers.SerializerMethodField('_num_participants')
    registration_allowed = serializers.SerializerMethodField(
        '_registration_allowed')
    has_fields = serializers.SerializerMethodField('_has_fields')
118
    is_pizza_event = serializers.SerializerMethodField('_is_pizza_event')
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    status = serializers.SerializerMethodField('_status')  # DEPRECATED

    REGISTRATION_NOT_NEEDED = -1
    REGISTRATION_NOT_YET_OPEN = 0
    REGISTRATION_OPEN = 1
    REGISTRATION_OPEN_NO_CANCEL = 2
    REGISTRATION_CLOSED = 3
    REGISTRATION_CLOSED_CANCEL_ONLY = 4

    """ DEPRECATED """

    def _status(self, instance):
        now = timezone.now()
        if instance.registration_start or instance.registration_end:
            if now <= instance.registration_start:
                return self.REGISTRATION_NOT_YET_OPEN
            elif (instance.registration_end <= now
                    < instance.cancel_deadline):
                return self.REGISTRATION_CLOSED_CANCEL_ONLY
            elif (instance.cancel_deadline <= now <
                    instance.registration_end):
                return self.REGISTRATION_OPEN_NO_CANCEL
            elif (now >= instance.registration_end and
                    now >= instance.cancel_deadline):
                return self.REGISTRATION_CLOSED
            else:
                return self.REGISTRATION_OPEN
        else:
            return self.REGISTRATION_NOT_NEEDED
AuckeBos's avatar
AuckeBos committed
148

149
    def _description(self, instance):
150
        return unescape(strip_tags(instance.description))
151

152
    def _num_participants(self, instance):
153
        if (instance.max_participants and
154
                instance.participants.count() > instance.max_participants):
155
            return instance.max_participants
156
        return instance.participants.count()
157
158
159
160

    def _user_registration(self, instance):
        try:
            reg = instance.registration_set.get(
161
                member=self.context['request'].member)
162
            return RegistrationListSerializer(reg, context=self.context).data
163
164
165
166
        except Registration.DoesNotExist:
            return None

    def _registration_allowed(self, instance):
167
168
169
        member = self.context['request'].member
        return (member.has_active_membership and
                member.can_attend_events)
170
171
172
173

    def _has_fields(self, instance):
        return instance.has_fields()

174
175
176
    def _is_pizza_event(self, instance):
        return instance.is_pizza_event()

177

178
class EventListSerializer(serializers.ModelSerializer):
AuckeBos's avatar
AuckeBos committed
179
180
    class Meta:
        model = Event
181
        fields = ('pk', 'title', 'description', 'start', 'end',
182
                  'location', 'price', 'registered', 'pizza')
183
184

    description = serializers.SerializerMethodField('_description')
185
    registered = serializers.SerializerMethodField('_registered')
186
    pizza = serializers.SerializerMethodField('_pizza')
187
188

    def _description(self, instance):
189
        return unescape(strip_tags(instance.description))
190
191
192

    def _registered(self, instance):
        try:
193
194
            return services.is_user_registered(self.context['request'].user,
                                               instance)
195
196
197
        except AttributeError:
            return None

198
199
200
201
    def _pizza(self, instance):
        pizza_events = PizzaEvent.objects.filter(event=instance)
        return pizza_events.exists()

202

203
class RegistrationListSerializer(serializers.ModelSerializer):
204
205
    class Meta:
        model = Registration
206
        fields = ('pk', 'member', 'name', 'photo', 'avatar', 'registered_on',
207
                  'is_late_cancellation', 'is_cancelled', 'queue_position')
208
209
210

    name = serializers.SerializerMethodField('_name')
    photo = serializers.SerializerMethodField('_photo')
211
    avatar = serializers.SerializerMethodField('_avatar')
212
    member = serializers.SerializerMethodField('_member')
213
    registered_on = serializers.DateTimeField(source='date')
214
215
216
217
    is_cancelled = serializers.SerializerMethodField('_is_cancelled')
    is_late_cancellation = serializers.SerializerMethodField(
        '_is_late_cancellation')
    queue_position = serializers.SerializerMethodField(
218
        '_queue_position', read_only=False)
219

220
    def _is_late_cancellation(self, instance):
221
        return instance.is_late_cancellation()
222
223

    def _queue_position(self, instance):
224
225
226
227
228
        pos = instance.queue_position
        return pos if pos > 0 else None

    def _is_cancelled(self, instance):
        return instance.date_cancelled is not None
229

230
231
    def _member(self, instance):
        if instance.member:
232
            return instance.member.pk
233
        return None
234

235
236
    def _name(self, instance):
        if instance.member:
237
            return instance.member.profile.display_name()
238
239
240
        return instance.name

    def _photo(self, instance):
241
        if instance.member and instance.member.profile.photo:
242
            return self.context['request'].build_absolute_uri(
243
                '%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
244
245
246
247
        else:
            return self.context['request'].build_absolute_uri(
                static('members/images/default-avatar.jpg'))

248
249
250
    def _avatar(self, instance):
        placeholder = self.context['request'].build_absolute_uri(
            static('members/images/default-avatar.jpg'))
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
251
        file = None
252
        if instance.member and instance.member.profile.photo:
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
253
254
255
256
            file = instance.member.profile.photo
        return create_image_thumbnail_dict(
            self.context['request'], file, placeholder=placeholder,
            size_large='800x800')
257

258
259
260
261
262
263

class RegistrationSerializer(serializers.ModelSerializer):
    information_fields = None

    class Meta:
        model = Registration
264
        fields = ('pk', 'member', 'name', 'photo', 'avatar', 'registered_on',
265
                  'is_late_cancellation', 'is_cancelled',
266
                  'queue_position', 'fields')
267
268
269

    name = serializers.SerializerMethodField('_name')
    photo = serializers.SerializerMethodField('_photo')
270
    avatar = serializers.SerializerMethodField('_avatar')
271
272
273
274
275
276
277
    member = serializers.SerializerMethodField('_member')
    registered_on = serializers.DateTimeField(source='date', read_only=True)
    is_cancelled = serializers.SerializerMethodField('_is_cancelled')
    is_late_cancellation = serializers.SerializerMethodField(
        '_is_late_cancellation')
    queue_position = serializers.SerializerMethodField(
        '_queue_position', read_only=False)
278
    fields = serializers.HiddenField(default='')
279
280
281
282
283

    def _is_late_cancellation(self, instance):
        val = instance.is_late_cancellation()
        return False if val is None else val

284
    def _is_cancelled(self, instance):
285
286
287
288
289
        return instance.date_cancelled is not None

    def _queue_position(self, instance):
        pos = instance.queue_position
        return pos if pos > 0 else None
290
291
292

    def _member(self, instance):
        if instance.member:
293
            return instance.member.pk
294
295
296
297
        return None

    def _name(self, instance):
        if instance.member:
298
            return instance.member.profile.display_name()
299
300
301
        return instance.name

    def _photo(self, instance):
302
        if instance.member and instance.member.profile.photo:
303
            return self.context['request'].build_absolute_uri(
304
                '%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
305
        else:
306
            return self.context['request'].build_absolute_uri(
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
307
                static('members/images/default-avatar.jpg'))
308

309
310
311
    def _avatar(self, instance):
        placeholder = self.context['request'].build_absolute_uri(
            static('members/images/default-avatar.jpg'))
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
312
        file = None
313
        if instance.member and instance.member.profile.photo:
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
314
315
316
317
            file = instance.member.profile.photo
        return create_image_thumbnail_dict(
            self.context['request'], file, placeholder=placeholder,
            size_large='800x800')
318

319
320
321
322
323
    def __init__(self, instance=None, data=empty, **kwargs):
        super().__init__(instance, data, **kwargs)
        try:
            if instance:
                self.information_fields = services.registration_fields(
324
                    instance.member, instance.event)
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
        except RegistrationError:
            pass

    def get_fields(self):
        fields = super().get_fields()

        if self.information_fields:
            for key, field in self.information_fields.items():
                key = 'fields[{}]'.format(key)
                field_type = field['type']

                if field_type == RegistrationInformationField.BOOLEAN_FIELD:
                    fields[key] = serializers.BooleanField(
                        required=False,
                        write_only=True
                    )
                elif field_type == RegistrationInformationField.INTEGER_FIELD:
                    fields[key] = serializers.IntegerField(
                        required=field['required'],
                        write_only=True
                    )
                elif field_type == RegistrationInformationField.TEXT_FIELD:
                    fields[key] = serializers.CharField(
                        required=field['required'],
                        write_only=True
                    )

                fields[key].label = field['label']
                fields[key].help_text = field['description']
                fields[key].initial = field['value']
                fields[key].default = field['value']

                try:
                    if key in self.information_fields:
                        fields[key].initial = self.validated_data[key]
                except AssertionError:
                    pass

        return fields

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['fields'] = self.information_fields
        return data

    def field_values(self):
        return ((name[7:len(name) - 1], value)
                for name, value in self.validated_data.items()
                if "info_field" in name)