myModelSerializer.py 6.51 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
6
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
7
from backend.utils import does_user_have_moderation_rights
Florent Chehab's avatar
Florent Chehab committed
8
from .myModel import MyModel
Florent Chehab's avatar
Florent Chehab committed
9
from .pendingModeration import PendingModerationSerializer
Florent Chehab's avatar
Florent Chehab committed
10
from backend.utils import get_user_level
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


26
27
28
29
30
class MyModelSerializer(serializers.ModelSerializer):
    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
37
    def get_model_config(self, obj):
        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
51
52
53
54
55
    def my_validate(self, attrs):
        return attrs

    def validate(self, attrs):
        self.user = self.get_user_in_request()
        self.user_level = get_user_level(self.user)

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

Florent Chehab's avatar
Florent Chehab committed
57
58
59
60
61
62
63
64
65
66
            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)

    def moderation_required(self, obj_in_db):
        model_moderation_level = self.Meta.model.model_config['moderation_level']

        if model_moderation_level == 0:
67
            return False
68
        else:
Florent Chehab's avatar
Florent Chehab committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
            # At this point we have to check the obj_moderation_level
            if obj_in_db is not None:
                obj_moderation_level = obj_in_db.obj_moderation_level
                if self.user_level < obj_moderation_level:
                    return True

            if model_moderation_level == 1:
                if settings.MODERATION_ACTIVATED:
                    return not does_user_have_moderation_rights(self.user)
                else:
                    return False
            elif model_moderation_level == 2:
                return not does_user_have_moderation_rights(self.user)
            else:
                raise Exception(
                    "No other moderation level should be defined...")
85

86
87
88
    def get_user_in_request(self):
        return self.context['request'].user

89
    def set_model_attr_no_moder(self, moderated_and_updated):
90
        user = self.get_user_in_request()
91
        now = timezone.now()
Florent Chehab's avatar
Florent Chehab committed
92
93
94
95
        self.override_validated_data({
            'moderated_by': user,
            'moderated_on': now,
        })
96
97

        if moderated_and_updated:
Florent Chehab's avatar
Florent Chehab committed
98
99
100
101
            self.override_validated_data({
                'updated_by': user,
                'updated_on': now,
            })
102
103

    def clean_validated_data(self):
Florent Chehab's avatar
Florent Chehab committed
104
        self.override_validated_data(CLEANED_MY_MODEL_DATA)
105

106
107
108
109
110
    def get_pending_models(self):
        ct = ContentType.objects.get_for_model(self.Meta.model)
        return PendingModeration.objects.filter(
            content_type=ct, object_id=self.instance.pk)

Florent Chehab's avatar
Florent Chehab committed
111
112
113
114
115
116
117
118
119
120
    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
121
122
    def save(self, *args, **kwargs):
        return self.my_save(*args, **kwargs)
123

Florent Chehab's avatar
Florent Chehab committed
124
    def my_save(self, *args, **kwargs):
125
        user = self.get_user_in_request()
126
        self.clean_validated_data()
Florent Chehab's avatar
Florent Chehab committed
127
        self.my_pre_save()
128

Florent Chehab's avatar
Florent Chehab committed
129
        if self.moderation_required(self.instance):
130
131
            if self.instance is None:  # we need to create the main model
                self.instance = super(
Florent Chehab's avatar
Florent Chehab committed
132
                    MyModelSerializer, self).save(*args, **kwargs)
133

134
            objs_pending_db = self.get_pending_models()
135

Florent Chehab's avatar
Florent Chehab committed
136
137
138
139
140
141
142
143
144
            data_to_save = dict()
            for key in self.validated_data:
                try:
                    # retreive the submitted data
                    data_to_save[key] = self.initial_data[key]
                except KeyError:
                    pass

            data_to_save = override_data(data_to_save, CLEANED_MY_MODEL_DATA)
145
146
            if len(objs_pending_db) > 0:
                pending_instance = objs_pending_db[0]
147
148
                pending_instance.updated_on = timezone.now()
                pending_instance.updated_by = user
Florent Chehab's avatar
Florent Chehab committed
149
                pending_instance.new_object = data_to_save
150
            else:
Florent Chehab's avatar
Florent Chehab committed
151
                # there is no pending instance, we have to create one
152
153
                pending_instance = PendingModeration(
                    referenced_object=self.instance,
154
155
                    updated_by=user,
                    updated_on=timezone.now(),
Florent Chehab's avatar
Florent Chehab committed
156
                    new_object=data_to_save
157
                )
Florent Chehab's avatar
Florent Chehab committed
158

159
            pending_instance.save()
160
161
162
            return self.instance

        else:
163

164
            moderated_and_updated = True
165
            if self.instance is None:
166
                self.set_model_attr_no_moder(moderated_and_updated)
Florent Chehab's avatar
Florent Chehab committed
167
                return super(MyModelSerializer, self).save(*args, **kwargs)
168
169
            else:
                # We check if we don't have any moderation pending
170
                objs_pending_db = self.get_pending_models()
171
                if len(objs_pending_db) > 0:
172
173
174
175
176
177
178
                    obj_pending_db = objs_pending_db[0]
                    self.clean_validated_data()  # Make that it is done...
                    if obj_pending_db.new_object == self.validated_data:
                        moderated_and_updated = False
                        self.validated_data['updated_by'] = obj_pending_db.updated_by
                        self.validated_data['updated_on'] = obj_pending_db.updated_on

179
180
                    objs_pending_db.delete()

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