diff --git a/seed/tests/test_account_views.py b/seed/tests/test_account_views.py index 8c17a8fda5..dab726d33c 100644 --- a/seed/tests/test_account_views.py +++ b/seed/tests/test_account_views.py @@ -18,7 +18,8 @@ from seed.models.cycles import Cycle from seed.models.properties import PropertyState from seed.models.tax_lots import TaxLotState -from seed.tests.util import FakeRequest +from seed.test_helpers.fake import FakePropertyFactory, FakePropertyViewFactory, FakeTaxLotFactory, FakeTaxLotViewFactory +from seed.tests.util import AccessLevelBaseTestCase, FakeRequest from seed.utils.organizations import create_organization from seed.utils.users import get_js_role, get_role_from_js from seed.views.main import _get_default_org @@ -873,6 +874,69 @@ def test_create_sub_org(self): self.assertTrue(Organization.objects.filter(name="test").exists()) +class AccountsViewAHTests(AccessLevelBaseTestCase): + def setUp(self): + super().setUp() + self.property_factory = FakePropertyFactory(organization=self.org) + self.taxlot_factory = FakeTaxLotFactory(organization=self.org) + self.property_view_factory = FakePropertyViewFactory(organization=self.org) + self.taxlot_view_factory = FakeTaxLotViewFactory(organization=self.org) + + self.child_viewer_user_details = {"username": "child_viewer@demo.com", "password": "test_pass"} + self.child_viewer_user = User.objects.create_user(**self.child_viewer_user_details) + self.org.add_member(self.child_viewer_user, self.child_level_instance.pk, ROLE_VIEWER) + self.org.save() + + self.cycle = self.org.cycles.first() + # create 5 properties and 3 taxlots for both users + for i in range(5): + self.property_view_factory.get_property_view(organization=self.org, cycle=self.cycle, user=self.root_owner_user) + if i < 3: + self.taxlot_view_factory.get_taxlot_view(organization=self.org, cycle=self.cycle, user=self.root_owner_user) + + for i in range(5): + prprty = self.property_factory.get_property(organization=self.org, access_level_instance=self.child_level_instance) + taxlot = self.taxlot_factory.get_taxlot(organization=self.org, access_level_instance=self.child_level_instance) + self.property_view_factory.get_property_view(organization=self.org, cycle=self.cycle, prprty=prprty) + if i < 3: + self.taxlot_view_factory.get_taxlot_view(organization=self.org, cycle=self.cycle, taxlot=taxlot) + + def test_org_data_permissions(self): + """ + Org data for non owners: + - does not include organization owners list + - number of properties/taxlots include only those the user has ALI access to + """ + self.login_as_root_owner() + response = self.client.get(reverse_lazy("api:v3:organizations-list")) + data = response.json()["organizations"][0] + + self.assertEqual(len(data["owners"]), 2) + cycle_data = data["cycles"][0] + self.assertEqual(cycle_data["num_properties"], 10) + self.assertEqual(cycle_data["num_taxlots"], 6) + + # member can see owners, child sees limited properties/taxlots + self.login_as_child_member() + response = self.client.get(reverse_lazy("api:v3:organizations-list")) + + data = response.json()["organizations"][0] + self.assertEqual(len(data["owners"]), 2) + cycle_data = data["cycles"][0] + self.assertEqual(cycle_data["num_properties"], 5) + self.assertEqual(cycle_data["num_taxlots"], 3) + + # viewer cannot see owners + self.client.login(**self.child_viewer_user_details) + response = self.client.get(reverse_lazy("api:v3:organizations-list")) + + data = response.json()["organizations"][0] + self.assertEqual(len(data["owners"]), 0) + cycle_data = data["cycles"][0] + self.assertEqual(cycle_data["num_properties"], 5) + self.assertEqual(cycle_data["num_taxlots"], 3) + + class AuthViewTests(TestCase): def setUp(self): user_details = { diff --git a/seed/views/v3/organizations.py b/seed/views/v3/organizations.py index 0737a5929b..d07b39bd4a 100644 --- a/seed/views/v3/organizations.py +++ b/seed/views/v3/organizations.py @@ -88,18 +88,6 @@ def _dict_org(request, organizations): orgs = [] for o in organizations: - org_cycles = Cycle.objects.filter(organization=o).only("id", "name").order_by("name") - cycles = [] - for c in org_cycles: - cycles.append( - { - "name": c.name, - "cycle_id": c.pk, - "num_properties": PropertyView.objects.filter(cycle=c).count(), - "num_taxlots": TaxLotView.objects.filter(cycle=c).count(), - } - ) - # We don't wish to double count sub organization memberships. org_users = ( OrganizationUser.objects.select_related("user") @@ -110,15 +98,39 @@ def _dict_org(request, organizations): owners = [] role_level = None user_is_owner = False + ali = None for ou in org_users: - if ou.role_level == ROLE_OWNER: + owner = ou.role_level == ROLE_OWNER + viewer = ou.role_level == ROLE_VIEWER + if owner: owners.append({"first_name": ou.user.first_name, "last_name": ou.user.last_name, "email": ou.user.email, "id": ou.user.id}) - if ou.user == request.user: - user_is_owner = True - if ou.user == request.user: + user_is_owner = owner + user_is_viewer = viewer role_level = get_js_role(ou.role_level) + ali = ou.access_level_instance + + cycles = [] + if ali: + org_cycles = Cycle.objects.filter(organization=o).only("id", "name").order_by("name") + for c in org_cycles: + cycles.append( + { + "name": c.name, + "cycle_id": c.pk, + "num_properties": PropertyView.objects.filter( + cycle=c, + property__access_level_instance__lft__gte=ali.lft, + property__access_level_instance__rgt__lte=ali.rgt, + ).count(), + "num_taxlots": TaxLotView.objects.filter( + cycle=c, + taxlot__access_level_instance__lft__gte=ali.lft, + taxlot__access_level_instance__rgt__lte=ali.rgt, + ).count(), + } + ) org = { "name": o.name, @@ -127,7 +139,7 @@ def _dict_org(request, organizations): "number_of_users": len(org_users), "user_is_owner": user_is_owner, "user_role": role_level, - "owners": owners, + "owners": [] if user_is_viewer else owners, "sub_orgs": _dict_org(request, o.child_orgs.all()), "is_parent": o.is_parent, "parent_id": o.parent_id,