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 <[email protected]> Reviewed-by: Daniel Axtens <[email protected]> Reviewed-by: Andy Doan <[email protected]> --- patchwork/api/user.py | 20 ++++++++++++++++---- patchwork/tests/test_rest_api.py | 16 +++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/patchwork/api/user.py b/patchwork/api/user.py index 8fe3e74..c5f7c05 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 d764945..195a71a 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': '[email protected]'}) + 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': '[email protected]'}) + resp = self.client.post(self.api_url(user.id), {'email': '[email protected]'}) self.assertEqual(status.HTTP_405_METHOD_NOT_ALLOWED, resp.status_code) -- 2.7.4 _______________________________________________ Patchwork mailing list [email protected] https://lists.ozlabs.org/listinfo/patchwork
