diff --git a/primed/cdsa/adapters.py b/primed/cdsa/adapters.py index b32edc11..a4767906 100644 --- a/primed/cdsa/adapters.py +++ b/primed/cdsa/adapters.py @@ -2,7 +2,7 @@ from anvil_consortium_manager.forms import WorkspaceForm from anvil_consortium_manager.models import Workspace -from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable +from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceUserTable from . import forms, models, tables @@ -27,7 +27,7 @@ def get_extra_detail_context_data(self, workspace, request): associated_data_prep = Workspace.objects.filter( dataprepworkspace__target_workspace=workspace ) - extra_context["associated_data_prep_workspaces"] = DataPrepWorkspaceTable( + extra_context["associated_data_prep_workspaces"] = DataPrepWorkspaceUserTable( associated_data_prep ) extra_context["data_prep_active"] = associated_data_prep.filter( diff --git a/primed/cdsa/tables.py b/primed/cdsa/tables.py index 4fd93ce1..f39d6988 100644 --- a/primed/cdsa/tables.py +++ b/primed/cdsa/tables.py @@ -299,11 +299,10 @@ def render_date_shared(self, record): return "—" -class CDSAWorkspaceStaffTable(tables.Table): +class CDSAWorkspaceUserTable(tables.Table): """A table for the CDSAWorkspace model.""" name = tables.Column(linkify=True) - billing_project = tables.Column(linkify=True) cdsaworkspace__data_use_permission__abbreviation = tables.Column( verbose_name="DUO permission", linkify=lambda record: record.cdsaworkspace.data_use_permission.get_absolute_url(), @@ -329,7 +328,6 @@ class Meta: model = Workspace fields = ( "name", - "billing_project", "cdsaworkspace__study", "cdsaworkspace__data_use_permission__abbreviation", "cdsaworkspace__data_use_modifiers", @@ -351,27 +349,10 @@ def render_cdsaworkspace__requires_study_review(self, record): return mark_safe(f'') -class CDSAWorkspaceUserTable(tables.Table): +class CDSAWorkspaceStaffTable(CDSAWorkspaceUserTable): """A table for the CDSAWorkspace model.""" - name = tables.Column(linkify=True) - billing_project = tables.Column() - cdsaworkspace__data_use_permission__abbreviation = tables.Column( - verbose_name="DUO permission", - ) - cdsaworkspace__study = tables.Column() - cdsaworkspace__data_use_modifiers = tables.ManyToManyColumn( - transform=lambda x: x.abbreviation, - verbose_name="DUO modifiers", - ) - cdsaworkspace__requires_study_review = BooleanIconColumn( - verbose_name="Study review required?", - orderable=False, - true_icon="dash-circle-fill", - true_color="#ffc107", - ) - cdsaworkspace__gsr_restricted = BooleanIconColumn(orderable=False) - is_shared = WorkspaceSharedWithConsortiumColumn() + billing_project = tables.Column(linkify=True) class Meta: model = Workspace @@ -385,15 +366,3 @@ class Meta: "cdsaworkspace__gsr_restricted", ) order_by = ("name",) - - def render_cdsaworkspace__requires_study_review(self, record): - try: - if record.cdsaworkspace.get_primary_cdsa().requires_study_review: - icon = "dash-circle-fill" - color = "#ffc107" - else: - return "" - except models.DataAffiliateAgreement.DoesNotExist: - icon = "question-circle-fill" - color = "red" - return mark_safe(f'') diff --git a/primed/cdsa/tests/test_views.py b/primed/cdsa/tests/test_views.py index beb8e4e8..ab203d0a 100644 --- a/primed/cdsa/tests/test_views.py +++ b/primed/cdsa/tests/test_views.py @@ -30,7 +30,7 @@ from freezegun import freeze_time from primed.duo.tests.factories import DataUseModifierFactory, DataUsePermissionFactory -from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable +from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceUserTable from primed.miscellaneous_workspaces.tests.factories import DataPrepWorkspaceFactory from primed.primed_anvil.tests.factories import ( AvailableDataFactory, @@ -7436,6 +7436,29 @@ def test_render_duo_modifiers(self): self.assertContains(response, modifiers[0].abbreviation) self.assertContains(response, modifiers[1].abbreviation) + def test_associated_data_prep_view_user(self): + """View users do not see the associated data prep section""" + user = User.objects.create_user(username="test-view", password="test-view") + user.user_permissions.add( + Permission.objects.get( + codename=AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME + ) + ) + + obj = factories.CDSAWorkspaceFactory.create() + DataPrepWorkspaceFactory.create(target_workspace=obj.workspace) + self.client.force_login(user) + response = self.client.get(obj.get_absolute_url()) + self.assertNotContains(response, "Associated data prep workspaces") + + def test_associated_data_prep_staff_view_user(self): + """Staff view users do see the associated data prep section.""" + obj = factories.CDSAWorkspaceFactory.create() + DataPrepWorkspaceFactory.create(target_workspace=obj.workspace) + self.client.force_login(self.user) + response = self.client.get(obj.get_absolute_url()) + self.assertContains(response, "Associated data prep workspaces") + def test_associated_data_prep_workspaces_context_exists(self): obj = factories.CDSAWorkspaceFactory.create() self.client.force_login(self.user) @@ -7443,7 +7466,7 @@ def test_associated_data_prep_workspaces_context_exists(self): self.assertIn("associated_data_prep_workspaces", response.context_data) self.assertIsInstance( response.context_data["associated_data_prep_workspaces"], - DataPrepWorkspaceTable, + DataPrepWorkspaceUserTable, ) def test_only_show_one_associated_data_prep_workspace(self): diff --git a/primed/collaborative_analysis/tables.py b/primed/collaborative_analysis/tables.py index a17c5cb1..dfaeddb7 100644 --- a/primed/collaborative_analysis/tables.py +++ b/primed/collaborative_analysis/tables.py @@ -2,12 +2,10 @@ from anvil_consortium_manager.models import Workspace -class CollaborativeAnalysisWorkspaceStaffTable(tables.Table): +class CollaborativeAnalysisWorkspaceUserTable(tables.Table): """Class to render a table of Workspace objects with CollaborativeAnalysisWorkspace data.""" name = tables.columns.Column(linkify=True) - billing_project = tables.Column(linkify=True) - collaborativeanalysisworkspace__custodian = tables.Column(linkify=True) number_source_workspaces = tables.columns.Column( accessor="pk", verbose_name="Number of source workspaces", @@ -18,7 +16,6 @@ class Meta: model = Workspace fields = ( "name", - "billing_project", "collaborativeanalysisworkspace__custodian", "number_source_workspaces", ) @@ -29,16 +26,12 @@ def render_number_source_workspaces(self, record): return record.collaborativeanalysisworkspace.source_workspaces.count() -class CollaborativeAnalysisWorkspaceUserTable(tables.Table): +class CollaborativeAnalysisWorkspaceStaffTable(CollaborativeAnalysisWorkspaceUserTable): """Class to render a table of Workspace objects with CollaborativeAnalysisWorkspace data.""" name = tables.columns.Column(linkify=True) - billing_project = tables.Column() - number_source_workspaces = tables.columns.Column( - accessor="pk", - verbose_name="Number of source workspaces", - orderable=False, - ) + billing_project = tables.Column(linkify=True) + collaborativeanalysisworkspace__custodian = tables.Column(linkify=True) class Meta: model = Workspace @@ -49,7 +42,3 @@ class Meta: "number_source_workspaces", ) order_by = ("name",) - - def render_number_source_workspaces(self, record): - """Render the number of source workspaces.""" - return record.collaborativeanalysisworkspace.source_workspaces.count() diff --git a/primed/dbgap/adapters.py b/primed/dbgap/adapters.py index 626a3c10..a2ed57a9 100644 --- a/primed/dbgap/adapters.py +++ b/primed/dbgap/adapters.py @@ -2,7 +2,7 @@ from anvil_consortium_manager.forms import WorkspaceForm from anvil_consortium_manager.models import Workspace -from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable +from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceUserTable from . import forms, models, tables @@ -25,7 +25,7 @@ def get_extra_detail_context_data(self, workspace, request): associated_data_prep = Workspace.objects.filter( dataprepworkspace__target_workspace=workspace ) - extra_context["associated_data_prep_workspaces"] = DataPrepWorkspaceTable( + extra_context["associated_data_prep_workspaces"] = DataPrepWorkspaceUserTable( associated_data_prep ) extra_context["data_prep_active"] = associated_data_prep.filter( diff --git a/primed/dbgap/tables.py b/primed/dbgap/tables.py index 08443706..fa22c5b1 100644 --- a/primed/dbgap/tables.py +++ b/primed/dbgap/tables.py @@ -74,11 +74,10 @@ def render_dbgap_phs(self, value): return "phs{0:06d}".format(value) -class dbGaPWorkspaceStaffTable(tables.Table): +class dbGaPWorkspaceUserTable(tables.Table): """Class to render a table of Workspace objects with dbGaPWorkspace workspace data.""" name = tables.columns.Column(linkify=True) - billing_project = tables.Column(linkify=True) dbgap_accession = dbGaPAccessionColumn( accessor="dbgapworkspace__get_dbgap_accession", dbgap_link_accessor="dbgapworkspace__get_dbgap_link", @@ -91,11 +90,6 @@ class dbGaPWorkspaceStaffTable(tables.Table): dbgapworkspace__dbgap_consent_abbreviation = tables.columns.Column( verbose_name="Consent" ) - number_approved_dars = tables.columns.Column( - accessor="pk", - verbose_name="Approved DARs", - orderable=False, - ) dbgapworkspace__gsr_restricted = BooleanIconColumn( orderable=False, true_icon="dash-circle-fill", true_color="#ffc107" ) @@ -105,43 +99,23 @@ class Meta: model = Workspace fields = ( "name", - "billing_project", "dbgap_accession", "dbgapworkspace__dbgap_consent_abbreviation", - "number_approved_dars", "dbgapworkspace__gsr_restricted", "is_shared", ) order_by = ("name",) - def render_number_approved_dars(self, record): - n = ( - record.dbgapworkspace.get_data_access_requests(most_recent=True) - .filter(dbgap_current_status=models.dbGaPDataAccessRequest.APPROVED) - .count() - ) - return n - -class dbGaPWorkspaceUserTable(tables.Table): +class dbGaPWorkspaceStaffTable(dbGaPWorkspaceUserTable): """Class to render a table of Workspace objects with dbGaPWorkspace workspace data.""" - name = tables.columns.Column(linkify=True) - billing_project = tables.Column() - dbgap_accession = dbGaPAccessionColumn( - accessor="dbgapworkspace__get_dbgap_accession", - dbgap_link_accessor="dbgapworkspace__get_dbgap_link", - order_by=( - "dbgapworkspace__dbgap_study_accession__dbgap_phs", - "dbgapworkspace__dbgap_version", - "dbgapworkspace__dbgap_participant_set", - ), - ) - dbgapworkspace__dbgap_consent_abbreviation = tables.columns.Column( - verbose_name="Consent" + billing_project = tables.Column(linkify=True) + number_approved_dars = tables.columns.Column( + accessor="pk", + verbose_name="Approved DARs", + orderable=False, ) - dbgapworkspace__gsr_restricted = BooleanIconColumn(orderable=False) - is_shared = WorkspaceSharedWithConsortiumColumn() class Meta: model = Workspace @@ -150,11 +124,20 @@ class Meta: "billing_project", "dbgap_accession", "dbgapworkspace__dbgap_consent_abbreviation", + "number_approved_dars", "dbgapworkspace__gsr_restricted", "is_shared", ) order_by = ("name",) + def render_number_approved_dars(self, record): + n = ( + record.dbgapworkspace.get_data_access_requests(most_recent=True) + .filter(dbgap_current_status=models.dbGaPDataAccessRequest.APPROVED) + .count() + ) + return n + class dbGaPApplicationTable(tables.Table): """Class to render a table of dbGaPApplication objects.""" diff --git a/primed/dbgap/tests/test_views.py b/primed/dbgap/tests/test_views.py index c33fb131..a2ebf614 100644 --- a/primed/dbgap/tests/test_views.py +++ b/primed/dbgap/tests/test_views.py @@ -32,7 +32,7 @@ from freezegun import freeze_time from primed.duo.tests.factories import DataUseModifierFactory, DataUsePermissionFactory -from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable +from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceUserTable from primed.miscellaneous_workspaces.tests.factories import DataPrepWorkspaceFactory from primed.primed_anvil.tests.factories import ( # DataUseModifierFactory,; DataUsePermissionFactory, StudyFactory, @@ -953,6 +953,29 @@ def test_links_audit_access_view_permission(self): ), ) + def test_associated_data_prep_view_user(self): + """View users do not see the associated data prep section""" + user = User.objects.create_user(username="test-view", password="test-view") + user.user_permissions.add( + Permission.objects.get( + codename=AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME + ) + ) + + obj = factories.dbGaPWorkspaceFactory.create() + DataPrepWorkspaceFactory.create(target_workspace=obj.workspace) + self.client.force_login(user) + response = self.client.get(obj.get_absolute_url()) + self.assertNotContains(response, "Associated data prep workspaces") + + def test_associated_data_prep_staff_view_user(self): + """Staff view users do see the associated data prep section.""" + obj = factories.dbGaPWorkspaceFactory.create() + DataPrepWorkspaceFactory.create(target_workspace=obj.workspace) + self.client.force_login(self.user) + response = self.client.get(obj.get_absolute_url()) + self.assertContains(response, "Associated data prep workspaces") + def test_associated_data_prep_workspaces_context_exists(self): obj = factories.dbGaPWorkspaceFactory.create() self.client.force_login(self.user) @@ -960,7 +983,7 @@ def test_associated_data_prep_workspaces_context_exists(self): self.assertIn("associated_data_prep_workspaces", response.context_data) self.assertIsInstance( response.context_data["associated_data_prep_workspaces"], - DataPrepWorkspaceTable, + DataPrepWorkspaceUserTable, ) def test_only_show_one_associated_data_prep_workspace(self): diff --git a/primed/miscellaneous_workspaces/adapters.py b/primed/miscellaneous_workspaces/adapters.py index 24262017..17bdfb9b 100644 --- a/primed/miscellaneous_workspaces/adapters.py +++ b/primed/miscellaneous_workspaces/adapters.py @@ -93,8 +93,8 @@ class DataPrepWorkspaceAdapter(BaseWorkspaceAdapter): type = "data_prep" name = "Data prep workspace" description = "Workspaces used to prepare data for sharing or update data that is already shared" - list_table_class_staff_view = tables.DataPrepWorkspaceTable - list_table_class_view = tables.DataPrepWorkspaceTable + list_table_class_staff_view = tables.DataPrepWorkspaceStaffTable + list_table_class_view = tables.DataPrepWorkspaceUserTable workspace_form_class = WorkspaceForm workspace_data_model = models.DataPrepWorkspace workspace_data_form_class = forms.DataPrepWorkspaceForm diff --git a/primed/miscellaneous_workspaces/tables.py b/primed/miscellaneous_workspaces/tables.py index fd1132df..014f746c 100644 --- a/primed/miscellaneous_workspaces/tables.py +++ b/primed/miscellaneous_workspaces/tables.py @@ -9,30 +9,29 @@ ) -class OpenAccessWorkspaceStaffTable(tables.Table): +class OpenAccessWorkspaceUserTable(tables.Table): """Class to render a table of Workspace objects with OpenAccessWorkspace workspace data.""" name = tables.columns.Column(linkify=True) - billing_project = tables.Column(linkify=True) is_shared = WorkspaceSharedWithConsortiumColumn() + openaccessworkspace__studies = tables.ManyToManyColumn( + linkify_item=True, + ) class Meta: model = Workspace fields = ( "name", - "billing_project", "openaccessworkspace__studies", "is_shared", ) order_by = ("name",) -class OpenAccessWorkspaceUserTable(tables.Table): +class OpenAccessWorkspaceStaffTable(OpenAccessWorkspaceUserTable): """Class to render a table of Workspace objects with OpenAccessWorkspace workspace data.""" - name = tables.columns.Column(linkify=True) - billing_project = tables.Column() - is_shared = WorkspaceSharedWithConsortiumColumn() + billing_project = tables.Column(linkify=True) class Meta: model = Workspace @@ -45,11 +44,10 @@ class Meta: order_by = ("name",) -class DataPrepWorkspaceTable(tables.Table): +class DataPrepWorkspaceUserTable(tables.Table): """Class to render a table of Workspace objects with DataPrepWorkspace workspace data.""" name = tables.columns.Column(linkify=True) - # TODO: Figure out why this is not showing up dataprepworkspace__target_workspace__name = tables.columns.Column( linkify=True, verbose_name="Target workspace" ) @@ -65,3 +63,19 @@ class Meta: "dataprepworkspace__is_active", ) order_by = ("name",) + + +class DataPrepWorkspaceStaffTable(DataPrepWorkspaceUserTable): + """Class to render a table of Workspace objects with DataPrepWorkspace workspace data.""" + + billing_project = tables.columns.Column(linkify=True) + + class Meta: + model = Workspace + fields = ( + "name", + "billing_project", + "dataprepworkspace__target_workspace__name", + "dataprepworkspace__is_active", + ) + order_by = ("name",) diff --git a/primed/miscellaneous_workspaces/tests/test_tables.py b/primed/miscellaneous_workspaces/tests/test_tables.py index de536164..d6252a70 100644 --- a/primed/miscellaneous_workspaces/tests/test_tables.py +++ b/primed/miscellaneous_workspaces/tests/test_tables.py @@ -49,11 +49,32 @@ def test_row_count_with_two_objects(self): self.assertEqual(len(table.rows), 2) -class DataPrepWorkspaceTableTest(TestCase): - """Tests for the DataPrepWorkspaceTable table.""" +class DataPrepWorkspaceUserTableTest(TestCase): + """Tests for the DataPrepWorkspaceUserTable table.""" model_factory = factories.DataPrepWorkspaceFactory - table_class = tables.DataPrepWorkspaceTable + table_class = tables.DataPrepWorkspaceUserTable + + def test_row_count_with_no_objects(self): + table = self.table_class(Workspace.objects.filter(workspace_type="data_prep")) + self.assertEqual(len(table.rows), 0) + + def test_row_count_with_one_object(self): + self.model_factory.create() + table = self.table_class(Workspace.objects.filter(workspace_type="data_prep")) + self.assertEqual(len(table.rows), 1) + + def test_row_count_with_two_objects(self): + self.model_factory.create_batch(2) + table = self.table_class(Workspace.objects.filter(workspace_type="data_prep")) + self.assertEqual(len(table.rows), 2) + + +class DataPrepWorkspaceStaffTableTest(TestCase): + """Tests for the DataPrepWorkspaceUserTable table.""" + + model_factory = factories.DataPrepWorkspaceFactory + table_class = tables.DataPrepWorkspaceStaffTable def test_row_count_with_no_objects(self): table = self.table_class(Workspace.objects.filter(workspace_type="data_prep")) diff --git a/primed/primed_anvil/tables.py b/primed/primed_anvil/tables.py index 30048579..24534216 100644 --- a/primed/primed_anvil/tables.py +++ b/primed/primed_anvil/tables.py @@ -59,42 +59,38 @@ def _get_bool_value(self, record, value, bound_column): return is_shared -class DefaultWorkspaceStaffTable(tables.Table): +class DefaultWorkspaceUserTable(tables.Table): """Class to use for default workspace tables in PRIMED.""" name = tables.Column(linkify=True, verbose_name="Workspace") - billing_project = tables.Column(linkify=True) - number_groups = tables.Column( - verbose_name="Number of groups shared with", - empty_values=(), - orderable=False, - accessor="workspacegroupsharing_set__count", - ) is_shared = WorkspaceSharedWithConsortiumColumn() class Meta: model = Workspace fields = ( "name", - "billing_project", - "number_groups", "is_shared", ) order_by = ("name",) -class DefaultWorkspaceUserTable(tables.Table): +class DefaultWorkspaceStaffTable(DefaultWorkspaceUserTable): """Class to use for default workspace tables in PRIMED.""" - name = tables.Column(linkify=True, verbose_name="Workspace") - billing_project = tables.Column() - is_shared = WorkspaceSharedWithConsortiumColumn() + billing_project = tables.Column(linkify=True) + number_groups = tables.Column( + verbose_name="Number of groups shared with", + empty_values=(), + orderable=False, + accessor="workspacegroupsharing_set__count", + ) class Meta: model = Workspace fields = ( "name", "billing_project", + "number_groups", "is_shared", ) order_by = ("name",) diff --git a/primed/templates/snippets/data_prep_workspace_table.html b/primed/templates/snippets/data_prep_workspace_table.html index cb9c9b66..32d04cff 100644 --- a/primed/templates/snippets/data_prep_workspace_table.html +++ b/primed/templates/snippets/data_prep_workspace_table.html @@ -1,5 +1,7 @@ {% load render_table from django_tables2 %} +{% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %} +
@@ -18,3 +20,5 @@

+ +{% endif %}