From: Stephen Finucane Date: Thu, 17 Nov 2016 01:00:04 +0000 (+0000) Subject: REST: Make 'User.first_name', 'last_name' editable X-Git-Tag: v2.0.0-rc1~120 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9ca87ce79fc3146185610d4581416d481bbf3a30;p=thirdparty%2Fpatchwork.git REST: Make 'User.first_name', 'last_name' editable 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 Reviewed-by: Daniel Axtens Reviewed-by: Andy Doan --- diff --git a/patchwork/api/user.py b/patchwork/api/user.py index 8fe3e74a..c5f7c056 100644 --- a/patchwork/api/user.py +++ b/patchwork/api/user.py @@ -19,16 +19,28 @@ 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 diff --git a/patchwork/tests/test_rest_api.py b/patchwork/tests/test_rest_api.py index d7649450..195a71af 100644 --- a/patchwork/tests/test_rest_api.py +++ b/patchwork/tests/test_rest_api.py @@ -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)