Improve the document tag serializer. Add document tag detail view.

Add more API tests. Tweak URLs to conform with API design best practices.
This commit is contained in:
Roberto Rosario
2017-02-08 00:53:33 -04:00
parent 66fb3a4530
commit f885d886bd
4 changed files with 89 additions and 43 deletions

View File

@@ -17,8 +17,8 @@ from rest_api.permissions import MayanPermission
from .models import Tag
from .permissions import (
permission_tag_create, permission_tag_delete, permission_tag_edit,
permission_tag_remove, permission_tag_view
permission_tag_attach, permission_tag_create, permission_tag_delete,
permission_tag_edit, permission_tag_remove, permission_tag_view
)
from .serializers import (
DocumentTagSerializer, NewDocumentTagSerializer, TagSerializer,
@@ -123,15 +123,21 @@ class APITagDocumentListView(generics.ListAPIView):
class APIDocumentTagListView(generics.ListCreateAPIView):
"""
Returns a list of all the tags attached to a document.
"""
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {'GET': (permission_tag_view,)}
mayan_object_permissions = {
'GET': (permission_tag_view,),
'POST': (permission_tag_attach,)
}
def get(self, *args, **kwargs):
"""
Returns a list of all the tags attached to a document.
"""
return super(APIDocumentTagListView, self).get(*args, **kwargs)
def get_document(self):
return get_object_or_404(Document, pk=self.kwargs['pk'])
return get_object_or_404(Document, pk=self.kwargs['document_pk'])
def get_queryset(self):
document = self.get_document()
@@ -146,6 +152,12 @@ class APIDocumentTagListView(generics.ListCreateAPIView):
return document.attached_tags().all()
def get_serializer_class(self):
if self.request.method == 'GET':
return DocumentTagSerializer
elif self.request.method == 'POST':
return NewDocumentTagSerializer
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
@@ -157,12 +169,6 @@ class APIDocumentTagListView(generics.ListCreateAPIView):
'view': self
}
def get_serializer_class(self):
if self.request.method == 'GET':
return DocumentTagSerializer
elif self.request.method == 'POST':
return NewDocumentTagSerializer
def perform_create(self, serializer):
serializer.save(document=self.get_document())

View File

@@ -81,14 +81,35 @@ class WritableTagSerializer(serializers.ModelSerializer):
return instance
class DocumentTagSerializer(TagSerializer):
document_tag_url = serializers.SerializerMethodField(
help_text=_(
'API URL pointing to a tag in relation to the document '
'attached to it. This URL is different than the canonical '
'tag URL.'
)
)
class Meta(TagSerializer.Meta):
fields = TagSerializer.Meta.fields + ('document_tag_url',)
read_only_fields = TagSerializer.Meta.fields
def get_document_tag_url(self, instance):
return reverse(
'rest_api:document-tag-detail', args=(
self.context['document'].pk, instance.pk
), request=self.context['request'], format=self.context['format']
)
class NewDocumentTagSerializer(serializers.Serializer):
tag = serializers.IntegerField(
tag_pk = serializers.IntegerField(
help_text=_('Primary key of the tag to be added.')
)
def create(self, validated_data):
try:
tag = Tag.objects.get(pk=validated_data['tag'])
tag = Tag.objects.get(pk=validated_data['tag_pk'])
try:
Permission.check_permissions(
@@ -103,19 +124,4 @@ class NewDocumentTagSerializer(serializers.Serializer):
except Exception as exception:
raise ValidationError(exception)
return {'tag': tag.pk}
class DocumentTagSerializer(TagSerializer):
remove = serializers.SerializerMethodField()
def get_remove(self, instance):
return reverse(
'rest_api:document-tag', args=(
self.context['document'].pk, instance.pk,
), request=self.context['request'], format=self.context['format']
)
class Meta(TagSerializer.Meta):
fields = TagSerializer.Meta.fields + ('remove',)
read_only_fields = TagSerializer.Meta.fields
return {'tag_pk': tag.pk}

View File

@@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.test import override_settings
from django.utils.encoding import force_text
from rest_framework.test import APITestCase
@@ -92,6 +93,19 @@ class TagAPITestCase(APITestCase):
self.assertEqual(Tag.objects.count(), 0)
def test_tag_document_list_view(self):
tag = Tag.objects.create(color=TEST_TAG_COLOR, label=TEST_TAG_LABEL)
document = self._document_create()
tag.documents.add(document)
response = self.client.get(
reverse('rest_api:tag-document-list', args=(tag.pk,))
)
self.assertEqual(
response.data['results'][0]['uuid'], force_text(document.uuid)
)
def test_tag_edit_via_patch(self):
tag = Tag.objects.create(color=TEST_TAG_COLOR, label=TEST_TAG_LABEL)
@@ -124,26 +138,46 @@ class TagAPITestCase(APITestCase):
self.assertEqual(tag.label, TEST_TAG_LABEL_EDITED)
self.assertEqual(tag.color, TEST_TAG_COLOR_EDITED)
def test_tag_document_add(self):
def test_document_attach_tag_view(self):
tag = Tag.objects.create(color=TEST_TAG_COLOR, label=TEST_TAG_LABEL)
document = self._document_create()
self.client.post(
response = self.client.post(
reverse('rest_api:document-tag-list', args=(document.pk,)),
{'tag': tag.pk}
{'tag_pk': tag.pk}
)
self.assertQuerysetEqual(document.tags.all(), (repr(tag),))
def test_document_tag_detail_view(self):
tag = Tag.objects.create(color=TEST_TAG_COLOR, label=TEST_TAG_LABEL)
document = self._document_create()
tag.documents.add(document)
response = self.client.get(
reverse('rest_api:document-tag-detail', args=(document.pk, tag.pk))
)
self.assertEqual(tag.documents.count(), 1)
self.assertEqual(response.data['label'], tag.label)
def test_tag_document_remove(self):
def test_document_tag_list_view(self):
tag = Tag.objects.create(color=TEST_TAG_COLOR, label=TEST_TAG_LABEL)
document = self._document_create()
tag.documents.add(document)
response = self.client.get(
reverse('rest_api:document-tag-list', args=(document.pk,))
)
self.assertEqual(response.data['results'][0]['label'], tag.label)
def test_document_tag_remove_view(self):
tag = Tag.objects.create(color=TEST_TAG_COLOR, label=TEST_TAG_LABEL)
document = self._document_create()
tag.documents.add(document)
self.client.delete(
reverse('rest_api:document-tag', args=(document.pk, tag.pk)),
reverse(
'rest_api:document-tag-detail', args=(document.pk, tag.pk)
),
)
self.assertEqual(tag.documents.count(), 0)

View File

@@ -61,11 +61,11 @@ api_urls = patterns(
url(r'^tags/(?P<pk>[0-9]+)/$', APITagView.as_view(), name='tag-detail'),
url(r'^tags/$', APITagListView.as_view(), name='tag-list'),
url(
r'^document/(?P<pk>[0-9]+)/tags/$', APIDocumentTagListView.as_view(),
name='document-tag-list'
r'^documents/(?P<document_pk>[0-9]+)/tags/$',
APIDocumentTagListView.as_view(), name='document-tag-list'
),
url(
r'^document/(?P<document_pk>[0-9]+)/tags/(?P<pk>[0-9]+)/$',
APIDocumentTagView.as_view(), name='document-tag'
r'^documents/(?P<document_pk>[0-9]+)/tags/(?P<pk>[0-9]+)/$',
APIDocumentTagView.as_view(), name='document-tag-detail'
),
)