This exports user objects via the REST API. Security Constraints: * The API is read-only to authenticated users
Signed-off-by: Andy Doan <[email protected]> --- patchwork/rest_serializers.py | 12 ++++++++-- patchwork/tests/test_rest_api.py | 48 ++++++++++++++++++++++++++++++++++++++-- patchwork/views/rest_api.py | 9 +++++++- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/patchwork/rest_serializers.py b/patchwork/rest_serializers.py index 0bb8f23..4f22870 100644 --- a/patchwork/rest_serializers.py +++ b/patchwork/rest_serializers.py @@ -17,19 +17,27 @@ # along with Patchwork; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +from django.contrib.auth.models import User + from rest_framework.serializers import HyperlinkedModelSerializer from patchwork.models import Person, Project +class UserSerializer(HyperlinkedModelSerializer): + class Meta: + model = User + exclude = ('date_joined', 'groups', 'is_active', 'is_staff', + 'is_superuser', 'last_login', 'password', + 'user_permissions') + + 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 diff --git a/patchwork/tests/test_rest_api.py b/patchwork/tests/test_rest_api.py index 05886bd..80943b4 100644 --- a/patchwork/tests/test_rest_api.py +++ b/patchwork/tests/test_rest_api.py @@ -142,8 +142,9 @@ class TestPersonAPI(APITestCase): resp = self.client.get(self.api_url()) self.assertEqual(status.HTTP_200_OK, resp.status_code) self.assertEqual(1, len(resp.data)) + user_url = reverse('api_1.0:user-detail', args=[user.id]) self.assertEqual(user.username, resp.data[0]['name']) - self.assertEqual(user.username, resp.data[0]['username']) + self.assertIn(user_url, resp.data[0]['user']) self.assertEqual(user.email, resp.data[0]['email']) def test_unlinked_user(self): @@ -155,7 +156,50 @@ class TestPersonAPI(APITestCase): self.assertEqual(2, len(resp.data)) self.assertEqual( defaults.patch_author_person.name, resp.data[0]['name']) - self.assertEqual('', resp.data[0]['username']) + self.assertIsNone(resp.data[0]['user']) + + 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': '[email protected]'}) + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) + + resp = self.client.post(self.api_url(), {'email': '[email protected]'}) + self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code) + + [email protected](settings.ENABLE_REST_API, 'requires ENABLE_REST_API') +class TestUserAPI(APITestCase): + fixtures = ['default_states'] + + @staticmethod + def api_url(item=None): + if item is None: + return reverse('api_1.0:user-list') + return reverse('api_1.0:user-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]['username']) + self.assertNotIn('password', resp.data[0]) + self.assertNotIn('is_superuser', resp.data[0]) def test_readonly(self): defaults.project.save() diff --git a/patchwork/views/rest_api.py b/patchwork/views/rest_api.py index c7e511f..1cb8c88 100644 --- a/patchwork/views/rest_api.py +++ b/patchwork/views/rest_api.py @@ -19,7 +19,8 @@ from django.conf import settings -from patchwork.rest_serializers import ProjectSerializer, PersonSerializer +from patchwork.rest_serializers import ( + ProjectSerializer, PersonSerializer, UserSerializer) from rest_framework import permissions from rest_framework.pagination import PageNumberPagination @@ -88,6 +89,11 @@ class PeopleViewSet(PatchworkViewSet): return qs.select_related('user__username') +class UserViewSet(PatchworkViewSet): + permission_classes = (AuthenticatedReadOnly, ) + serializer_class = UserSerializer + + class ProjectViewSet(PatchworkViewSet): permission_classes = (PatchworkPermission, ) serializer_class = ProjectSerializer @@ -96,3 +102,4 @@ class ProjectViewSet(PatchworkViewSet): router = DefaultRouter() router.register('people', PeopleViewSet, 'person') router.register('projects', ProjectViewSet, 'project') +router.register('users', UserViewSet, 'user') -- 2.7.4 _______________________________________________ Patchwork mailing list [email protected] https://lists.ozlabs.org/listinfo/patchwork
