[PATCH v5 05/10] REST: Add Users to the API
Andy Doan
andy.doan at linaro.org
Fri May 27 11:12:41 AEST 2016
This exports user objects via the REST API.
Security Constraints:
* The API is read-only to authenticated users
Signed-off-by: Andy Doan <andy.doan at linaro.org>
---
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': 'foo at f.com'})
+ self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
+
+ resp = self.client.post(self.api_url(), {'email': 'foo at f.com'})
+ self.assertEqual(status.HTTP_403_FORBIDDEN, resp.status_code)
+
+
+ at unittest.skipUnless(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
More information about the Patchwork
mailing list