diff --git a/gregor_django/gregor_anvil/tables.py b/gregor_django/gregor_anvil/tables.py index 68fcc008..5461e75f 100644 --- a/gregor_django/gregor_anvil/tables.py +++ b/gregor_django/gregor_anvil/tables.py @@ -1,6 +1,6 @@ import django_tables2 as tables from anvil_consortium_manager.adapters.workspace import workspace_adapter_registry -from anvil_consortium_manager.models import Account, Workspace +from anvil_consortium_manager.models import Account, ManagedGroup, Workspace from django.utils.html import format_html from . import models @@ -80,20 +80,26 @@ def render_cycle(self, record): return str(record) -class WorkspaceSharedWithConsortiumTable(tables.Table): +class WorkspaceConsortiumAccessTable(tables.Table): """Table including a column to indicate if a workspace is shared with PRIMED_ALL.""" - is_shared = tables.columns.Column( + consortium_access = tables.columns.Column( accessor="pk", - verbose_name="Shared with GREGoR?", + verbose_name="Consortium access?", orderable=False, ) - def render_is_shared(self, record): - is_shared = record.workspacegroupsharing_set.filter( - group__name="GREGOR_ALL" - ).exists() - if is_shared: + def render_consortium_access(self, record): + try: + group = ManagedGroup.objects.get(name="GREGOR_ALL") + except ManagedGroup.DoesNotExist: + has_consortium_access = False + else: + has_consortium_access = record.is_in_authorization_domain( + group + ) and record.is_shared(group) + + if has_consortium_access: icon = "check-circle-fill" color = "green" value = format_html( @@ -104,7 +110,7 @@ def render_is_shared(self, record): return value -class DefaultWorkspaceTable(WorkspaceSharedWithConsortiumTable, tables.Table): +class DefaultWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table): """Class to use for default workspace tables in GREGoR.""" name = tables.Column(linkify=True, verbose_name="Workspace") @@ -122,12 +128,12 @@ class Meta: "name", "billing_project", "number_groups", - "is_shared", + "consortium_access", ) order_by = ("name",) -class UploadWorkspaceTable(WorkspaceSharedWithConsortiumTable, tables.Table): +class UploadWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table): """A table for Workspaces that includes fields from UploadWorkspace.""" name = tables.columns.Column(linkify=True) @@ -140,11 +146,11 @@ class Meta: "uploadworkspace__upload_cycle", "uploadworkspace__research_center", "uploadworkspace__consent_group", - "is_shared", + "consortium_access", ) -class TemplateWorkspaceTable(WorkspaceSharedWithConsortiumTable, tables.Table): +class TemplateWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table): """A table for Workspaces that includes fields from TemplateWorkspace.""" name = tables.columns.Column(linkify=True) @@ -154,7 +160,7 @@ class Meta: fields = ( "name", "templateworkspace__intended_use", - "is_shared", + "consortium_access", ) @@ -177,7 +183,7 @@ def render_workspace_type(self, value): class CombinedConsortiumDataWorkspaceTable( - WorkspaceSharedWithConsortiumTable, tables.Table + WorkspaceConsortiumAccessTable, tables.Table ): """A table for Workspaces that includes fields from CombinedConsortiumDataWorkspace.""" @@ -224,7 +230,7 @@ class Meta: ) -class DCCProcessedDataWorkspaceTable(WorkspaceSharedWithConsortiumTable, tables.Table): +class DCCProcessedDataWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table): """A table for Workspaces that includes fields from DCCProcessedDataWorkspace.""" name = tables.columns.Column(linkify=True) @@ -236,5 +242,5 @@ class Meta: "name", "dccprocesseddataworkspace__upload_cycle", "dccprocesseddataworkspace__consent_group", - "is_shared", + "consortium_access", ) diff --git a/gregor_django/gregor_anvil/tests/test_tables.py b/gregor_django/gregor_anvil/tests/test_tables.py index 1608908a..64b38ccb 100644 --- a/gregor_django/gregor_anvil/tests/test_tables.py +++ b/gregor_django/gregor_anvil/tests/test_tables.py @@ -2,6 +2,11 @@ from anvil_consortium_manager.tests.factories import ( AccountFactory, GroupAccountMembershipFactory, + GroupGroupMembershipFactory, + ManagedGroupFactory, + WorkspaceAuthorizationDomainFactory, + WorkspaceFactory, + WorkspaceGroupSharingFactory, ) from django.db.models import Count, Q from django.test import TestCase @@ -112,6 +117,114 @@ def test_row_count_with_two_objects(self): self.assertEqual(len(table.rows), 2) +class WorkspaceConsortiumAccessTableTest(TestCase): + """Tests for the is_shared column.""" + + def setUp(self): + self.gregor_all = ManagedGroupFactory.create(name="GREGOR_ALL") + + def test_is_shared_no_auth_domain_not_shared(self): + """Workspace has no auth domain and is not shared with GREGOR_ALL.""" + workspace = WorkspaceFactory.create() + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_no_auth_domain_shared(self): + """Workspace has no auth domain and is shared with GREGOR_ALL.""" + workspace = WorkspaceFactory.create() + WorkspaceGroupSharingFactory.create(workspace=workspace, group=self.gregor_all) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_no_auth_domain_shared_other_group(self): + """Workspace has no auth domain and is shared with a different group.""" + workspace = WorkspaceFactory.create() + WorkspaceGroupSharingFactory.create(workspace=workspace) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_not_shared_not_in_auth_domain(self): + """GREGOR_ALL is not in auth domain and workspace is not shared.""" + workspace = WorkspaceFactory.create() + WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_not_shared_in_auth_domain(self): + """GREGOR_ALL is in auth domain and workspace is not shared.""" + workspace = WorkspaceFactory.create() + auth_domain = WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + GroupGroupMembershipFactory.create( + parent_group=auth_domain.group, child_group=self.gregor_all + ) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_shared_different_group_in_auth_domain(self): + """GREGOR_ALL is in auth domain and workspace is shared with a different group.""" + workspace = WorkspaceFactory.create() + auth_domain = WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + GroupGroupMembershipFactory.create( + parent_group=auth_domain.group, child_group=self.gregor_all + ) + WorkspaceGroupSharingFactory.create(workspace=workspace) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_shared_with_gregor_all_not_in_auth_domain(self): + """GREGOR_ALL is not in auth domain and workspace is shared with GREGOR_ALL.""" + workspace = WorkspaceFactory.create() + WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + WorkspaceGroupSharingFactory.create(workspace=workspace, group=self.gregor_all) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_shared_with_auth_domain_not_in_auth_domain(self): + """GREGOR_ALL is not in auth domain and workspace is shared with its auth domain.""" + workspace = WorkspaceFactory.create() + auth_domain = WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + WorkspaceGroupSharingFactory.create( + workspace=workspace, group=auth_domain.group + ) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_shared_with_gregor_all_in_auth_domain(self): + """GREGOR_ALL is in auth domain and workspace is shared with GREGOR_ALL.""" + workspace = WorkspaceFactory.create() + auth_domain = WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + GroupGroupMembershipFactory.create( + parent_group=auth_domain.group, child_group=self.gregor_all + ) + WorkspaceGroupSharingFactory.create(workspace=workspace, group=self.gregor_all) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_shared_with_auth_domain_in_auth_domain(self): + """GREGOR_ALL is in auth domain and workspace is shared with its auth domain.""" + workspace = WorkspaceFactory.create() + auth_domain = WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + GroupGroupMembershipFactory.create( + parent_group=auth_domain.group, child_group=self.gregor_all + ) + WorkspaceGroupSharingFactory.create( + workspace=workspace, group=auth_domain.group + ) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertIn("check-circle-fill", table.render_consortium_access(workspace)) + + def test_is_shared_one_auth_domain_shared_with_different_group_in_auth_domain(self): + """GREGOR_ALL is in auth domain and workspace is shared with a different group.""" + workspace = WorkspaceFactory.create() + auth_domain = WorkspaceAuthorizationDomainFactory.create(workspace=workspace) + GroupGroupMembershipFactory.create( + parent_group=auth_domain.group, child_group=self.gregor_all + ) + WorkspaceGroupSharingFactory.create(workspace=workspace) + table = tables.WorkspaceConsortiumAccessTable(Workspace.objects.all()) + self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace)) + + class UploadWorkspaceTableTest(TestCase): model = Workspace model_factory = factories.UploadWorkspaceFactory