]> git.ipfire.org Git - thirdparty/patchwork.git/commitdiff
REST: Add Users to the API
authorAndy Doan <andy.doan@linaro.org>
Thu, 16 Jun 2016 21:13:19 +0000 (16:13 -0500)
committerStephen Finucane <stephen.finucane@intel.com>
Mon, 27 Jun 2016 17:20:17 +0000 (18:20 +0100)
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@linaro.org>
Signed-off-by: Stephen Finucane <stephen.finucane@intel.com>
patchwork/rest_serializers.py
patchwork/tests/test_rest_api.py
patchwork/views/rest_api.py

index 974d6d36db244284675fd0f5c070b6a45b5a03d4..0d6c041fbd9623f2d75bfd3671fdc6f293f28a54 100644 (file)
 # 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 Project
 
 
+class UserSerializer(HyperlinkedModelSerializer):
+    class Meta:
+        model = User
+        exclude = ('date_joined', 'groups', 'is_active', 'is_staff',
+                   'is_superuser', 'last_login', 'password',
+                   'user_permissions')
+
+
 class ProjectSerializer(HyperlinkedModelSerializer):
     class Meta:
         model = Project
index 010900ad21db88492cc35451b1604059652dadbc..d877941a120422b8d13c3ef2f7f7461c87694818 100644 (file)
@@ -114,3 +114,46 @@ class TestProjectAPI(APITestCase):
         resp = self.client.delete(self.api_url(self.project.id))
         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 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()
+        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@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)
index 8c207ff76402ae58fde6c5f7a9e26605ae9e073c..8cff44ea995523a95b310ab1b7331b7da4fe9840 100644 (file)
@@ -19,8 +19,8 @@
 
 from django.conf import settings
 
-from patchwork.models import Project
-from patchwork.rest_serializers import ProjectSerializer
+from patchwork.rest_serializers import (
+    ProjectSerializer, UserSerializer)
 
 from rest_framework import permissions
 from rest_framework.pagination import PageNumberPagination
@@ -67,12 +67,29 @@ 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 UserViewSet(PatchworkViewSet):
+    permission_classes = (AuthenticatedReadOnly, )
+    serializer_class = UserSerializer
+
+
+class ProjectViewSet(PatchworkViewSet):
     permission_classes = (PatchworkPermission, )
-    queryset = Project.objects.all()
     serializer_class = ProjectSerializer
-    pagination_class = LinkHeaderPagination
 
 
 router = DefaultRouter()
 router.register('projects', ProjectViewSet, 'project')
+router.register('users', UserViewSet, 'user')