Skip to content

Commit

Permalink
Resolve #612: Don’t show party picker if there are no parties
Browse files Browse the repository at this point in the history
  • Loading branch information
seav committed Sep 6, 2016
1 parent 1b39a37 commit 360cd95
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 47 deletions.
7 changes: 0 additions & 7 deletions cadasta/core/static/css/main.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 1 addition & 9 deletions cadasta/core/static/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1262,11 +1262,6 @@ div.add-btn-btm { // add party link at bottom of table
margin-bottom: 20px;
}

#new-item {
background: $body-bg;
padding: 20px 20px 0 20px;
}

.more-menu {
float: left;
font-size: 24px;
Expand Down Expand Up @@ -1420,7 +1415,7 @@ div.add-btn-btm { // add party link at bottom of table
background-color: $alert-warning-bg;
padding: 10px;
}

ul.errorlist {
margin-bottom: 0;
padding-left: 0;
Expand Down Expand Up @@ -1462,9 +1457,6 @@ tr.contacts-error {
-------------------------------------------------------------- */

#select-party {
label {
display: block;
}
#party-select {
width: 100%;
}
Expand Down
3 changes: 1 addition & 2 deletions cadasta/core/static/js/rel_new_item.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
$('button#add-party').click(function() {
var val = $('#new_entity_field').val();
$('#new_entity_field').val((val === 'on' ? '' : 'on'));
$('#new_entity_field').val('on');
});
27 changes: 18 additions & 9 deletions cadasta/spatial/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,12 @@ def save(self):


class TenureRelationshipForm(forms.Form):
id = forms.CharField(
required=False,
max_length=ID_FIELD_LENGTH)
# new_entity should be first because the other fields depend on it
new_entity = forms.BooleanField(required=False, widget=NewEntityWidget())
id = forms.CharField(required=False, max_length=ID_FIELD_LENGTH)
name = forms.CharField(required=False, max_length=200)
party_type = forms.ChoiceField(choices=Party.TYPE_CHOICES)
tenure_type = forms.ChoiceField(choices=[])
party_type = forms.ChoiceField(required=False, choices=[])
tenure_type = forms.ChoiceField(required=True, choices=[])

class Media:
js = ('/static/js/rel_tenure.js',)
Expand All @@ -61,16 +60,18 @@ def __init__(self, project, spatial_unit, schema_selectors=(),
*args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['id'].widget = SelectPartyWidget(project.id)
tenuretypes = TenureRelationshipType.objects.values_list('id', 'label')
self.fields['party_type'].choices = (
[('', _("Please select a party type"))] +
list(Party.TYPE_CHOICES))
self.fields['tenure_type'].choices = (
[('', _('Please select a relationship type'))] +
list(tenuretypes))
[('', _("Please select a relationship type"))] +
list(TenureRelationshipType.objects.values_list('id', 'label')))
self.project = project
self.spatial_unit = spatial_unit
self.add_attribute_fields(schema_selectors)

def clean_id(self):
new_entity = self.data.get('new_entity', None)
new_entity = self.cleaned_data.get('new_entity', None)
id = self.cleaned_data.get('id', '')

if not new_entity and not id:
Expand All @@ -85,6 +86,14 @@ def clean_name(self):
raise forms.ValidationError(_("This field is required."))
return name

def clean_party_type(self):
new_entity = self.cleaned_data.get('new_entity', None)
party_type = self.cleaned_data.get('party_type', None)

if new_entity and not party_type:
raise forms.ValidationError(_("This field is required."))
return party_type

def create_model_fields(self, model, field_prefix, selectors,
new_item=False):
content_type = ContentType.objects.get_for_model(model)
Expand Down
68 changes: 60 additions & 8 deletions cadasta/spatial/tests/test_views_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from resources.tests.factories import ResourceFactory
from resources.tests.utils import clear_temp # noqa
from resources.forms import AddResourceFromLibraryForm, ResourceForm
from party.tests.factories import TenureRelationshipFactory
from party.tests.factories import PartyFactory, TenureRelationshipFactory
from party.models import Party, TenureRelationship

from .factories import SpatialUnitFactory
Expand Down Expand Up @@ -725,22 +725,26 @@ def get_template_context(self):
{'name': 'questionnaire',
'value': self.project.current_questionnaire,
'selector': self.project.current_questionnaire}
)),
),
initial={
'new_entity': not self.project.parties.exists(),
},
),
'geojson': json.dumps(SpatialUnitGeoJsonSerializer(
[self.spatial_unit], many=True).data)
[self.spatial_unit], many=True).data),
}

def test_get_with_authorized_user(self):
response, content = self.request(user=self.authorized_user)
assert response.status_code == 200
assert content == self.expected_content()

def test_get_from_non_existend_project(self):
def test_get_from_non_existent_project(self):
with pytest.raises(Http404):
self.request(user=self.authorized_user,
url_kwargs={'project': 'abc123'})

def test_get_non_existend_location(self):
def test_get_non_existent_location(self):
with pytest.raises(Http404):
self.request(user=self.authorized_user,
url_kwargs={'location': 'abc123'})
Expand All @@ -757,7 +761,7 @@ def test_get_with_unauthenticated_user(self):
assert response.status_code == 302
assert '/account/login/' in response['location']

def test_post_with_authorized(self):
def test_post_new_party_with_authorized(self):
response = self.request(method='POST', user=self.authorized_user)
assert response.status_code == 302
assert (response['location'] ==
Expand All @@ -770,14 +774,30 @@ def test_post_with_authorized(self):
party = Party.objects.first()
assert party.attributes.get('p_name') == 'Party Name'

def test_post_with_authorized_invalid_data(self):
def test_post_existing_party_with_authorized(self):
party = PartyFactory.create(project=self.project)
response = self.request(method='POST', user=self.authorized_user,
data={'new_entity': '', 'id': party.id})
assert response.status_code == 302
assert (response['location'] ==
self.expected_success_url + '#relationships')

assert TenureRelationship.objects.count() == 1
rel = TenureRelationship.objects.first()
assert rel.attributes.get('r_name') == 'Rel Name'
assert Party.objects.count() == 1
assert Party.objects.first().name == party.name

def test_post_with_authorized_invalid_new_party_data(self):
response, content = self.request(method='POST',
user=self.authorized_user,
data={'name': ''})
data={'name': '',
'party_type': ''})
assert response.status_code == 200
context = self.get_template_context()
data = self.get_post_data()
data['name'] = ''
data['party_type'] = ''
context['form'] = forms.TenureRelationshipForm(
project=self.project,
spatial_unit=self.spatial_unit,
Expand All @@ -800,6 +820,38 @@ def test_post_with_authorized_invalid_data(self):
assert TenureRelationship.objects.count() == 0
assert Party.objects.count() == 0

def test_post_with_authorized_invalid_existing_party_data(self):
party = PartyFactory.create(project=self.project)
response, content = self.request(method='POST',
user=self.authorized_user,
data={'new_entity': ''})
assert response.status_code == 200
context = self.get_template_context()
data = self.get_post_data()
data['new_entity'] = ''
context['form'] = forms.TenureRelationshipForm(
project=self.project,
spatial_unit=self.spatial_unit,
data=data,
schema_selectors=(
{'name': 'organization',
'value': self.project.organization,
'selector': self.project.organization.id},
{'name': 'project',
'value': self.project,
'selector': self.project.id},
{'name': 'questionnaire',
'value': self.project.current_questionnaire,
'selector': self.project.current_questionnaire}
))
expected = render_to_string(
self.template, context, request=self.request)
assert content == expected

assert TenureRelationship.objects.count() == 0
assert Party.objects.count() == 1
assert Party.objects.first().name == party.name

def test_post_with_unauthorized_user(self):
response = self.request(method='POST', user=self.unauthorized_user)
assert response.status_code == 302
Expand Down
6 changes: 5 additions & 1 deletion cadasta/spatial/views/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,12 @@ def get_context_data(self, *args, **kwargs):

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
prj = self.get_project()

kwargs['initial'] = {
'new_entity': not self.get_project().parties.exists(),
}

prj = self.get_project()
kwargs['schema_selectors'] = ()
if prj.current_questionnaire:
kwargs['schema_selectors'] = (
Expand Down
16 changes: 10 additions & 6 deletions cadasta/spatial/widgets.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
from django.forms.widgets import HiddenInput
from django.forms.widgets import Widget
from django.utils.translation import ugettext as _
from party.models import Party


class SelectPartyWidget(HiddenInput):
class SelectPartyWidget(Widget):
def __init__(self, project, *args, **kwargs):
super().__init__(*args, **kwargs)
self.project = project

def render(self, name, value, attrs={}):
prj_parties = Party.objects.filter(project_id=self.project)
parties = ['<option value="' + p.id + '" data-type="' +
p.get_type_display() + '">' + p.name + '</option>'
for p in prj_parties]
parties = [
'<option value="' + p.id + '" data-type="' +
p.get_type_display() + '"' +
(' selected="selected"' if p.id == value else '') + '>' +
p.name + '</option>' for p in prj_parties
]

return (
'<select id="party-select" name="{name}">'
'<option value="" data-type="">Please select a party</option>'
'{parties}'
'</select>'
).format(parties=''.join(parties), name=name)


class NewEntityWidget(HiddenInput):
class NewEntityWidget(Widget):
class Media:
js = ('/static/js/rel_new_item.js',)

Expand Down
17 changes: 12 additions & 5 deletions cadasta/templates/spatial/relationship_add.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
{% block extra_head %}
{{ block.super }}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2-bootstrap-theme/0.1.0-beta.9/select2-bootstrap.min.css" rel="stylesheet" />
{% endblock %}

{% block location_extra_script %}
Expand All @@ -28,6 +29,7 @@
$("#party-select").select2({
minimumResultsForSearch: 6,
templateResult: template,
theme: "bootstrap",
});
});
</script>
Expand All @@ -48,13 +50,18 @@ <h3 class="modal-title">{% trans "Add new relationship" %}</h3>

<div class="modal-body">
{% csrf_token %}

<h4 class="step">{% trans "1. Connected party" %}</h4>
<div id="select-party" class="clearfix">
<label>{% trans "Choose an existing party to connect to this location" %}</label>
{% render_field form.id class+="form-control" %}
<div id="select-party" class="clearfix{% if form.new_entity.value %} hidden{% endif %}">
<div class="form-group{% if form.id.errors %} has-error{% endif %}">
<label for="{{ form.id.id_for_label }}">{% trans "Choose an existing party to connect to this location" %}</label>
<label class="pull-right control-label">{{ form.id.errors }}</label>
{{ form.id }}
</div>

<label>{% trans "Or add a new party" %}</label>
{% render_field form.new_entity class+="form-control" %}
<div class="form-group">
{{ form.new_entity }}
</div>
</div>

<div id="new-item" class="clearfix{% if not form.new_entity.value %} hidden{% endif %}">
Expand Down

0 comments on commit 360cd95

Please sign in to comment.