Skip to content

Commit

Permalink
Merge pull request #214 from Cadasta/bugs/private-projects-display
Browse files Browse the repository at this point in the history
Fixes #196: Private projects only visible to organization members
  • Loading branch information
ian-ross committed Jun 6, 2016
2 parents ec49265 + d406463 commit e20fadd
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 19 deletions.
56 changes: 49 additions & 7 deletions cadasta/core/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def add_test_projects(self):
This is a test project. This is a test project. This is a test
project. This is a test project. This is a test project. This
is a test project. This is a test project.""",
organization=orgs[0],
organization=orgs[1],
country='KE',
extent=('SRID=4326;'
'POLYGON ((-5.1031494140625000 8.1299292850467957, '
Expand All @@ -144,7 +144,7 @@ def add_test_projects(self):
This is a test project. This is a test project. This is a test
project. This is a test project. This is a test project. This
is a test project. This is a test project.""",
organization=orgs[0],
organization=orgs[1],
country='PH',
extent=('SRID=4326;'
'POLYGON ((-63.6328125000000000 44.7233201889582475, '
Expand All @@ -161,7 +161,7 @@ def add_test_projects(self):
project. This is another test project. This is a test project.
This is another test project. This is another test project.
This is another test project.""",
organization=orgs[1],
organization=orgs[0],
country='ID',
extent=('SRID=4326;'
'POLYGON ((-57.0520019531250000 -1.0793428942462329, '
Expand All @@ -179,7 +179,7 @@ def add_test_projects(self):
project. This is another test project. This is a test project.
This is another test project. This is another test project.
This is another test project.""",
organization=orgs[1],
organization=orgs[0],
country='MM'
))
projs.append(ProjectFactory.create(
Expand All @@ -190,7 +190,7 @@ def add_test_projects(self):
project. This is another test project. This is a test project.
This is another test project. This is another test project.
This is another test project.""",
organization=orgs[1],
organization=orgs[0],
country='MM',
extent=GEOSGeometry(
'{"type": "Polygon",'
Expand All @@ -212,7 +212,7 @@ def add_test_projects(self):
project. This is another test project. This is a test project.
This is another test project. This is another test project.
This is another test project.""",
organization=orgs[1],
organization=orgs[0],
country='MM',
extent=GEOSGeometry(
'{"type": "Polygon",'
Expand All @@ -233,7 +233,7 @@ def add_test_projects(self):
project. This is another test project. This is a test project.
This is another test project. This is another test project.
This is another test project.""",
organization=orgs[0],
organization=orgs[1],
extent=GEOSGeometry(
'{"type": "Polygon",'
'"coordinates": [['
Expand All @@ -251,6 +251,48 @@ def add_test_projects(self):
'[-245.3981566429138, -3.331934566552203],'
'[-245.39695501327512, -3.328635665488632]]]}')
))

projs.append(ProjectFactory.create(
name='Private Cadasta Test Project',
slug='private-cadasta',
description=""""This is a private test project. This is pivate test
project. This is pivate test project. This is pivate test
project. This is pivate test project. This is a test project.
This is another test project. This is another test project.
This is another test project.""",
organization=orgs[0],
extent=GEOSGeometry(
'{"type": "Polygon",'
'"coordinates": [['
'[-21.81009292602539, 64.07722793795327],'
'[-21.81009292602539, 64.09425757251603],'
'[-21.76013946533203, 64.09425757251603],'
'[-21.76013946533203, 64.07722793795327],'
'[-21.81009292602539, 64.07722793795327]]'
']}'),
access='private'
))

projs.append(ProjectFactory.create(
name='Private H4H Test Project',
slug='private-h4h',
description=""""This is a private test project. This is pivate test
project. This is pivate test project. This is pivate test
project. This is pivate test project. This is a test project.
This is another test project. This is another test project.
This is another test project.""",
organization=orgs[1],
extent=GEOSGeometry(
'{"type": "Polygon",'
'"coordinates": [['
'[-166.18331909179688, 59.891003681240576],'
'[-166.18331909179688, 60.06346983332297],'
'[-165.596923828125, 60.06346983332297],'
'[-165.596923828125, 59.891003681240576],'
'[-166.18331909179688, 59.891003681240576]]]}'),
access='private'
))

print('\nSuccessfully added organizations {}'.
format(Project.objects.all()))

Expand Down
2 changes: 1 addition & 1 deletion cadasta/core/tests/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_fixture_setup(self):
assert User.objects.count() == 20
assert Policy.objects.count() == 7
assert Organization.objects.count() == 2
assert Project.objects.count() == 7
assert Project.objects.count() == 9
assert SpatialUnit.objects.count() == 7
assert SpatialUnitRelationship.objects.count() == 2

Expand Down
54 changes: 54 additions & 0 deletions cadasta/core/tests/test_views_default.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import json

from django.test import TestCase
from django.http import HttpRequest
from django.contrib.auth.models import AnonymousUser
from django.template import RequestContext
from django.template.loader import render_to_string

from accounts.tests.factories import UserFactory
from organization.tests.factories import OrganizationFactory, ProjectFactory
from organization.models import OrganizationRole, Project
from organization.serializers import ProjectGeometrySerializer

from ..views.default import IndexPage, Dashboard

Expand Down Expand Up @@ -31,8 +38,40 @@ def setUp(self):
self.view = Dashboard.as_view()
self.request = HttpRequest()
setattr(self.request, 'method', 'GET')
self.org = OrganizationFactory.create()
extent = ('SRID=4326;'
'POLYGON ((-5.1031494140625000 8.1299292850467957, '
'-5.0482177734375000 7.6837733211111425, '
'-4.6746826171875000 7.8252894725496338, '
'-4.8641967773437491 8.2278005261522775, '
'-5.1031494140625000 8.1299292850467957))')
ProjectFactory.create(organization=self.org, extent=extent)
ProjectFactory.create(organization=self.org, extent=extent)
ProjectFactory.create(
name='Private Project',
access='private', organization=self.org, extent=extent)

setattr(self.request, 'user', AnonymousUser())

def _test_projects_rendered(self, response, member=False):
content = response.render().content.decode('utf-8')

context = RequestContext(self.request)
projects = []
if member:
projects.extend(Project.objects.filter(
organization__slug=self.org.slug, access='private'))
projects.extend(Project.objects.filter(access='public'))
context['geojson'] = json.dumps(
ProjectGeometrySerializer(projects, many=True).data
)
expected = render_to_string(
'core/dashboard.html',
context
)

assert expected == content

def test_redirects_when_user_is_not_signed_in(self):
response = self.view(self.request)
assert response.status_code == 302
Expand All @@ -43,3 +82,18 @@ def test_page_is_rendered_when_user_is_signed_in(self):
setattr(self.request, 'user', user)
response = self.view(self.request)
assert response.status_code == 200

def test_private_projects_rendered_when_org_member_is_signed_in(self):
user = UserFactory.create()
OrganizationRole.objects.create(organization=self.org, user=user)
setattr(self.request, 'user', user)
response = self.view(self.request)
assert response.status_code == 200
self._test_projects_rendered(response, member=True)

def test_private_projects_not_rendered_when_not_an_org_member(self):
user = UserFactory.create()
setattr(self.request, 'user', user)
response = self.view(self.request)
assert response.status_code == 200
self._test_projects_rendered(response)
17 changes: 14 additions & 3 deletions cadasta/core/views/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.shortcuts import redirect
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from organization.models import Project
from organization.models import Project, Organization

from organization.serializers import ProjectGeometrySerializer

Expand All @@ -21,10 +21,21 @@ def get(self, request, *args, **kwargs):
class Dashboard(LoginRequiredMixin, TemplateView):
template_name = 'core/dashboard.html'

def get_context_data(self, **kwargs):
def get_context_data(self, projects, **kwargs):
context = super().get_context_data(**kwargs)
projects = Project.objects.filter(extent__isnull=False)
projects.extend(Project.objects.filter(access='public'))
context['geojson'] = json.dumps(
ProjectGeometrySerializer(projects, many=True).data
)
return context

def get(self, request, *args, **kwargs):
projects = []
if hasattr(self.request.user, 'organizations'):
user_orgs = self.request.user.organizations.all()
if len(user_orgs) > 0:
for org in Organization.objects.all():
if org in user_orgs:
projects.extend(org.projects.filter(access='private'))
context = self.get_context_data(projects=projects)
return super(TemplateView, self).render_to_response(context)
6 changes: 6 additions & 0 deletions cadasta/organization/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ def __str__(self):
def __repr__(self):
return str(self)

def public_projects(self):
return self.projects.filter(access='public')

def all_projects(self):
return self.projects.all()


class OrganizationRole(RandomIDModel):
organization = models.ForeignKey(Organization)
Expand Down
36 changes: 31 additions & 5 deletions cadasta/organization/tests/test_views_default_organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

from accounts.tests.factories import UserFactory
from ..views import default
from ..models import Organization, OrganizationRole
from ..models import Organization, OrganizationRole, Project
from .. import forms
from .factories import OrganizationFactory, clause
from .factories import OrganizationFactory, ProjectFactory, clause


class OrganizationListTest(TestCase):
Expand Down Expand Up @@ -137,6 +137,9 @@ def setUp(self):
setattr(self.request, 'method', 'GET')

self.org = OrganizationFactory.create()
self.projs = ProjectFactory.create_batch(2, organization=self.org)
self.private_proj = ProjectFactory.create(
organization=self.org, access='private')

clauses = {
'clause': [
Expand All @@ -155,17 +158,29 @@ def setUp(self):
self.user = UserFactory.create()
setattr(self.request, 'user', self.user)

def _get(self, slug, status=None):
def _get(self, slug, status=None, user=None, make_org_member=None,):
if user is None:
user = self.user
if make_org_member is not None:
OrganizationRole.objects.create(organization=self.org, user=user)
setattr(self.request, 'user', user)
response = self.view(self.request, slug=slug)
if status is not None:
assert response.status_code == status
return response

def _check_ok(self, response):
def _check_ok(self, response, org=None, member=False):
content = response.render().content.decode('utf-8')

context = RequestContext(self.request)
context['object'] = self.org
context['object'] = org or self.org
if member:
context['projects'] = Project.objects.filter(
organization__slug=self.org.slug)
elif org is None:
context['projects'] = Project.objects.filter(
organization__slug=self.org.slug, access='public')

expected = render_to_string(
'organization/organization_dashboard.html',
context
Expand All @@ -182,6 +197,17 @@ def test_get_with_unauthorized_user(self):
response = self._get(self.org.slug, status=200)
self._check_ok(response)

def test_get_with_org_membership(self):
response = self._get(
self.org.slug, status=200, make_org_member=self.org)
self._check_ok(response, member=True)

def test_get_with_new_org(self):
new_org = OrganizationFactory.create()
assign_user_policies(self.user, self.policy)
response = self._get(new_org.slug, status=200)
self._check_ok(response, org=new_org)


class OrganizationEditTest(TestCase):
def setUp(self):
Expand Down
19 changes: 19 additions & 0 deletions cadasta/organization/views/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,25 @@ class OrganizationDashboard(PermissionRequiredMixin, generic.DetailView):
template_name = 'organization/organization_dashboard.html'
permission_required = 'org.view'

def get_context_data(self, member=False, **kwargs):
context = super(OrganizationDashboard, self).get_context_data(**kwargs)
if member:
projects = self.object.all_projects()
else:
projects = self.object.public_projects()
context['projects'] = projects
return context

def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data()
if hasattr(self.request.user, 'organizations'):
orgs = self.request.user.organizations.all()
for org in orgs:
if org.slug == self.kwargs['slug']:
context = self.get_context_data(member=True)
return super(generic.DetailView, self).render_to_response(context)


class OrganizationEdit(LoginPermissionRequiredMixin,
generic.UpdateView):
Expand Down
4 changes: 2 additions & 2 deletions cadasta/templates/organization/organization_dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ <h2>{{ object.name }}</h2>
<div class="col-md-8 col-text">
<h2 class="page-title">{% trans "Overview" %}</h2>
<div class="project-list">
{% if object.projects.all %}
{% if projects %}
<table class="table table-hover datatable" data-paging-type="simple">
<thead>
<tr>
Expand All @@ -95,7 +95,7 @@ <h2 class="page-title">{% trans "Overview" %}</h2>
</tr>
</thead>
<tbody>
{% for prj in object.projects.all %}
{% for prj in projects %}
<tr onclick="window.document.location='{% url 'organization:project-dashboard' organization=object.slug project=prj.slug %}';">
<td>{{ prj.name }}</td>
<td>{{ prj.country }}</td>
Expand Down
6 changes: 5 additions & 1 deletion cadasta/templates/organization/organization_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ <h4>{{ org.name }}</h4>
{% endif %}
</div>
</td>
<td>{{ org.projects.count }}</td>
{% if user.is_authenticated and org in user.organizations.all %}
<td>{{ org.all_projects.count }}</td>
{% else %}
<td>{{ org.public_projects.count }}</td>
{% endif %}
</tr>
{% endfor %}
</table>
Expand Down

0 comments on commit e20fadd

Please sign in to comment.