From 9816df36a8ec4d393e1b5aeac647b048b5926bfc Mon Sep 17 00:00:00 2001 From: ariannedee Date: Thu, 24 Sep 2020 19:25:45 -0700 Subject: [PATCH] DIV-1154 and 1156: Update API to retrieve document metadata and get image --- edivorce/apps/core/models.py | 19 +++++++++++--- edivorce/apps/core/serializer.py | 30 ++++++++++++++++++---- edivorce/apps/core/urls.py | 10 +++----- edivorce/apps/core/views/api.py | 43 ++++++++++++++++++++++++++------ 4 files changed, 79 insertions(+), 23 deletions(-) diff --git a/edivorce/apps/core/models.py b/edivorce/apps/core/models.py index 95933c4b..7397e5e3 100644 --- a/edivorce/apps/core/models.py +++ b/edivorce/apps/core/models.py @@ -1,5 +1,7 @@ from django.contrib import admin from django.db import models +from django.db.models import F +from django.urls import reverse from django.utils import timezone from django.utils.encoding import python_2_unicode_compatible @@ -143,8 +145,10 @@ class Document(models.Model): unique_together = ("bceid_user", "doc_type", "party_code", "filename", "size") def save(self, *args, **kwargs): - self.filename = self.file.name - self.size = self.file.size + if not self.filename: + self.filename = self.file.name + if not self.size: + self.size = self.file.size super(Document, self).save(*args, **kwargs) @@ -153,12 +157,19 @@ class Document(models.Model): Override delete so we can delete the Redis object when this instance is deleted. """ self.file.delete(save=False) - + self.update_sort_orders() super(Document, self).delete(**kwargs) - def str(self): + def __str__(self): return f'User {self.bceid_user.display_name}: {self.filename} ({self.doc_type} - {self.party_code})' + def get_file_url(self): + return reverse('document', kwargs={'filename': self.filename, 'doc_type': self.doc_type, 'party_code': self.party_code, 'size': self.size}) + + def update_sort_orders(self): + q = Document.objects.filter(bceid_user=self.bceid_user, doc_type=self.doc_type, party_code=self.party_code, sort_order__gt=self.sort_order) + q.update(sort_order=F('sort_order') - 1) + class DontLog: def log_addition(self, *args): diff --git a/edivorce/apps/core/serializer.py b/edivorce/apps/core/serializer.py index 12981ab5..fe11a4e2 100644 --- a/edivorce/apps/core/serializer.py +++ b/edivorce/apps/core/serializer.py @@ -23,18 +23,19 @@ class UserResponseSerializer(serializers.ModelSerializer): instance.save() -class DocumentSerializer(serializers.ModelSerializer): - doc_type = serializers.CharField() - party_code = serializers.IntegerField(min_value=0, max_value=2) - file = serializers.FileField() +class CreateDocumentSerializer(serializers.ModelSerializer): + doc_type = serializers.CharField(required=True) + party_code = serializers.IntegerField(min_value=0, max_value=2, required=True) + file = serializers.FileField(required=True) filename = serializers.CharField(read_only=True) size = serializers.IntegerField(read_only=True) rotation = serializers.IntegerField(read_only=True) sort_order = serializers.IntegerField(read_only=True) + file_url = serializers.URLField(source='get_file_url', read_only=True) class Meta: model = Document - fields = ('file', 'doc_type', 'party_code', 'filename', 'size', 'rotation', 'sort_order') + fields = ('file', 'doc_type', 'party_code', 'filename', 'size', 'rotation', 'sort_order', 'file_url') def create(self, validated_data): filename = validated_data['file'].name @@ -47,3 +48,22 @@ class DocumentSerializer(serializers.ModelSerializer): except IntegrityError: raise ValidationError("You have already uploaded that file") return response + + +def valid_rotation(value): + if value % 90 != 0: + raise serializers.ValidationError('Rotation must be 0, 90, 180, or 270') + + +class DocumentMetadataSerializer(serializers.ModelSerializer): + doc_type = serializers.CharField(read_only=True) + party_code = serializers.IntegerField(read_only=True) + filename = serializers.CharField(read_only=True) + size = serializers.IntegerField(read_only=True) + rotation = serializers.IntegerField(min_value=0, max_value=270, validators=[valid_rotation]) + sort_order = serializers.IntegerField(read_only=True) + file_url = serializers.URLField(source='get_file_url', read_only=True) + + class Meta: + model = Document + fields = ('doc_type', 'party_code', 'filename', 'size', 'rotation', 'sort_order', 'file_url') diff --git a/edivorce/apps/core/urls.py b/edivorce/apps/core/urls.py index 187b61fc..bc77a4b9 100644 --- a/edivorce/apps/core/urls.py +++ b/edivorce/apps/core/urls.py @@ -1,12 +1,14 @@ from django.conf.urls import url -from rest_framework.routers import DefaultRouter +from django.urls import path from .views import main, system, pdf, api, localdev -from .views.api import DocumentViewSet urlpatterns = [ # url(r'^guide$', styleguide.guide), url(r'^api/response$', api.UserResponseHandler.as_view()), + url(r'^api/documents/$', api.DocumentCreateView.as_view(), name='documents'), + path('api/documents///', api.DocumentMetaDataView.as_view(), name='documents-meta'), + path('api/documents/////', api.DocumentView.as_view(), name='document'), # url(r'^login/headers$', system.headers), @@ -34,7 +36,3 @@ urlpatterns = [ url(r'^current$', system.current, name="current"), url(r'^$', main.home, name="home"), ] - -router = DefaultRouter() -router.register(r'api/documents', DocumentViewSet, basename='document') -urlpatterns += router.urls diff --git a/edivorce/apps/core/views/api.py b/edivorce/apps/core/views/api.py index 24d92888..8215a636 100644 --- a/edivorce/apps/core/views/api.py +++ b/edivorce/apps/core/views/api.py @@ -1,10 +1,11 @@ +from django.http import HttpResponse, HttpResponseGone from rest_framework import permissions, status +from rest_framework.generics import CreateAPIView, ListAPIView, RetrieveUpdateDestroyAPIView from rest_framework.views import APIView from rest_framework.response import Response -from rest_framework.viewsets import ModelViewSet from ..models import Document, Question -from ..serializer import DocumentSerializer, UserResponseSerializer +from ..serializer import CreateDocumentSerializer, DocumentMetadataSerializer, UserResponseSerializer from ..utils.question_step_mapping import question_step_mapping from ..utils.user_response import save_to_session, save_to_db @@ -50,12 +51,38 @@ class UserResponseHandler(APIView): return Response(status=status.HTTP_200_OK) -class DocumentViewSet(ModelViewSet): - permission_classes = [permissions.IsAuthenticatedOrReadOnly] +class DocumentCreateView(CreateAPIView): + serializer_class = CreateDocumentSerializer + permission_classes = [permissions.IsAuthenticated] queryset = Document.objects.all() - serializer_class = DocumentSerializer + + +class DocumentMetaDataView(ListAPIView): + serializer_class = DocumentMetadataSerializer + permission_classes = [permissions.IsAuthenticated] def get_queryset(self): - if self.request.user.is_anonymous: - return Document.objects.none() - return Document.objects.filter(bceid_user=self.request.user) \ No newline at end of file + doc_type = self.kwargs['doc_type'] + party_code = self.kwargs['party_code'] + return Document.objects.filter(doc_type=doc_type, party_code=party_code, bceid_user=self.request.user).order_by('sort_order') + + +class DocumentView(RetrieveUpdateDestroyAPIView): + serializer_class = DocumentMetadataSerializer + permission_classes = [permissions.IsAuthenticated] + + def get_object(self): + return Document.objects.get(bceid_user=self.request.user, **self.kwargs) + + def retrieve(self, request, *args, **kwargs): + """ Return the file instead of meta data """ + doc = self.get_object() + content_type = 'application/pdf' if 'pdf' in doc.filename else 'image/jpeg' + + # If file doesn't exist anymore, delete it + try: + file_contents = doc.file.read() + except TypeError: + doc.delete() + return HttpResponseGone('File no longer exists') + return HttpResponse(file_contents, content_type=content_type)