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

Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
10
from thaliawebsite.api.services import create_image_thumbnail_dict
11
12
13
from events import services
from events.exceptions import RegistrationError
from events.models import Event, Registration, RegistrationInformationField
14
from pizzas.models import PizzaEvent
15
from thaliawebsite.templatetags.bleach_tags import bleach
16
from utils.snippets import create_google_maps_url
17
18
19


class CalenderJSSerializer(serializers.ModelSerializer):
20
21
22
    """
    Serializer using the right format for CalendarJS
    """
23
24
25
26
    class Meta:
        fields = (
            'start', 'end', 'all_day', 'is_birthday',
            'url', 'title', 'description',
27
            'backgroundColor', 'textColor', 'blank'
28
29
30
31
32
33
34
35
36
        )

    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')
37
38
39
    backgroundColor = serializers.SerializerMethodField('_background_color')
    textColor = serializers.SerializerMethodField('_text_color')
    blank = serializers.SerializerMethodField('_target_blank')
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

    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):
60
        return unescape(strip_tags(instance.description))
61
62
63
64
65
66
67
68
69
70
71

    def _background_color(self, instance):
        pass

    def _text_color(self, instance):
        pass

    def _target_blank(self, instance):
        return False


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
    def _background_color(self, instance):
80
        try:
81
82
83
            if services.is_user_registered(self.context['member'],
                                           instance):
                return "#E62272"
84
        except AttributeError:
85
86
            pass
        return "#616161"
87
88
89


class UnpublishedEventSerializer(CalenderJSSerializer):
90
91
92
    """
    See CalenderJSSerializer, customised colors
    """
93
94
95
96
    class Meta(CalenderJSSerializer.Meta):
        model = Event

    def _background_color(self, instance):
97
        return "rgba(255,0,0,0.3)"
98
99

    def _text_color(self, instance):
100
        return "black"
101
102

    def _url(self, instance):
103
        return reverse('admin:events_event_details', kwargs={
104
            'pk': instance.id})
Gijs Hendriksen's avatar
Gijs Hendriksen committed
105
106


107
class EventRetrieveSerializer(serializers.ModelSerializer):
108
109
110
    """
    Serializer for events
    """
Gijs Hendriksen's avatar
Gijs Hendriksen committed
111
112
    class Meta:
        model = Event
113
114
115
        fields = ('pk', 'title', 'description', 'start', 'end', 'organiser',
                  'category', 'registration_start', 'registration_end',
                  'cancel_deadline', 'location', 'map_location', 'price',
116
                  'fine', 'max_participants', 'num_participants',
117
                  'user_registration', 'registration_allowed',
118
119
                  'no_registration_message', 'has_fields', 'is_pizza_event',
                  'google_maps_url')
AuckeBos's avatar
AuckeBos committed
120

121
    description = serializers.SerializerMethodField('_description')
122
123
124
125
126
    user_registration = serializers.SerializerMethodField('_user_registration')
    num_participants = serializers.SerializerMethodField('_num_participants')
    registration_allowed = serializers.SerializerMethodField(
        '_registration_allowed')
    has_fields = serializers.SerializerMethodField('_has_fields')
127
    is_pizza_event = serializers.SerializerMethodField('_is_pizza_event')
128
    google_maps_url = serializers.SerializerMethodField('_google_maps_url')
AuckeBos's avatar
AuckeBos committed
129

130
    def _description(self, instance):
131
        return strip_spaces_between_tags(bleach(instance.description))
132

133
    def _num_participants(self, instance):
134
        if (instance.max_participants and
135
                instance.participants.count() > instance.max_participants):
136
            return instance.max_participants
137
        return instance.participants.count()
138
139
140
141

    def _user_registration(self, instance):
        try:
            reg = instance.registration_set.get(
142
                member=self.context['request'].member)
143
            return RegistrationListSerializer(reg, context=self.context).data
144
145
146
147
        except Registration.DoesNotExist:
            return None

    def _registration_allowed(self, instance):
148
149
150
        member = self.context['request'].member
        return (member.has_active_membership and
                member.can_attend_events)
151
152
153
154

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

155
156
157
    def _is_pizza_event(self, instance):
        return instance.is_pizza_event()

158
    def _google_maps_url(self, instance):
Thom Wiggers's avatar
Thom Wiggers committed
159
160
161
162
        return create_google_maps_url(
                instance.map_location,
                zoom=13,
                size='450x250')
163

164

165
class EventListSerializer(serializers.ModelSerializer):
166
    """Custom list serializer for events"""
AuckeBos's avatar
AuckeBos committed
167
168
    class Meta:
        model = Event
169
        fields = ('pk', 'title', 'description', 'start', 'end',
170
                  'location', 'price', 'registered', 'pizza')
171
172

    description = serializers.SerializerMethodField('_description')
173
    registered = serializers.SerializerMethodField('_registered')
174
    pizza = serializers.SerializerMethodField('_pizza')
175
176

    def _description(self, instance):
177
        return unescape(strip_tags(instance.description))
178
179
180

    def _registered(self, instance):
        try:
181
182
            return services.is_user_registered(self.context['request'].user,
                                               instance)
183
184
185
        except AttributeError:
            return None

186
187
188
189
    def _pizza(self, instance):
        pizza_events = PizzaEvent.objects.filter(event=instance)
        return pizza_events.exists()

190

191
class RegistrationListSerializer(serializers.ModelSerializer):
192
    """Custom registration list serializer"""
193
194
    class Meta:
        model = Registration
195
        fields = ('pk', 'member', 'name', 'photo', 'avatar', 'registered_on',
196
197
                  'is_late_cancellation', 'is_cancelled', 'queue_position',
                  'payment', 'present')
198
199
200

    name = serializers.SerializerMethodField('_name')
    photo = serializers.SerializerMethodField('_photo')
201
    avatar = serializers.SerializerMethodField('_avatar')
202
    member = serializers.SerializerMethodField('_member')
203
    registered_on = serializers.DateTimeField(source='date')
204
205
206
207
    is_cancelled = serializers.SerializerMethodField('_is_cancelled')
    is_late_cancellation = serializers.SerializerMethodField(
        '_is_late_cancellation')
    queue_position = serializers.SerializerMethodField(
208
        '_queue_position', read_only=False)
209

210
    def _is_late_cancellation(self, instance):
211
        return instance.is_late_cancellation()
212
213

    def _queue_position(self, instance):
214
215
216
217
218
        pos = instance.queue_position
        return pos if pos > 0 else None

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

220
221
    def _member(self, instance):
        if instance.member:
222
            return instance.member.pk
223
        return None
224

225
226
    def _name(self, instance):
        if instance.member:
227
            return instance.member.profile.display_name()
228
229
230
        return instance.name

    def _photo(self, instance):
231
        if instance.member and instance.member.profile.photo:
232
            return self.context['request'].build_absolute_uri(
233
                '%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
234
235
236
237
        else:
            return self.context['request'].build_absolute_uri(
                static('members/images/default-avatar.jpg'))

238
239
240
    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
241
        file = None
242
        if instance.member and instance.member.profile.photo:
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
243
244
245
246
            file = instance.member.profile.photo
        return create_image_thumbnail_dict(
            self.context['request'], file, placeholder=placeholder,
            size_large='800x800')
247

248
249

class RegistrationSerializer(serializers.ModelSerializer):
250
    """Registration serializer"""
251
252
253
254
    information_fields = None

    class Meta:
        model = Registration
255
        fields = ('pk', 'member', 'name', 'photo', 'avatar', 'registered_on',
256
                  'is_late_cancellation', 'is_cancelled',
257
258
                  'queue_position', 'fields',
                  'payment', 'present')
259
260
261

    name = serializers.SerializerMethodField('_name')
    photo = serializers.SerializerMethodField('_photo')
262
    avatar = serializers.SerializerMethodField('_avatar')
263
264
265
266
267
268
269
    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)
270
    fields = serializers.HiddenField(default='')
271
272
273
274
275

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

276
    def _is_cancelled(self, instance):
277
278
279
280
281
        return instance.date_cancelled is not None

    def _queue_position(self, instance):
        pos = instance.queue_position
        return pos if pos > 0 else None
282
283
284

    def _member(self, instance):
        if instance.member:
285
            return instance.member.pk
286
287
288
289
        return None

    def _name(self, instance):
        if instance.member:
290
            return instance.member.profile.display_name()
291
292
293
        return instance.name

    def _photo(self, instance):
294
        if instance.member and instance.member.profile.photo:
295
            return self.context['request'].build_absolute_uri(
296
                '%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
297
        else:
298
            return self.context['request'].build_absolute_uri(
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
299
                static('members/images/default-avatar.jpg'))
300

301
302
303
    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
304
        file = None
305
        if instance.member and instance.member.profile.photo:
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
306
307
308
309
            file = instance.member.profile.photo
        return create_image_thumbnail_dict(
            self.context['request'], file, placeholder=placeholder,
            size_large='800x800')
310

311
312
313
314
315
    def __init__(self, instance=None, data=empty, **kwargs):
        super().__init__(instance, data, **kwargs)
        try:
            if instance:
                self.information_fields = services.registration_fields(
316
                    kwargs['context']['request'],
317
                    instance.member, instance.event)
318
319
320
321
322
323
324
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
        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)