Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy to prod #650

Merged
merged 12 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/pip-compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:

jobs:
update-requirements-files:
permissions:
pull-requests: write
runs-on: ubuntu-latest

steps:
Expand Down
2 changes: 2 additions & 0 deletions add_cdsa_example_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
signed_agreement__version=v10,
study_site=cc,
)
cdsa_1001.signed_agreement.representative.study_sites.add(cc)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1001.signed_agreement.anvil_access_group)

cdsa_1002 = factories.MemberAgreementFactory.create(
Expand All @@ -81,6 +82,7 @@
signed_agreement__version=v10,
study_site=cardinal,
)
cdsa_1002.signed_agreement.representative.study_sites.add(cardinal)
GroupGroupMembershipFactory.create(parent_group=cdsa_group, child_group=cdsa_1002.signed_agreement.anvil_access_group)

cdsa_1003 = factories.MemberAgreementFactory.create(
Expand Down
20 changes: 20 additions & 0 deletions primed/primed_anvil/migrations/0007_studysite_member_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.13 on 2024-07-10 20:21

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('anvil_consortium_manager', '0019_accountuserarchive'),
('primed_anvil', '0006_studysite_drupal_node_id'),
]

operations = [
migrations.AddField(
model_name='studysite',
name='member_group',
field=models.ForeignKey(blank=True, help_text='The AnVIL Managed Group associated with this site.', null=True, on_delete=django.db.models.deletion.PROTECT, to='anvil_consortium_manager.managedgroup'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.13 on 2024-07-10 20:24

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('anvil_consortium_manager', '0019_accountuserarchive'),
('primed_anvil', '0007_studysite_member_group'),
]

operations = [
migrations.AlterField(
model_name='studysite',
name='member_group',
field=models.OneToOneField(blank=True, help_text='The AnVIL Managed Group associated with this site.', null=True, on_delete=django.db.models.deletion.PROTECT, to='anvil_consortium_manager.managedgroup'),
),
]
10 changes: 10 additions & 0 deletions primed/primed_anvil/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from anvil_consortium_manager.models import ManagedGroup
from django.conf import settings
from django.db import models
from django.urls import reverse
Expand Down Expand Up @@ -37,6 +38,15 @@ class StudySite(TimeStampedModel, models.Model):
full_name = models.CharField(max_length=255)
"""The full name of the Study Sites."""

member_group = models.OneToOneField(
ManagedGroup,
on_delete=models.PROTECT,
help_text="The AnVIL Managed Group associated with this site.",
null=True,
blank=True,
unique=True,
)

drupal_node_id = models.IntegerField(blank=True, null=True)
"""Reference node ID for entity in drupal"""

Expand Down
16 changes: 12 additions & 4 deletions primed/primed_anvil/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,11 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, extra_columns=extra_columns, **kwargs)


class UserAccountSingleGroupMembershipTable(tables.Table):
"""A table with users and info about whether they are members of a group."""
class UserAccountTable(tables.Table):
"""A table for `User`s with `Account` information."""

name = tables.Column(linkify=True)
account = tables.Column(linkify=True, verbose_name="AnVIL account")

class Meta:
model = User
Expand All @@ -167,8 +170,13 @@ class Meta:
)
order_by = ("name",)

name = tables.Column(linkify=lambda record: record.get_absolute_url())
account = tables.Column(verbose_name="AnVIL account")

class UserAccountSingleGroupMembershipTable(UserAccountTable):
"""A table with users and info about whether they are members of a group."""

class Meta(UserAccountTable.Meta):
pass

is_group_member = tables.BooleanColumn(verbose_name="Has access?", default=False)

def __init__(self, *args, managed_group=None, **kwargs):
Expand Down
20 changes: 20 additions & 0 deletions primed/primed_anvil/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests of models in the `primed_anvil` app."""

from anvil_consortium_manager.tests.factories import ManagedGroupFactory
from django.core.exceptions import ValidationError
from django.db.utils import IntegrityError
from django.test import TestCase
Expand Down Expand Up @@ -48,6 +49,7 @@ class StudySiteTest(TestCase):
def test_model_saving(self):
"""Creation using the model constructor and .save() works."""
instance = models.StudySite(full_name="Test name", short_name="TEST")
instance.full_clean()
instance.save()
self.assertIsInstance(instance, models.StudySite)

Expand All @@ -72,6 +74,24 @@ def test_unique_short_name(self):
with self.assertRaises(IntegrityError):
instance2.save()

def test_can_set_members_group(self):
member_group = ManagedGroupFactory.create()
instance = models.StudySite(full_name="Test name", short_name="TEST", member_group=member_group)
instance.full_clean()
instance.save()
self.assertIsInstance(instance, models.StudySite)

def test_same_member_group_different_sites(self):
member_group = ManagedGroupFactory.create()
factories.StudySiteFactory.create(member_group=member_group)
instance = factories.StudySiteFactory.build(member_group=member_group)
with self.assertRaises(ValidationError) as e:
instance.full_clean()
self.assertEqual(len(e.exception.message_dict), 1)
self.assertIn("member_group", e.exception.message_dict)
self.assertEqual(len(e.exception.message_dict["member_group"]), 1)
self.assertIn("Study site with this Member group already exists.", e.exception.message_dict["member_group"][0])


class AvailableDataTest(TestCase):
"""Tests for the AvailableData model."""
Expand Down
29 changes: 29 additions & 0 deletions primed/primed_anvil/tests/test_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,35 @@ def test_render_not_workspace(self):
column.render(None, "foo", None)


class UserAccountTableTest(TestCase):
"""Tests for the UserAccountTable class."""

def setUp(self):
self.managed_group = ManagedGroupFactory.create()

def test_row_count_with_no_objects(self):
table = tables.UserAccountTable(User.objects.all())
self.assertEqual(len(table.rows), 0)

def test_row_count_with_one_object(self):
UserFactory.create()
table = tables.UserAccountTable(User.objects.all())
self.assertEqual(len(table.rows), 1)

def test_row_count_with_two_objects(self):
UserFactory.create_batch(2)
table = tables.UserAccountTable(User.objects.all())
self.assertEqual(len(table.rows), 2)

def test_ordering(self):
"""Users are ordered alphabetically by name"""
user_foo = UserFactory.create(name="Foo")
user_bar = UserFactory.create(name="Bar")
table = tables.UserAccountTable(User.objects.all())
self.assertEqual(table.data[0], user_bar)
self.assertEqual(table.data[1], user_foo)


class UserAccountSingleGroupMembershipTableTest(TestCase):
"""Tests for the UserAccountSingleGroupMembershipTable class."""

Expand Down
60 changes: 58 additions & 2 deletions primed/primed_anvil/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from anvil_consortium_manager import models as acm_models
from anvil_consortium_manager.tests.factories import (
AccountFactory,
GroupAccountMembershipFactory,
ManagedGroupFactory,
WorkspaceGroupSharingFactory,
)
Expand All @@ -17,13 +18,13 @@
from django.test import RequestFactory, TestCase
from django.urls import reverse

from primed.cdsa.tables import CDSAWorkspaceStaffTable, CDSAWorkspaceUserTable
from primed.cdsa.tables import CDSAWorkspaceStaffTable, CDSAWorkspaceUserTable, MemberAgreementTable
from primed.cdsa.tests.factories import (
CDSAWorkspaceFactory,
DataAffiliateAgreementFactory,
MemberAgreementFactory,
)
from primed.dbgap.tables import dbGaPWorkspaceStaffTable, dbGaPWorkspaceUserTable
from primed.dbgap.tables import dbGaPApplicationTable, dbGaPWorkspaceStaffTable, dbGaPWorkspaceUserTable
from primed.dbgap.tests.factories import (
dbGaPApplicationFactory,
dbGaPStudyAccessionFactory,
Expand Down Expand Up @@ -843,6 +844,22 @@ def test_view_status_code_with_invalid_pk(self):
with self.assertRaises(Http404):
self.get_view()(request, pk=obj.pk + 1)

def test_table_classes(self):
"""Table classes are correct."""
obj = self.model_factory.create()
self.client.force_login(self.user)
response = self.client.get(self.get_url(obj.pk))
self.assertIn("tables", response.context_data)
self.assertEqual(len(response.context_data["tables"]), 4)
self.assertIsInstance(response.context_data["tables"][0], tables.UserAccountTable)
self.assertEqual(len(response.context_data["tables"][0].data), 0)
self.assertIsInstance(response.context_data["tables"][1], dbGaPApplicationTable)
self.assertEqual(len(response.context_data["tables"][1].data), 0)
self.assertIsInstance(response.context_data["tables"][2], MemberAgreementTable)
self.assertEqual(len(response.context_data["tables"][2].data), 0)
self.assertIsInstance(response.context_data["tables"][3], tables.AccountTable)
self.assertEqual(len(response.context_data["tables"][3].data), 0)

def test_site_user_table(self):
"""Contains a table of site users with the correct users."""
obj = self.model_factory.create()
Expand Down Expand Up @@ -883,6 +900,45 @@ def test_cdsa_table(self):
self.assertIn(site_cdsa, table.data)
self.assertNotIn(other_cdsa, table.data)

def test_site_user_table_when_member_group_is_set(self):
"""The site user table is the correct class when the member group is set."""
member_group = ManagedGroupFactory.create()
obj = self.model_factory.create(member_group=member_group)
self.client.force_login(self.user)
response = self.client.get(self.get_url(obj.pk))
table = response.context_data["tables"][0]
self.assertIsInstance(table, tables.UserAccountSingleGroupMembershipTable)
self.assertEqual(table.managed_group, member_group)

def test_member_group_table(self):
member_group = ManagedGroupFactory.create()
obj = self.model_factory.create(member_group=member_group)
account = AccountFactory.create(verified=True)
GroupAccountMembershipFactory.create(account=account, group=member_group)
other_account = AccountFactory.create(verified=True)
self.client.force_login(self.user)
response = self.client.get(self.get_url(obj.pk))
table = response.context_data["tables"][3]
self.assertEqual(len(table.rows), 1)
self.assertIn(account, table.data)
self.assertNotIn(other_account, table.data)

def test_member_table_group_not_set(self):
obj = self.model_factory.create()
AccountFactory.create(verified=True)
self.client.force_login(self.user)
response = self.client.get(self.get_url(obj.pk))
table = response.context_data["tables"][3]
self.assertEqual(len(table.rows), 0)

def test_link_to_member_group(self):
"""Response includes a link to the member group if it exists."""
member_group = ManagedGroupFactory.create()
obj = self.model_factory.create(member_group=member_group)
self.client.force_login(self.user)
response = self.client.get(self.get_url(obj.pk))
self.assertContains(response, member_group.get_absolute_url())


class StudySiteListTest(TestCase):
"""Tests for the StudySiteList view."""
Expand Down
27 changes: 16 additions & 11 deletions primed/primed_anvil/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
AnVILConsortiumManagerStaffViewRequired,
AnVILConsortiumManagerViewRequired,
)
from anvil_consortium_manager.models import AnVILProjectManagerAccess, Workspace
from anvil_consortium_manager.models import Account, AnVILProjectManagerAccess, Workspace
from dal import autocomplete
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin
Expand Down Expand Up @@ -33,7 +33,6 @@
OpenAccessWorkspaceStaffTable,
OpenAccessWorkspaceUserTable,
)
from primed.users.tables import UserTable

from . import filters, helpers, models, tables

Expand Down Expand Up @@ -124,19 +123,25 @@ class StudySiteDetail(AnVILConsortiumManagerStaffViewRequired, MultiTableMixin,
"""View to show details about a `StudySite`."""

model = models.StudySite
tables = [
UserTable,
dbGaPApplicationTable,
MemberAgreementTable,
]

# def get_table(self):
# return UserTable(User.objects.filter(study_sites=self.object))
def get_tables_data(self):
def get_tables(self):
user_qs = User.objects.filter(study_sites=self.object)
if self.object.member_group:
user_table = tables.UserAccountSingleGroupMembershipTable(user_qs, managed_group=self.object.member_group)
else:
user_table = tables.UserAccountTable(user_qs, exclude="study_sites")
dbgap_qs = dbGaPApplication.objects.filter(principal_investigator__study_sites=self.object)
cdsa_qs = MemberAgreement.objects.filter(study_site=self.object)
return [user_qs, dbgap_qs, cdsa_qs]
if self.object.member_group:
account_qs = Account.objects.filter(groupaccountmembership__group=self.object.member_group)
else:
account_qs = Account.objects.none()
return [
user_table,
dbGaPApplicationTable(dbgap_qs),
MemberAgreementTable(cdsa_qs),
tables.AccountTable(account_qs, exclude=("number_groups")),
]


class StudySiteList(AnVILConsortiumManagerStaffViewRequired, SingleTableView):
Expand Down
Loading