myModelSerializer.py 5.21 KB
Newer Older
1
from rest_framework import serializers
Florent Chehab's avatar
Florent Chehab committed
2
from rest_framework.validators import ValidationError
3
from django.utils import timezone
4
from .pendingModeration import PendingModeration
5
from django.contrib.contenttypes.models import ContentType
Florent Chehab's avatar
Florent Chehab committed
6
from .myModel import MyModel
Florent Chehab's avatar
Florent Chehab committed
7
from .pendingModeration import PendingModerationSerializer
Florent Chehab's avatar
Florent Chehab committed
8
from backend.utils import get_user_level
9
from backend.permissions import is_moderation_required
Florent Chehab's avatar
Florent Chehab committed
10
from backend.models.tools import MySerializerWithJSON
11

Florent Chehab's avatar
Florent Chehab committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CLEANED_MY_MODEL_DATA = {
    'moderated_by': None,
    'moderated_on': None,
    'updated_by': None,
    'updated_on': None,
}


def override_data(old_data, new_data):
    for key in new_data:
        old_data[key] = new_data[key]
    return old_data


Florent Chehab's avatar
Florent Chehab committed
26
class MyModelSerializer(MySerializerWithJSON):
27
28
29
30
    moderated_on = serializers.DateTimeField(
        format="%Y-%m-%d %H:%M:%S", read_only=True)
    updated_on = serializers.DateTimeField(
        format="%Y-%m-%d %H:%M:%S", read_only=True)
31
32
    moderated_by = serializers.CharField(read_only=True)
    updated_by = serializers.CharField(read_only=True)
33
    pending_moderation = serializers.SerializerMethodField()
Florent Chehab's avatar
Florent Chehab committed
34
    model_config = serializers.SerializerMethodField()
35

Florent Chehab's avatar
Florent Chehab committed
36
    def get_model_config(self, obj=None):
Florent Chehab's avatar
Florent Chehab committed
37
        return self.Meta.model.model_config
38

39
40
41
42
43
    def get_pending_moderation(self, obj):
        if self.context['view'].action != 'list':
            return PendingModerationSerializer(obj.pending_moderation, many=True, read_only=True, context=self.context).data
        return None

44
45
46
    class Meta:
        model = MyModel

Florent Chehab's avatar
Florent Chehab committed
47
48
49
50
    def my_validate(self, attrs):
        return attrs

    def validate(self, attrs):
Florent Chehab's avatar
Florent Chehab committed
51
52
53
54
        """
        TODO unit test this
        """
        self.user = self.context['request'].user
Florent Chehab's avatar
Florent Chehab committed
55
56
57
58
        self.user_level = get_user_level(self.user)

        if "obj_moderation_level" in attrs:
            requested_obj_moder_lv = attrs["obj_moderation_level"]
59

Florent Chehab's avatar
Florent Chehab committed
60
61
62
63
64
65
            if requested_obj_moder_lv > self.user_level:
                raise ValidationError(
                    "You can't request moderation for a higher rank than you.")

        return self.my_validate(attrs)

66
67
    def set_model_attr_no_moder(self, moderated_and_updated):
        now = timezone.now()
Florent Chehab's avatar
Florent Chehab committed
68
        self.override_validated_data({
Florent Chehab's avatar
Florent Chehab committed
69
            'moderated_by': self.user,
Florent Chehab's avatar
Florent Chehab committed
70
71
            'moderated_on': now,
        })
72
73

        if moderated_and_updated:
Florent Chehab's avatar
Florent Chehab committed
74
            self.override_validated_data({
Florent Chehab's avatar
Florent Chehab committed
75
                'updated_by': self.user,
Florent Chehab's avatar
Florent Chehab committed
76
77
                'updated_on': now,
            })
78
79

    def clean_validated_data(self):
Florent Chehab's avatar
Florent Chehab committed
80
        self.override_validated_data(CLEANED_MY_MODEL_DATA)
81

Florent Chehab's avatar
Florent Chehab committed
82
83
84
85
86
87
88
89
90
91
    def override_validated_data(self, new_data):
        """
        Method used to force specific attributes when saving a model
        """
        for key in new_data:
            self.validated_data[key] = new_data[key]

    def my_pre_save(self):
        pass

Florent Chehab's avatar
Florent Chehab committed
92
93
    def save(self, *args, **kwargs):
        return self.my_save(*args, **kwargs)
94

Florent Chehab's avatar
Florent Chehab committed
95
    def my_save(self, *args, **kwargs):
96
        self.clean_validated_data()
Florent Chehab's avatar
Florent Chehab committed
97
        self.my_pre_save()
Florent Chehab's avatar
Florent Chehab committed
98
        ct = ContentType.objects.get_for_model(self.Meta.model)
99

Florent Chehab's avatar
Florent Chehab committed
100
        if is_moderation_required(self.get_model_config()['moderation_level'], self.instance, self.user, self.user_level):
101
102
            if self.instance is None:  # we need to create the main model
                self.instance = super(
Florent Chehab's avatar
Florent Chehab committed
103
                    MyModelSerializer, self).save(*args, **kwargs)
104

Florent Chehab's avatar
Florent Chehab committed
105
106
107
            data_to_save = dict()
            for key in self.validated_data:
                try:
Florent Chehab's avatar
Florent Chehab committed
108
109
                    # retrieve the submitted data and save the clean json
                    # to make sure it will be savable
Florent Chehab's avatar
Florent Chehab committed
110
111
112
113
114
                    data_to_save[key] = self.initial_data[key]
                except KeyError:
                    pass

            data_to_save = override_data(data_to_save, CLEANED_MY_MODEL_DATA)
Florent Chehab's avatar
Florent Chehab committed
115
116
117
118
119
120
121
122
123

            PendingModeration.objects.update_or_create(
                content_type=ct,
                object_id=self.instance.pk,
                defaults={
                    'updated_on': timezone.now(),
                    'updated_by': self.user,
                    'new_object': data_to_save
                })
124
125
126
            return self.instance

        else:
127

128
            moderated_and_updated = True
129
            if self.instance is None:
130
                self.set_model_attr_no_moder(moderated_and_updated)
Florent Chehab's avatar
Florent Chehab committed
131
                return super(MyModelSerializer, self).save(*args, **kwargs)
132
            else:
Florent Chehab's avatar
Florent Chehab committed
133
134
135
136
137
                try:
                    pending_instance = PendingModeration.objects.get(
                        content_type=ct,
                        object_id=self.instance.pk,
                    )
138
                    self.clean_validated_data()  # Make that it is done...
Florent Chehab's avatar
Florent Chehab committed
139
                    if pending_instance.new_object == self.validated_data:
140
                        moderated_and_updated = False
Florent Chehab's avatar
Florent Chehab committed
141
142
143
                        self.validated_data['updated_by'] = pending_instance.updated_by
                        self.validated_data['updated_on'] = pending_instance.updated_on
                    pending_instance.delete()
144

Florent Chehab's avatar
Florent Chehab committed
145
146
                except PendingModeration.DoesNotExist:
                    pass
147

148
                self.set_model_attr_no_moder(moderated_and_updated)
Florent Chehab's avatar
Florent Chehab committed
149
                return super(MyModelSerializer, self).save(*args, **kwargs)