diff --git a/cadasta/questionnaires/managers.py b/cadasta/questionnaires/managers.py
index 9eb4468ec..8bca1f608 100644
--- a/cadasta/questionnaires/managers.py
+++ b/cadasta/questionnaires/managers.py
@@ -43,7 +43,9 @@
def create_children(children, errors=[], project=None, kwargs={}):
if children:
for c in children:
- if c.get('type') == 'group':
+ if c.get('type') == 'repeat':
+ create_children(c['children'], errors, project, kwargs)
+ elif c.get('type') == 'group':
model_name = 'QuestionGroup'
# parse attribute group
@@ -61,8 +63,9 @@ def create_children(children, errors=[], project=None, kwargs={}):
else:
model_name = 'Question'
- model = apps.get_model('questionnaires', model_name)
- model.objects.create_from_dict(dict=c, errors=errors, **kwargs)
+ if c.get('type') != 'repeat':
+ model = apps.get_model('questionnaires', model_name)
+ model.objects.create_from_dict(dict=c, errors=errors, **kwargs)
def create_options(options, question, errors=[]):
@@ -234,7 +237,6 @@ class QuestionManager(models.Manager):
def create_from_dict(self, errors=[], **kwargs):
dict = kwargs.pop('dict')
instance = self.model(**kwargs)
-
type_dict = {name: code for code, name in instance.TYPE_CHOICES}
instance.type = type_dict[dict.get('type')]
diff --git a/cadasta/questionnaires/tests/files/t_questionnaire.xlsx b/cadasta/questionnaires/tests/files/t_questionnaire.xlsx
new file mode 100644
index 000000000..868bbcd25
Binary files /dev/null and b/cadasta/questionnaires/tests/files/t_questionnaire.xlsx differ
diff --git a/cadasta/questionnaires/tests/files/test_standard_questionnaire_bad.xlsx b/cadasta/questionnaires/tests/files/t_questionnaire_bad.xlsx
similarity index 100%
rename from cadasta/questionnaires/tests/files/test_standard_questionnaire_bad.xlsx
rename to cadasta/questionnaires/tests/files/t_questionnaire_bad.xlsx
diff --git a/cadasta/questionnaires/tests/files/test_standard_questionnaire_2.xlsx b/cadasta/questionnaires/tests/files/t_questionnaire_geotype_select.xlsx
similarity index 100%
rename from cadasta/questionnaires/tests/files/test_standard_questionnaire_2.xlsx
rename to cadasta/questionnaires/tests/files/t_questionnaire_geotype_select.xlsx
diff --git a/cadasta/questionnaires/tests/files/t_questionnaire_repeat_location.xlsx b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_location.xlsx
new file mode 100644
index 000000000..59ec8e252
Binary files /dev/null and b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_location.xlsx differ
diff --git a/cadasta/questionnaires/tests/files/t_questionnaire_repeat_minus_tenure.xlsx b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_minus_tenure.xlsx
new file mode 100644
index 000000000..ce2c0251a
Binary files /dev/null and b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_minus_tenure.xlsx differ
diff --git a/cadasta/questionnaires/tests/files/t_questionnaire_repeat_party.xlsx b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_party.xlsx
new file mode 100644
index 000000000..3ccdbef78
Binary files /dev/null and b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_party.xlsx differ
diff --git a/cadasta/questionnaires/tests/files/t_questionnaire_repeat_party_minus_tenure.xlsx b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_party_minus_tenure.xlsx
new file mode 100644
index 000000000..af02224f6
Binary files /dev/null and b/cadasta/questionnaires/tests/files/t_questionnaire_repeat_party_minus_tenure.xlsx differ
diff --git a/cadasta/questionnaires/tests/files/test_standard_questionnaire.xlsx b/cadasta/questionnaires/tests/files/test_standard_questionnaire.xlsx
deleted file mode 100644
index abe282aeb..000000000
Binary files a/cadasta/questionnaires/tests/files/test_standard_questionnaire.xlsx and /dev/null differ
diff --git a/cadasta/questionnaires/tests/test_managers.py b/cadasta/questionnaires/tests/test_managers.py
index b86ee82c4..db555855c 100644
--- a/cadasta/questionnaires/tests/test_managers.py
+++ b/cadasta/questionnaires/tests/test_managers.py
@@ -58,6 +58,51 @@ def test_create_children(self):
questionnaire=questionnaire,
question_group__isnull=False).count() == 1
+ def test_create_children_with_repeat_group(self):
+ questionnaire = factories.QuestionnaireFactory.create()
+ children = [{
+ 'label': 'This form showcases the different question',
+ 'name': 'intro',
+ 'type': 'note'
+ }, {
+ 'label': 'Text question type',
+ 'name': 'text_questions',
+ 'type': 'repeat',
+ 'children': [
+ {
+ 'hint': 'Can be short or long but '
+ 'always one line (type = '
+ 'text)',
+ 'label': 'Text',
+ 'name': 'my_string',
+ 'type': 'text'
+ },
+ {
+ 'hint': 'Nested group',
+ 'label': 'Group',
+ 'name': 'my_group',
+ 'type': 'group',
+ 'children': [
+ {
+ 'hint': 'More text',
+ 'label': 'Text',
+ 'name': 'my_group_string',
+ 'type': 'text'
+ },
+ ]
+ }
+ ],
+ }]
+ create_children(children, kwargs={'questionnaire': questionnaire})
+
+ assert models.QuestionGroup.objects.filter(
+ questionnaire=questionnaire).count() == 1
+ assert models.Question.objects.filter(
+ questionnaire=questionnaire).count() == 3
+ assert models.Question.objects.filter(
+ questionnaire=questionnaire,
+ question_group__isnull=False).count() == 1
+
class CreateOptionsTest(TestCase):
diff --git a/cadasta/xforms/mixins/model_helper.py b/cadasta/xforms/mixins/model_helper.py
index 3270198e0..bd7d20db0 100644
--- a/cadasta/xforms/mixins/model_helper.py
+++ b/cadasta/xforms/mixins/model_helper.py
@@ -24,7 +24,7 @@ def __init__(self, *arg):
self.arg = arg
def create_models(self, data):
- questionnaire = self.get_questionnaire(
+ questionnaire = self._get_questionnaire(
id_string=data['id'], version=data['version']
)
project = questionnaire.project
@@ -32,96 +32,265 @@ def create_models(self, data):
if project.current_questionnaire != questionnaire.id:
raise InvalidXMLSubmission(_('Form out of date'))
- party = self.create_party(
+ party, party_resources = self.create_party(
data=data,
project=project
)
- location = self.create_spatial_unit(
+ location, location_resources = self.create_spatial_unit(
data=data,
project=project,
questionnaire=questionnaire,
party=party
)
- tenure = self.create_tenure_relationship(
+ tenure_resources = self.create_tenure_relationship(
data=data,
project=project,
party=party,
location=location
)
- return questionnaire, party.id, location.id, tenure.id
+ return (questionnaire, party_resources, location_resources,
+ tenure_resources)
def create_party(self, data, project):
+ party_objects = []
+ party_resources = []
try:
- party = Party.objects.create(
- project=project,
- name=data['party_name'],
- type=data['party_type'],
- attributes=self.get_attributes(data, 'party')
- )
+ party_groups = self._format_repeat(data, ['party'])
+ for group in party_groups:
+ party = Party.objects.create(
+ project=project,
+ name=group['party_name'],
+ type=group['party_type'],
+ attributes=self._get_attributes(group, 'party')
+ )
+
+ party_resources.append(
+ self._get_resource_names(group, party, 'party')
+ )
+ party_objects.append(party)
+
except Exception as e:
raise InvalidXMLSubmission(_(
"Party error: {}".format(e)))
- return party
+ return party_objects, party_resources
def create_spatial_unit(self, data, project, questionnaire, party=None):
- if 'location_geotrace' in data.keys():
- location_geometry = data['location_geotrace']
- geoshape = False
- elif 'location_geoshape' in data.keys():
- location_geometry = data['location_geoshape']
- geoshape = True
- else:
- location_geometry = data['location_geometry']
- geoshape = Question.objects.filter(
- questionnaire=questionnaire, type='GS').exists()
+ location_resources = []
+ location_objects = []
try:
- location = SpatialUnit.objects.create(
- project=project,
- type=data['location_type'],
- geometry=self._format_geometry(location_geometry, geoshape),
- attributes=self.get_attributes(data, 'location')
- )
+ location_group = self._format_repeat(data, ['location'])
+
+ for group in location_group:
+ if 'location_geotrace' in group.keys():
+ location_geometry = group['location_geotrace']
+ geoshape = False
+ elif 'location_geoshape' in group.keys():
+ location_geometry = group['location_geoshape']
+ geoshape = True
+ else:
+ location_geometry = group['location_geometry']
+ geoshape = Question.objects.filter(
+ questionnaire=questionnaire, type='GS').exists()
+
+ location = SpatialUnit.objects.create(
+ project=project,
+ type=group['location_type'],
+ geometry=self._format_geometry(
+ location_geometry,
+ geoshape
+ ),
+ attributes=self._get_attributes(group, 'location')
+ )
+
+ location_resources.append(
+ self._get_resource_names(group, location, 'location')
+ )
+ location_objects.append(location)
+
except Exception as e:
raise InvalidXMLSubmission(_(
'Location error: {}'.format(e)))
- return location
+ return location_objects, location_resources
def create_tenure_relationship(self, data, party, location, project):
+ tenure_resources = []
try:
- tenure = TenureRelationship.objects.create(
- project=project,
- party=party,
- spatial_unit=location,
- tenure_type=TenureRelationshipType.objects.get(
- id=data['tenure_type']),
- attributes=self.get_attributes(data, 'tenure_relationship')
- )
+ if data.get('tenure_type'):
+ tenure_group = [data]
+ else:
+ tenure_group = self._format_repeat(data, ['party', 'location'])
+
+ for p in range(len(party)):
+ for l in range(len(location)):
+ t = 0
+ if len(tenure_group) > 1:
+ if p > l:
+ t = p
+ else:
+ t = l
+ tenure = TenureRelationship.objects.create(
+ project=project,
+ party=party[p],
+ spatial_unit=location[l],
+ tenure_type=TenureRelationshipType.objects.get(
+ id=tenure_group[t]['tenure_type']),
+ attributes=self._get_attributes(
+ tenure_group[t],
+ 'tenure_relationship')
+ )
+ tenure_resources.append(
+ self._get_resource_names(
+ tenure_group[t], tenure, 'tenure')
+ )
+
except Exception as e:
raise InvalidXMLSubmission(_(
"Tenure relationship error: {}".format(e)))
- return tenure
+ return tenure_resources
- def add_file_to_resource(self, data, user, project, content_object=None):
+ def create_resource(self, data, user, project, content_object=None):
Storage = get_storage_class()
- storage = Storage()
- url = storage.save('resources/' + data.name, data.file.read())
+ file = data.file.read()
try:
- resource = Resource.objects.create(
- name=data.name,
- file=url,
- content_object=content_object,
- mime_type=data.content_type,
- contributor=user,
- project=project,
- original_file=data.name
- )
- resource.full_clean()
+ if file == b'':
+ Resource.objects.get(
+ name=data.name,
+ contributor=user,
+ mime_type=data.content_type,
+ project=project,
+ original_file=data.name
+ ).content_objects.create(
+ content_object=content_object
+ )
+ else:
+ url = Storage().save('resources/' + data.name, file)
+ Resource.objects.create(
+ name=data.name,
+ file=url,
+ content_object=content_object,
+ mime_type=data.content_type,
+ contributor=user,
+ project=project,
+ original_file=data.name
+ ).full_clean()
except Exception as e:
raise InvalidXMLSubmission(_("{}".format(e)))
+ def upload_submission_data(self, request):
+ if 'xml_submission_file' not in request.data.keys():
+ raise InvalidXMLSubmission(_('XML submission not found'))
+
+ xml_submission_file = request.data['xml_submission_file'].read()
+ full_submission = XFormToDict(
+ xml_submission_file.decode('utf-8')).get_dict()
+
+ submission = full_submission[list(full_submission.keys())[0]]
+
+ with transaction.atomic():
+ questionnaire, party, location, tenure = self.create_models(
+ submission)
+
+ party_submission = [submission]
+ location_submission = [submission]
+ tenure_submission = [submission]
+
+ if 'party_repeat' in submission:
+ party_submission = self._format_repeat(submission, ['party'])
+ if 'tenure_type' in party_submission[0]:
+ tenure_submission = party_submission
+
+ elif 'location_repeat' in submission:
+ location_submission = self._format_repeat(
+ submission, ['location'])
+ if 'tenure_type' in location_submission[0]:
+ tenure_submission = location_submission
+
+ party_resources = []
+ location_resources = []
+ tenure_resources = []
+
+ for group in party_submission:
+ party_resources.extend(
+ self._get_resource_files(group, 'party')
+ )
+
+ for group in location_submission:
+ location_resources.extend(
+ self._get_resource_files(group, 'location')
+ )
+
+ for group in tenure_submission:
+ tenure_resources.extend(
+ self._get_resource_files(group, 'tenure')
+ )
+
+ resource_data = {
+ 'project': questionnaire.project,
+ 'location_resources': location_resources,
+ 'locations': location,
+ 'party_resources': party_resources,
+ 'parties': party,
+ 'tenure_resources': tenure_resources,
+ 'tenures': tenure,
+ }
+ self.upload_resource_files(request, resource_data)
+
+ return XFormSubmission(
+ json_submission=full_submission,
+ user=request.user,
+ questionnaire=questionnaire)
+
+ def upload_resource_files(self, request, data):
+ user = request.user
+ files = request.FILES
+ files.pop('xml_submission_file')
+ project = data['project']
+ for file_name in files:
+ if file_name in data['location_resources']:
+ for location in data['locations']:
+ if file_name in location['resources']:
+ content_object = SpatialUnit.objects.get(
+ id=location['id'])
+
+ self.create_resource(data=files[file_name],
+ user=user,
+ project=project,
+ content_object=content_object
+ )
+
+ elif file_name in data['party_resources']:
+ for party in data['parties']:
+ if file_name in party['resources']:
+ content_object = Party.objects.get(
+ id=party['id'])
+
+ self.create_resource(data=files[file_name],
+ user=user,
+ project=project,
+ content_object=content_object
+ )
+
+ elif file_name in data['tenure_resources']:
+ for tenure in data['tenures']:
+ if file_name in tenure['resources']:
+ content_object = TenureRelationship.objects.get(
+ id=tenure['id'])
+
+ self.create_resource(data=files[file_name],
+ user=user,
+ project=project,
+ content_object=content_object
+ )
+ else:
+ self.create_resource(data=files[file_name],
+ user=user,
+ project=project,
+ content_object=None
+ )
+
def _format_geometry(self, coords, geoshape=False):
if coords == '':
return ''
@@ -153,7 +322,18 @@ def _format_geometry(self, coords, geoshape=False):
latlng = [x for x in latlng if x]
return dumps(Point(float(latlng[1]), float(latlng[0])))
- def get_questionnaire(self, id_string, version):
+ def _format_repeat(self, data, model_type):
+ repeat_group = [data]
+ for model in model_type:
+ if '{}_repeat'.format(model) in data:
+ repeat_group = data['{}_repeat'.format(model)]
+
+ if type(repeat_group) != list:
+ repeat_group = [repeat_group]
+
+ return repeat_group
+
+ def _get_questionnaire(self, id_string, version):
try:
return Questionnaire.objects.get(
id_string=id_string, version=int(version)
@@ -161,7 +341,7 @@ def get_questionnaire(self, id_string, version):
except Questionnaire.DoesNotExist:
raise ValidationError(_('Questionnaire not found.'))
- def get_attributes(self, data, model_type):
+ def _get_attributes(self, data, model_type):
attributes = {}
for attr_group in data:
if '{model}_attributes'.format(model=model_type) in attr_group:
@@ -169,73 +349,28 @@ def get_attributes(self, data, model_type):
attributes[item] = data[attr_group][item]
return attributes
+ def _get_resource_files(self, data, model_type):
+ resources = []
+ for file_name in data.keys():
+ if ("{}_resource".format(model_type) in file_name or
+ "{}_photo".format(model_type) in file_name):
+ resources.append(data[file_name])
+ return resources
+
+ def _get_resource_names(self, data, model, model_type):
+ resources = {'id': model.id, 'resources': []}
+ # for legacy xlsforms
+ if '{}_photo'.format(model_type) in data.keys():
+ resources['resources'].append(
+ data['{}_photo'.format(model_type)])
+
+ for key in data.keys():
+ if '{}_resource'.format(model_type) in key:
+ resources['resources'].append(
+ data[key])
+ return resources
+
# ~~~~~~~~~~~~~~~
# To Do:
# Add location<->location and party<->party relationship
# ~~~~~~~~~~~~~~~
- def upload_submission_data(self, request):
- if 'xml_submission_file' not in request.data.keys():
- raise InvalidXMLSubmission(_('XML submission not found'))
-
- xml_submission_file = request.data['xml_submission_file'].read()
- full_submission = XFormToDict(
- xml_submission_file.decode('utf-8')
- ).get_dict()
-
- submission = full_submission[list(full_submission.keys())[0]]
-
- with transaction.atomic():
- questionnaire, party, location, tenure = self.create_models(
- submission)
- party_resources = []
- location_resources = []
- tenure_resources = []
- for file_name in submission.keys():
- if ("party_resource" in file_name or
- "party_photo" in file_name):
- party_resources.append(submission[file_name])
-
- if ("location_resource" in file_name or
- "location_photo" in file_name):
- location_resources.append(submission[file_name])
-
- if ("tenure_resource" in file_name):
- tenure_resources.append(submission[file_name])
-
- resource_data = {
- 'project': questionnaire.project,
- 'location_resources': location_resources,
- 'location': location,
- 'party_resources': party_resources,
- 'party_id': party,
- 'tenure_resources': tenure_resources,
- 'tenure_id': tenure,
- }
- self.upload_files(request, resource_data)
-
- return XFormSubmission(
- json_submission=full_submission,
- user=request.user,
- questionnaire=questionnaire)
-
- def upload_files(self, request, data):
- user = request.user
- files = request.FILES
- files.pop('xml_submission_file')
- project = data['project']
- for file_name in files:
- content_object = None
- if file_name in data['location_resources']:
- content_object = SpatialUnit.objects.get(
- id=data['location'])
- elif file_name in data['party_resources']:
- content_object = Party.objects.get(
- id=data['party_id'])
- elif file_name in data['tenure_resources']:
- content_object = TenureRelationship.objects.get(
- id=data['tenure_id'])
-
- self.add_file_to_resource(data=files[file_name],
- user=user,
- project=project,
- content_object=content_object)
diff --git a/cadasta/xforms/tests/files/test_image_five.png b/cadasta/xforms/tests/files/test_image_five.png
new file mode 100644
index 000000000..e092ea3a5
Binary files /dev/null and b/cadasta/xforms/tests/files/test_image_five.png differ
diff --git a/cadasta/xforms/tests/files/test_image_four.png b/cadasta/xforms/tests/files/test_image_four.png
new file mode 100644
index 000000000..3f35d2d7a
Binary files /dev/null and b/cadasta/xforms/tests/files/test_image_four.png differ
diff --git a/cadasta/xforms/tests/files/test_image_three.png b/cadasta/xforms/tests/files/test_image_three.png
new file mode 100644
index 000000000..994331cdd
Binary files /dev/null and b/cadasta/xforms/tests/files/test_image_three.png differ
diff --git a/cadasta/xforms/tests/files/test_resources.py b/cadasta/xforms/tests/files/test_resources.py
index 81dc161da..161f1368d 100644
--- a/cadasta/xforms/tests/files/test_resources.py
+++ b/cadasta/xforms/tests/files/test_resources.py
@@ -1,6 +1,6 @@
-FORM = '''
-
+STANDARD = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -13,6 +13,9 @@
test_image_one.png
test_image_two.png
test_audio_one.mp3
+ test_image_one.png
+ test_image_two.png
+ test_image_three.png
LH
Middle Earth
@@ -34,48 +37,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-INVALID_FORM = '''
-
- 2016-07-07T16:38:20.310-04
- 2016-07-07T16:39:23.673-04
- 2016-07-07
- 00:bb:3a:44:d0:fb
-
- IN
-
- 40.6890612 -73.9925067 0.0 0.0;
- MI
- test_image.png
-
- LH
-
- Null Island
-
-
- Party attribute default notes.
-
-
- f
- no
- 2016-07-07
-
-
- Party relationship notes.
-
-
- Tenure relationship notes.
-
-
- uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
-
- '''.strip()
-
-POLY_FORM = '''
-
+POLY = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -96,11 +62,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-LINE_FORM = '''
-
+LINE = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -122,11 +88,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-MISSING_SEMI_FORM = '''
-
+MISSING_SEMI = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -145,11 +111,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-GEOSHAPE_FORM = '''
-
+GEOTYPE_SELECT = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -172,11 +138,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-NEITHER_FORM = '''
-
+GEOTYPE_NEITHER = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -199,7 +165,7 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
BAD_QUESTIONNAIRE = '''
@@ -220,9 +186,9 @@
'''.strip()
-BAD_LOCATION_FORM = '''
-
+BAD_LOCATION = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -236,11 +202,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-BAD_PARTY_FORM = '''
-
+BAD_PARTY = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -254,11 +220,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-BAD_TENURE_FORM = '''
-
+BAD_TENURE = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -272,11 +238,11 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
-BAD_RESOURCE_FORM = '''
-
+BAD_RESOURCE = '''
+
2016-07-07T16:38:20.310-04
2016-07-07T16:39:23.673-04
2016-07-07
@@ -291,19 +257,353 @@
uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
- '''.strip()
+ '''.strip()
+
+REPEAT_PARTY = '''
+
+ 2016-07-07T16:38:20.310-04
+ 2016-07-07T16:39:23.673-04
+ 2016-07-07
+ 00:bb:3a:44:d0:fb
+
+ 40.6890612 -73.9925067 0.0 0.0;
+ MI
+ test_audio_one.mp3
+ test_image_one.png
+
+ Middle Earth
+
+
+ IN
+ Bilbo Baggins
+ test_image_two.png
+ test_image_three.png
+
+ Party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+ LH
+
+ Tenure relationship notes.
+
+ test_image_four.png
+
+
+ IN
+ Samwise Gamgee
+ test_image_five.png
+
+
+ Repeated party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+ LH
+
+ Tenure relationship notes.
+
+
+
+
+ uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
+
+ '''.strip()
+
+REPEAT_ONE_PARTY = '''
+
+ 2016-07-07T16:38:20.310-04
+ 2016-07-07T16:39:23.673-04
+ 2016-07-07
+ 00:bb:3a:44:d0:fb
+
+ 40.6890612 -73.9925067 0.0 0.0;
+ MI
+ test_audio_one.mp3
+ test_image_one.png
+
+ Middle Earth
+
+
+ IN
+ Bilbo Baggins
+ test_image_two.png
+ test_image_three.png
+
+ Party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+ LH
+
+ Tenure relationship notes.
+
+ test_image_four.png
+
+
+ uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
+
+ '''.strip()
+
+REPEAT_LOCATION = '''
+
+ 2016-07-07T16:38:20.310-04
+ 2016-07-07T16:39:23.673-04
+ 2016-07-07
+ 00:bb:3a:44:d0:fb
+
+
+ 40.6890612 -73.9925067 0.0 0.0;
+
+ MI
+ test_audio_one.mp3
+ test_image_one.png
+
+ Middle Earth
+
+ CR
+
+ Tenure relationship notes.
+
+ test_image_two.png
+
+
+ 40.6890612 -73.9925067 0.0 0.0;
+
+ CB
+
+ test_image_three.png
+
+ Middle Earth
+
+ LH
+
+ Tenure relationship notes.
+
+
+
+ IN
+ Bilbo Baggins
+ test_image_four.png
+ test_image_five.png
+
+ Party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+
+ uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
+
+ '''.strip()
+
+REPEAT_ONE_LOCATION = '''
+
+ 2016-07-07T16:38:20.310-04
+ 2016-07-07T16:39:23.673-04
+ 2016-07-07
+ 00:bb:3a:44:d0:fb
+
+
+ 40.6890612 -73.9925067 0.0 0.0;
+
+ MI
+ test_audio_one.mp3
+ test_image_one.png
+
+ Middle Earth
+
+ CR
+
+ Tenure relationship notes.
+
+ test_image_two.png
+
+ IN
+ Bilbo Baggins
+ test_image_four.png
+ test_image_five.png
+
+ Party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+
+ uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
+
+ '''.strip()
+
+REPEAT_MINUS_TENURE = '''
+
+ 2016-07-07T16:38:20.310-04
+ 2016-07-07T16:39:23.673-04
+ 2016-07-07
+ 00:bb:3a:44:d0:fb
+
+
+ 40.6890612 -73.9925067 0.0 0.0;
+
+ MI
+ test_audio_one.mp3
+ test_image_one.png
+
+ Middle Earth
+
+
+
+ 40.6890612 -73.9925067 0.0 0.0;
+
+ CB
+
+ test_image_three.png
+
+ Middle Earth
+
+
+ CR
+
+ Tenure relationship notes.
+
+ test_image_two.png
+ IN
+ Bilbo Baggins
+ test_image_four.png
+ test_image_five.png
+
+ Party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+
+ uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
+
+ '''.strip()
+
+REPEAT_PARTY_MINUS_TENURE = '''
+
+ 2016-07-07T16:38:20.310-04
+ 2016-07-07T16:39:23.673-04
+ 2016-07-07
+ 00:bb:3a:44:d0:fb
+
+ 40.6890612 -73.9925067 0.0 0.0;
+
+ MI
+ test_audio_one.mp3
+ test_image_one.png
+
+ Middle Earth
+
+ CR
+
+ Tenure relationship notes.
+
+ test_image_two.png
+
+ IN
+ Bilbo Baggins
+ test_image_three.png
+ test_image_four.png
+
+ Party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+
+
+ IN
+ Samwise Gamgee
+ test_image_five.png
+
+
+ Repeated party attribute default notes.
+
+
+ f
+ no
+ 2016-07-07
+
+
+ Party relationship notes.
+
+ LH
+
+ Tenure relationship notes.
+
+
+
+
+ uuid:b3f225d3-0fac-4a0b-80c7-60e6db4cc0ad
+
+ '''.strip()
responses = {
- 'form': FORM,
- 'invalid_form': INVALID_FORM,
- 'line_form': LINE_FORM,
- 'poly_form': POLY_FORM,
- 'missing_semi_form': MISSING_SEMI_FORM,
- 'geoshape_form': GEOSHAPE_FORM,
- 'location_geoshape_form': NEITHER_FORM,
- 'bad_questionnaire': BAD_QUESTIONNAIRE,
- 'bad_location_form': BAD_LOCATION_FORM,
- 'bad_party_form': BAD_PARTY_FORM,
- 'bad_tenure_form': BAD_TENURE_FORM,
- 'bad_resource_form': BAD_RESOURCE_FORM,
+ 'submission': STANDARD,
+ 'submission_line': LINE,
+ 'submission_poly': POLY,
+ 'submission_missing_semi': MISSING_SEMI,
+ 'submission_geotype_select': GEOTYPE_SELECT,
+ 'submission_geotype_neither': GEOTYPE_NEITHER,
+ 'submission_bad_questionnaire': BAD_QUESTIONNAIRE,
+ 'submission_bad_location': BAD_LOCATION,
+ 'submission_bad_party': BAD_PARTY,
+ 'submission_bad_tenure': BAD_TENURE,
+ 'submission_bad_resource': BAD_RESOURCE,
+ 'submission_party_repeat': REPEAT_PARTY,
+ 'submission_party_one_repeat': REPEAT_ONE_PARTY,
+ 'submission_location_repeat': REPEAT_LOCATION,
+ 'submission_location_one_repeat': REPEAT_ONE_LOCATION,
+ 'submission_repeat_minus_tenure': REPEAT_MINUS_TENURE,
+ 'submission_repeat_party_minus_tenure': REPEAT_PARTY_MINUS_TENURE,
}
diff --git a/cadasta/xforms/tests/test_model_helper.py b/cadasta/xforms/tests/test_model_helper.py
new file mode 100644
index 000000000..3c0742460
--- /dev/null
+++ b/cadasta/xforms/tests/test_model_helper.py
@@ -0,0 +1,778 @@
+import os
+import io
+import pytest
+from django.conf import settings
+from django.test import TestCase
+from django.core.exceptions import ValidationError
+from django.core.files.uploadedfile import InMemoryUploadedFile
+from django.contrib.contenttypes.models import ContentType
+from jsonattrs.models import Attribute, AttributeType, Schema
+from jsonattrs.management.commands import loadattrtypes
+from jsonattrs.models import create_attribute_types
+
+from accounts.tests.factories import UserFactory
+from core.tests.factories import PolicyFactory
+from party.tests.factories import PartyFactory
+from organization.tests.factories import ProjectFactory
+from spatial.tests.factories import SpatialUnitFactory
+from questionnaires.tests.factories import (QuestionnaireFactory,
+ QuestionFactory,)
+
+from party.models import (Party, TenureRelationship,
+ load_tenure_relationship_types)
+from organization.models import OrganizationRole
+from resources.models import Resource
+from spatial.models import SpatialUnit
+from xforms.mixins.model_helper import ModelHelper as mh
+from xforms.exceptions import InvalidXMLSubmission
+
+path = os.path.dirname(settings.BASE_DIR)
+
+
+class XFormModelHelperTest(TestCase):
+ def setUp(self):
+ super().setUp()
+ PolicyFactory.load_policies()
+ create_attribute_types()
+
+ loadattrtypes.Command().handle(force=True)
+ load_tenure_relationship_types(force=True)
+
+ self.user = UserFactory.create()
+ self.project = ProjectFactory.create(
+ current_questionnaire='a1')
+
+ self.questionnaire = QuestionnaireFactory.create(
+ id_string='a1', version=0, project=self.project, id='a1')
+ QuestionFactory.create(
+ name='location_geometry',
+ label='Location of Parcel',
+ type='GS',
+ questionnaire=self.questionnaire)
+
+ content_type_party = ContentType.objects.get(
+ app_label='party', model='party')
+ content_type_spatial = ContentType.objects.get(
+ app_label='spatial', model='spatialunit')
+ content_type_tenure = ContentType.objects.get(
+ app_label='party', model='tenurerelationship')
+ for content_type in [content_type_party, content_type_tenure,
+ content_type_spatial]:
+ schema = Schema.objects.create(
+ content_type=content_type,
+ selectors=(self.project.organization.id, self.project.id, 'a1')
+ )
+ attr_type = AttributeType.objects.get(name='boolean')
+ Attribute.objects.create(
+ schema=schema,
+ name='fname', long_name='True or False',
+ attr_type=attr_type, index=0,
+ required=False, omit=False
+ )
+ attr_type = AttributeType.objects.get(name='text')
+ Attribute.objects.create(
+ schema=schema,
+ name='fname_two', long_name='Notes',
+ attr_type=attr_type, index=1,
+ required=False, omit=False
+ )
+
+ OrganizationRole.objects.create(
+ user=self.user, organization=self.project.organization)
+
+ def test_create_models(self):
+ geoshape = ('45.56342779158167 -122.67650283873081 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0;'
+ '45.56151562182025 -122.67490658909082 0.0 0.0;'
+ '45.563479432877415 -122.67494414001703 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0')
+ data = {
+ 'id': 'a1',
+ 'version': str(self.questionnaire.version),
+ 'party_name': 'Party One',
+ 'party_type': 'IN',
+ 'party_attributes_individual': {
+ 'fname': False,
+ 'fname_two': 'socks',
+ },
+ 'party_photo': 'sad_birthday.png',
+ 'party_resource_invite': 'invitation.pdf',
+ 'location_type': 'BU',
+ 'location_geometry': geoshape,
+ 'location_attributes': {
+ 'fname': False,
+ 'fname_two': 'Location One',
+ },
+ 'location_photo': 'resource_one.png',
+ 'location_resource_invite': 'resource_two.pdf',
+ 'tenure_type': 'CO',
+ 'tenure_relationship_attributes': {
+ 'fname': False,
+ 'fname_two': 'Tenure One'
+ },
+ 'tenure_resource_photo': 'resource_three.png'
+ }
+
+ (questionnaire,
+ party_resources,
+ location_resources,
+ tenure_resources) = mh.create_models(mh(), data)
+
+ assert questionnaire == self.questionnaire
+ party = Party.objects.get(name='Party One')
+ assert party_resources[0]['id'] == party.id
+ assert 'sad_birthday.png' in party_resources[0]['resources']
+ assert 'invitation.pdf' in party_resources[0]['resources']
+
+ location = SpatialUnit.objects.get(type='BU')
+ assert location_resources[0]['id'] == location.id
+ assert 'resource_two.pdf' in location_resources[0]['resources']
+
+ tenure = TenureRelationship.objects.get(spatial_unit=location)
+ assert tenure.party == party
+ assert tenure_resources[0]['id'] == tenure.id
+ assert 'resource_three.png' in tenure_resources[0]['resources']
+
+ def test_create_party(self):
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test without repeats
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ data = {
+ 'party_name': 'Party One',
+ 'party_type': 'IN',
+ 'party_attributes_individual': {
+ 'fname': False,
+ 'fname_two': 'socks',
+ },
+ 'party_photo': 'sad_birthday.png',
+ 'party_resource_invite': 'invitation.pdf',
+ }
+
+ party_objects, party_resources = mh.create_party(
+ mh(), data, self.project
+ )
+ assert len(party_objects) == 1
+ party = Party.objects.get(name='Party One')
+ assert party.type == 'IN'
+ assert party.attributes == {'fname': False, 'fname_two': 'socks'}
+ assert len(party_resources) == 1
+ assert party_resources[0]['id'] == party.id
+ assert len(party_resources[0]['resources']) == 2
+ assert 'sad_birthday.png' in party_resources[0]['resources']
+ assert 'invitation.pdf' in party_resources[0]['resources']
+ assert party.project == self.project
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test with repeats
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ data = {
+ 'party_repeat': [{
+ 'party_name': 'Party Two',
+ 'party_type': 'IN',
+ 'party_attributes_individual': {
+ 'fname': False,
+ 'fname_two': 'socks',
+ },
+ 'party_photo': 'sad_birthday.png',
+ 'party_resource_invite': 'invitation.pdf',
+
+ }, {
+ 'party_name': 'Party Three',
+ 'party_type': 'GR',
+ 'party_attributes_group': {
+ 'fname': True,
+ 'fname_two': 'video games',
+ },
+ 'party_photo': 'awesome_birthday.png',
+ 'party_resource_invite': 'invitation_two.pdf',
+
+ }]
+ }
+ party_objects, party_resources = mh.create_party(
+ mh(), data, self.project
+ )
+ assert len(party_objects) == 2
+ party = Party.objects.get(name='Party Two')
+ assert party.type == 'IN'
+ assert party.attributes == {'fname': False, 'fname_two': 'socks'}
+ party2 = Party.objects.get(name='Party Three')
+ assert party2.type == 'GR'
+ assert party2.attributes == {
+ 'fname': True, 'fname_two': 'video games'}
+
+ assert len(party_resources) == 2
+ assert party_resources[0]['id'] == party.id
+ assert len(party_resources[0]['resources']) == 2
+ assert 'sad_birthday.png' in party_resources[0]['resources']
+ assert 'invitation.pdf' in party_resources[0]['resources']
+ assert party.project == self.project
+
+ assert party_resources[1]['id'] == party2.id
+ assert len(party_resources[1]['resources']) == 2
+ assert 'awesome_birthday.png' in party_resources[1]['resources']
+ assert 'invitation_two.pdf' in party_resources[1]['resources']
+ assert party2.project == self.project
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test without fails
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ data = {
+ 'party_nonsense': 'Blah blah blah',
+ 'party_type': 'IN',
+ 'party_attributes_individual': {
+ 'fname': False,
+ 'fname_two': 'socks',
+ },
+ 'party_photo': 'sad_birthday.png',
+ 'party_resource_invite': 'invitation.pdf',
+ }
+
+ with pytest.raises(InvalidXMLSubmission):
+ mh.create_party(
+ mh(), data, self.project
+ )
+ assert Party.objects.count() == 3
+
+ def test_create_spatial_unit(self):
+ geoshape = ('45.56342779158167 -122.67650283873081 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0;'
+ '45.56151562182025 -122.67490658909082 0.0 0.0;'
+ '45.563479432877415 -122.67494414001703 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0')
+
+ line = ('45.56342779158167 -122.67650283873081 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0;'
+ '45.56151562182025 -122.67490658909082 0.0 0.0;')
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test without repeats
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ data = {
+ 'location_type': 'BU',
+ 'location_geometry': geoshape,
+ 'location_attributes': {
+ 'fname': False,
+ 'fname_two': 'Location One',
+ },
+ 'location_photo': 'resource.png',
+ 'location_resource_invite': 'resource_two.pdf',
+ }
+
+ location_objects, location_resources = mh.create_spatial_unit(
+ mh(), data, self.project, self.questionnaire)
+ assert len(location_objects) == 1
+ location = SpatialUnit.objects.get(type='BU')
+ assert location.attributes == {
+ 'fname': False, 'fname_two': 'Location One'}
+ assert location.geometry.geom_type == 'Polygon'
+ assert len(location_resources) == 1
+ assert location_resources[0]['id'] == location.id
+ assert len(location_resources[0]['resources']) == 2
+ assert 'resource.png' in location_resources[0]['resources']
+ assert 'resource_two.pdf' in location_resources[0]['resources']
+ assert location.project == self.project
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test with repeats
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ data = {
+ 'location_repeat': [{
+ 'location_type': 'PA',
+ 'location_geotrace': line,
+ 'location_attributes': {
+ 'fname': False,
+ 'fname_two': 'Location One',
+ },
+ 'location_photo': 'resource.png',
+ 'location_resource_invite': 'resource_two.pdf',
+ }, {
+ 'location_type': 'CB',
+ 'location_geoshape': geoshape,
+ 'location_attributes': {
+ 'fname': True,
+ 'fname_two': 'Location Two',
+ },
+ 'location_photo': 'resource_three.png',
+ 'location_resource_invite': 'resource_four.pdf',
+ }]
+ }
+
+ location_objects, location_resources = mh.create_spatial_unit(
+ mh(), data, self.project, self.questionnaire)
+
+ assert len(location_objects) == 2
+ location = SpatialUnit.objects.get(type='PA')
+ assert location.geometry.geom_type == 'LineString'
+ assert location.attributes == {
+ 'fname': False, 'fname_two': 'Location One'}
+ location2 = SpatialUnit.objects.get(type='CB')
+ assert location2.geometry.geom_type == 'Polygon'
+ assert location2.attributes == {
+ 'fname': True, 'fname_two': 'Location Two'}
+
+ assert len(location_resources) == 2
+ assert location_resources[0]['id'] == location.id
+ assert len(location_resources[0]['resources']) == 2
+ assert 'resource.png' in location_resources[0]['resources']
+ assert 'resource_two.pdf' in location_resources[0]['resources']
+ assert location.project == self.project
+
+ assert location_resources[1]['id'] == location2.id
+ assert len(location_resources[1]['resources']) == 2
+ assert 'resource_three.png' in location_resources[1]['resources']
+ assert 'resource_four.pdf' in location_resources[1]['resources']
+ assert location2.project == self.project
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test fails
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ data = {
+ 'location_nonsense': 'BLAH BLAH',
+ 'location_geometry': line,
+ 'location_attributes': {
+ 'fname': False,
+ 'fname_two': 'Location One',
+ },
+ 'location_photo': 'resource.png',
+ 'location_resource_invite': 'resource_two.pdf',
+ }
+
+ with pytest.raises(InvalidXMLSubmission):
+ mh.create_spatial_unit(
+ mh(), data, self.project, self.questionnaire)
+ assert SpatialUnit.objects.count() == 3
+
+ def test_create_tenure_relationship(self):
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test without repeats
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ party = PartyFactory.create(project=self.project)
+ location = SpatialUnitFactory.create(project=self.project)
+
+ data = {
+ 'tenure_type': 'CO',
+ 'tenure_relationship_attributes': {
+ 'fname': False,
+ 'fname_two': 'Tenure One'
+ },
+ 'tenure_resource_photo': 'resource.png'
+ }
+
+ tenure_resources = mh.create_tenure_relationship(
+ mh(), data, [party], [location], self.project)
+ tenure = TenureRelationship.objects.get(tenure_type='CO')
+ assert tenure.party == party
+ assert tenure.spatial_unit == location
+ assert tenure.attributes == {'fname': False, 'fname_two': 'Tenure One'}
+ assert len(tenure_resources) == 1
+ assert tenure_resources[0]['id'] == tenure.id
+ assert 'resource.png' in tenure_resources[0]['resources']
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # inside party_repeat
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ party2 = PartyFactory.create(project=self.project)
+ party3 = PartyFactory.create(project=self.project)
+
+ data = {
+ 'party_repeat': [{
+ 'tenure_type': 'WR',
+ 'tenure_relationship_attributes': {
+ 'fname': False,
+ 'fname_two': 'Tenure Two'
+ },
+ 'tenure_resource_photo': 'resource_two.png'
+ }, {
+ 'tenure_type': 'CO',
+ 'tenure_relationship_attributes': {
+ 'fname': True,
+ 'fname_two': 'Tenure Three'
+ },
+ 'tenure_resource_photo': 'resource_three.png'
+ }]
+ }
+
+ tenure_resources = mh.create_tenure_relationship(
+ mh(), data, [party2, party3], [location], self.project)
+ tenure2 = TenureRelationship.objects.get(party=party2)
+ tenure3 = TenureRelationship.objects.get(party=party3)
+
+ assert tenure2.spatial_unit == location
+ assert tenure2.tenure_type.id == 'WR'
+ assert tenure2.attributes == {
+ 'fname': False, 'fname_two': 'Tenure Two'}
+
+ assert tenure3.spatial_unit == location
+ assert tenure3.tenure_type.id == 'CO'
+ assert tenure3.attributes == {
+ 'fname': True, 'fname_two': 'Tenure Three'}
+
+ assert len(tenure_resources) == 2
+ assert tenure_resources[0]['id'] == tenure2.id
+ assert 'resource_two.png' in tenure_resources[0]['resources']
+
+ assert tenure_resources[1]['id'] == tenure3.id
+ assert 'resource_three.png' in tenure_resources[1]['resources']
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # inside location_repeat
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ location2 = SpatialUnitFactory.create(project=self.project)
+ location3 = SpatialUnitFactory.create(project=self.project)
+
+ data = {
+ 'location_repeat': [{
+ 'tenure_type': 'WR',
+ 'tenure_relationship_attributes': {
+ 'fname': False,
+ 'fname_two': 'Tenure Four'
+ },
+ 'tenure_resource_photo': 'resource_four.png'
+ }, {
+ 'tenure_type': 'CO',
+ 'tenure_relationship_attributes': {
+ 'fname': True,
+ 'fname_two': 'Tenure Five'
+ },
+ 'tenure_resource_photo': 'resource_five.png'
+ }]
+ }
+
+ tenure_resources = mh.create_tenure_relationship(
+ mh(), data, [party], [location2, location3], self.project)
+
+ tenure4 = TenureRelationship.objects.get(spatial_unit=location2)
+ tenure5 = TenureRelationship.objects.get(spatial_unit=location3)
+
+ assert tenure4.party == party
+ assert tenure4.tenure_type.id == 'WR'
+ assert tenure4.attributes == {
+ 'fname': False, 'fname_two': 'Tenure Four'}
+
+ assert tenure5.party == party
+ assert tenure5.tenure_type.id == 'CO'
+ assert tenure5.attributes == {
+ 'fname': True, 'fname_two': 'Tenure Five'}
+
+ assert len(tenure_resources) == 2
+ assert tenure_resources[0]['id'] == tenure4.id
+ assert 'resource_four.png' in tenure_resources[0]['resources']
+
+ assert tenure_resources[1]['id'] == tenure5.id
+ assert 'resource_five.png' in tenure_resources[1]['resources']
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # outside party_repeat
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ party4 = PartyFactory.create(project=self.project)
+ party5 = PartyFactory.create(project=self.project)
+
+ data = {
+ 'party_repeat': [],
+ 'tenure_type': 'CO',
+ 'tenure_relationship_attributes': {
+ 'fname': True,
+ 'fname_two': 'Tenure 6, 7'
+ },
+ 'tenure_resource_photo': 'resource_six.png'
+ }
+
+ tenure_resources = mh.create_tenure_relationship(
+ mh(), data, [party4, party5], [location], self.project)
+ tenure6 = TenureRelationship.objects.get(party=party4)
+ tenure7 = TenureRelationship.objects.get(party=party5)
+
+ assert tenure6.spatial_unit == location
+ assert tenure6.tenure_type.id == 'CO'
+ assert tenure6.attributes == {
+ 'fname': True, 'fname_two': 'Tenure 6, 7'}
+
+ assert tenure7.spatial_unit == location
+ assert tenure7.tenure_type.id == 'CO'
+ assert tenure7.attributes == {
+ 'fname': True, 'fname_two': 'Tenure 6, 7'}
+
+ assert len(tenure_resources) == 2
+ assert tenure_resources[0]['id'] == tenure6.id
+ assert 'resource_six.png' in tenure_resources[0]['resources']
+
+ assert tenure_resources[1]['id'] == tenure7.id
+ assert 'resource_six.png' in tenure_resources[1]['resources']
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # outside location_repeat
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ location4 = SpatialUnitFactory.create(project=self.project)
+ location5 = SpatialUnitFactory.create(project=self.project)
+
+ data = {
+ 'location_repeat': [],
+ 'tenure_type': 'WR',
+ 'tenure_relationship_attributes': {
+ 'fname': False,
+ 'fname_two': 'Tenure 8, 9'
+ },
+ 'tenure_resource_photo': 'resource_seven.png'
+ }
+
+ tenure_resources = mh.create_tenure_relationship(
+ mh(), data, [party], [location4, location5], self.project)
+
+ tenure8 = TenureRelationship.objects.get(spatial_unit=location4)
+ tenure9 = TenureRelationship.objects.get(spatial_unit=location5)
+
+ assert tenure8.party == party
+ assert tenure8.tenure_type.id == 'WR'
+ assert tenure8.attributes == {
+ 'fname': False, 'fname_two': 'Tenure 8, 9'}
+
+ assert tenure9.party == party
+ assert tenure9.tenure_type.id == 'WR'
+ assert tenure9.attributes == {
+ 'fname': False, 'fname_two': 'Tenure 8, 9'}
+
+ assert len(tenure_resources) == 2
+ assert tenure_resources[0]['id'] == tenure8.id
+ assert 'resource_seven.png' in tenure_resources[0]['resources']
+
+ assert tenure_resources[1]['id'] == tenure9.id
+ assert 'resource_seven.png' in tenure_resources[1]['resources']
+
+ data = {
+ 'location_repeat': [],
+ 'tenure_nonsense': 'Blah blah blah',
+ 'tenure_relationship_attributes': {
+ 'fname': False,
+ 'fname_two': 'Tenure 8, 9'
+ },
+ 'tenure_resource_photo': 'resource_seven.png'
+ }
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test failing
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ with pytest.raises(InvalidXMLSubmission):
+ mh.create_tenure_relationship(
+ mh(), data, [party], [location4, location5], self.project)
+ assert TenureRelationship.objects.count() == 9
+
+ def test_create_resource(self):
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test attaching resources
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ file = open(
+ path + '/xforms/tests/files/test_image_one.png', 'rb'
+ ).read()
+
+ data = InMemoryUploadedFile(
+ file=io.BytesIO(file),
+ field_name='test_image_one',
+ name='{}.png'.format('test_image_one'),
+ content_type='image/png',
+ size=len(file),
+ charset='utf-8',
+ )
+ party = PartyFactory.create(project=self.project)
+ mh.create_resource(
+ self, data, self.user, self.project, content_object=party)
+ assert len(party.resources) == 1
+ resource = Resource.objects.get(name='test_image_one.png')
+ assert resource in party.resources
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test attaching existing resources
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ party2 = PartyFactory.create(project=self.project)
+ mh.create_resource(
+ self, data, self.user, self.project, content_object=party2)
+
+ assert Resource.objects.count() == 1
+ assert len(party2.resources) == 1
+ assert resource in party2.resources
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test without content object
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ file = open(
+ path + '/xforms/tests/files/test_image_two.png', 'rb'
+ ).read()
+
+ data = InMemoryUploadedFile(
+ file=io.BytesIO(file),
+ field_name='test_image_two',
+ name='{}.png'.format('test_image_two'),
+ content_type='image/png',
+ size=len(file),
+ charset='utf-8',
+ )
+
+ mh.create_resource(
+ self, data, self.user, self.project, content_object=None)
+
+ assert Resource.objects.count() == 2
+ resource = Resource.objects.get(name='test_image_two.png')
+ assert resource.content_objects.count() == 0
+
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # test failing
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ with pytest.raises(InvalidXMLSubmission):
+ mh.create_resource(
+ self, data, self.user, self.project, content_object='ardvark')
+ assert Resource.objects.count() == 2
+
+ # def test_upload_submission_data(self):
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # covered by the view tests
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ # def test_upload_resource_files(self):
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # covered by the view tests
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ def test_format_geometry(self):
+ point = '40.6890612 -73.9925067 0.0 0.0;'
+ geometry = mh._format_geometry(self, point, False)
+ assert 'POINT' in geometry
+
+ point_minus_semi = '340.6890612 -373.9925067 0.0 0.0'
+ geometry = mh._format_geometry(self, point_minus_semi, False)
+ assert 'POINT' in geometry
+
+ polygon = ('40.6890612 -73.9925067 0.0 0.0;'
+ '41.6890612 -73.9925067 0.0 0.0;'
+ '41.6890612 -72.9925067 0.0 0.0;'
+ '40.6890612 -72.9925067 0.0 0.0;'
+ '40.6890612 -73.9925067 0.0 0.0;')
+ geometry = mh._format_geometry(self, polygon, False)
+ assert 'POLYGON' in geometry
+
+ line = ('45.56342779158167 -122.67650283873081 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0;'
+ '45.56151562182025 -122.67490658909082 0.0 0.0;')
+ geometry = mh._format_geometry(self, line, False)
+ assert 'LINESTRING' in geometry
+
+ geoshape = ('45.56342779158167 -122.67650283873081 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0;'
+ '45.56151562182025 -122.67490658909082 0.0 0.0;'
+ '45.563479432877415 -122.67494414001703 0.0 0.0;'
+ '45.56176327330353 -122.67669159919024 0.0 0.0')
+ geometry = mh._format_geometry(self, geoshape, True)
+ assert 'POLYGON' in geometry
+
+ def test_format_repeat(self):
+ data = {
+ 'party_type': 'Not repeating',
+ 'party_name': 'Still not repeating'
+ }
+ group = mh._format_repeat(self, data, ['party'])
+ assert type(group) == list
+ assert group[0] == data
+
+ data = {
+ 'party_type': 'Repeating',
+ 'party_name': 'Totally repeating',
+ 'party_repeat': [{
+ 'repeat_type': 'Just One'
+ }]
+ }
+
+ group = mh._format_repeat(self, data, ['party'])
+ assert type(group) == list
+ assert len(group) == 1
+ assert group[0]['repeat_type'] == 'Just One'
+
+ assert 'party_repeat' not in group
+ assert 'party_type' not in group
+ assert 'party_name' not in group
+
+ data = {
+ 'party_type': 'Repeating',
+ 'party_name': 'Totally repeating',
+ 'party_repeat': [{
+ 'repeat_type': 'First!'
+ }, {
+ 'repeat_type': 'Second!'
+ }]
+ }
+
+ group = mh._format_repeat(self, data, ['party'])
+ assert type(group) == list
+ assert len(group) == 2
+ assert group[0]['repeat_type'] == 'First!'
+ assert group[1]['repeat_type'] == 'Second!'
+
+ assert 'party_repeat' not in group
+ assert 'party_type' not in group
+ assert 'party_name' not in group
+
+ def test_get_questionnaire(self):
+ questionnaire = mh._get_questionnaire(
+ self, 'a1', '0')
+ assert questionnaire == self.questionnaire
+
+ with pytest.raises(ValidationError):
+ mh._get_questionnaire(
+ self, 'bad_info', '0')
+
+ def test_get_attributes(self):
+ data = {
+ 'party_type': 'Party Type',
+ 'party_attributes_individual': {
+ 'name_indv': 'Party Indv Attrs',
+ 'type_indv': 'Party for one',
+ },
+ 'party_attributes_people': {
+ 'name_ppl': 'Party People Attrs',
+ 'type_ppl': 'Where my party people at?',
+ },
+ 'party_name': 'House Party'
+ }
+ attributes = mh._get_attributes(self, data, 'party')
+
+ assert attributes['name_indv'] == 'Party Indv Attrs'
+ assert attributes['type_indv'] == 'Party for one'
+ assert attributes['name_ppl'] == 'Party People Attrs'
+ assert attributes['type_ppl'] == 'Where my party people at?'
+ assert 'party_name' not in attributes
+ assert 'party_type' not in attributes
+
+ def test_get_resource_files(self):
+ data = {
+ 'ardvark': 'Ardvark!',
+ 'party_resource_thing': 'Party Resource Thing!',
+ 'location_resource_thing': 'Location Resource!',
+ 'party_photo': 'Party Photo!'
+ }
+ resources = mh._get_resource_files(self, data, 'party')
+ assert type(resources) == list
+ assert 'Party Resource Thing!' in resources
+ assert 'Party Photo!' in resources
+
+ assert 'Ardvark!' not in resources
+ assert 'Location Resource!' not in resources
+
+ resources = mh._get_resource_files(self, data, 'location')
+ assert 'Location Resource!' in resources
+
+ assert 'Ardvark!' not in resources
+ assert 'Party Resource Thing!' not in resources
+ assert 'Party Photo!' not in resources
+
+ def test_get_resource_names(self):
+ data = {
+ 'party_type': 'Party Type',
+ 'party_photo': 'Party Photo',
+ 'party_resource_thing': 'Party Resource Thing',
+ 'tenure_resource_thing': 'Tenure Resource Thing',
+ }
+ model = PartyFactory.create()
+ resources = mh._get_resource_names(self, data, model, 'party')
+ assert resources['id'] == model.id
+ assert 'Party Photo' in resources['resources']
+ assert 'Party Resource Thing' in resources['resources']
+
+ assert 'Tenure Resource Thing' not in resources['resources']
+ assert 'Party Type' not in resources['resources']
diff --git a/cadasta/xforms/tests/test_views_api.py b/cadasta/xforms/tests/test_views_api.py
index 0dec2680a..2af3d9bae 100644
--- a/cadasta/xforms/tests/test_views_api.py
+++ b/cadasta/xforms/tests/test_views_api.py
@@ -26,6 +26,7 @@
from spatial.models import SpatialUnit
from tutelary.models import Role
from xforms.tests.files.test_resources import responses
+from xforms.models import XFormSubmission
from ..views import api
from .attr_schemas import (default_party_xform_group,
@@ -95,7 +96,6 @@ def test_get_xforms_with_no_superuser(self):
response = self.request(user=self.user)
assert response.status_code == 200
- print(response.content)
xml = etree.fromstring(response.content.encode('utf-8'))
ns = {'xf': 'http://openrosa.org/xforms/xformsList'}
@@ -123,72 +123,39 @@ def setup_models(self):
self.user = UserFactory.create()
self.org = OrganizationFactory.create()
self.prj = ProjectFactory.create(organization=self.org)
- self.prj_2 = ProjectFactory.create(organization=self.org)
- self.prj_3 = ProjectFactory.create(organization=self.org)
OrganizationRole.objects.create(
organization=self.org, user=self.user, admin=True)
- QuestionnaireFactory.create(
- project=self.prj,
- xls_form=get_form('test_standard_questionnaire'),
- filename='test_standard_questionnaire',
- id_string='test_standard_questionnaire',
- version=20160727122110)
-
+ def _create_questionnaire(self, questionnaire_name, version,
+ schema=True):
questionnaire = QuestionnaireFactory.create(
- project=self.prj_2,
- xls_form=get_form('test_standard_questionnaire_2'),
- filename='test_standard_questionnaire_2',
- id_string='test_standard_questionnaire_2',
- version=20160727122111)
-
- QuestionFactory.create(
- name='location_geometry',
- label='Location of Parcel',
- type='GS',
- questionnaire=questionnaire)
+ project=self.prj,
+ xls_form=get_form(questionnaire_name),
+ filename=questionnaire_name,
+ id_string=questionnaire_name,
+ version=(20160727122110 + version))
- QuestionnaireFactory.create(
- project=self.prj_3,
- xls_form=get_form('test_standard_questionnaire_bad'),
- filename='test_standard_questionnaire_bad',
- id_string='test_standard_questionnaire_bad',
- version=20160727122112)
+ if schema:
+ self._create_attrs_schema(self.prj)
- # project 1
- create_attrs_schema(
- project=self.prj, dict=default_party_xform_group,
- content_type=ContentType.objects.get(
- app_label='party', model='party'), errors=[])
- create_attrs_schema(
- project=self.prj, dict=individual_party_xform_group,
- content_type=ContentType.objects.get(
- app_label='party', model='party'), errors=[])
- create_attrs_schema(
- project=self.prj, dict=location_xform_group,
- content_type=ContentType.objects.get(
- app_label='spatial', model='spatialunit'), errors=[])
- create_attrs_schema(
- project=self.prj, dict=tenure_relationship_xform_group,
- content_type=ContentType.objects.get(
- app_label='party', model='tenurerelationship'), errors=[])
+ return questionnaire
- # project 2
+ def _create_attrs_schema(self, prj):
create_attrs_schema(
- project=self.prj_2, dict=default_party_xform_group,
+ project=prj, dict=default_party_xform_group,
content_type=ContentType.objects.get(
app_label='party', model='party'), errors=[])
create_attrs_schema(
- project=self.prj_2, dict=individual_party_xform_group,
+ project=prj, dict=individual_party_xform_group,
content_type=ContentType.objects.get(
app_label='party', model='party'), errors=[])
create_attrs_schema(
- project=self.prj_2, dict=location_xform_group,
+ project=prj, dict=location_xform_group,
content_type=ContentType.objects.get(
app_label='spatial', model='spatialunit'), errors=[])
create_attrs_schema(
- project=self.prj_2, dict=tenure_relationship_xform_group,
+ project=prj, dict=tenure_relationship_xform_group,
content_type=ContentType.objects.get(
app_label='party', model='tenurerelationship'), errors=[])
@@ -265,9 +232,16 @@ def _getResponseMessage(self, response):
ns = {'or': 'http://openrosa.org/http/response'}
return xml.find('.//or:message', namespaces=ns).text
+ def _test_resource(self, resource, model):
+ assert Resource.objects.get(
+ name__contains=resource) in model.resources
+
def test_submission_upload(self):
- data = self._submission(form='form',
- image=['test_image_one', 'test_image_two'],
+ questionnaire = self._create_questionnaire('t_questionnaire', 0)
+ data = self._submission(form='submission',
+ image=['test_image_one',
+ 'test_image_two',
+ 'test_image_three'],
audio=['test_audio_one'])
response = self.request(method='POST', user=self.user, post_data=data,
@@ -276,18 +250,21 @@ def test_submission_upload(self):
party = Party.objects.get(name='Bilbo Baggins')
location = SpatialUnit.objects.get(attributes={'name': 'Middle Earth'})
- assert location in party.tenure_relationships.all()
- assert len(location.resources) == 1
- assert location.resources[0] == Resource.objects.get(
- name__contains='test_image_one')
- assert len(party.resources) == 2
- assert Resource.objects.get(
- name__contains='test_image_two') in party.resources
- assert Resource.objects.get(
- name__contains='test_audio_one') in party.resources
+ tenure = TenureRelationship.objects.get(party=party)
+ assert tenure.spatial_unit == location
+ self._test_resource('test_image_one', location)
+ self._test_resource('test_image_two', party)
+ self._test_resource('test_audio_one', party)
+ self._test_resource('test_image_three', tenure)
+
+ response = XFormSubmission.objects.get(user=self.user)
+ assert response.questionnaire == questionnaire
+ assert ('Bilbo Baggins' in
+ response.json_submission['t_questionnaire']['party_name'])
def test_line_upload(self):
- data = self._submission(form='line_form')
+ self._create_questionnaire('t_questionnaire', 0)
+ data = self._submission(form='submission_line')
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
@@ -296,7 +273,8 @@ def test_line_upload(self):
assert geom.geometry.geom_type == 'LineString'
def test_polygon_upload(self):
- data = self._submission(form='poly_form',
+ self._create_questionnaire('t_questionnaire', 0)
+ data = self._submission(form='submission_poly',
audio=['test_audio_one'])
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
@@ -307,11 +285,11 @@ def test_polygon_upload(self):
assert geom.geometry.geom_type == 'Polygon'
tenure = TenureRelationship.objects.get(tenure_type='LH')
- assert Resource.objects.get(
- name__contains='test_audio_one') in tenure.resources
+ self._test_resource('test_audio_one', tenure)
def test_point_upload(self):
- data = self._submission(form='missing_semi_form')
+ self._create_questionnaire('t_questionnaire', 0)
+ data = self._submission(form='submission_missing_semi')
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
@@ -320,7 +298,15 @@ def test_point_upload(self):
assert geom.geometry.geom_type == 'Point'
def test_geoshape_upload(self):
- data = self._submission(form='geoshape_form')
+ questionnaire = self._create_questionnaire(
+ 't_questionnaire_geotype_select', 1)
+ QuestionFactory.create(
+ name='location_geometry',
+ label='Location of Parcel',
+ type='GS',
+ questionnaire=questionnaire)
+
+ data = self._submission(form='submission_geotype_select')
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
@@ -329,7 +315,15 @@ def test_geoshape_upload(self):
assert geom.geometry.geom_type == 'Polygon'
def test_geoshape_as_location_geometry_upload(self):
- data = self._submission(form='location_geoshape_form')
+ questionnaire = self._create_questionnaire(
+ 't_questionnaire_geotype_select', 1)
+ QuestionFactory.create(
+ name='location_geometry',
+ label='Location of Parcel',
+ type='GS',
+ questionnaire=questionnaire)
+
+ data = self._submission(form='submission_geotype_neither')
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
@@ -338,6 +332,7 @@ def test_geoshape_as_location_geometry_upload(self):
assert geom.geometry.geom_type == 'Polygon'
def test_invalid_submission_upload(self):
+ self._create_questionnaire('t_questionnaire', 0)
# testing submitting with a missing xml_submission_file
data = self._invalid_submission(form='This is not an xml form!')
response = self.request(method='POST', user=self.user, post_data=data,
@@ -346,21 +341,21 @@ def test_invalid_submission_upload(self):
msg = self._getResponseMessage(response)
assert msg == "XML submission not found"
- data = self._submission(form='bad_location_form')
+ data = self._submission(form='submission_bad_location')
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
assert response.status_code == 400
msg = self._getResponseMessage(response)
assert msg == "Location error: 'location_type'"
- data = self._submission(form='bad_party_form')
+ data = self._submission(form='submission_bad_party')
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
assert response.status_code == 400
msg = self._getResponseMessage(response)
assert msg == "Party error: 'party_name'"
- data = self._submission(form='bad_tenure_form')
+ data = self._submission(form='submission_bad_tenure')
response = self.request(method='POST', user=self.user, post_data=data,
content_type='multipart/form-data')
assert response.status_code == 400
@@ -373,7 +368,8 @@ def test_invalid_submission_upload(self):
).read()
bad_file = bad_file.decode('utf-8')
- data = self._submission(form='bad_resource_form',
+ self._create_questionnaire('t_questionnaire_bad', 2, False)
+ data = self._submission(form='submission_bad_resource',
image=['test_image_one'],
file=bad_file)
response = self.request(method='POST', user=self.user, post_data=data,
@@ -388,14 +384,15 @@ def test_invalid_submission_upload(self):
assert len(Resource.objects.all()) == 0
def test_anonymous_user(self):
- data = self._submission(form='form')
+ self._create_questionnaire('t_questionnaire', 0)
+ data = self._submission(form='submission')
response = self.request(method='POST', post_data=data,
content_type='multipart/form-data')
assert response.status_code == 403
def test_questionnaire_not_found(self):
with pytest.raises(ValidationError):
- data = self._submission(form='bad_questionnaire')
+ data = self._submission(form='submission_bad_questionnaire')
response = self.request(method='POST',
post_data=data,
user=self.user,
@@ -408,16 +405,180 @@ def test_no_content_head(self):
def test_form_not_current_questionnaire(self):
# update the default form to a new version
- QuestionnaireFactory.create(
- project=self.prj,
- xls_form=get_form('test_standard_questionnaire'),
- filename='test_standard_questionnaire_updated',
- id_string='test_standard_questionnaire',
- version=20160727122111
- )
- data = self._submission(form='form')
+ self._create_questionnaire('t_questionnaire', 0)
+ self._create_questionnaire('t_questionnaire', 1)
+
+ data = self._submission(form='submission')
response = self.request(method='POST', post_data=data,
user=self.user,
content_type='multipart/form-data')
msg = self._getResponseMessage(response)
assert msg == 'Form out of date'
+
+ def test_form_with_repeat_party(self):
+ self._create_questionnaire('t_questionnaire_repeat_party', 3)
+ data = self._submission(form='submission_party_repeat',
+ image=['test_image_one',
+ 'test_image_two',
+ 'test_image_three',
+ 'test_image_four',
+ 'test_image_five'],
+ audio=['test_audio_one'])
+
+ response = self.request(method='POST', user=self.user, post_data=data,
+ content_type='multipart/form-data')
+ assert response.status_code == 201
+
+ party_one = Party.objects.get(name='Bilbo Baggins')
+ party_two = Party.objects.get(name='Samwise Gamgee')
+ location = SpatialUnit.objects.get(type='MI')
+ tenure = TenureRelationship.objects.get(party=party_one)
+ assert tenure.spatial_unit == location
+ self._test_resource('test_audio_one', location)
+ self._test_resource('test_image_one', location)
+ self._test_resource('test_image_two', party_one)
+ self._test_resource('test_image_three', party_one)
+ self._test_resource('test_image_four', tenure)
+ self._test_resource('test_image_five', party_two)
+
+ def test_form_repeat_with_one_party(self):
+ self._create_questionnaire('t_questionnaire_repeat_party', 3)
+ data = self._submission(form='submission_party_one_repeat',
+ image=['test_image_one',
+ 'test_image_two',
+ 'test_image_three',
+ 'test_image_four'],
+ audio=['test_audio_one'])
+
+ response = self.request(method='POST', user=self.user, post_data=data,
+ content_type='multipart/form-data')
+ assert response.status_code == 201
+
+ party = Party.objects.get(name='Bilbo Baggins')
+ location = SpatialUnit.objects.get(type='MI')
+ tenure = TenureRelationship.objects.get(
+ party=party)
+ assert tenure.spatial_unit == location
+ self._test_resource('test_audio_one', location)
+ self._test_resource('test_image_one', location)
+ self._test_resource('test_image_two', party)
+ self._test_resource('test_image_three', party)
+ self._test_resource('test_image_four', tenure)
+
+ def test_form_with_repeat_location(self):
+ self._create_questionnaire('t_questionnaire_repeat_location', 4)
+ data = self._submission(form='submission_location_repeat',
+ image=['test_image_one',
+ 'test_image_two',
+ 'test_image_three',
+ 'test_image_four',
+ 'test_image_five'],
+ audio=['test_audio_one'])
+
+ response = self.request(method='POST', user=self.user, post_data=data,
+ content_type='multipart/form-data')
+ assert response.status_code == 201
+
+ party = Party.objects.get(name='Bilbo Baggins')
+ location_one = SpatialUnit.objects.get(type='MI')
+ location_two = SpatialUnit.objects.get(type='CB')
+ tenure_one = TenureRelationship.objects.get(
+ spatial_unit=location_one)
+ assert tenure_one.party == party
+ tenure = TenureRelationship.objects.get(
+ spatial_unit=location_two)
+
+ assert tenure.party == party
+ self._test_resource('test_audio_one', location_one)
+ self._test_resource('test_image_one', location_one)
+ self._test_resource('test_image_two', tenure_one)
+ self._test_resource('test_image_three', location_two)
+ self._test_resource('test_image_four', party)
+ self._test_resource('test_image_five', party)
+
+ def test_form_repeat_with_one_location(self):
+ self._create_questionnaire('t_questionnaire_repeat_location', 4)
+ data = self._submission(form='submission_location_one_repeat',
+ image=['test_image_one',
+ 'test_image_two',
+ 'test_image_four',
+ 'test_image_five'],
+ audio=['test_audio_one'])
+
+ response = self.request(method='POST', user=self.user, post_data=data,
+ content_type='multipart/form-data')
+ assert response.status_code == 201
+
+ party = Party.objects.get(name='Bilbo Baggins')
+ location = SpatialUnit.objects.get(type='MI')
+ tenure = TenureRelationship.objects.get(
+ spatial_unit=location)
+
+ assert tenure.party == party
+ self._test_resource('test_audio_one', location)
+ self._test_resource('test_image_one', location)
+ self._test_resource('test_image_two', tenure)
+ self._test_resource('test_image_four', party)
+ self._test_resource('test_image_five', party)
+
+ def test_form_repeat_minus_tenure(self):
+ self._create_questionnaire('t_questionnaire_repeat_minus_tenure', 5)
+ data = self._submission(form='submission_repeat_minus_tenure',
+ image=['test_image_one',
+ 'test_image_two',
+ 'test_image_three',
+ 'test_image_four',
+ 'test_image_five'],
+ audio=['test_audio_one'])
+
+ response = self.request(method='POST', user=self.user, post_data=data,
+ content_type='multipart/form-data')
+ assert response.status_code == 201
+
+ party = Party.objects.get(name='Bilbo Baggins')
+ location_one = SpatialUnit.objects.get(type='MI')
+ location_two = SpatialUnit.objects.get(type='CB')
+ tenure_one = TenureRelationship.objects.get(
+ spatial_unit=location_one)
+ tenure_two = TenureRelationship.objects.get(
+ spatial_unit=location_two)
+ assert tenure_one.party == party and tenure_two.party == party
+
+ self._test_resource('test_audio_one', location_one)
+ self._test_resource('test_image_one', location_one)
+ self._test_resource('test_image_two', tenure_one)
+ self._test_resource('test_image_two', tenure_two)
+ self._test_resource('test_image_three', location_two)
+ self._test_resource('test_image_four', party)
+ self._test_resource('test_image_five', party)
+
+ def test_form_repeat_party_minus_tenure(self):
+ self._create_questionnaire(
+ 't_questionnaire_repeat_party_minus_tenure', 6)
+ data = self._submission(form='submission_repeat_party_minus_tenure',
+ image=['test_image_one',
+ 'test_image_two',
+ 'test_image_three',
+ 'test_image_four',
+ 'test_image_five'],
+ audio=['test_audio_one'])
+
+ response = self.request(method='POST', user=self.user, post_data=data,
+ content_type='multipart/form-data')
+ assert response.status_code == 201
+
+ party_one = Party.objects.get(name='Bilbo Baggins')
+ party_two = Party.objects.get(name='Samwise Gamgee')
+ location = SpatialUnit.objects.get(type='MI')
+ tenure_one = TenureRelationship.objects.get(party=party_one)
+ tenure_two = TenureRelationship.objects.get(party=party_two)
+ assert tenure_one.spatial_unit == location
+ assert tenure_two.spatial_unit == location
+
+ self._test_resource('test_audio_one', location)
+ self._test_resource('test_image_one', location)
+ self._test_resource('test_image_two', tenure_one)
+ self._test_resource('test_image_two', tenure_two)
+ self._test_resource('test_image_three', party_one)
+ self._test_resource('test_image_four', party_one)
+ self._test_resource('test_image_five', party_two)
diff --git a/cadasta/xforms/views/api.py b/cadasta/xforms/views/api.py
index 8f551cf33..9a74c5a4e 100644
--- a/cadasta/xforms/views/api.py
+++ b/cadasta/xforms/views/api.py
@@ -17,7 +17,8 @@
from ..exceptions import InvalidXMLSubmission
-logger = logging.getLogger('xform.submissions')
+logger = logging
+# logger = logging.getLogger('xform.submissions')
OPEN_ROSA_ENVELOPE = """
@@ -46,9 +47,10 @@ def create(self, request, *args, **kwargs):
status=status.HTTP_204_NO_CONTENT,)
try:
instance = ModelHelper(
- ).upload_submission_data(request)
+ ).upload_submission_data(request)
except InvalidXMLSubmission as e:
- logger.debug(str(e))
+ # logger.debug(str(e))
+ logger.error(str(e))
return self._sendErrorResponse(request, e)
serializer = XFormSubmissionSerializer(instance)
@@ -93,11 +95,11 @@ class XFormListView(OpenRosaHeadersMixin,
def get_user_forms(self):
forms = []
policies = self.request.user.assigned_policies()
- orgs = self.request.user.organizations.all()
+ orgs = self.request.user.organizations.filter(archived=False)
if Role.objects.get(name='superuser') in policies:
- return Questionnaire.objects.all()
+ return Questionnaire.objects.filter(project__archived=False)
for org in orgs:
- projects = org.projects.all()
+ projects = org.projects.filter(archived=False)
for project in projects:
try:
questionnaire = Questionnaire.objects.get(