Browse Source

Merge pull request #110 from bcgov/DIV-1152

DIV-1152: Add API for uploading documents
pull/170/head
Arianne 5 years ago
committed by GitHub
parent
commit
c175590b87
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 159 additions and 72 deletions
  1. +33
    -0
      edivorce/apps/core/migrations/0021_document.py
  2. +58
    -6
      edivorce/apps/core/models.py
  3. +27
    -1
      edivorce/apps/core/serializer.py
  4. +1
    -2
      edivorce/apps/core/tests/test_storage.py
  5. +7
    -2
      edivorce/apps/core/urls.py
  6. +15
    -3
      edivorce/apps/core/views/api.py
  7. +16
    -0
      edivorce/apps/poc/migrations/0010_delete_document.py
  8. +0
    -56
      edivorce/apps/poc/models.py
  9. +1
    -1
      edivorce/apps/poc/views.py
  10. +1
    -1
      vue/src/components/Uploader/Uploader.vue

+ 33
- 0
edivorce/apps/core/migrations/0021_document.py View File

@ -0,0 +1,33 @@
# Generated by Django 2.2.15 on 2020-09-24 00:37
from django.db import migrations, models
import django.db.models.deletion
import edivorce.apps.core.redis
class Migration(migrations.Migration):
dependencies = [
('core', '0020_auto_20200903_2328'),
]
operations = [
migrations.CreateModel(
name='Document',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('filename', models.CharField(max_length=128, null=True)),
('size', models.IntegerField(default=0)),
('file', models.FileField(storage=edivorce.apps.core.redis.RedisStorage(), upload_to=edivorce.apps.core.redis.generate_unique_filename)),
('doc_type', models.CharField(blank=True, max_length=4, null=True)),
('party_code', models.IntegerField(default=0)),
('sort_order', models.IntegerField(default=1)),
('rotation', models.IntegerField(default=0)),
('date_uploaded', models.DateTimeField(auto_now_add=True)),
('bceid_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='uploads', to='core.BceidUser')),
],
options={
'unique_together': {('bceid_user', 'doc_type', 'party_code', 'filename', 'size')},
},
),
]

+ 58
- 6
edivorce/apps/core/models.py View File

@ -3,6 +3,8 @@ from django.db import models
from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from edivorce.apps.core import redis
@python_2_unicode_compatible
class BceidUser(models.Model):
@ -109,6 +111,55 @@ class UserResponse(models.Model):
return '%s -> %s' % (self.bceid_user, self.question.key)
class Document(models.Model):
filename = models.CharField(max_length=128, null=True) # saving the original filename separately
""" File name and extension """
size = models.IntegerField(default=0)
""" Size of the file (size and name uniquely identify each file on the input) """
file = models.FileField(upload_to=redis.generate_unique_filename, storage=redis.RedisStorage())
""" File temporarily stored in Redis """
doc_type = models.CharField(max_length=4, null=True, blank=True)
""" CEIS Document Type Code (2-4 letters) """
party_code = models.IntegerField(default=0)
""" 1 = You, 2 = Your Spouse, 0 = Shared """
sort_order = models.IntegerField(default=1)
""" file order (page number in the PDF) """
rotation = models.IntegerField(default=0)
""" 0, 90, 180 or 270 """
bceid_user = models.ForeignKey(BceidUser, related_name='uploads', on_delete=models.CASCADE)
""" User who uploaded the attachment """
date_uploaded = models.DateTimeField(auto_now_add=True)
""" Date the record was last updated """
class Meta:
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
super(Document, self).save(*args, **kwargs)
def delete(self, **kwargs):
"""
Override delete so we can delete the Redis object when this instance is deleted.
"""
self.file.delete(save=False)
super(Document, self).delete(**kwargs)
def str(self):
return f'User {self.bceid_user.display_name}: {self.filename} ({self.doc_type} - {self.party_code})'
class DontLog:
def log_addition(self, *args):
return
@ -120,7 +171,11 @@ class DontLog:
return
class UserResponseAdmin(DontLog, admin.ModelAdmin):
class BaseAdmin(DontLog, admin.ModelAdmin):
pass
class UserResponseAdmin(BaseAdmin):
list_display = ['get_user_name', 'question', 'value']
def get_user_name(self, obj):
@ -130,10 +185,7 @@ class UserResponseAdmin(DontLog, admin.ModelAdmin):
get_user_name.short_description = 'User'
class QuestionAdmin(DontLog, admin.ModelAdmin):
pass
admin.site.register(BceidUser)
admin.site.register(Question, QuestionAdmin)
admin.site.register(Question, BaseAdmin)
admin.site.register(UserResponse, UserResponseAdmin)
admin.site.register(Document, BaseAdmin)

+ 27
- 1
edivorce/apps/core/serializer.py View File

@ -1,5 +1,8 @@
from django.db import IntegrityError
from rest_framework import serializers
from .models import UserResponse
from rest_framework.exceptions import ValidationError
from .models import Document, UserResponse
class UserResponseSerializer(serializers.ModelSerializer):
@ -20,4 +23,27 @@ 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()
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)
class Meta:
model = Document
fields = ('file', 'doc_type', 'party_code', 'filename', 'size', 'rotation', 'sort_order')
def create(self, validated_data):
filename = validated_data['file'].name
size = validated_data['file'].size
user = self.context['request'].user
order = Document.objects.filter(bceid_user=user, doc_type=validated_data['doc_type'], party_code=validated_data['party_code']).count() + 1
response = Document(bceid_user=user, filename=filename, size=size, sort_order=order, **validated_data)
try:
response.save()
except IntegrityError:
raise ValidationError("You have already uploaded that file")
return response

+ 1
- 2
edivorce/apps/core/tests/test_storage.py View File

@ -4,9 +4,8 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TransactionTestCase
from redis.exceptions import ConnectionError
from edivorce.apps.core.models import BceidUser
from edivorce.apps.core.models import BceidUser, Document
from edivorce.apps.core.redis import generate_unique_filename
from edivorce.apps.poc.models import Document
class UploadStorageTests(TransactionTestCase):


+ 7
- 2
edivorce/apps/core/urls.py View File

@ -1,7 +1,8 @@
from django.conf.urls import url
from rest_framework.routers import DefaultRouter
from .views import main, system, pdf, api, localdev
from .views.api import DocumentViewSet
urlpatterns = [
# url(r'^guide$', styleguide.guide),
@ -32,4 +33,8 @@ urlpatterns = [
url(r'^question/(?P<step>.*)$', main.question, name="question_steps"),
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

+ 15
- 3
edivorce/apps/core/views/api.py View File

@ -1,9 +1,10 @@
from rest_framework import status
from rest_framework import permissions, status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from ..models import Question
from ..serializer import UserResponseSerializer
from ..models import Document, Question
from ..serializer import DocumentSerializer, UserResponseSerializer
from ..utils.question_step_mapping import question_step_mapping
from ..utils.user_response import save_to_session, save_to_db
@ -47,3 +48,14 @@ class UserResponseHandler(APIView):
return Response(status=status.HTTP_500_INTERNAL_ERROR)
return Response(status=status.HTTP_200_OK)
class DocumentViewSet(ModelViewSet):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Document.objects.all()
serializer_class = DocumentSerializer
def get_queryset(self):
if self.request.user.is_anonymous:
return Document.objects.none()
return Document.objects.filter(bceid_user=self.request.user)

+ 16
- 0
edivorce/apps/poc/migrations/0010_delete_document.py View File

@ -0,0 +1,16 @@
# Generated by Django 2.2.15 on 2020-09-24 00:37
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('poc', '0009_auto_20200922_1033'),
]
operations = [
migrations.DeleteModel(
name='Document',
),
]

+ 0
- 56
edivorce/apps/poc/models.py View File

@ -1,56 +0,0 @@
from django.db import models
from django.conf import settings
from edivorce.apps.core.models import BceidUser
from edivorce.apps.core import redis
class Document(models.Model):
"""
This is only a POC model and should not be loaded on a production system.
"""
filename = models.CharField(max_length=128, null=True) # saving the original filename separately
""" File name and extension """
size = models.IntegerField(default=0)
""" Size of the file (size and name uniquely identify each file on the input) """
file = models.FileField(upload_to=redis.generate_unique_filename, storage=redis.RedisStorage())
""" File temporarily stored in Redis """
doc_type = models.CharField(max_length=4, null=True, blank=True)
""" CEIS Document Type Code (2-4 letters) """
party_code = models.IntegerField(default=0)
""" 1 = You, 2 = Your Spouse, 0 = Shared """
sort_order = models.IntegerField(default=1)
""" file order (page number in the PDF) """
rotation = models.IntegerField(default=0)
""" 0, 90, 180 or 270 """
bceid_user = models.ForeignKey(BceidUser, related_name='uploads', on_delete=models.CASCADE)
""" User who uploaded the attachment """
date_uploaded = models.DateTimeField(auto_now_add=True)
""" Date the record was last updated """
class Meta:
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
super(Document, self).save(*args, **kwargs)
def delete(self, **kwargs):
"""
Override delete so we can delete the Redis object when this instance is deleted.
:param kwargs:
:return:
"""
self.file.delete(save=False)
super(Document, self).delete(**kwargs)

+ 1
- 1
edivorce/apps/poc/views.py View File

@ -10,7 +10,7 @@ from django.conf import settings
from edivorce.apps.core.efilinghub import EFilingHub, PACKAGE_PARTY_FORMAT
from edivorce.apps.core.validators import file_scan_validation
from edivorce.apps.poc.models import Document
from edivorce.apps.core.models import Document
logger = logging.getLogger(__name__)


+ 1
- 1
vue/src/components/Uploader/Uploader.vue View File

@ -126,7 +126,7 @@ export default {
return FormDefinitions[this.docType];
},
postAction() {
return this.$parent.proxyRootPath + "poc/storage"
return this.$parent.proxyRootPath + "api/documents/"
},
uniqueId() {
if (this.party === 0) {


Loading…
Cancel
Save