This exports person objects via the REST API. Security Constraints: * The API is read-only to authenticated users
Signed-off-by: Andy Doan <andy.d...@linaro.org> --- patchwork/rest_serializers.py | 13 +++++++++- patchwork/tests/test_rest_api.py | 54 ++++++++++++++++++++++++++++++++++++++++ patchwork/views/rest_api.py | 30 ++++++++++++++++++---- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/patchwork/rest_serializers.py b/patchwork/rest_serializers.py index bbeae37..0bb8f23 100644 --- a/patchwork/rest_serializers.py +++ b/patchwork/rest_serializers.py @@ -19,7 +19,18 @@ from rest_framework.serializers import HyperlinkedModelSerializer -from patchwork.models import Project +from patchwork.models import Person, Project + + +class PersonSerializer(HyperlinkedModelSerializer): + class Meta: + model = Person + exclude = ('user',) + + def to_representation(self, instance): + data = super(PersonSerializer, self).to_representation(instance) + data['username'] = instance.user.username if instance.user else '' + return data class ProjectSerializer(HyperlinkedModelSerializer): diff --git a/patchwork/tests/test_rest_api.py b/patchwork/tests/test_rest_api.py index 56c07a4..05886bd 100644 --- a/patchwork/tests/test_rest_api.py +++ b/patchwork/tests/test_rest_api.py @@ -118,3 +118,57 @@ class TestProjectAPI(APITestCase): resp = self.client.delete(self.api_url(1)) self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) 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.username, resp.data[0]['username']) + self.assertEqual(user.email, resp.data[0]['email']) + + 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.assertEqual('', resp.data[0]['username']) + + 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(1)) + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) + + resp = self.client.patch(self.api_url(1), {'email': 'f...@f.com'}) + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) + + resp = self.client.post(self.api_url(), {'email': 'f...@f.com'}) + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) diff --git a/patchwork/views/rest_api.py b/patchwork/views/rest_api.py index 8c207ff..c7e511f 100644 --- a/patchwork/views/rest_api.py +++ b/patchwork/views/rest_api.py @@ -19,8 +19,7 @@ from django.conf import settings -from patchwork.models import Project -from patchwork.rest_serializers import ProjectSerializer +from patchwork.rest_serializers import ProjectSerializer, PersonSerializer from rest_framework import permissions from rest_framework.pagination import PageNumberPagination @@ -67,12 +66,33 @@ class PatchworkPermission(permissions.BasePermission): return obj.is_editable(request.user) -class ProjectViewSet(ModelViewSet): +class AuthenticatedReadOnly(permissions.BasePermission): + def has_permission(self, request, view): + authenticated = request.user.is_authenticated() + return authenticated and request.method in permissions.SAFE_METHODS + + +class PatchworkViewSet(ModelViewSet): + pagination_class = LinkHeaderPagination + + def get_queryset(self): + return self.serializer_class.Meta.model.objects.all() + + +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, ) - queryset = Project.objects.all() serializer_class = ProjectSerializer - pagination_class = LinkHeaderPagination router = DefaultRouter() +router.register('people', PeopleViewSet, 'person') router.register('projects', ProjectViewSet, 'project') -- 2.7.4 _______________________________________________ Patchwork mailing list Patchwork@lists.ozlabs.org https://lists.ozlabs.org/listinfo/patchwork