diff --git a/edivorce/apps/core/models.py b/edivorce/apps/core/models.py index b65401b5..0b1dddfa 100644 --- a/edivorce/apps/core/models.py +++ b/edivorce/apps/core/models.py @@ -1,3 +1,5 @@ +import re + from django.contrib import admin from django.db import models from django.db.models import F @@ -173,10 +175,33 @@ class Document(models.Model): 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 get_content_type(self): + return Document.content_type_from_filename(self.filename) + 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) + @staticmethod + def get_file(file_key): + return redis.RedisStorage().open(file_key) + + @staticmethod + def content_type_from_filename(filename): + content_types = { + "pdf": "application/pdf", + "gif": "image/gif", + "png": "image/png", + "jpe": "image/jpeg", + "jpg": "image/jpeg", + "jpeg": "image/jpeg" + } + extension = re.split(r'[\._]', filename.lower())[-1] + content_type = content_types.get(extension) + if not content_type: + return "application/unknown" + return content_type + class DontLog: def log_addition(self, *args): diff --git a/edivorce/apps/core/tests/test_logic.py b/edivorce/apps/core/tests/test_logic.py index 2eb0ac8c..94dc2b37 100644 --- a/edivorce/apps/core/tests/test_logic.py +++ b/edivorce/apps/core/tests/test_logic.py @@ -5,6 +5,7 @@ from django.test import TestCase from edivorce.apps.core.models import BceidUser, UserResponse from edivorce.apps.core.utils.conditional_logic import get_cleaned_response_value, get_num_children_living_with from edivorce.apps.core.utils.user_response import get_data_for_user +from edivorce.apps.core.models import Document class ConditionalLogicTestCase(TestCase): @@ -51,3 +52,21 @@ class ConditionalLogicTestCase(TestCase): self.assertEqual(get_num_children_living_with(self.questions_dict, 'Lives with you'), '1') self.assertEqual(get_num_children_living_with(self.questions_dict, 'Lives with spouse'), '2') self.assertEqual(get_num_children_living_with(self.questions_dict, 'Lives with both'), '3') + + +class ViewLogic(TestCase): + def test_content_type_from_filename(self): + self.assertEqual(Document.content_type_from_filename('test_file1.pdf'), 'application/pdf') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file1_pdf'), 'application/pdf') + self.assertEqual(Document.content_type_from_filename('test_file2.png'), 'image/png') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file2_png'), 'image/png') + self.assertEqual(Document.content_type_from_filename('Test File 3.GIF'), 'image/gif') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file_3_GIF'), 'image/gif') + self.assertEqual(Document.content_type_from_filename('Test_File--4.JPEG'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file_4_jpeg'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('TestFile5.jpe'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('redis_key_test_file_5_jpe'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('testFile6.jpeg'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('redis_key_testfile_6_jpeg'), 'image/jpeg') + self.assertEqual(Document.content_type_from_filename('test_file7.HEIC'), 'application/unknown') + self.assertEqual(Document.content_type_from_filename('redis_key_testfile_7_svgg'), 'application/unknown') diff --git a/edivorce/apps/core/urls.py b/edivorce/apps/core/urls.py index 53e613f2..62284f2e 100644 --- a/edivorce/apps/core/urls.py +++ b/edivorce/apps/core/urls.py @@ -7,8 +7,10 @@ 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'), + path('api/documents//', api.get_document_file_by_key, name='document_by_key'), + + # we add an extra 'x' to the file extension so the siteminder proxy doesn't treat it as an image + path('api/documents///x//', api.DocumentView.as_view(), name='document'), # url(r'^login/headers$', system.headers), diff --git a/edivorce/apps/core/views/api.py b/edivorce/apps/core/views/api.py index e3bf3005..cfc85f4f 100644 --- a/edivorce/apps/core/views/api.py +++ b/edivorce/apps/core/views/api.py @@ -1,12 +1,11 @@ import graphene import graphene_django -from django.http import HttpResponse, HttpResponseGone +from django.http import Http404, HttpResponse, HttpResponseGone from graphql import GraphQLError 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 os.path import splitext from ..models import Document, Question from ..serializer import CreateDocumentSerializer, DocumentMetadataSerializer, UserResponseSerializer @@ -61,16 +60,6 @@ class DocumentCreateView(CreateAPIView): queryset = Document.objects.all() -class DocumentMetaDataView(ListAPIView): - serializer_class = DocumentMetadataSerializer - permission_classes = [permissions.IsAuthenticated] - - def get_queryset(self): - 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] @@ -80,31 +69,30 @@ class DocumentView(RetrieveUpdateDestroyAPIView): def retrieve(self, request, *args, **kwargs): """ Return the file instead of meta data """ - doc = self.get_object() - - # Get the content-type based on the file extension - content_types = { - ".pdf": "application/pdf", - ".gif": "image/gif", - ".png": "image/png", - ".jpe": "image/jpeg", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg" - } - _, extension = splitext(doc.filename.lower()) - content_type = content_types[extension] + document = self.get_object() + content_type = Document.content_type_from_filename(document.filename) # If file doesn't exist anymore, delete it try: - file_contents = doc.file.read() + file_contents = document.file.read() except TypeError: - doc.delete() + document.delete() return HttpResponseGone('File no longer exists') return HttpResponse(file_contents, content_type=content_type) +def get_document_file_by_key(request, file_key): + file = Document.get_file(file_key) + content_type = Document.content_type_from_filename(file.name) + try: + return HttpResponse(file, content_type=content_type) + except TypeError: + raise Http404("File not found") + + class DocumentType(graphene_django.DjangoObjectType): file_url = graphene.String(source='get_file_url') + content_type = graphene.String(source='get_content_type') class Meta: model = Document diff --git a/edivorce/apps/poc/views.py b/edivorce/apps/poc/views.py index b6ac114a..69c8c566 100644 --- a/edivorce/apps/poc/views.py +++ b/edivorce/apps/poc/views.py @@ -60,6 +60,7 @@ class UploadStorage(CreateView): class UploadStorageDelete(DeleteView): model = Document success_url = settings.FORCE_SCRIPT_NAME + 'poc/storage' + template_name = 'poc/document_confirm_delete.html' def view_document_file(request, document_id): diff --git a/vue/README.md b/vue/README.md index e021a491..bcf8b254 100644 --- a/vue/README.md +++ b/vue/README.md @@ -5,12 +5,7 @@ npm install ``` -### Compiles and hot-reloads for development -``` -npm run serve -``` - -### Compiles and minifies for production +### Compile and minify ``` npm run build ``` diff --git a/vue/src/components/Uploader/Image.vue b/vue/src/components/Uploader/Image.vue index 12dd6ec0..e0b8a448 100644 --- a/vue/src/components/Uploader/Image.vue +++ b/vue/src/components/Uploader/Image.vue @@ -92,11 +92,12 @@ export default { i.fa-file-pdf-o, i.fa-frown-o { display: block; - font-size: 105px; - margin-left: 32px; - margin-top: 15px; - position: absolute; - top: 0; + font-size: 48px; + margin-left: 60px; + } + + i.fa-file-pdf-o { + color: #D5D5D5; } i.fa-frown-o { @@ -112,7 +113,7 @@ export default { } &.valid:hover { - background-color: #6484d3; + background-color: #365EBE; cursor: pointer; button.btn-remove { @@ -129,7 +130,7 @@ export default { } &:hover img { - opacity: 0.3; + opacity: 0.12; } } diff --git a/vue/src/components/Uploader/ItemTile.vue b/vue/src/components/Uploader/ItemTile.vue index b9c44196..d9736e52 100644 --- a/vue/src/components/Uploader/ItemTile.vue +++ b/vue/src/components/Uploader/ItemTile.vue @@ -1,11 +1,16 @@