]> git.ipfire.org Git - thirdparty/patchwork.git/commitdiff
REST: Make 'User.first_name', 'last_name' editable
authorStephen Finucane <stephen@that.guru>
Thu, 17 Nov 2016 01:00:04 +0000 (01:00 +0000)
committerStephen Finucane <stephen@that.guru>
Fri, 23 Dec 2016 23:41:33 +0000 (23:41 +0000)
In an ideal world, everything that can be done with the UI should also
be doable from the command line. The first and last names of the User
are low-value fields to allow customization of, but they are easily
implmented and move us towards the above goal.

Signed-off-by: Stephen Finucane <stephen@that.guru>
Reviewed-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Andy Doan <andy.doan@linaro.org>
patchwork/api/user.py
patchwork/tests/test_rest_api.py

index 8fe3e74ad9a82e6b0f39b37efcc90a1446471eee..c5f7c056bd94d4a9a5febb18b3a4cc45e3241a79 100644 (file)
 
 from django.contrib.auth.models import User
 from rest_framework.generics import ListAPIView
-from rest_framework.generics import RetrieveAPIView
-from rest_framework.permissions import IsAuthenticated
+from rest_framework.generics import RetrieveUpdateAPIView
+from rest_framework import permissions
 from rest_framework.serializers import HyperlinkedModelSerializer
 
 
+class IsOwnerOrReadOnly(permissions.BasePermission):
+
+    def has_object_permission(self, request, view, obj):
+        if request.method in permissions.SAFE_METHODS:
+            return True
+
+        return obj == request.user
+
+
 class UserSerializer(HyperlinkedModelSerializer):
 
     class Meta:
         model = User
         fields = ('url', 'username', 'first_name', 'last_name', 'email')
+        # we don't allow updating of emails via the API, as we need to
+        # validate that the User actually owns said email first
+        read_only_fields = ('username', 'email')
         extra_kwargs = {
             'url': {'view_name': 'api-user-detail'},
         }
@@ -37,7 +49,7 @@ class UserSerializer(HyperlinkedModelSerializer):
 class UserMixin(object):
 
     queryset = User.objects.all()
-    permission_classes = (IsAuthenticated,)
+    permission_classes = (permissions.IsAuthenticated, IsOwnerOrReadOnly)
     serializer_class = UserSerializer
 
 
@@ -47,7 +59,7 @@ class UserList(UserMixin, ListAPIView):
     pass
 
 
-class UserDetail(UserMixin, RetrieveAPIView):
+class UserDetail(UserMixin, RetrieveUpdateAPIView):
     """Show a user."""
 
     pass
index d76494508c239cd491d8361f567b4530952afbbf..195a71af2e79ce1c61703456030aabb66d5e3e11 100644 (file)
@@ -233,19 +233,25 @@ class TestUserAPI(APITestCase):
         self.assertNotIn('password', resp.data[0])
         self.assertNotIn('is_superuser', resp.data[0])
 
-    def test_readonly(self):
+    def test_update(self):
         user = create_maintainer()
         user.is_superuser = True
         user.save()
         self.client.force_authenticate(user=user)
 
-        resp = self.client.delete(self.api_url(1))
-        self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code)
+        resp = self.client.patch(self.api_url(user.id), {'first_name': 'Tan'})
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
 
-        resp = self.client.patch(self.api_url(1), {'email': 'foo@f.com'})
+    def test_create_delete(self):
+        user = create_maintainer()
+        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_405_METHOD_NOT_ALLOWED, resp.status_code)
 
-        resp = self.client.post(self.api_url(), {'email': 'foo@f.com'})
+        resp = self.client.post(self.api_url(user.id), {'email': 'foo@f.com'})
         self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code)