Skip to content

Commit db08336

Browse files
fdambrineartragis
fdambrine
authored andcommitted
Ajoute un endpoint d'API pour les catégories de tuto.
En effet en corrigeant les problèmes des sérializers je me suis rendu compte que cela est nécessaire car ces derniers demandent à envoyer les pk des catégories pour créer/supprimer le contenu. Notons que le même problème se posera pour les licences mais semble pouvoir être corrigé rapidement.
1 parent 16045ee commit db08336

File tree

9 files changed

+193
-143
lines changed

9 files changed

+193
-143
lines changed

zds/tutorialv2/api/permissions.py

+29-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,31 @@
22

33

44
class IsOwner(BasePermission):
5-
def has_permission(self, request, view):
6-
request_param_user = request.kwargs.get('user', 0)
5+
owner_mark = 'author'
6+
7+
@staticmethod
8+
def is_owner(request):
9+
10+
request_param_user = request.parser_context['kwargs'].get('user', '0')
711
current_user = request.user
8-
return current_user and current_user.pk == request_param_user
12+
try:
13+
return current_user and current_user.pk == int(request_param_user)
14+
except ValueError: # not an int
15+
return False
16+
17+
def is_object_owner(self, request, object):
18+
request_param_user = request.parser_context['kwargs'].get('user', 0)
19+
try:
20+
object_owner = getattr(object, self.owner_mark, None).pk
21+
return request_param_user == object_owner
22+
except AttributeError:
23+
return False
24+
25+
def has_permission(self, request, view):
26+
return IsOwner.is_owner(request)
27+
28+
def has_object_permission(self, request, view, obj):
29+
return self.is_object_owner(request, obj)
930

1031

1132
class CanModerate(DjangoModelPermissions):
@@ -18,3 +39,8 @@ class CanModerate(DjangoModelPermissions):
1839
'PATCH': ['%(app_label)s.change_%(model_name)s'],
1940
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
2041
}
42+
43+
44+
class CanModerateOrIsOwner(CanModerate, IsOwner):
45+
def has_permission(self, request, view):
46+
return IsOwner.is_owner(request) or CanModerate.has_permission(self, request, view)

zds/tutorialv2/api/serializers.py

+53-28
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import copy
2+
import datetime
23
import logging
34
from collections import Counter
45

@@ -7,13 +8,13 @@
78
from rest_framework.exceptions import ValidationError
89
from rest_framework.fields import CharField, empty
910

10-
from zds.api.serializers import ZdSModelSerializer
1111
from zds.tutorialv2.api.view_models import ChildrenViewModel, ChildrenListViewModel, UpdateChildrenListViewModel
12-
from gettext import gettext as _
12+
from django.utils.translation import ugettext as _
1313

1414
from zds.tutorialv2.models.database import PublishableContent
1515
from zds.tutorialv2.utils import init_new_repo
1616
from zds.utils.forms import TagValidator
17+
from zds.utils.models import SubCategory
1718

1819
logger = logging.getLogger(__name__)
1920

@@ -26,6 +27,14 @@ def __init__(self, *, filter_function=None, **kwargs):
2627
super().__init__(**kwargs)
2728
self.filter_method = filter_function
2829

30+
def __deepcopy__(self, memodict):
31+
args = []
32+
kwargs = {
33+
key: (copy.deepcopy(value) if (key not in ('validators', 'regex', 'filter_function')) else value)
34+
for key, value in self._kwargs.items()
35+
}
36+
return self.__class__(*args, **kwargs)
37+
2938
def to_internal_value(self, data):
3039
if isinstance(data, (list, tuple)):
3140
return super().to_internal_value(','.join(str(value) for value in data))
@@ -54,7 +63,7 @@ def decorated(*args, **kwargs):
5463
try:
5564
return func(*args, **kwargs)
5665
except exception1:
57-
logger.warning('Error translated fril %s to %s', exception1, exception2(message))
66+
logger.warning('Error translated from %s to %s', exception1, exception2(message))
5867
raise exception2(message)
5968
return decorated
6069
return wrapper
@@ -73,9 +82,6 @@ class ChildrenListSerializer(serializers.Serializer):
7382
Serialize children list so that api can handle them
7483
"""
7584

76-
def update(self, instance, validated_data):
77-
pass
78-
7985
extracts = serializers.ListField(child=ChildrenSerializer(), source='extracts')
8086
containers = serializers.ListField(child=ChildrenSerializer(), source='containers')
8187
extract_number = serializers.IntegerField(source='extracts.__len__')
@@ -118,16 +124,21 @@ def is_valid(self, raise_exception=False):
118124
self._validated_data[field_name] = value
119125
if self._validated_data.get('extracts', None):
120126
self._validated_data['extracts'] = [ChildrenViewModel(**v) for v in self._validated_data['extracts']]
127+
has_error = self.validate_extracts_structure(has_error, messages)
121128
if self.initial_data.get('containers', None):
122129
self._validated_data['containers'] = [ChildrenViewModel(**v) for v in self._validated_data['containers']]
123-
if not all(c.child_type.lower() == 'extract' for c in self._validated_data.get('extracts', [])):
124-
has_error = True
125-
messages['extracts'] = _('un extrait est mal configuré')
126-
if len(self._validated_data['extracts']) != len(set(e.title for e in self._validated_data['extracts'])):
130+
has_error = self.validate_container_structure(has_error, messages)
131+
self._validated_data['conclusion'] = self.initial_data.get('conclusion', '')
132+
if not self._validated_data['extracts'] and not self._validated_data['containers']:
127133
has_error = True
128-
titles = Counter(list(e.title for e in self._validated_data['extracts']))
129-
doubly = [key for key, v in titles.items() if v > 1]
130-
messages['extracts'] = _('Certains titres sont en double : {}').format(','.join(doubly))
134+
messages['extracts'] = _('Le contenu semble vide.')
135+
if raise_exception and has_error:
136+
self._errors.update(messages)
137+
raise ValidationError(self.errors)
138+
139+
return not has_error
140+
141+
def validate_container_structure(self, has_error, messages):
131142
if len(self._validated_data['containers']) != len(set(e.title for e in self._validated_data['containers'])):
132143
has_error = True
133144
titles = Counter(list(e.title for e in self._validated_data['containers']))
@@ -137,15 +148,18 @@ def is_valid(self, raise_exception=False):
137148
has_error = True
138149
messages['containers'] = _('Un conteneur est mal configuré')
139150
self._validated_data['introduction'] = self.initial_data.get('introduction', '')
140-
self._validated_data['conclusion'] = self.initial_data.get('conclusion', '')
141-
if not self._validated_data['extracts'] and not self._validated_data['containers']:
142-
has_error = True
143-
messages['extracts'] = _('Le contenu semble vide.')
144-
if raise_exception and has_error:
145-
self._errors.update(messages)
146-
raise ValidationError(self.errors)
151+
return has_error
147152

148-
return not has_error
153+
def validate_extracts_structure(self, has_error, messages):
154+
if not all(c.child_type.lower() == 'extract' for c in self._validated_data.get('extracts', [])):
155+
has_error = True
156+
messages['extracts'] = _('un extrait est mal configuré')
157+
if len(self._validated_data['extracts']) != len(set(e.title for e in self._validated_data['extracts'])):
158+
has_error = True
159+
titles = Counter(list(e.title for e in self._validated_data['extracts']))
160+
doubly = [key for key, v in titles.items() if v > 1]
161+
messages['extracts'] = _('Certains titres sont en double : {}').format(','.join(doubly))
162+
return has_error
149163

150164
def to_representation(self, instance):
151165
dic_repr = {}
@@ -176,7 +190,7 @@ class Meta:
176190
'introduction', 'conclusion', 'original_sha')
177191

178192
def is_valid(self, raise_exception=False):
179-
error = not super(ChildrenListModifySerializer, self).is_valid(raise_exception)
193+
error = not super().is_valid(raise_exception)
180194
messages = {}
181195
if not self._validated_data['original_sha']:
182196
messages['original_sha'] = _("Vous n'avez pas fourni de marqueur de version")
@@ -193,27 +207,32 @@ def create(self, validated_data):
193207
return UpdateChildrenListViewModel(**validated_data)
194208

195209

196-
class PublishableMetaDataSerializer(ZdSModelSerializer):
197-
tags = CommaSeparatedCharField(source='tags', required=False, filter_function=TagValidator().validate_one_element)
210+
class PublishableMetaDataSerializer(serializers.ModelSerializer):
211+
tags = CommaSeparatedCharField(required=False, filter_function=TagValidator().validate_one_element)
198212

199213
class Meta:
200214
model = PublishableContent
201-
exclude = ('is_obsolete', 'must_reindex', 'last_note', 'helps', 'beta_topic', 'image', 'content_type_attribute')
202-
read_only_fields = ('authors', 'gallery', 'public_version', 'js_support', 'is_locked', 'relative_images_path',
215+
exclude = ('is_obsolete', 'must_reindex', 'last_note', 'helps', 'beta_topic', 'image')
216+
read_only_fields = ('authors', 'gallery', 'public_version', 'is_locked', 'relative_images_path',
203217
'sha_picked', 'sha_draft', 'sha_validation', 'sha_beta', 'sha_public', 'picked_date',
204218
'update_date', 'pubdate', 'creation_date', 'slug')
205219
depth = 2
206220

207221
def create(self, validated_data):
208222
# default db values
209-
validated_data['is_js'] = False # Always false when we create
223+
validated_data['js_support'] = False # Always false when we create
224+
validated_data['creation_date'] = datetime.datetime.now()
210225

211226
# links to other entities
212227
tags = validated_data.pop('tags', '')
213228
content = super().create(validated_data)
229+
content.save()
214230
content.add_tags(tags)
215-
content.add_author(self.context['author'])
216231
init_new_repo(content, '', '', _('Création de {}').format(content.title), do_commit=True)
232+
content.authors.add(self.context['author'])
233+
content.create_gallery()
234+
content.save()
235+
content.ensure_author_gallery()
217236
return content
218237

219238
def update(self, instance, validated_data):
@@ -240,3 +259,9 @@ def update(self, instance, validated_data):
240259
do_commit=True
241260
)
242261
return super.update(instance, working_dictionary)
262+
263+
264+
class ContentCategorySerializer(serializers.ModelSerializer):
265+
class Meta:
266+
model = SubCategory
267+
depth = 1

0 commit comments

Comments
 (0)