Browse Source

Merge branch 'master' into DIV-1022

# Conflicts:
#	edivorce/apps/core/static/css/main.css
pull/172/head
ariannedee 5 years ago
parent
commit
7b27ad520a
10 changed files with 112 additions and 50 deletions
  1. +2
    -18
      edivorce/apps/core/serializer.py
  2. +1
    -1
      edivorce/apps/core/static/css/main.css
  3. +15
    -0
      edivorce/apps/core/static/css/main.scss
  4. +3
    -5
      edivorce/apps/core/templates/partials/alias_field.html
  5. +1
    -1
      edivorce/apps/core/templates/partials/filing_location.html
  6. +11
    -3
      edivorce/apps/core/tests/test_api.py
  7. +3
    -3
      edivorce/apps/core/tests/test_logic.py
  8. +21
    -16
      edivorce/apps/core/tests/test_upload.py
  9. +37
    -2
      edivorce/apps/core/utils/conditional_logic.py
  10. +18
    -1
      edivorce/apps/core/validators.py

+ 2
- 18
edivorce/apps/core/serializer.py View File

@ -3,6 +3,7 @@ from rest_framework import serializers
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from .models import Document, UserResponse from .models import Document, UserResponse
from .validators import file_scan_validation, valid_file_extension, valid_doc_type, valid_rotation
class UserResponseSerializer(serializers.ModelSerializer): class UserResponseSerializer(serializers.ModelSerializer):
@ -23,22 +24,10 @@ class UserResponseSerializer(serializers.ModelSerializer):
instance.save() instance.save()
def valid_file_extension(file):
extension = file.name.split('.')[-1]
if extension.lower() not in ['pdf', 'png', 'gif', 'jpg', 'jpe', 'jpeg']:
raise ValidationError(f'File type not supported: {extension}')
def valid_doc_type(value):
valid_codes = ['AAI', 'AFDO', 'AFTL', 'CSA', 'EFSS', 'MC', 'NCV', 'OFI', 'RDP']
if value.upper() not in valid_codes:
raise ValidationError(f'Doc type not supported: {value}. Valid codes: {", ".join(valid_codes)}')
class CreateDocumentSerializer(serializers.ModelSerializer): class CreateDocumentSerializer(serializers.ModelSerializer):
doc_type = serializers.CharField(required=True, validators=[valid_doc_type]) doc_type = serializers.CharField(required=True, validators=[valid_doc_type])
party_code = serializers.IntegerField(min_value=0, max_value=2, required=True) party_code = serializers.IntegerField(min_value=0, max_value=2, required=True)
file = serializers.FileField(required=True, validators=[valid_file_extension])
file = serializers.FileField(required=True, validators=[valid_file_extension,file_scan_validation])
filename = serializers.CharField(read_only=True) filename = serializers.CharField(read_only=True)
size = serializers.IntegerField(read_only=True) size = serializers.IntegerField(read_only=True)
rotation = serializers.IntegerField(read_only=True) rotation = serializers.IntegerField(read_only=True)
@ -62,11 +51,6 @@ class CreateDocumentSerializer(serializers.ModelSerializer):
return response 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): class DocumentMetadataSerializer(serializers.ModelSerializer):
doc_type = serializers.CharField(read_only=True) doc_type = serializers.CharField(read_only=True)
party_code = serializers.IntegerField(read_only=True) party_code = serializers.IntegerField(read_only=True)


+ 1
- 1
edivorce/apps/core/static/css/main.css
File diff suppressed because it is too large
View File


+ 15
- 0
edivorce/apps/core/static/css/main.scss View File

@ -646,6 +646,21 @@ select.form-control {
} }
} }
div#other_names_fields {
.form-inline {
.form-group {
@media (min-width: 992px) {
flex: inherit;
}
}
label {
width: calc(100% - 90px);
text-align: left;
}
}
}
/* Buttons & Icons*/ /* Buttons & Icons*/
.btn { .btn {
line-height: initial; line-height: initial;


+ 3
- 5
edivorce/apps/core/templates/partials/alias_field.html View File

@ -1,5 +1,5 @@
{% load input_field %} {% load input_field %}
<div class="form-inline clearfix alias-field-group">
<div class="form-inline clearfix alias-field-group alias-header">
{% comment As per request, alias type will fixed to "also know as" %} {% comment As per request, alias type will fixed to "also know as" %}
<select class="response-dropdown alias-type form-control" name={{name}}> <select class="response-dropdown alias-type form-control" name={{name}}>
<option value="also known as" {% if alias_type == 'also known as' %} selected {% endif %}>Also known as</option> <option value="also known as" {% if alias_type == 'also known as' %} selected {% endif %}>Also known as</option>
@ -9,10 +9,8 @@
</select> </select>
{% endcomment %} {% endcomment %}
<div class="alias-header">
<label>Also known as</label>
<input type="button" class="btn btn-danger btn-delete-name form-control pull-right" value="Delete" />
</div>
<label>Also known as</label>
<input type="button" class="btn btn-danger btn-delete-name form-control pull-right" value="Delete" />
<div class="form-group name-group alias-body"> <div class="form-group name-group alias-body">
<div> <div>
<p>First Name</p> <p>First Name</p>


+ 1
- 1
edivorce/apps/core/templates/partials/filing_location.html View File

@ -1,6 +1,6 @@
{% if court_registry_for_filing %} {% if court_registry_for_filing %}
<ul class="no-bullets" id="court-registry-location"> <ul class="no-bullets" id="court-registry-location">
<li id="court-registry-city">{{ court_registry_for_filing }}</li>
<li id="court-registry-city"><b>{{ court_registry_for_filing }}</b></li>
<li id="court-registry-address"></li> <li id="court-registry-address"></li>
<li id="court-registry-postal-code"></li> <li id="court-registry-postal-code"></li>
</ul> </ul>


+ 11
- 3
edivorce/apps/core/tests/test_api.py View File

@ -72,7 +72,10 @@ class APITest(APITestCase):
'party_code': 1 'party_code': 1
} }
self.client.force_authenticate(self.user) self.client.force_authenticate(self.user)
response = self.client.post(url, data)
with self.settings(CLAMAV_ENABLED=False):
response = self.client.post(url, data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Document.objects.count(), 1) self.assertEqual(Document.objects.count(), 1)
@ -97,13 +100,18 @@ class APITest(APITestCase):
'party_code': 1 'party_code': 1
} }
self.client.force_authenticate(self.user) self.client.force_authenticate(self.user)
response = self.client.post(url, data)
with self.settings(CLAMAV_ENABLED=False):
response = self.client.post(url, data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Document.objects.count(), 1) self.assertEqual(Document.objects.count(), 1)
file.seek(0) # file.seek(0) #
response = self.client.post(url, data)
with self.settings(CLAMAV_ENABLED=False):
response = self.client.post(url, data)
self.assertContains(response, self.assertContains(response,
'This file appears to have already been uploaded for this document.', 'This file appears to have already been uploaded for this document.',
status_code=status.HTTP_400_BAD_REQUEST) status_code=status.HTTP_400_BAD_REQUEST)


+ 3
- 3
edivorce/apps/core/tests/test_logic.py View File

@ -32,13 +32,13 @@ class ConditionalLogicTestCase(TestCase):
self.assertIsNone(logic.get_cleaned_response_value(' ')) self.assertIsNone(logic.get_cleaned_response_value(' '))
self.assertIsNone(logic.get_cleaned_response_value('[]')) self.assertIsNone(logic.get_cleaned_response_value('[]'))
self.assertIsNone(logic.get_cleaned_response_value('[[""," "]]')) self.assertIsNone(logic.get_cleaned_response_value('[[""," "]]'))
self.assertIsNone(logic.get_cleaned_response_value('[["also known as",""]]'))
self.assertIsNone(logic.get_cleaned_response_value('[["also known as",""],["also known as",""]]'))
self.assertIsNone(logic.get_cleaned_response_value('[["also known as","","","",""]]'))
self.assertIsNone(logic.get_cleaned_response_value('[["also known as","","","",""],["also known as","","","",""]]'))
def test_get_cleaned_response_with_value(self): def test_get_cleaned_response_with_value(self):
self.assertIsNotNone(logic.get_cleaned_response_value('0')) self.assertIsNotNone(logic.get_cleaned_response_value('0'))
self.assertIsNotNone(logic.get_cleaned_response_value('["hi"]')) self.assertIsNotNone(logic.get_cleaned_response_value('["hi"]'))
self.assertIsNotNone(logic.get_cleaned_response_value('[["also known as","a"]]'))
self.assertIsNotNone(logic.get_cleaned_response_value('[["also known as","a","b","",""]]'))
def test_num_children(self): def test_num_children(self):
# No children # No children


+ 21
- 16
edivorce/apps/core/tests/test_upload.py View File

@ -2,15 +2,20 @@ import clamd
from clamd import BufferTooLongError from clamd import BufferTooLongError
from unittest import mock from unittest import mock
from django import forms
from django.test import TestCase from django.test import TestCase
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from rest_framework import serializers
from ..validators import file_scan_validation from ..validators import file_scan_validation
from ..models import Document
class TestUploadForm(forms.Form):
upload = forms.FileField(validators=[file_scan_validation])
class TestUploadSerializer(serializers.ModelSerializer):
upload = serializers.FileField(validators=[file_scan_validation])
class Meta:
model = Document
fields = ('upload', 'filename')
class UploadScanTests(TestCase): class UploadScanTests(TestCase):
@ -18,17 +23,17 @@ class UploadScanTests(TestCase):
def test_validation_disabled(self): def test_validation_disabled(self):
with self.settings(CLAMAV_ENABLED=False): with self.settings(CLAMAV_ENABLED=False):
infected = SimpleUploadedFile('infected.txt', clamd.EICAR) infected = SimpleUploadedFile('infected.txt', clamd.EICAR)
form = TestUploadForm(files={'upload': infected})
serializer = TestUploadSerializer(data={'upload': infected})
self.assertTrue(form.is_valid(), form.errors)
self.assertTrue(serializer.is_valid(), serializer.errors)
def test_validation_invalid_network_connection(self): def test_validation_invalid_network_connection(self):
with self.settings(CLAMAV_TCP_PORT=9999): with self.settings(CLAMAV_TCP_PORT=9999):
infected = SimpleUploadedFile('infected.txt', clamd.EICAR) infected = SimpleUploadedFile('infected.txt', clamd.EICAR)
form = TestUploadForm(files={'upload': infected})
serializer = TestUploadSerializer(data={'upload': infected})
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['upload'][0], 'Unable to scan file.')
self.assertFalse(serializer.is_valid())
self.assertEqual(serializer.errors['upload'][0], 'Unable to scan file.')
@mock.patch('clamd.ClamdNetworkSocket.instream') @mock.patch('clamd.ClamdNetworkSocket.instream')
def test_validation_buffer_overflow(self, mock_clam): def test_validation_buffer_overflow(self, mock_clam):
@ -36,26 +41,26 @@ class UploadScanTests(TestCase):
# by default clamav has a 10mb limit for instream # by default clamav has a 10mb limit for instream
clean = SimpleUploadedFile('clean.txt', b'clean file') clean = SimpleUploadedFile('clean.txt', b'clean file')
form = TestUploadForm(files={'upload': clean})
serializer = TestUploadSerializer(data={'upload': clean})
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['upload'][0], 'Unable to scan file.')
self.assertFalse(serializer.is_valid())
self.assertEqual(serializer.errors['upload'][0], 'Unable to scan file.')
@mock.patch('clamd.ClamdNetworkSocket.instream') @mock.patch('clamd.ClamdNetworkSocket.instream')
def test_validation_virus_found(self, mock_clam): def test_validation_virus_found(self, mock_clam):
mock_clam.return_value = {'stream': ('FOUND', 'Eicar-Test-Signature')} mock_clam.return_value = {'stream': ('FOUND', 'Eicar-Test-Signature')}
infected = SimpleUploadedFile('infected.txt', clamd.EICAR) infected = SimpleUploadedFile('infected.txt', clamd.EICAR)
form = TestUploadForm(files={'upload': infected})
serializer = TestUploadSerializer(data={'upload': infected})
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['upload'][0], 'Infected file found.')
self.assertFalse(serializer.is_valid())
self.assertEqual(serializer.errors['upload'][0], 'Infected file found.')
@mock.patch('clamd.ClamdNetworkSocket.instream') @mock.patch('clamd.ClamdNetworkSocket.instream')
def test_validation_no_virus_found(self, mock_clam): def test_validation_no_virus_found(self, mock_clam):
mock_clam.return_value = {'stream': ('OK', None)} mock_clam.return_value = {'stream': ('OK', None)}
clean = SimpleUploadedFile('clean.txt', b'clean file') clean = SimpleUploadedFile('clean.txt', b'clean file')
form = TestUploadForm(files={'upload': clean})
serializer = TestUploadSerializer(data={'upload': clean})
self.assertTrue(form.is_valid())
self.assertTrue(serializer.is_valid())

+ 37
- 2
edivorce/apps/core/utils/conditional_logic.py View File

@ -194,7 +194,42 @@ def get_cleaned_response_value(response):
if response is None: if response is None:
return None return None
response = response.strip() response = response.strip()
search_text = response.replace('also known as', '')
if re.search(r'\w+', search_text):
if response.startswith('[["also known as","'):
return __get_cleaned_aka(response)
if re.search(r'\w+', response):
return response return response
return None return None
def __get_cleaned_aka(response):
"""Checks is other_name_you and other_name_spouse (a.k.a. fields) are valid, and
containt both a first name and a last name"""
try:
aka = json.loads(response)
except:
return None
if len(aka) == 0 or len(aka[0]) != 5:
return None
has_lastname1 = re.search(r'\w+', aka[0][1])
has_firstname1 = re.search(r'\w+', aka[0][2])
if has_lastname1 and has_firstname1:
if len(aka) == 1:
return response
has_lastname2 = re.search(r'\w+', aka[1][1])
has_firstname2 = re.search(r'\w+', aka[1][2])
# firstname and lastname can both be blank or both have values
# but you can't have a value for one and not the other.
if has_lastname2 and has_firstname2:
return response
if not has_lastname2 and not has_firstname2:
return response
return None

+ 18
- 1
edivorce/apps/core/validators.py View File

@ -2,7 +2,7 @@ import logging
import clamd import clamd
import sys import sys
from django.core.exceptions import ValidationError
from rest_framework.exceptions import ValidationError
from django.conf import settings from django.conf import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -42,3 +42,20 @@ def file_scan_validation(file):
if result and result['stream'][0] == 'FOUND': if result and result['stream'][0] == 'FOUND':
logger.warning('Virus found: {}'.format(file.name)) logger.warning('Virus found: {}'.format(file.name))
raise ValidationError('Infected file found.', code='infected') raise ValidationError('Infected file found.', code='infected')
def valid_file_extension(file):
extension = file.name.split('.')[-1]
if extension.lower() not in ['pdf', 'png', 'gif', 'jpg', 'jpe', 'jpeg']:
raise ValidationError(f'File type not supported: {extension}')
def valid_doc_type(value):
valid_codes = ['AAI', 'AFDO', 'AFTL', 'CSA', 'EFSS', 'MC', 'NCV', 'OFI', 'RDP']
if value.upper() not in valid_codes:
raise ValidationError(f'Doc type not supported: {value}. Valid codes: {", ".join(valid_codes)}')
def valid_rotation(value):
if value % 90 != 0:
raise ValidationError('Rotation must be 0, 90, 180, or 270')

Loading…
Cancel
Save