Skip to content

Commit

Permalink
Merge pull request #652 from Cadasta/enhancement/#272
Browse files Browse the repository at this point in the history
Fixing #272
  • Loading branch information
ian-ross authored Sep 8, 2016
2 parents c190062 + 7de9b14 commit 0fe8f50
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 156 deletions.
2 changes: 1 addition & 1 deletion cadasta/config/permissions/org-admin.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
{
"effect": "allow",
"action": ["project.*", "project.users.*", "questionaire.*",
"action": ["project.*", "project.users.*", "questionnaire.*",
"resource.*", "spatial.*", "spatial_rel.*",
"party.*", "party_rel.*", "tenure_rel.*"],
"object": ["project/$organization/*"]
Expand Down
4 changes: 2 additions & 2 deletions cadasta/config/permissions/project-manager.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
// organization.
{
"effect": "allow",
"action": ["project.*", "project.users.*", "questionaire.*",
"action": ["project.*", "project.users.*", "questionnaire.*",
"resource.*", "spatial.*", "spatial_rel.*",
"party.*", "party_rel.*", "tenure_rel.*"],
"object": ["project/$organization/$project"]
},
{
"effect": "deny",
"action": ["project.archive", "project.unarchive", "questionaire.add"],
"action": ["project.archive", "project.unarchive", "questionnaire.add"],
"object": ["project/$organization/$project"]
},

Expand Down
27 changes: 15 additions & 12 deletions cadasta/organization/forms.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import time
from zipfile import ZipFile

from accounts.models import User
from buckets.widgets import S3FileUploadWidget
from core.form_mixins import SuperUserCheck
from core.util import slugify
from django import forms
from django.conf import settings
from django.contrib.postgres import forms as pg_forms
from django.contrib.gis import forms as gisforms
from core.util import slugify
from django.utils.translation import ugettext as _
from django.contrib.postgres import forms as pg_forms
from django.db import transaction
from django.forms.utils import ErrorDict

from django.utils.translation import ugettext as _
from leaflet.forms.widgets import LeafletWidget
from questionnaires.models import Questionnaire
from tutelary.models import check_perms
from buckets.widgets import S3FileUploadWidget

from accounts.models import User
from core.form_mixins import SuperUserCheck
from questionnaires.models import Questionnaire
from .models import Organization, Project, OrganizationRole, ProjectRole
from .choices import ADMIN_CHOICES, ROLE_CHOICES
from .fields import ProjectRoleField, PublicPrivateField, ContactsField
from .download.xls import XLSExporter
from .download.resources import ResourceExporter
from .download.shape import ShapeExporter
from .download.xls import XLSExporter
from .fields import ContactsField, ProjectRoleField, PublicPrivateField
from .models import Organization, OrganizationRole, Project, ProjectRole

FORM_CHOICES = ROLE_CHOICES + (('Pb', _('Public User')),)
QUESTIONNAIRE_TYPES = [
Expand Down Expand Up @@ -245,7 +245,7 @@ class ProjectAddDetails(SuperUserCheck, forms.Form):
description = forms.CharField(required=False, widget=forms.Textarea)
access = PublicPrivateField(initial='public')
url = forms.URLField(required=False)
questionaire = forms.CharField(
questionnaire = forms.CharField(
required=False,
widget=S3FileUploadWidget(upload_to='xls-forms',
accepted_types=QUESTIONNAIRE_TYPES))
Expand Down Expand Up @@ -348,6 +348,7 @@ def clean_name(self):


class PermissionsForm(SuperUserCheck):

def check_admin(self, user):
if not hasattr(self, 'admins'):
self.admins = [
Expand Down Expand Up @@ -379,6 +380,7 @@ def set_fields(self):


class ProjectAddPermissions(PermissionsForm, forms.Form):

def __init__(self, organization, *args, **kwargs):
super().__init__(*args, **kwargs)
if organization is not None:
Expand All @@ -387,6 +389,7 @@ def __init__(self, organization, *args, **kwargs):


class ProjectEditPermissions(PermissionsForm, forms.Form):

def __init__(self, *args, **kwargs):
self.project = kwargs.pop('instance')
super().__init__(*args, **kwargs)
Expand Down
117 changes: 63 additions & 54 deletions cadasta/organization/tests/test_views_default_projects.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
import pytest
import json
import os
import os.path
import json
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import HttpRequest, Http404
from django.contrib.auth.models import AnonymousUser
from django.template.loader import render_to_string
from django.template import RequestContext
from django.contrib.messages.storage.fallback import FallbackStorage
from django.contrib.messages.api import get_messages

from tutelary.models import Policy, Role, assign_user_policies
from buckets.test.storage import FakeS3Storage
import pytest

from accounts.tests.factories import UserFactory
from buckets.test.storage import FakeS3Storage
from core.tests.base_test_case import UserTestCase
from core.tests.util import make_dirs # noqa
from accounts.tests.factories import UserFactory
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.contrib.messages.api import get_messages
from django.contrib.messages.storage.fallback import FallbackStorage
from django.core.urlresolvers import reverse
from django.http import Http404, HttpRequest
from django.template import RequestContext
from django.template.loader import render_to_string
from organization.models import OrganizationRole, Project, ProjectRole
from questionnaires.tests.factories import QuestionnaireFactory
from questionnaires.models import Questionnaire
from resources.utils.io import ensure_dirs
from questionnaires.tests.factories import QuestionnaireFactory
from resources.tests.utils import clear_temp # noqa
from ..views import default
from resources.utils.io import ensure_dirs
from tutelary.models import Policy, Role, assign_user_policies

from .. import forms
from ..views import default
from .factories import OrganizationFactory, ProjectFactory, clause


class ProjectListTest(UserTestCase):

def setUp(self):
super().setUp()
self.view = default.ProjectList.as_view()
Expand Down Expand Up @@ -115,7 +117,7 @@ def _get(self, user=None, status=None, projs=None,
assert expected == content

def test_get_with_valid_user(self):
self._get(status=200, projs=self.projs+self.unauth_projs)
self._get(status=200, projs=self.projs + self.unauth_projs)

def test_get_with_unauthenticated_user(self):
self._get(status=200, user=AnonymousUser(),
Expand All @@ -127,7 +129,7 @@ def test_get_with_unauthorized_user(self):
# above because the policy includes clauses denying access to
# some projects.
self._get(status=200, user=UserFactory.create(),
projs=self.projs+self.unauth_projs)
projs=self.projs + self.unauth_projs)

def test_get_with_org_membership(self):
self._get(status=200, make_org_member=[self.ok_org1],
Expand All @@ -138,7 +140,7 @@ def test_get_with_org_memberships(self):
self._get(status=200, make_org_member=[self.ok_org1, self.ok_org2],
projs=self.projs + self.unauth_projs + [
self.priv_proj1, self.priv_proj2, self.priv_proj3
])
])

def test_get_with_superuser(self):
superuser = UserFactory.create()
Expand All @@ -149,6 +151,7 @@ def test_get_with_superuser(self):


class ProjectDashboardTest(UserTestCase):

def setUp(self):
super().setUp()
self.view = default.ProjectDashboard.as_view()
Expand Down Expand Up @@ -337,6 +340,7 @@ def test_get_private_project_with_superuser(self):

@pytest.mark.usefixtures('make_dirs')
class ProjectAddTest(UserTestCase):

def setUp(self):
super().setUp()
self.view = default.ProjectAddWizard.as_view()
Expand Down Expand Up @@ -476,14 +480,27 @@ def _get_xls_form(self, form_name):
'permissions-org_member_3': 'PU',
'permissions-bad_user': 'PU'
}
DETAILS_POST_DATA_MANIPULATED = {
'project_add_wizard-current_step': 'details',
'details-organization': 'test-org',
'details-name': 'Test Project FAKE',
'details-description': 'This is a test project',
'details-access': 'on',
'details-url': 'http://www.test.org',
'details-contacts-TOTAL_FORMS': 1,
'details-contacts-INITIAL_FORMS': 0,
'details-contacts-0-name': "John Lennon",
'details-contacts-0-email': '[email protected]',
'details-contacts-0-tel': ''
}

def test_full_flow_valid(self):
self.client.force_login(self.users[0])
extents_response = self.client.post(
reverse('project:add'), self.EXTENTS_POST_DATA
)
assert extents_response.status_code == 200
self.DETAILS_POST_DATA['details-questionaire'] = self._get_xls_form(
self.DETAILS_POST_DATA['details-questionnaire'] = self._get_xls_form(
'xls-form')
details_response = self.client.post(
reverse('project:add'), self.DETAILS_POST_DATA
Expand Down Expand Up @@ -534,36 +551,23 @@ def test_full_flow_invalid_xlsform(self):
reverse('project:add'), self.EXTENTS_POST_DATA
)
assert extents_response.status_code == 200
self.DETAILS_POST_DATA['details-questionaire'] = self._get_xls_form(
details_post_data = self.DETAILS_POST_DATA.copy()
details_post_data[
'details-questionnaire'] = self._get_xls_form(
'xls-form-invalid')
details_response = self.client.post(
reverse('project:add'), self.DETAILS_POST_DATA
reverse('project:add'), details_post_data
)
assert details_response.status_code == 200
permissions_response = self.client.post(
reverse('project:add'), self.PERMISSIONS_POST_DATA
)
assert permissions_response.status_code == 302
assert ('/organizations/test-org/projects/test-project/' in
permissions_response['location'])

proj = Project.objects.get(organization=self.org, name='Test Project')
assert proj.slug == 'test-project'
assert proj.description == 'This is a test project'
assert len(proj.contacts) == 1
assert proj.contacts[0]['name'] == "John Lennon"
assert proj.contacts[0]['email'] == '[email protected]'
for r in ProjectRole.objects.filter(project=proj):
if r.user.username == 'org_member_1':
assert r.role == 'PM'
elif r.user.username == 'org_member_2':
assert r.role == 'DC'
elif r.user.username == 'org_member_3':
assert r.role == 'PU'
else:
assert False

assert Questionnaire.objects.filter(project=proj).exists() is False
assert permissions_response.status_code == 200
assert permissions_response.context_data['form'].is_valid() is False
with pytest.raises(Project.DoesNotExist) as e:
Project.objects.get(
organization=self.org, slug='test-project')
assert e.message == 'Project matching query does not exist.'

def test_full_flow_long_slug(self):
project_name = (
Expand All @@ -585,6 +589,7 @@ def test_full_flow_long_slug(self):
permissions_response = self.client.post(
reverse('project:add'), self.PERMISSIONS_POST_DATA
)

assert permissions_response.status_code == 302
assert (
'/organizations/test-org/projects/{}/'.format(expected_slug)
Expand Down Expand Up @@ -779,7 +784,7 @@ def test_get_with_authorized_user(self):
{'project': self.project,
'object': self.project,
'form': forms.ProjectEditDetails(
instance=self.project)},
instance=self.project)},
request=self.request)

assert expected == content
Expand All @@ -797,8 +802,8 @@ def test_get_with_authorized_user_include_questionnaire(self):
{'project': self.project,
'object': self.project,
'form': forms.ProjectEditDetails(
instance=self.project,
initial={'questionnaire': questionnaire.xls_form.url})},
instance=self.project,
initial={'questionnaire': questionnaire.xls_form.url})},
request=self.request)

assert expected == content
Expand Down Expand Up @@ -847,17 +852,17 @@ def test_post_invalid_form(self):
content = response.content.decode('utf-8')

form = forms.ProjectEditDetails(
instance=self.project,
initial={'questionnaire': questionnaire},
data=self.post_data)
instance=self.project,
initial={'questionnaire': questionnaire},
data=self.post_data)

form.add_error('questionnaire',
"Unknown question type 'interger'.")
form.add_error('questionnaire',
"'interger' is not an accepted question type")
form.add_error('questionnaire',
"'select multiple list' is not an accepted question "
"type")
# form.add_error('questionnaire',
# "'interger' is not an accepted question type")
# form.add_error('questionnaire',
# "'select multiple list' is not an accepted question "
# "type")

expected = render_to_string(
'organization/project_edit_details.html',
Expand Down Expand Up @@ -889,6 +894,7 @@ def test_post_with_unauthenticated_user(self):


class ProjectEditPermissionsTest(UserTestCase):

def setUp(self):
super().setUp()
self.view = default.ProjectEditPermissions.as_view()
Expand Down Expand Up @@ -1002,6 +1008,7 @@ def test_post_with_unauthenticated_user(self):


class ProjectArchiveTest(UserTestCase):

def setUp(self):
super().setUp()
self.view = default.ProjectArchive.as_view()
Expand Down Expand Up @@ -1062,6 +1069,7 @@ def test_archive_with_unauthenticated_user(self):


class ProjectUnarchiveTest(UserTestCase):

def setUp(self):
super().setUp()
self.view = default.ProjectUnarchive.as_view()
Expand Down Expand Up @@ -1124,6 +1132,7 @@ def test_archive_with_unauthenticated_user(self):
@pytest.mark.usefixtures('make_dirs')
@pytest.mark.usefixtures('clear_temp')
class ProjectDataDownloadTest(UserTestCase):

def setUp(self):
super().setUp()
ensure_dirs()
Expand Down
Loading

0 comments on commit 0fe8f50

Please sign in to comment.