Skip to content

Commit

Permalink
Merge pull request #634 from UW-GAC/main
Browse files Browse the repository at this point in the history
Deploy to stage
  • Loading branch information
amstilp authored Jul 1, 2024
2 parents 8e6d416 + ddecf59 commit 199063d
Show file tree
Hide file tree
Showing 19 changed files with 269 additions and 78 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ jobs:
backend: ["sqlite", "mariadb"]
mariadb-version: ["10.4"]
include:
- python-version: 3.12 # Possible future version.
- python-version: "3.10" # Future ubuntu 22.04 upgrade.
backend: "mariadb"
mariadb-version: "10.5"
mariadb-version: "10.6"
pip-recompile: true
- python-version: 3.12 # Possible future version.
- python-version: 3.12 # Future ubuntu 24.04.01 upgrade.
backend: "mariadb"
mariadb-version: "10.11"
pip-recompile: true
Expand Down
47 changes: 32 additions & 15 deletions add_cdsa_example_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,28 @@
dum = DataUseModifier.objects.get(abbreviation="NPU")

# Create some study sites.
StudySiteFactory.create(short_name="CC", full_name="Coordinating Center")
StudySiteFactory.create(short_name="CARDINAL", full_name="CARDINAL")
try:
cc = StudySite.objects.get(short_name="CC")
except StudySite.DoesNotExist:
cc = StudySiteFactory.create(short_name="CC", full_name="Coordinating Center")
try:
cardinal = StudySite.objects.get(short_name="CARDINAL")
except StudySite.DoesNotExist:
cardinal = StudySiteFactory.create(short_name="CARDINAL", full_name="CARDINAL")

# Create some studies.
StudyFactory.create(short_name="Amish", full_name="Amish")
StudyFactory.create(short_name="MESA", full_name="MESA")
try:
amish = Study.objects.get(short_name="Amish")
except Study.DoesNotExist:
amish = StudyFactory.create(short_name="Amish", full_name="Amish")
try:
mesa = Study.objects.get(short_name="MESA")
except Study.DoesNotExist:
mesa = StudyFactory.create(short_name="MESA", full_name="MESA")
try:
aric = Study.objects.get(short_name="ARIC")
except Study.DoesNotExist:
aric = Study.objects.create(short_name="ARIC", full_name="Atherosclerosis Risk in Communities")

# Create some CDSAs
cdsa_1001 = factories.MemberAgreementFactory.create(
Expand All @@ -51,7 +68,7 @@
signed_agreement__representative_role="Contact PI",
is_primary=True,
signed_agreement__version=v10,
study_site=StudySite.objects.get(short_name="CC"),
study_site=cc,
)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1001.signed_agreement.anvil_access_group)

Expand All @@ -62,7 +79,7 @@
signed_agreement__representative_role="Contact PI",
is_primary=True,
signed_agreement__version=v10,
study_site=StudySite.objects.get(short_name="CARDINAL"),
study_site=cardinal,
)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1002.signed_agreement.anvil_access_group)

Expand All @@ -73,7 +90,7 @@
signed_agreement__representative_role="Co-PI",
is_primary=False,
signed_agreement__version=v10,
study_site=StudySite.objects.get(short_name="CARDINAL"),
study_site=cardinal,
)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1003.signed_agreement.anvil_access_group)

Expand All @@ -84,7 +101,7 @@
signed_agreement__representative_role="Co-I",
is_primary=False,
signed_agreement__version=v11,
study_site=StudySite.objects.get(short_name="CARDINAL"),
study_site=cardinal,
)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1004.signed_agreement.anvil_access_group)

Expand All @@ -93,7 +110,7 @@
signed_agreement__representative=User.objects.get(name="Brackie Mitchell"),
signed_agreement__signing_institution="UMaryland",
signed_agreement__representative_role="Study PI",
study=Study.objects.get(short_name="Amish"),
study=amish,
signed_agreement__version=v10,
)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1005.signed_agreement.anvil_access_group)
Expand All @@ -103,7 +120,7 @@
signed_agreement__representative=UserFactory.create(name="Robyn"),
signed_agreement__representative_role="DCC PI",
signed_agreement__signing_institution="UW",
study=Study.objects.get(short_name="MESA"),
study=mesa,
signed_agreement__version=v10,
additional_limitations="This data can only be used for testing the app.",
requires_study_review=True,
Expand All @@ -116,7 +133,7 @@
signed_agreement__signing_institution="JHU",
signed_agreement__representative_role="Field Center PI",
is_primary=False,
study=Study.objects.get(short_name="MESA"),
study=mesa,
signed_agreement__version=v10,
)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1007.signed_agreement.anvil_access_group)
Expand All @@ -127,7 +144,7 @@
signed_agreement__signing_institution="Lundquist",
signed_agreement__representative_role="Analysis Center PI",
is_primary=False,
study=Study.objects.get(short_name="MESA"),
study=mesa,
signed_agreement__version=v10,
)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1008.signed_agreement.anvil_access_group)
Expand Down Expand Up @@ -209,7 +226,7 @@
cdsa_workspace_1 = factories.CDSAWorkspaceFactory.create(
workspace__billing_project__name="demo-primed-cdsa",
workspace__name="DEMO_PRIMED_CDSA_MESA_1",
study=Study.objects.get(short_name="MESA"),
study=mesa,
data_use_permission=dup,
)
GroupGroupMembershipFactory.create(
Expand All @@ -222,7 +239,7 @@
cdsa_workspace_2 = factories.CDSAWorkspaceFactory.create(
workspace__billing_project__name="demo-primed-cdsa",
workspace__name="DEMO_PRIMED_CDSA_MESA_2",
study=Study.objects.get(short_name="MESA"),
study=mesa,
data_use_permission=dup,
additional_limitations="Additional limitations for workspace.",
)
Expand All @@ -233,6 +250,6 @@
cdsa_workspace_3 = factories.CDSAWorkspaceFactory.create(
workspace__billing_project__name="demo-primed-cdsa",
workspace__name="DEMO_PRIMED_CDSA_ARIC_1",
study=Study.objects.create(short_name="ARIC", full_name="Atherosclerosis Risk in Communities"),
study=aric,
data_use_permission=dup,
)
42 changes: 38 additions & 4 deletions add_dbgap_example_data.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
# Temporary script to create some test data.
# Run with: python manage.py shell < add_cdsa_example_data.py

from anvil_consortium_manager.tests.factories import GroupGroupMembershipFactory
from anvil_consortium_manager.tests.factories import (
AccountFactory,
GroupAccountMembershipFactory,
GroupGroupMembershipFactory,
)

from primed.dbgap import models
from primed.dbgap.tests import factories
from primed.primed_anvil.tests.factories import StudyFactory
from primed.users.tests.factories import UserFactory

# Studies
fhs = StudyFactory.create(short_name="FHS", full_name="Framingham Heart Study")
mesa = StudyFactory.create(short_name="MESA", full_name="Multi-Ethnic Study of Atherosclerosis")
aric = StudyFactory.create(short_name="ARIC", full_name="Atherosclerosis Risk in Communities")
try:
fhs = models.Study.objects.get(short_name="FHS")
except models.Study.DoesNotExist:
fhs = StudyFactory.create(short_name="FHS", full_name="Framingham Heart Study")
try:
mesa = models.Study.objects.get(short_name="MESA")
except models.Study.DoesNotExist:
mesa = StudyFactory.create(short_name="MESA", full_name="Multi-Ethnic Study of Atherosclerosis")
try:
aric = models.Study.objects.get(short_name="ARIC")
except models.Study.DoesNotExist:
aric = StudyFactory.create(short_name="ARIC", full_name="Atherosclerosis Risk in Communities")

# dbGaP study accessions
dbgap_study_accession_fhs = factories.dbGaPStudyAccessionFactory.create(dbgap_phs=7, studies=[fhs])
Expand Down Expand Up @@ -124,3 +137,24 @@
parent_group=workspace_fhs_1.workspace.authorization_domains.first(),
child_group=dbgap_application_1.anvil_access_group,
)

# Add the PI to the access group for the first application.
GroupAccountMembershipFactory.create(
group=dbgap_application_1.anvil_access_group,
account__user=dbgap_application_1.principal_investigator,
)
# Add some collaborators for the first application.
users = UserFactory.create_batch(3)
dbgap_application_1.collaborators.add(users[0])
GroupAccountMembershipFactory.create(
group=dbgap_application_1.anvil_access_group,
account__user=users[0],
)
# # Do not add as an collaborator so we can check auditing.
# dbgap_application_1.collaborators.add(users[1])
GroupAccountMembershipFactory.create(
group=dbgap_application_1.anvil_access_group,
account__user=users[1],
)
dbgap_application_1.collaborators.add(users[2])
AccountFactory.create(user=users[2], verified=True)
12 changes: 6 additions & 6 deletions primed/cdsa/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2879,7 +2879,7 @@ def test_response_is_primary(self):
self.assertContains(response, "Primary?")
self.assertContains(
response,
"""<dt class="col-sm-2">Primary?</dt><dd class="col-sm-9">Yes <i class="bi bi-check-circle-fill px-2" style="color: green;"></i></dd>""", # noqa: E501
"""<dt class="col-sm-3">Primary?</dt><dd class="col-sm-9">Yes <i class="bi bi-check-circle-fill px-2" style="color: green;"></i></dd>""", # noqa: E501
html=True,
)
instance.is_primary = False
Expand All @@ -2888,7 +2888,7 @@ def test_response_is_primary(self):
self.assertContains(response, "Primary?")
self.assertContains(
response,
"""<dt class="col-sm-2">Primary?</dt><dd class="col-sm-9">No <i class="bi bi-x-circle-fill px-2" style="color: red;"></i></dd>""", # noqa: E501
"""<dt class="col-sm-3">Primary?</dt><dd class="col-sm-9">No <i class="bi bi-x-circle-fill px-2" style="color: red;"></i></dd>""", # noqa: E501
html=True,
)

Expand Down Expand Up @@ -4698,7 +4698,7 @@ def test_response_is_primary(self):
self.assertContains(response, "Primary?")
self.assertContains(
response,
"""<dt class="col-sm-2">Primary?</dt><dd class="col-sm-9">Yes <i class="bi bi-check-circle-fill px-2" style="color: green;"></i></dd>""", # noqa: E501
"""<dt class="col-sm-3">Primary?</dt><dd class="col-sm-9">Yes <i class="bi bi-check-circle-fill px-2" style="color: green;"></i></dd>""", # noqa: E501
html=True,
)
instance.is_primary = False
Expand All @@ -4707,7 +4707,7 @@ def test_response_is_primary(self):
self.assertContains(response, "Primary?")
self.assertContains(
response,
"""<dt class="col-sm-2">Primary?</dt><dd class="col-sm-9">No <i class="bi bi-x-circle-fill px-2" style="color: red;"></i></dd>""", # noqa: E501
"""<dt class="col-sm-3">Primary?</dt><dd class="col-sm-9">No <i class="bi bi-x-circle-fill px-2" style="color: red;"></i></dd>""", # noqa: E501
html=True,
)

Expand All @@ -4720,7 +4720,7 @@ def test_response_requires_study_review(self):
# import ipdb; ipdb.set_trace()
self.assertContains(
response,
"""<dt class="col-sm-2">Study review required?</dt> <dd class="col-sm-9">Yes <i class="bi bi-check-circle-fill px-2" style="color: green;"></i></dd>""", # noqa: E501
"""<dt class="col-sm-3">Study review required?</dt> <dd class="col-sm-9">Yes <i class="bi bi-check-circle-fill px-2" style="color: green;"></i></dd>""", # noqa: E501
html=True,
)
instance.requires_study_review = False
Expand All @@ -4729,7 +4729,7 @@ def test_response_requires_study_review(self):
self.assertContains(response, "Study review required?")
self.assertContains(
response,
"""<dt class="col-sm-2">Study review required?</dt> <dd class="col-sm-9">No <i class="bi bi-x-circle-fill px-2" style="color: red;"></i></dd>""", # noqa: E501
"""<dt class="col-sm-3">Study review required?</dt> <dd class="col-sm-9">No <i class="bi bi-x-circle-fill px-2" style="color: red;"></i></dd>""", # noqa: E501
html=True,
)

Expand Down
4 changes: 4 additions & 0 deletions primed/dbgap/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,7 @@ def test_staff_edit_links(self):
self.assertContains(
response, reverse("anvil_consortium_manager:managed_groups:detail", args=[self.obj.anvil_access_group.name])
)
self.assertContains(response, reverse("dbgap:dbgap_applications:update", args=[self.obj.dbgap_project_id]))

def test_staff_view_links(self):
"""No edit links if staff user only has view permission."""
Expand All @@ -1475,6 +1476,7 @@ def test_staff_view_links(self):
self.assertContains(
response, reverse("anvil_consortium_manager:managed_groups:detail", args=[self.obj.anvil_access_group.name])
)
self.assertNotContains(response, reverse("dbgap:dbgap_applications:update", args=[self.obj.dbgap_project_id]))

def test_links_pi(self):
"""Links seen by PI are correct."""
Expand All @@ -1500,6 +1502,7 @@ def test_links_pi(self):
self.assertNotContains(
response, reverse("anvil_consortium_manager:managed_groups:detail", args=[self.obj.anvil_access_group.name])
)
self.assertNotContains(response, reverse("dbgap:dbgap_applications:update", args=[self.obj.dbgap_project_id]))

def test_links_collaborators(self):
"""Links seen by collaborators are correct."""
Expand All @@ -1526,6 +1529,7 @@ def test_links_collaborators(self):
self.assertNotContains(
response, reverse("anvil_consortium_manager:managed_groups:detail", args=[self.obj.anvil_access_group.name])
)
self.assertNotContains(response, reverse("dbgap:dbgap_applications:update", args=[self.obj.dbgap_project_id]))

def test_table_classes(self):
"""The table classes are correct."""
Expand Down
3 changes: 2 additions & 1 deletion primed/dbgap/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ class dbGaPApplicationUpdate(AnVILConsortiumManagerStaffEditRequired, SuccessMes

model = models.dbGaPApplication
form_class = forms.dbGaPApplicationUpdateForm
success_message = "dbGaP application successfully updated."
success_message = "dbGaP collaborators successfully updated."
template_name = "dbgap/dbgapapplication_update_collaborators.html"

def get_object(self, queryset=None):
queryset = self.get_queryset()
Expand Down
9 changes: 9 additions & 0 deletions primed/primed_anvil/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@
from anvil_consortium_manager.models import Account
from django_filters import FilterSet

from .models import Study


class AccountListFilter(FilterSet):
class Meta:
model = Account
fields = {"email": ["icontains"], "user__name": ["icontains"]}
form = FilterForm


class StudyListFilter(FilterSet):
class Meta:
model = Study
fields = {"short_name": ["icontains"], "full_name": ["icontains"]}
form = FilterForm
62 changes: 61 additions & 1 deletion primed/primed_anvil/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from primed.primed_anvil.tests.factories import AvailableDataFactory, StudyFactory
from primed.users.tests.factories import UserFactory

from .. import models, tables, views
from .. import filters, models, tables, views
from . import factories

# from .utils import AnVILAPIMockTestMixin
Expand Down Expand Up @@ -724,6 +724,66 @@ def test_view_with_two_objects(self):
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 2)

def test_filterset_class(self):
self.model_factory.create()
request = self.factory.get(self.get_url())
request.user = self.user
response = self.get_view()(request)
self.assertIn("filter", response.context_data)
self.assertIsInstance(response.context_data["filter"], filters.StudyListFilter)

def test_view_with_filter_return_no_object(self):
self.model_factory.create(short_name="TEST", full_name="Test study")
self.client.force_login(self.user)
response = self.client.get(self.get_url(), {"short_name__icontains": "abc"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 0)
response = self.client.get(self.get_url(), {"full_name__icontains": "abc"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 0)

def test_view_with_filter_returns_one_object_exact(self):
self.model_factory.create(short_name="TEST", full_name="Test Study")
self.model_factory.create(short_name="ABC", full_name="ABC Study")
self.client.force_login(self.user)
response = self.client.get(self.get_url(), {"short_name__icontains": "TEST"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 1)
response = self.client.get(self.get_url(), {"full_name__icontains": "Test Study"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 1)

def test_view_with_filter_returns_one_object_case_insensitive(self):
self.model_factory.create(short_name="TEST", full_name="TEST Study")
self.client.force_login(self.user)
response = self.client.get(self.get_url(), {"short_name__icontains": "test"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 1)
response = self.client.get(self.get_url(), {"full_name__icontains": "test study"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 1)

def test_view_with_filter_returns_one_object_contains(self):
self.model_factory.create(short_name="TEST", full_name="TEST Study")
self.client.force_login(self.user)
response = self.client.get(self.get_url(), {"short_name__icontains": "TES"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 1)
response = self.client.get(self.get_url(), {"full_name__icontains": "TES"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 1)

def test_view_with_filter_returns_all_objects(self):
self.model_factory.create(short_name="Test 1", full_name="Test 1 Study")
self.model_factory.create(short_name="Test 2", full_name="Test 2 Study")
self.client.force_login(self.user)
response = self.client.get(self.get_url(), {"short_name__icontains": "Test"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 2)
response = self.client.get(self.get_url(), {"full_name__icontains": "Test"})
self.assertIn("table", response.context_data)
self.assertEqual(len(response.context_data["table"].rows), 2)


class StudySiteDetailTest(TestCase):
"""Tests for the StudySiteDetail view."""
Expand Down
Loading

0 comments on commit 199063d

Please sign in to comment.