Skip to content

Commit

Permalink
Ajoute un endpoint d'API pour les catégories de tuto.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
fdambrine authored and artragis committed Sep 5, 2018
1 parent e3db836 commit 15d8b99
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 144 deletions.
32 changes: 29 additions & 3 deletions zds/tutorialv2/api/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,31 @@


class IsOwner(BasePermission):
def has_permission(self, request, view):
request_param_user = request.kwargs.get('user', 0)
owner_mark = 'author'

@staticmethod
def is_owner(request):

request_param_user = request.parser_context['kwargs'].get('user', '0')
current_user = request.user
return current_user and current_user.pk == request_param_user
try:
return current_user and current_user.pk == int(request_param_user)
except ValueError: # not an int
return False

def is_object_owner(self, request, object):
request_param_user = request.parser_context['kwargs'].get('user', 0)
try:
object_owner = getattr(object, self.owner_mark, None).pk
return request_param_user == object_owner
except AttributeError:
return False

def has_permission(self, request, view):
return IsOwner.is_owner(request)

def has_object_permission(self, request, view, obj):
return self.is_object_owner(request, obj)


class CanModerate(DjangoModelPermissions):
Expand All @@ -18,3 +39,8 @@ class CanModerate(DjangoModelPermissions):
'PATCH': ['%(app_label)s.change_%(model_name)s'],
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
}


class CanModerateOrIsOwner(CanModerate, IsOwner):
def has_permission(self, request, view):
return IsOwner.is_owner(request) or CanModerate.has_permission(self, request, view)
81 changes: 53 additions & 28 deletions zds/tutorialv2/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import datetime
import logging
from collections import Counter

Expand All @@ -7,13 +8,13 @@
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, empty

from zds.api.serializers import ZdSModelSerializer
from zds.tutorialv2.api.view_models import ChildrenViewModel, ChildrenListViewModel, UpdateChildrenListViewModel
from gettext import gettext as _
from django.utils.translation import ugettext as _

from zds.tutorialv2.models.database import PublishableContent
from zds.tutorialv2.utils import init_new_repo
from zds.utils.forms import TagValidator
from zds.utils.models import SubCategory

logger = logging.getLogger(__name__)

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

def __deepcopy__(self, memodict):
args = []
kwargs = {
key: (copy.deepcopy(value) if (key not in ('validators', 'regex', 'filter_function')) else value)
for key, value in self._kwargs.items()
}
return self.__class__(*args, **kwargs)

def to_internal_value(self, data):
if isinstance(data, (list, tuple)):
return super().to_internal_value(','.join(str(value) for value in data))
Expand Down Expand Up @@ -54,7 +63,7 @@ def decorated(*args, **kwargs):
try:
return func(*args, **kwargs)
except exception1:
logger.warning('Error translated fril %s to %s', exception1, exception2(message))
logger.warning('Error translated from %s to %s', exception1, exception2(message))
raise exception2(message)
return decorated
return wrapper
Expand All @@ -73,9 +82,6 @@ class ChildrenListSerializer(serializers.Serializer):
Serialize children list so that api can handle them
"""

def update(self, instance, validated_data):
pass

extracts = serializers.ListField(child=ChildrenSerializer(), source='extracts')
containers = serializers.ListField(child=ChildrenSerializer(), source='containers')
extract_number = serializers.IntegerField(source='extracts.__len__')
Expand Down Expand Up @@ -118,16 +124,21 @@ def is_valid(self, raise_exception=False):
self._validated_data[field_name] = value
if self._validated_data.get('extracts', None):
self._validated_data['extracts'] = [ChildrenViewModel(**v) for v in self._validated_data['extracts']]
has_error = self.validate_extracts_structure(has_error, messages)
if self.initial_data.get('containers', None):
self._validated_data['containers'] = [ChildrenViewModel(**v) for v in self._validated_data['containers']]
if not all(c.child_type.lower() == 'extract' for c in self._validated_data.get('extracts', [])):
has_error = True
messages['extracts'] = _('un extrait est mal configuré')
if len(self._validated_data['extracts']) != len(set(e.title for e in self._validated_data['extracts'])):
has_error = self.validate_container_structure(has_error, messages)
self._validated_data['conclusion'] = self.initial_data.get('conclusion', '')
if not self._validated_data['extracts'] and not self._validated_data['containers']:
has_error = True
titles = Counter(list(e.title for e in self._validated_data['extracts']))
doubly = [key for key, v in titles.items() if v > 1]
messages['extracts'] = _('Certains titres sont en double : {}').format(','.join(doubly))
messages['extracts'] = _('Le contenu semble vide.')
if raise_exception and has_error:
self._errors.update(messages)
raise ValidationError(self.errors)

return not has_error

def validate_container_structure(self, has_error, messages):
if len(self._validated_data['containers']) != len(set(e.title for e in self._validated_data['containers'])):
has_error = True
titles = Counter(list(e.title for e in self._validated_data['containers']))
Expand All @@ -137,15 +148,18 @@ def is_valid(self, raise_exception=False):
has_error = True
messages['containers'] = _('Un conteneur est mal configuré')
self._validated_data['introduction'] = self.initial_data.get('introduction', '')
self._validated_data['conclusion'] = self.initial_data.get('conclusion', '')
if not self._validated_data['extracts'] and not self._validated_data['containers']:
has_error = True
messages['extracts'] = _('Le contenu semble vide.')
if raise_exception and has_error:
self._errors.update(messages)
raise ValidationError(self.errors)
return has_error

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

def to_representation(self, instance):
dic_repr = {}
Expand Down Expand Up @@ -176,7 +190,7 @@ class Meta:
'introduction', 'conclusion', 'original_sha')

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


class PublishableMetaDataSerializer(ZdSModelSerializer):
tags = CommaSeparatedCharField(source='tags', required=False, filter_function=TagValidator().validate_one_element)
class PublishableMetaDataSerializer(serializers.ModelSerializer):
tags = CommaSeparatedCharField(required=False, filter_function=TagValidator().validate_one_element)

class Meta:
model = PublishableContent
exclude = ('is_obsolete', 'must_reindex', 'last_note', 'helps', 'beta_topic', 'image', 'content_type_attribute')
read_only_fields = ('authors', 'gallery', 'public_version', 'js_support', 'is_locked', 'relative_images_path',
exclude = ('is_obsolete', 'must_reindex', 'last_note', 'helps', 'beta_topic', 'image')
read_only_fields = ('authors', 'gallery', 'public_version', 'is_locked', 'relative_images_path',
'sha_picked', 'sha_draft', 'sha_validation', 'sha_beta', 'sha_public', 'picked_date',
'update_date', 'pubdate', 'creation_date', 'slug')
depth = 2

def create(self, validated_data):
# default db values
validated_data['is_js'] = False # Always false when we create
validated_data['js_support'] = False # Always false when we create
validated_data['creation_date'] = datetime.datetime.now()

# links to other entities
tags = validated_data.pop('tags', '')
content = super().create(validated_data)
content.save()
content.add_tags(tags)
content.add_author(self.context['author'])
init_new_repo(content, '', '', _('Création de {}').format(content.title), do_commit=True)
content.authors.add(self.context['author'])
content.create_gallery()
content.save()
content.ensure_author_gallery()
return content

def update(self, instance, validated_data):
Expand All @@ -240,3 +259,9 @@ def update(self, instance, validated_data):
do_commit=True
)
return super.update(instance, working_dictionary)


class ContentCategorySerializer(serializers.ModelSerializer):
class Meta:
model = SubCategory
depth = 1
Loading

0 comments on commit 15d8b99

Please sign in to comment.