From 276df7ab062e2dc92d2760da915c36748ab51b1c Mon Sep 17 00:00:00 2001 From: Adrienne Stilp Date: Tue, 28 Feb 2023 10:23:38 -0800 Subject: [PATCH 1/3] Show combined accession in dbGaPWorkspaceTable The dbGaPWorkspace table had separate columns for the phs, the version, and the participant set. Combine them into one column showing the accession string. Also show the full workspace and billing project name instead of just the workspace name. --- primed/dbgap/tables.py | 33 +++++++++++++++++++------------ primed/dbgap/tests/test_tables.py | 24 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/primed/dbgap/tables.py b/primed/dbgap/tables.py index 522388bd..cd1604f1 100644 --- a/primed/dbgap/tables.py +++ b/primed/dbgap/tables.py @@ -33,24 +33,31 @@ def render_dbgap_phs(self, value): class dbGaPWorkspaceTable(tables.Table): """Class to render a table of Workspace objects with dbGaPWorkspace workspace data.""" - name = tables.columns.Column(linkify=True) - - class Meta: - model = Workspace - fields = ( - "name", - "dbgapworkspace__dbgap_study_accession__studies", + workspace = tables.columns.Column( + linkify=True, accessor="pk", order_by=("billing_project__name", "name") + ) + dbgap_accession = tables.columns.Column( + verbose_name="dbGaP accession", + accessor="pk", + order_by=( "dbgapworkspace__dbgap_study_accession__dbgap_phs", "dbgapworkspace__dbgap_version", "dbgapworkspace__dbgap_participant_set", - "dbgapworkspace__dbgap_consent_abbreviation", - ) + ), + ) + dbgapworkspace__dbgap_consent_abbreviation = tables.columns.Column( + verbose_name="Consent" + ) - def render_dbgapworkspace__dbgap_phs(self, value): - return "phs{0:06d}".format(value) + class Meta: + model = Workspace + fields = () + + def render_workspace(self, record): + return str(record) - def render_dbgapworkspace__version(self, value): - return "v{}".format(value) + def render_dbgap_accession(self, record): + return record.dbgapworkspace.get_dbgap_accession() class ManyToManyDateTimeColumn(tables.columns.ManyToManyColumn): diff --git a/primed/dbgap/tests/test_tables.py b/primed/dbgap/tests/test_tables.py index 7c656327..31531d57 100644 --- a/primed/dbgap/tests/test_tables.py +++ b/primed/dbgap/tests/test_tables.py @@ -70,6 +70,30 @@ def test_row_count_with_two_objects(self): table = self.table_class(self.model.objects.all()) self.assertEqual(len(table.rows), 2) + def test_render_workspace(self): + """render_workspace returns the correct value.""" + instance = self.model_factory.create( + workspace__billing_project__name="bp", workspace__name="ws" + ) + table = self.table_class(self.model.objects.all()) + self.assertEqual(table.render_workspace(instance.workspace), "bp/ws") + self.assertEqual(table.rows[0].get_cell_value("workspace"), "bp/ws") + + def test_render_dbgap_accession(self): + """render_workspace returns the correct value.""" + instance = self.model_factory.create( + dbgap_study_accession__dbgap_phs=1, + dbgap_version=2, + dbgap_participant_set=3, + ) + table = self.table_class(self.model.objects.all()) + self.assertEqual( + table.render_dbgap_accession(instance.workspace), "phs000001.v2.p3" + ) + self.assertEqual( + table.rows[0].get_cell_value("dbgap_accession"), "phs000001.v2.p3" + ) + class dbGaPApplicationTableTest(TestCase): model = models.dbGaPApplication From 896386151d03b61d2ad0f442bb5e53b34eecc0f0 Mon Sep 17 00:00:00 2001 From: Adrienne Stilp Date: Tue, 28 Feb 2023 11:02:00 -0800 Subject: [PATCH 2/3] Add the number of approved DARs to the dbGaPWorkspace table --- primed/dbgap/tables.py | 13 ++++++++++ primed/dbgap/tests/test_tables.py | 41 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/primed/dbgap/tables.py b/primed/dbgap/tables.py index cd1604f1..739c2f7d 100644 --- a/primed/dbgap/tables.py +++ b/primed/dbgap/tables.py @@ -48,6 +48,11 @@ class dbGaPWorkspaceTable(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, + ) class Meta: model = Workspace @@ -59,6 +64,14 @@ def render_workspace(self, record): def render_dbgap_accession(self, record): return record.dbgapworkspace.get_dbgap_accession() + 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 ManyToManyDateTimeColumn(tables.columns.ManyToManyColumn): """A django-tables2 column to render a many-to-many date time column using human-readable date time formatting.""" diff --git a/primed/dbgap/tests/test_tables.py b/primed/dbgap/tests/test_tables.py index 31531d57..9458b432 100644 --- a/primed/dbgap/tests/test_tables.py +++ b/primed/dbgap/tests/test_tables.py @@ -94,6 +94,47 @@ def test_render_dbgap_accession(self): table.rows[0].get_cell_value("dbgap_accession"), "phs000001.v2.p3" ) + def test_render_number_approved_dars_no_dars(self): + instance = self.model_factory.create() + table = self.table_class(self.model.objects.all()) + self.assertEqual(table.render_number_approved_dars(instance.workspace), 0) + + def test_render_number_approved_dars_one_dar(self): + instance = self.model_factory.create() + factories.dbGaPDataAccessRequestForWorkspaceFactory(dbgap_workspace=instance) + table = self.table_class(self.model.objects.all()) + self.assertEqual(table.render_number_approved_dars(instance.workspace), 1) + + def test_render_number_approved_dars_one_dar_does_not_match(self): + instance = self.model_factory.create() + factories.dbGaPDataAccessRequestFactory() + table = self.table_class(self.model.objects.all()) + self.assertEqual(table.render_number_approved_dars(instance.workspace), 0) + + def test_render_number_approved_dars_two_dars(self): + instance = self.model_factory.create() + factories.dbGaPDataAccessRequestForWorkspaceFactory(dbgap_workspace=instance) + factories.dbGaPDataAccessRequestForWorkspaceFactory(dbgap_workspace=instance) + table = self.table_class(self.model.objects.all()) + self.assertEqual(table.render_number_approved_dars(instance.workspace), 2) + + def test_render_number_approved_dars_not_approved(self): + instance = self.model_factory.create() + factories.dbGaPDataAccessRequestForWorkspaceFactory( + dbgap_workspace=instance, + dbgap_current_status=models.dbGaPDataAccessRequest.REJECTED, + ) + table = self.table_class(self.model.objects.all()) + self.assertEqual(table.render_number_approved_dars(instance.workspace), 0) + + def test_render_number_approved_dars_only_most_recent(self): + instance = self.model_factory.create() + factories.dbGaPDataAccessRequestForWorkspaceFactory( + dbgap_workspace=instance, dbgap_data_access_snapshot__is_most_recent=False + ) + table = self.table_class(self.model.objects.all()) + self.assertEqual(table.render_number_approved_dars(instance.workspace), 0) + class dbGaPApplicationTableTest(TestCase): model = models.dbGaPApplication From eb6fbd33d735222ebfdec2eb30acceedce2fc675 Mon Sep 17 00:00:00 2001 From: Adrienne Stilp Date: Tue, 28 Feb 2023 15:17:35 -0800 Subject: [PATCH 3/3] Add a table column indicating if the workspace is shared with PRIMED_ALL --- primed/dbgap/tables.py | 19 +++++++++++++++++++ primed/dbgap/tests/test_tables.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/primed/dbgap/tables.py b/primed/dbgap/tables.py index 739c2f7d..84cd7687 100644 --- a/primed/dbgap/tables.py +++ b/primed/dbgap/tables.py @@ -53,6 +53,11 @@ class dbGaPWorkspaceTable(tables.Table): verbose_name="Approved DARs", orderable=False, ) + is_shared = tables.columns.Column( + accessor="pk", + verbose_name="Shared with PRIMED?", + orderable=False, + ) class Meta: model = Workspace @@ -72,6 +77,20 @@ def render_number_approved_dars(self, record): ) return n + def render_is_shared(self, record): + is_shared = record.workspacegroupsharing_set.filter( + group__name="PRIMED_ALL" + ).exists() + if is_shared: + icon = "check-circle-fill" + color = "green" + value = format_html( + """""".format(icon, color) + ) + else: + value = "" + return value + class ManyToManyDateTimeColumn(tables.columns.ManyToManyColumn): """A django-tables2 column to render a many-to-many date time column using human-readable date time formatting.""" diff --git a/primed/dbgap/tests/test_tables.py b/primed/dbgap/tests/test_tables.py index 9458b432..ba39ad9d 100644 --- a/primed/dbgap/tests/test_tables.py +++ b/primed/dbgap/tests/test_tables.py @@ -135,6 +135,34 @@ def test_render_number_approved_dars_only_most_recent(self): table = self.table_class(self.model.objects.all()) self.assertEqual(table.render_number_approved_dars(instance.workspace), 0) + def test_render_is_shared_not_shared(self): + """render_is_shared works correctly when the workspace is not shared with anyone.""" + factories.ManagedGroupFactory.create(name="PRIMED_ALL") + factories.dbGaPWorkspaceFactory.create() + table = self.table_class(self.model.objects.all()) + self.assertEqual("", table.rows[0].get_cell_value("is_shared")) + + def test_render_is_shared_true(self): + """render_is_shared works correctly when the workspace is shared with PRIMED_ALL.""" + group = factories.ManagedGroupFactory.create(name="PRIMED_ALL") + dbgap_workspace = factories.dbGaPWorkspaceFactory.create() + WorkspaceGroupSharingFactory.create( + group=group, workspace=dbgap_workspace.workspace + ) + table = self.table_class(self.model.objects.all()) + self.assertIn("circle-fill", table.rows[0].get_cell_value("is_shared")) + + def test_render_is_shared_shared_with_different_group(self): + """render_is_shared works correctly when the workspace is shared with a group other PRIMED_ALL.""" + factories.ManagedGroupFactory.create(name="PRIMED_ALL") + group = factories.ManagedGroupFactory.create() + dbgap_workspace = factories.dbGaPWorkspaceFactory.create() + WorkspaceGroupSharingFactory.create( + group=group, workspace=dbgap_workspace.workspace + ) + table = self.table_class(self.model.objects.all()) + self.assertEqual("", table.rows[0].get_cell_value("is_shared")) + class dbGaPApplicationTableTest(TestCase): model = models.dbGaPApplication