serializers.py 14.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

9
10
11
from events import services
from events.exceptions import RegistrationError
from events.models import Event, Registration, RegistrationInformationField
12
from pizzas.models import PizzaEvent
13
from thaliawebsite.settings import settings
14
from utils.templatetags.thumbnail import thumbnail
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(instance,
                                               self.context['member'])
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(
                instance, self.context['request'].user)
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
    def _avatar(self, instance):
        placeholder = self.context['request'].build_absolute_uri(
            static('members/images/default-avatar.jpg'))
        data = {
            'full': placeholder,
            'small': placeholder,
            'medium': placeholder,
            'large': placeholder,
        }
        if instance.member and instance.member.profile.photo:
            data['full'] = self.context['request'].build_absolute_uri(
                '%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
            data['small'] = self.context['request'].build_absolute_uri(
                thumbnail(instance.member.profile.photo, '110x110', 1))
            data['medium'] = self.context['request'].build_absolute_uri(
                thumbnail(instance.member.profile.photo, '220x220', 1))
            data['large'] = self.context['request'].build_absolute_uri(
                thumbnail(instance.member.profile.photo, '800x800', 1))
        return data

268
269
270
271
272
273

class RegistrationSerializer(serializers.ModelSerializer):
    information_fields = None

    class Meta:
        model = Registration
274
        fields = ('pk', 'member', 'name', 'photo', 'avatar', 'registered_on',
275
                  'is_late_cancellation', 'is_cancelled',
276
                  'queue_position', 'fields')
277
278
279

    name = serializers.SerializerMethodField('_name')
    photo = serializers.SerializerMethodField('_photo')
280
    avatar = serializers.SerializerMethodField('_avatar')
281
282
283
284
285
286
287
    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)
288
    fields = serializers.HiddenField(default='')
289
290
291
292
293

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

294
    def _is_cancelled(self, instance):
295
296
297
298
299
        return instance.date_cancelled is not None

    def _queue_position(self, instance):
        pos = instance.queue_position
        return pos if pos > 0 else None
300
301
302

    def _member(self, instance):
        if instance.member:
303
            return instance.member.pk
304
305
306
307
        return None

    def _name(self, instance):
        if instance.member:
308
            return instance.member.profile.display_name()
309
310
311
        return instance.name

    def _photo(self, instance):
312
        if instance.member and instance.member.profile.photo:
313
            return self.context['request'].build_absolute_uri(
314
                '%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
315
        else:
316
            return self.context['request'].build_absolute_uri(
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
317
                static('members/images/default-avatar.jpg'))
318

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
    def _avatar(self, instance):
        placeholder = self.context['request'].build_absolute_uri(
            static('members/images/default-avatar.jpg'))
        data = {
            'full': placeholder,
            'small': placeholder,
            'medium': placeholder,
            'large': placeholder,
        }
        if instance.member and instance.member.profile.photo:
            data['full'] = self.context['request'].build_absolute_uri(
                '%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
            data['small'] = self.context['request'].build_absolute_uri(
                thumbnail(instance.member.profile.photo, '110x110', 1))
            data['medium'] = self.context['request'].build_absolute_uri(
                thumbnail(instance.member.profile.photo, '220x220', 1))
            data['large'] = self.context['request'].build_absolute_uri(
                thumbnail(instance.member.profile.photo, '800x800', 1))
        return data

339
340
341
342
343
    def __init__(self, instance=None, data=empty, **kwargs):
        super().__init__(instance, data, **kwargs)
        try:
            if instance:
                self.information_fields = services.registration_fields(
344
                    instance.member, instance.event)
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
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
        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)