support fine-grained permission checks in API
[plstackapi.git] / planetstack / apigen / api.template.py
index e9dbeb8..f595d2b 100644 (file)
@@ -3,6 +3,7 @@ from rest_framework.response import Response
 from rest_framework.reverse import reverse
 from rest_framework import serializers
 from rest_framework import generics
+from rest_framework import status
 from core.models import *
 from django.forms import widgets
 from rest_framework import filters
@@ -70,6 +71,51 @@ serializerLookUp = {
                  None: None,
                 }
 
+class PlanetStackRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
+
+    # To handle fine-grained field permissions, we have to check can_update
+    # the object has been updated but before it has been saved.
+
+    def update(self, request, *args, **kwargs):\r
+        partial = kwargs.pop('partial', False)\r
+        self.object = self.get_object_or_none()\r
+\r
+        serializer = self.get_serializer(self.object, data=request.DATA,\r
+                                         files=request.FILES, partial=partial)\r
+\r
+        if not serializer.is_valid():\r
+            print "UpdateModelMixin: not serializer.is_valid"\r
+            print serializer.errors\r
+            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\r
+\r
+        try:\r
+            self.pre_save(serializer.object)\r
+        except ValidationError as err:\r
+            # full_clean on model instance may be called in pre_save,\r
+            # so we have to handle eventual errors.\r
+            return Response(err.message_dict, status=status.HTTP_400_BAD_REQUEST)\r
+\r
+        if serializer.object is not None:\r
+            if not serializer.object.can_update(request.user):\r
+                return Response(status=status.HTTP_400_BAD_REQUEST)\r
+\r
+        if self.object is None:\r
+            self.object = serializer.save(force_insert=True)\r
+            self.post_save(self.object, created=True)\r
+            return Response(serializer.data, status=status.HTTP_201_CREATED)\r
+\r
+        self.object = serializer.save(force_update=True)\r
+        self.post_save(self.object, created=False)\r
+        return Response(serializer.data, status=status.HTTP_200_OK)
+
+    def destroy(self, request, *args, **kwargs):
+        obj = self.get_object()
+        if obj.can_update(request.user):
+            return super({{ object.camel }}Detail, self).destroy(request, *args, **kwargs)
+        else:
+            return Response(status=status.HTTP_400_BAD_REQUEST)
+
+
 # Based on core/views/*.py
 {% for object in generator.all %}
 
@@ -99,7 +145,7 @@ class {{ object.camel }}List(generics.ListCreateAPIView):
         else:
             return Response(status=status.HTTP_400_BAD_REQUEST)
 
-class {{ object.camel }}Detail(generics.RetrieveUpdateDestroyAPIView):
+class {{ object.camel }}Detail(PlanetStackRetrieveUpdateDestroyAPIView):
     queryset = {{ object.camel }}.objects.select_related().all()
     serializer_class = {{ object.camel }}Serializer
     id_serializer_class = {{ object.camel }}IdSerializer
@@ -114,19 +160,8 @@ class {{ object.camel }}Detail(generics.RetrieveUpdateDestroyAPIView):
     def get_queryset(self):
         return {{ object.camel }}.select_by_user(self.request.user)
 
-    def update(self, request, *args, **kwargs):
-        obj = self.get_object()
-        if obj.can_update(request.user):
-            return super({{ object.camel }}Detail, self).update(request, *args, **kwargs)
-        else:
-            return Response(status=status.HTTP_400_BAD_REQUEST)
+    # update() is handled by PlanetStackRetrieveUpdateDestroyAPIView
 
-    def destroy(self, request, *args, **kwargs):
-        obj = self.get_object()
-        if obj.can_update(request.user):
-            return super({{ object.camel }}Detail, self).destroy(request, *args, **kwargs)
-        else:
-            return Response(status=status.HTTP_400_BAD_REQUEST)
-     
+    # destroy() is handled by PlanetStackRetrieveUpdateDestroyAPIView
 
 {% endfor %}