blob: ea84d9a5cb2100bc91356088426383c38ccad7c3 [file] [log] [blame]
Scott Baker8974e552015-02-10 19:26:00 -08001from rest_framework.response import Response
2from rest_framework import serializers
3from rest_framework import generics
4from rest_framework import status
5from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
6from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
7
8class XOSRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
9
10 # To handle fine-grained field permissions, we have to check can_update
11 # the object has been updated but before it has been saved.
12
13 def update(self, request, *args, **kwargs):
14 partial = kwargs.pop('partial', False)
15 self.object = self.get_object_or_none()
16
17 if self.object is None:
18 raise Exception("Use the List API for creating objects")
19
20 serializer = self.get_serializer(self.object, data=request.DATA,
21 files=request.FILES, partial=partial)
22
23 assert(serializer.object is not None)
24
25 serializer.object.caller = request.user
26
27 if not serializer.is_valid():
28 response = {"error": "validation",
29 "specific_error": "not serializer.is_valid()",
30 "reasons": serializer.errors}
31 return Response(response, status=status.HTTP_400_BAD_REQUEST)
32
33 try:
34 self.pre_save(serializer.object)
35 except ValidationError as err:
36 # full_clean on model instance may be called in pre_save,
37 # so we have to handle eventual errors.
38 response = {"error": "validation",
39 "specific_error": "ValidationError in pre_save",
40 "reasons": err.message_dict}
41 return Response(response, status=status.HTTP_400_BAD_REQUEST)
42
43 if not serializer.object.can_update(request.user):
44 return Response(status=status.HTTP_400_BAD_REQUEST)
45
46 self.object = serializer.save(force_update=True)
47 self.post_save(self.object, created=False)
48 return Response(serializer.data, status=status.HTTP_200_OK)
49
50 def destroy(self, request, *args, **kwargs):
51 obj = self.get_object()
Scott Baker3d85e0c2015-02-10 20:01:46 -080052 obj.caller = request.user
Scott Baker8974e552015-02-10 19:26:00 -080053 if obj.can_update(request.user):
Scott Baker3d85e0c2015-02-10 20:01:46 -080054 # this is the guts of DestroyModelMixin, copied here so that we
55 # can use the obj with caller set in it,
56 self.pre_delete(obj)
57 obj.delete()
58 self.post_delete(obj)
59 return Response(status=status.HTTP_204_NO_CONTENT)
Scott Baker8974e552015-02-10 19:26:00 -080060 else:
61 return Response(status=status.HTTP_400_BAD_REQUEST)
62
63 def handle_exception(self, exc):
64 # REST API drops the string attached to Django's PermissionDenied
65 # exception, and replaces it with a generic "Permission Denied"
66 if isinstance(exc, DjangoPermissionDenied):
67 response=Response({'detail': str(exc)}, status=status.HTTP_403_FORBIDDEN)
68 response.exception=True
69 return response
70 else:
71 return super(XOSRetrieveUpdateDestroyAPIView, self).handle_exception(exc)
72
73class XOSListCreateAPIView(generics.ListCreateAPIView):
74 def create(self, request, *args, **kwargs):
75 serializer = self.get_serializer(data=request.DATA, files=request.FILES)
76 if not (serializer.is_valid()):
77 response = {"error": "validation",
78 "specific_error": "not serializer.is_valid()",
79 "reasons": serializer.errors}
80 return Response(response, status=status.HTTP_400_BAD_REQUEST)
81
82 # now do XOS can_update permission checking
83
84 obj = serializer.object
85 obj.caller = request.user
86 if not obj.can_update(request.user):
87 response = {"error": "validation",
88 "specific_error": "failed can_update",
89 "reasons": []}
90 return Response(response, status=status.HTTP_400_BAD_REQUEST)
91
92 # stuff below is from generics.ListCreateAPIView
93
94 if (hasattr(self, "pre_save")):
95 # rest_framework 2.x
96 self.pre_save(serializer.object)
97 self.object = serializer.save(force_insert=True)
98 self.post_save(self.object, created=True)
99 else:
100 # rest_framework 3.x
101 self.perform_create(serializer)
102
103 headers = self.get_success_headers(serializer.data)
104 return Response(serializer.data, status=status.HTTP_201_CREATED,
105 headers=headers)
106
107 def handle_exception(self, exc):
108 # REST API drops the string attached to Django's PermissionDenied
109 # exception, and replaces it with a generic "Permission Denied"
110 if isinstance(exc, DjangoPermissionDenied):
111 response=Response({'detail': str(exc)}, status=status.HTTP_403_FORBIDDEN)
112 response.exception=True
113 return response
114 else:
115 return super(XOSListCreateAPIView, self).handle_exception(exc)
116