]> git.ipfire.org Git - thirdparty/patchwork.git/commitdiff
REST: Add Persons to the API
authorAndy Doan <andy.doan@linaro.org>
Thu, 16 Jun 2016 21:13:20 +0000 (16:13 -0500)
committerStephen Finucane <stephen.finucane@intel.com>
Mon, 27 Jun 2016 17:20:31 +0000 (18:20 +0100)
This exports person objects via the REST API.

Security Constraints:
 * The API is read-only to authenticated users

Signed-off-by: Andy Doan <andy.doan@linaro.org>
Reviewed-by: Stephen Finucane <stephen.finucane@intel.com>
patchwork/rest_serializers.py
patchwork/tests/test_rest_api.py
patchwork/views/rest_api.py

index 0d6c041fbd9623f2d75bfd3671fdc6f293f28a54..103280a4b641512d0fa884819aca0178a047f336 100644 (file)
 
 from django.contrib.auth.models import User
 
+from rest_framework.relations import HyperlinkedRelatedField
 from rest_framework.serializers import HyperlinkedModelSerializer
 
-from patchwork.models import Project
+from patchwork.models import Person, Project
+
+
+class URLSerializer(HyperlinkedModelSerializer):
+    """Just like parent but puts _url for fields"""
+
+    def to_representation(self, instance):
+        data = super(URLSerializer, self).to_representation(instance)
+        for name, field in self.fields.items():
+            if isinstance(field, HyperlinkedRelatedField) and name != 'url':
+                data[name + '_url'] = data.pop(name)
+        return data
+
+
+class PersonSerializer(URLSerializer):
+    class Meta:
+        model = Person
 
 
 class UserSerializer(HyperlinkedModelSerializer):
index d877941a120422b8d13c3ef2f7f7461c87694818..7e48fd8ea6aafa7bb385941f89ed59a4d0c55aeb 100644 (file)
@@ -116,6 +116,61 @@ class TestProjectAPI(APITestCase):
         self.assertEqual(1, Project.objects.all().count())
 
 
+@unittest.skipUnless(settings.ENABLE_REST_API, 'requires ENABLE_REST_API')
+class TestPersonAPI(APITestCase):
+    fixtures = ['default_states']
+
+    @staticmethod
+    def api_url(item=None):
+        if item is None:
+            return reverse('api_1.0:person-list')
+        return reverse('api_1.0:person-detail', args=[item])
+
+    def test_anonymous_list(self):
+        """The API should reject anonymous users."""
+        resp = self.client.get(self.api_url())
+        self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
+
+    def test_authenticated_list(self):
+        """This API requires authenticated users."""
+        user = create_user()
+        self.client.force_authenticate(user=user)
+        resp = self.client.get(self.api_url())
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(1, len(resp.data))
+        self.assertEqual(user.username, resp.data[0]['name'])
+        self.assertEqual(user.email, resp.data[0]['email'])
+        self.assertIn('users/%d/' % user.id, resp.data[0]['user_url'])
+
+    def test_unlinked_user(self):
+        defaults.patch_author_person.save()
+        user = create_user()
+        self.client.force_authenticate(user=user)
+        resp = self.client.get(self.api_url())
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(2, len(resp.data))
+        self.assertEqual(defaults.patch_author_person.name,
+                         resp.data[0]['name'])
+        self.assertIsNone(resp.data[0]['user_url'])
+
+    def test_readonly(self):
+        defaults.project.save()
+        user = create_maintainer(defaults.project)
+        user.is_superuser = True
+        user.save()
+        self.client.force_authenticate(user=user)
+
+        resp = self.client.delete(self.api_url(user.id))
+        self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
+
+        resp = self.client.patch(self.api_url(user.id),
+                                 {'email': 'foo@f.com'})
+        self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
+
+        resp = self.client.post(self.api_url(), {'email': 'foo@f.com'})
+        self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
+
+
 @unittest.skipUnless(settings.ENABLE_REST_API, 'requires ENABLE_REST_API')
 class TestUserAPI(APITestCase):
     fixtures = ['default_states']
index 8cff44ea995523a95b310ab1b7331b7da4fe9840..6e7f94e1c2bf88181147ff83a4af1f95add8543d 100644 (file)
@@ -20,7 +20,7 @@
 from django.conf import settings
 
 from patchwork.rest_serializers import (
-    ProjectSerializer, UserSerializer)
+    PersonSerializer, ProjectSerializer, UserSerializer)
 
 from rest_framework import permissions
 from rest_framework.pagination import PageNumberPagination
@@ -85,11 +85,21 @@ class UserViewSet(PatchworkViewSet):
     serializer_class = UserSerializer
 
 
+class PeopleViewSet(PatchworkViewSet):
+    permission_classes = (AuthenticatedReadOnly, )
+    serializer_class = PersonSerializer
+
+    def get_queryset(self):
+        qs = super(PeopleViewSet, self).get_queryset()
+        return qs.select_related('user__username')
+
+
 class ProjectViewSet(PatchworkViewSet):
     permission_classes = (PatchworkPermission, )
     serializer_class = ProjectSerializer
 
 
 router = DefaultRouter()
+router.register('people', PeopleViewSet, 'person')
 router.register('projects', ProjectViewSet, 'project')
 router.register('users', UserViewSet, 'user')