From bda24168cbbb6c459a66842597beddfc9666c2d3 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 4 Sep 2024 14:12:36 -0700
Subject: [PATCH 01/49] Map authenticated users to a Django group
This will let us grant that group view permission.
---
config/settings/base.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/config/settings/base.py b/config/settings/base.py
index 5539f254..152a97d2 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -344,6 +344,11 @@
"request_scope": True,
"django_group_name": "Approved by PI for AnVIL access",
},
+ {
+ "drupal_machine_name": "authenticated",
+ "request_scope": True,
+ "django_group_name": "Authenticated",
+ },
],
}
}
From 0c8e12929c1ce4365ab8104d12d1094114814e39 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 4 Sep 2024 14:28:30 -0700
Subject: [PATCH 02/49] Switch UploadCycleDetail to be visible by View users
Modify tests to use a view user by default. Change test structure for
checking links by having one test for view users, one for staff
view, and one for edit users; these tests check if the proper links
are or are not shown.
---
.../gregor_anvil/tests/test_views.py | 64 +++++++++++--------
gregor_django/gregor_anvil/views.py | 3 +-
.../gregor_anvil/uploadcycle_detail.html | 2 +
3 files changed, 40 insertions(+), 29 deletions(-)
diff --git a/gregor_django/gregor_anvil/tests/test_views.py b/gregor_django/gregor_anvil/tests/test_views.py
index 32806ab0..d77260a8 100644
--- a/gregor_django/gregor_anvil/tests/test_views.py
+++ b/gregor_django/gregor_anvil/tests/test_views.py
@@ -1006,7 +1006,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
def get_url(self, *args):
@@ -1147,45 +1147,53 @@ def test_partner_upload_workspace_table(self):
self.assertIn(workspace.workspace, table.data)
self.assertNotIn(other_workspace.workspace, table.data)
- def test_link_to_audit(self):
- """Response includes a link to the audit page."""
+ def test_links_view_user(self):
+ user = self.user
obj = self.model_factory.create()
- self.client.force_login(self.user)
+ self.client.force_login(user)
response = self.client.get(self.get_url(obj.cycle))
- self.assertContains(
+ self.assertNotContains(response, reverse("gregor_anvil:upload_cycles:update", args=[obj.cycle]))
+ self.assertNotContains(
response, reverse("gregor_anvil:audit:upload_workspaces:sharing:by_upload_cycle", args=[obj.cycle])
)
-
- def test_link_to_update_view_staff_edit(self):
- """Response includes a link to the update view for staff edit users."""
- obj = self.model_factory.create()
- self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ self.assertNotContains(
+ response, reverse("gregor_anvil:audit:upload_workspaces:auth_domains:by_upload_cycle", args=[obj.cycle])
)
- self.client.force_login(self.user)
- response = self.client.get(self.get_url(obj.cycle))
- self.assertContains(response, reverse("gregor_anvil:upload_cycles:update", args=[obj.cycle]))
- def test_link_to_update_view_staff_view(self):
- """Response includes a link to the update view for staff edit users."""
+ def test_links_staff_view_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
obj = self.model_factory.create()
- self.client.force_login(self.user)
+ self.client.force_login(user)
response = self.client.get(self.get_url(obj.cycle))
self.assertNotContains(response, reverse("gregor_anvil:upload_cycles:update", args=[obj.cycle]))
+ self.assertContains(
+ response, reverse("gregor_anvil:audit:upload_workspaces:sharing:by_upload_cycle", args=[obj.cycle])
+ )
+ self.assertContains(
+ response, reverse("gregor_anvil:audit:upload_workspaces:auth_domains:by_upload_cycle", args=[obj.cycle])
+ )
- def test_contains_sharing_audit_button(self):
- obj = self.model_factory.create()
- self.client.force_login(self.user)
- response = self.client.get(self.get_url(obj.cycle))
- url = reverse("gregor_anvil:audit:upload_workspaces:sharing:by_upload_cycle", args=[obj.cycle])
- self.assertContains(response, url)
-
- def test_contains_auth_domain_audit_button(self):
+ def test_links_staff_edit_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ )
obj = self.model_factory.create()
- self.client.force_login(self.user)
+ self.client.force_login(user)
response = self.client.get(self.get_url(obj.cycle))
- url = reverse("gregor_anvil:audit:upload_workspaces:auth_domains:by_upload_cycle", args=[obj.cycle])
- self.assertContains(response, url)
+ self.assertContains(response, reverse("gregor_anvil:upload_cycles:update", args=[obj.cycle]))
+ self.assertContains(
+ response, reverse("gregor_anvil:audit:upload_workspaces:sharing:by_upload_cycle", args=[obj.cycle])
+ )
+ self.assertContains(
+ response, reverse("gregor_anvil:audit:upload_workspaces:auth_domains:by_upload_cycle", args=[obj.cycle])
+ )
def test_includes_date_ready_for_compute(self):
obj = self.model_factory.create(is_past=True, date_ready_for_compute="2022-01-01")
diff --git a/gregor_django/gregor_anvil/views.py b/gregor_django/gregor_anvil/views.py
index cdf8c701..b499acd5 100644
--- a/gregor_django/gregor_anvil/views.py
+++ b/gregor_django/gregor_anvil/views.py
@@ -2,6 +2,7 @@
from anvil_consortium_manager.auth import (
AnVILConsortiumManagerStaffEditRequired,
AnVILConsortiumManagerStaffViewRequired,
+ AnVILConsortiumManagerViewRequired,
)
from anvil_consortium_manager.exceptions import AnVILGroupNotFound
from anvil_consortium_manager.models import (
@@ -124,7 +125,7 @@ class UploadCycleUpdate(AnVILConsortiumManagerStaffEditRequired, SuccessMessageM
success_message = "Successfully updated Upload Cycle."
-class UploadCycleDetail(AnVILConsortiumManagerStaffViewRequired, MultiTableMixin, DetailView):
+class UploadCycleDetail(AnVILConsortiumManagerViewRequired, MultiTableMixin, DetailView):
"""View to show details about an `UploadCycle`."""
model = models.UploadCycle
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index b8683f76..28e1850e 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -68,6 +68,7 @@ Partner upload workspaces
{% endif %}
+{% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
Audit consortium sharing
@@ -76,4 +77,5 @@ Partner upload workspaces
Audit auth domain membership
+{% endif %}
{% endblock action_buttons %}
From 8ae5e005cbbacbb1f65a90eb94d2529762081b7f Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 4 Sep 2024 14:46:32 -0700
Subject: [PATCH 03/49] Make the upload cycle detail page a bit prettier
---
.../gregor_anvil/uploadcycle_detail.html | 116 +++++++++++++++---
1 file changed, 98 insertions(+), 18 deletions(-)
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index 28e1850e..05a1f2ef 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -28,34 +28,114 @@
{% endblock panel %}
{% block after_panel %}
-Upload workspaces
-
- {% render_table tables.0 %}
+
+
The expandable tables below show information about workspaces associated with this upload cycle.
+
+
+
+
+
+
+ {% render_table tables.0 %}
+
+
+
-
Combined consortium data workspaces
-
- {% render_table tables.1 %}
+
+
+
+
+
+
+ {% render_table tables.1 %}
+
+
+
-
Release prep workspaces
-
- {% render_table tables.2 %}
+
+
+
+
+
+
+ {% render_table tables.3 %}
+
+
+
-
DCC processing workspaces
-
- {% render_table tables.3 %}
+
+
+
+
+
+
+ {% render_table tables.4 %}
+
+
+
-
DCC processed data workspaces
-
- {% render_table tables.4 %}
+
+
+
+
+
+
+ {% render_table tables.2 %}
+
+
+
-
Partner upload workspaces
-
- {% render_table tables.5 %}
+
+
+
+
+
+
+ {% render_table tables.5 %}
+
+
+
{% endblock after_panel %}
From 8ed852f81c1546e956190d6ecceaecc9b256741d Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 4 Sep 2024 15:01:00 -0700
Subject: [PATCH 04/49] Show an alert indicating if the upload cycle is
current, past, or future
---
.../gregor_anvil/tests/test_views.py | 21 +++++++++++++++++++
.../gregor_anvil/uploadcycle_detail.html | 5 +++++
2 files changed, 26 insertions(+)
diff --git a/gregor_django/gregor_anvil/tests/test_views.py b/gregor_django/gregor_anvil/tests/test_views.py
index d77260a8..0327789e 100644
--- a/gregor_django/gregor_anvil/tests/test_views.py
+++ b/gregor_django/gregor_anvil/tests/test_views.py
@@ -1202,6 +1202,27 @@ def test_includes_date_ready_for_compute(self):
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Jan. 1, 2022")
+ def test_alert_for_current_cycle(self):
+ upload_cycle = self.model_factory.create(is_current=True)
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(upload_cycle.cycle))
+ self.assertContains(response, "alert alert-success")
+ self.assertContains(response, "This is the current upload cycle.")
+
+ def test_alert_for_past_cycle(self):
+ upload_cycle = self.model_factory.create(is_past=True)
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(upload_cycle.cycle))
+ self.assertContains(response, "alert alert-danger")
+ self.assertContains(response, "This is a past upload cycle.")
+
+ def test_alert_for_future_cycle(self):
+ upload_cycle = self.model_factory.create(is_future=True)
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(upload_cycle.cycle))
+ self.assertContains(response, "alert alert-danger")
+ self.assertContains(response, "This is a future upload cycle.")
+
class UploadCycleListTest(TestCase):
"""Tests for the UploadCycleList view."""
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index 05a1f2ef..96d6398d 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -4,6 +4,11 @@
{% block title %}Upload Cycle: {{ object }}{% endblock %}
{% block note %}
+
+
+ This is {% if object.is_current %}the current{% elif object.is_past %}a past{% else %}a future{% endif %} upload cycle.
+
+
{% if object.note %}
Note : {{ object.note }}
From 772b20916a7ad3373ddfeda3398da970e8c9f1d8 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 4 Sep 2024 15:12:38 -0700
Subject: [PATCH 05/49] Switch icon for combined workspace
---
gregor_django/templates/gregor_anvil/uploadcycle_detail.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index 96d6398d..c3b12e57 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -58,7 +58,7 @@
-
+
Date: Thu, 5 Sep 2024 10:38:12 -0700
Subject: [PATCH 11/49] Wording modifications
---
.../templates/gregor_anvil/uploadcycle_detail.html | 7 ++++++-
gregor_django/templates/gregor_anvil/uploadcycle_list.html | 6 ++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index b3f9cb6e..6b945f46 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -34,7 +34,12 @@
{% block after_panel %}
-The expandable tables below show information about workspaces associated with this upload cycle.
+
+ The expandable tables below show information about workspaces associated with this upload cycle.
+ Workspaces are separated by type into different tables.
+ Click on each box to see a table of workspaces of that type.
+ Within the table for a workspace type, click on the name of a workspace within a table to see more information about that workspace.
+
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_list.html b/gregor_django/templates/gregor_anvil/uploadcycle_list.html
index cce9063a..c3a4f8b8 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_list.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_list.html
@@ -6,6 +6,12 @@
{% block content %}
Upload Cycles
+
+ The following table shows all GREGoR upload cycles to date.
+ Click on an upload cycle number to view more details about and workspaces associated with that cycle.
+
+
+
{% render_table table %}
{% endblock content %}
From 33bc3bb7c11d46359d081492c1e2bb84a542203e Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Thu, 5 Sep 2024 14:13:50 -0700
Subject: [PATCH 12/49] Show combined workspace before upload workspaces
---
.../gregor_anvil/uploadcycle_detail.html | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index 6b945f46..2524a95e 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -41,36 +41,36 @@
Within the table for a workspace type, click on the name of a workspace within a table to see more information about that workspace.
-
+
-
+
- {% render_table tables.0 %}
+ {% render_table tables.1 %}
-
+
-
+
- {% render_table tables.1 %}
+ {% render_table tables.0 %}
From 839f004ffbcddc2abab831fe8a8639a262fa29cc Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Thu, 5 Sep 2024 14:15:52 -0700
Subject: [PATCH 13/49] Show accordions uncollapsed by default
---
.../gregor_anvil/uploadcycle_detail.html | 36 +++++++++----------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index 2524a95e..8f3b2f29 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -41,16 +41,16 @@
Within the table for a workspace type, click on the name of a workspace within a table to see more information about that workspace.
-
+
-
+
{% render_table tables.1 %}
@@ -59,16 +59,16 @@
-
+
-
+
{% render_table tables.0 %}
@@ -77,16 +77,16 @@
-
+
-
+
{% render_table tables.3 %}
@@ -95,16 +95,16 @@
-
+
-
+
{% render_table tables.4 %}
@@ -113,16 +113,16 @@
-
+
-
+
{% render_table tables.2 %}
@@ -131,16 +131,16 @@
-
+
-
+
{% render_table tables.5 %}
From bd85e08df52c1918b63ba01672ca7d0aa7f236f9 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Thu, 5 Sep 2024 14:16:42 -0700
Subject: [PATCH 14/49] Only show combined and upload workspaces to view users
---
gregor_django/templates/gregor_anvil/uploadcycle_detail.html | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
index 8f3b2f29..f3678a02 100644
--- a/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
+++ b/gregor_django/templates/gregor_anvil/uploadcycle_detail.html
@@ -76,7 +76,7 @@
-
+{% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
+{% endif %}
{% endblock after_panel %}
From 17d0935fce15a97365beb8f61d0bba95c69dd56a Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 23 Oct 2024 12:17:56 -0700
Subject: [PATCH 15/49] Update workspace detail pages for view users
Now that all authenticated users will be getting view permission,
we need to make sure that the workspace detail pages only contain
information and links that they should see. Update workspace detail
page and tests as appropriate.
---
.../gregor_anvil/tests/test_views.py | 226 ++++++++++++++++--
...ombinedconsortiumdataworkspace_detail.html | 2 +-
.../dccprocesseddataworkspace_detail.html | 10 +-
.../exchangeworkspace_detail.html | 14 +-
.../partneruploadworkspace_detail.html | 33 +--
.../gregor_anvil/releaseworkspace_detail.html | 10 +-
6 files changed, 247 insertions(+), 48 deletions(-)
diff --git a/gregor_django/gregor_anvil/tests/test_views.py b/gregor_django/gregor_anvil/tests/test_views.py
index 6176ebec..40774942 100644
--- a/gregor_django/gregor_anvil/tests/test_views.py
+++ b/gregor_django/gregor_anvil/tests/test_views.py
@@ -1722,7 +1722,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
self.object = factories.ResourceWorkspaceFactory.create()
@@ -1989,10 +1989,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
- )
- self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
self.object = factories.CombinedConsortiumDataWorkspaceFactory.create()
@@ -2036,9 +2033,27 @@ def test_contains_upload_workspaces_from_previous_cycles(self):
self.assertIn(upload_workspace_1, response.context_data["upload_workspace_table"].data)
self.assertIn(upload_workspace_2, response.context_data["upload_workspace_table"].data)
- def test_contains_sharing_audit_button(self):
+ def test_includes_date_completed(self):
+ self.object.date_completed = "2022-01-01"
+ self.object.save()
self.client.force_login(self.user)
response = self.client.get(self.get_url(self.object.workspace.billing_project.name, self.object.workspace.name))
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, "Jan. 1, 2022")
+
+ def test_links_view_user(self):
+ user = self.user
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Audit links.
+ url = reverse(
+ "gregor_anvil:audit:combined_workspaces:auth_domains:by_workspace",
+ args=[
+ self.object.workspace.billing_project.name,
+ self.object.workspace.name,
+ ],
+ )
+ self.assertNotContains(response, url)
url = reverse(
"gregor_anvil:audit:combined_workspaces:sharing:by_workspace",
args=[
@@ -2046,11 +2061,16 @@ def test_contains_sharing_audit_button(self):
self.object.workspace.name,
],
)
- self.assertContains(response, url)
+ self.assertNotContains(response, url)
- def test_contains_auth_domain_audit_button(self):
- self.client.force_login(self.user)
- response = self.client.get(self.get_url(self.object.workspace.billing_project.name, self.object.workspace.name))
+ def test_links_staff_view_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Audit links.
url = reverse(
"gregor_anvil:audit:combined_workspaces:auth_domains:by_workspace",
args=[
@@ -2059,14 +2079,42 @@ def test_contains_auth_domain_audit_button(self):
],
)
self.assertContains(response, url)
+ url = reverse(
+ "gregor_anvil:audit:combined_workspaces:sharing:by_workspace",
+ args=[
+ self.object.workspace.billing_project.name,
+ self.object.workspace.name,
+ ],
+ )
+ self.assertContains(response, url)
- def test_includes_date_completed(self):
- self.object.date_completed = "2022-01-01"
- self.object.save()
- self.client.force_login(self.user)
- response = self.client.get(self.get_url(self.object.workspace.billing_project.name, self.object.workspace.name))
- self.assertEqual(response.status_code, 200)
- self.assertContains(response, "Jan. 1, 2022")
+ def test_links_staff_edit_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Audit links.
+ url = reverse(
+ "gregor_anvil:audit:combined_workspaces:auth_domains:by_workspace",
+ args=[
+ self.object.workspace.billing_project.name,
+ self.object.workspace.name,
+ ],
+ )
+ self.assertContains(response, url)
+ url = reverse(
+ "gregor_anvil:audit:combined_workspaces:sharing:by_workspace",
+ args=[
+ self.object.workspace.billing_project.name,
+ self.object.workspace.name,
+ ],
+ )
+ self.assertContains(response, url)
class ReleaseWorkspaceDetailTest(TestCase):
@@ -2305,7 +2353,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
self.object = factories.DCCProcessingWorkspaceFactory.create()
@@ -2329,7 +2377,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
self.object = factories.DCCProcessedDataWorkspaceFactory.create()
@@ -2343,6 +2391,40 @@ def test_status_code(self):
response = self.client.get(self.get_url(self.object.workspace.billing_project.name, self.object.workspace.name))
self.assertEqual(response.status_code, 200)
+ def test_links_view_user(self):
+ user = self.user
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertNotContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
+ def test_links_staff_view_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
+ def test_links_staff_edit_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
class ExchangeWorkspaceDetailTest(TestCase):
"""Tests of the anvil_consortium_manager WorkspaceDetail view using the ExchangeWorkspace adapter."""
@@ -2353,10 +2435,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
- )
- self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
self.object = factories.ExchangeWorkspaceFactory.create()
@@ -2370,6 +2449,40 @@ def test_status_code(self):
response = self.client.get(self.get_url(self.object.workspace.billing_project.name, self.object.workspace.name))
self.assertEqual(response.status_code, 200)
+ def test_links_view_user(self):
+ user = self.user
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertNotContains(
+ response, reverse("gregor_anvil:research_centers:detail", args=[self.object.research_center.pk])
+ )
+
+ def test_links_staff_view_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:research_centers:detail", args=[self.object.research_center.pk])
+ )
+
+ def test_links_staff_edit_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertContains(
+ response, reverse("gregor_anvil:research_centers:detail", args=[self.object.research_center.pk])
+ )
+
class ExchangeWorkspaceListTest(TestCase):
"""Tests of the anvil_consortium_manager WorkspaceList view using this app's adapter."""
@@ -2478,6 +2591,73 @@ def test_creates_upload_workspace(self):
self.assertEqual(new_workspace_data.research_center, research_center)
+class PartnerUploadWorkspaceDetailTest(TestCase):
+ """Tests of the anvil_consortium_manager WorkspaceDetail view using the PartnerUploadWorkspace adapter."""
+
+ def setUp(self):
+ """Set up test class."""
+ self.factory = RequestFactory()
+ # Create a user with both view and edit permission.
+ self.user = User.objects.create_user(username="test", password="test")
+ self.user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.object = factories.PartnerUploadWorkspaceFactory.create()
+
+ def get_url(self, *args):
+ """Get the url for the view being tested."""
+ return reverse("anvil_consortium_manager:workspaces:detail", args=args)
+
+ def test_status_code(self):
+ """Response has a status code of 200."""
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(self.object.workspace.billing_project.name, self.object.workspace.name))
+ self.assertEqual(response.status_code, 200)
+
+ def test_links_view_user(self):
+ user = self.user
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertNotContains(
+ response, reverse("gregor_anvil:partner_groups:detail", args=[self.object.partner_group.pk])
+ )
+ self.assertNotContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
+ def test_links_staff_view_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:partner_groups:detail", args=[self.object.partner_group.pk])
+ )
+ self.assertContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
+ def test_links_staff_edit_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertContains(
+ response, reverse("gregor_anvil:partner_groups:detail", args=[self.object.partner_group.pk])
+ )
+ self.assertContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
+
class ManagedGroupCreateTest(AnVILAPIMockTestMixin, TestCase):
"""Tests for custom ManagedGroup behavior."""
diff --git a/gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_detail.html b/gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_detail.html
index 6727465a..a8d7385a 100644
--- a/gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_detail.html
+++ b/gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_detail.html
@@ -10,7 +10,7 @@
{% block action_buttons %}
-{% if show_edit_links %}
+{% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
Audit consortium sharing
diff --git a/gregor_django/templates/gregor_anvil/dccprocesseddataworkspace_detail.html b/gregor_django/templates/gregor_anvil/dccprocesseddataworkspace_detail.html
index 38206481..8c588f99 100644
--- a/gregor_django/templates/gregor_anvil/dccprocesseddataworkspace_detail.html
+++ b/gregor_django/templates/gregor_anvil/dccprocesseddataworkspace_detail.html
@@ -9,9 +9,13 @@
{{ object.dccprocesseddataworkspace.upload_cycle }}
-
Consent group
-
- {{ object.dccprocesseddataworkspace.consent_group }}
+ Consent group
+ {% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
+ {{ workspace_data_object.consent_group }}
+ {% else %}
+ {{ workspace_data_object.consent_group }}
+ {% endif %}
+
{% endblock workspace_data %}
diff --git a/gregor_django/templates/gregor_anvil/exchangeworkspace_detail.html b/gregor_django/templates/gregor_anvil/exchangeworkspace_detail.html
index 4ff684e1..8490843e 100644
--- a/gregor_django/templates/gregor_anvil/exchangeworkspace_detail.html
+++ b/gregor_django/templates/gregor_anvil/exchangeworkspace_detail.html
@@ -2,7 +2,13 @@
{% block workspace_data %}
-
- Research Center {{ workspace_data_object.research_center }}
-
-{% endblock workspace_data %}
+
+ Research Center
+ {% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
+ {{ workspace_data_object.research_center }}
+ {% else %}
+ {{ workspace_data_object.research_center }}
+ {% endif %}
+
+
+ {% endblock workspace_data %}
diff --git a/gregor_django/templates/gregor_anvil/partneruploadworkspace_detail.html b/gregor_django/templates/gregor_anvil/partneruploadworkspace_detail.html
index 2f17783d..a6606c98 100644
--- a/gregor_django/templates/gregor_anvil/partneruploadworkspace_detail.html
+++ b/gregor_django/templates/gregor_anvil/partneruploadworkspace_detail.html
@@ -3,8 +3,23 @@
{% block workspace_data %}
- Partner Group {{ workspace_data_object.partner_group }}
- Consent group {{ workspace_data_object.consent_group }}
+ Partner Group
+ {% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
+ {{ workspace_data_object.partner_group }}
+ {% else %}
+ {{ workspace_data_object.partner_group }}
+ {% endif %}
+
+
+
+ Consent group
+ {% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
+ {{ workspace_data_object.consent_group }}
+ {% else %}
+ {{ workspace_data_object.consent_group }}
+ {% endif %}
+
+
Version {{ workspace_data_object.version }}
Date completed {{ workspace_data_object.date_completed }}
@@ -31,17 +46,3 @@
- Share with auth domain
-
- {% else %}
- no auth domain
- {% endif %}
-{% endif %}
-
-{{ block.super }}
-{% endblock action_buttons %}
diff --git a/gregor_django/templates/gregor_anvil/releaseworkspace_detail.html b/gregor_django/templates/gregor_anvil/releaseworkspace_detail.html
index c35dad75..c2ba3707 100644
--- a/gregor_django/templates/gregor_anvil/releaseworkspace_detail.html
+++ b/gregor_django/templates/gregor_anvil/releaseworkspace_detail.html
@@ -3,7 +3,15 @@
{% block workspace_data %}
- Consent group {{ object.releaseworkspace.consent_group }}
+
+ Consent group
+ {% if perms.anvil_consortium_manager.anvil_consortium_manager_staff_view %}
+ {{ workspace_data_object.consent_group }}
+ {% else %}
+ {{ workspace_data_object.consent_group }}
+ {% endif %}
+
+
dbGaP accession {{ object.releaseworkspace.get_dbgap_accession }}
Upload cycle {{ object.releaseworkspace.upload_cycle }}
From dc6df37facf39e9b8ae0a21c807fbe435e064645 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 23 Oct 2024 15:10:02 -0700
Subject: [PATCH 16/49] Improve tests checking for main ACM index link
---
.../gregor_anvil/tests/test_views.py | 25 ++++++-------------
1 file changed, 8 insertions(+), 17 deletions(-)
diff --git a/gregor_django/gregor_anvil/tests/test_views.py b/gregor_django/gregor_anvil/tests/test_views.py
index 40774942..01e9d227 100644
--- a/gregor_django/gregor_anvil/tests/test_views.py
+++ b/gregor_django/gregor_anvil/tests/test_views.py
@@ -50,8 +50,10 @@ def test_acm_link_without_permission(self):
user = User.objects.create_user(username="test-none", password="test-none")
self.client.force_login(user)
response = self.client.get(self.get_url())
- self.assertNotIn("AnVIL Consortium Manager", response.rendered_content)
- self.assertNotIn(reverse("anvil_consortium_manager:index"), response.rendered_content)
+ html = """AnVIL Consortium Manager """.format(
+ reverse("anvil_consortium_manager:index")
+ )
+ self.assertNotContains(response, html, html=True)
def test_acm_link_with_view_permission(self):
"""ACM link shows up if you have view permission."""
@@ -61,8 +63,10 @@ def test_acm_link_with_view_permission(self):
)
self.client.force_login(user)
response = self.client.get(self.get_url())
- self.assertIn("AnVIL Consortium Manager", response.rendered_content)
- self.assertIn(reverse("anvil_consortium_manager:index"), response.rendered_content)
+ html = """AnVIL Consortium Manager """.format(
+ reverse("anvil_consortium_manager:index")
+ )
+ self.assertContains(response, html, html=True)
def test_acm_link_with_view_and_edit_permission(self):
"""ACM link shows up if you have view and edit permission."""
@@ -78,19 +82,6 @@ def test_acm_link_with_view_and_edit_permission(self):
self.assertIn("AnVIL Consortium Manager", response.rendered_content)
self.assertIn(reverse("anvil_consortium_manager:index"), response.rendered_content)
- def test_acm_link_with_edit_but_not_view_permission(self):
- """ACM link does not show up if you only have edit permission.
-
- This is something that shouldn't happen but could if admin only gave EDIT but not VIEW permission."""
- user = User.objects.create_user(username="test-none", password="test-none")
- user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
- )
- self.client.force_login(user)
- response = self.client.get(self.get_url())
- self.assertNotIn("AnVIL Consortium Manager", response.rendered_content)
- self.assertNotIn(reverse("anvil_consortium_manager:index"), response.rendered_content)
-
def test_site_announcement_no_text(self):
user = User.objects.create_user(username="test-none", password="test-none")
self.client.force_login(user)
From 173831cfe72c28cc176aa895fbf981fc6c684b38 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 23 Oct 2024 15:10:17 -0700
Subject: [PATCH 17/49] Run ruff format
---
gregor_django/gregor_anvil/tests/test_migrations.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/gregor_django/gregor_anvil/tests/test_migrations.py b/gregor_django/gregor_anvil/tests/test_migrations.py
index fb377f31..0c0ed727 100644
--- a/gregor_django/gregor_anvil/tests/test_migrations.py
+++ b/gregor_django/gregor_anvil/tests/test_migrations.py
@@ -458,7 +458,9 @@ def prepare(self):
)
WorkspaceGroupSharing = self.old_state.apps.get_model("anvil_consortium_manager", "WorkspaceGroupSharing")
UploadCycle = self.old_state.apps.get_model("gregor_anvil", "UploadCycle")
- CombinedConsortiumDataWorkspace = self.old_state.apps.get_model("gregor_anvil", "CombinedConsortiumDataWorkspace")
+ CombinedConsortiumDataWorkspace = self.old_state.apps.get_model(
+ "gregor_anvil", "CombinedConsortiumDataWorkspace"
+ )
# Create an auth domain for the combined workspaces.
auth_domain_group = ManagedGroup.objects.create(
name="auth_domain",
@@ -517,7 +519,9 @@ def prepare(self):
)
def test_date_completed(self):
- CombinedConsortiumDataWorkspace = self.new_state.apps.get_model("gregor_anvil", "CombinedConsortiumDataWorkspace")
+ CombinedConsortiumDataWorkspace = self.new_state.apps.get_model(
+ "gregor_anvil", "CombinedConsortiumDataWorkspace"
+ )
workspace = CombinedConsortiumDataWorkspace.objects.get(pk=self.combined_workspace_shared.pk)
self.assertEqual(workspace.date_completed, self.date_shared)
workspace = CombinedConsortiumDataWorkspace.objects.get(pk=self.combined_workspace_not_shared.pk)
From 6a3698b7e8ab95c5533ca30066e90d923b864fe1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 8 Nov 2024 19:21:36 +0000
Subject: [PATCH 18/49] Bump werkzeug from 3.1.2 to 3.1.3
Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.1.2 to 3.1.3.
- [Release notes](https://github.com/pallets/werkzeug/releases)
- [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/werkzeug/compare/3.1.2...3.1.3)
---
updated-dependencies:
- dependency-name: werkzeug
dependency-type: direct:development
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
requirements/dev-requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/dev-requirements.txt b/requirements/dev-requirements.txt
index 21e1b81e..1cf75277 100644
--- a/requirements/dev-requirements.txt
+++ b/requirements/dev-requirements.txt
@@ -233,7 +233,7 @@ wcwidth==0.2.13
# via prompt-toolkit
websockets==12.0
# via sphinx-autobuild
-werkzeug==3.1.2
+werkzeug==3.1.3
# via -r requirements/dev-requirements.in
# The following packages are considered to be unsafe in a requirements file:
From 51b57234866249377feb194549ec7c982db8b16b Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 12 Nov 2024 11:02:55 -0800
Subject: [PATCH 19/49] Switch ACM to v0.26 in requirements file
---
requirements/requirements.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.in b/requirements/requirements.in
index e39662ee..ad7b93f0 100644
--- a/requirements/requirements.in
+++ b/requirements/requirements.in
@@ -35,7 +35,7 @@ django-extensions # https://github.com/django-extensions/django-extensions
# Bootstrap5 templates for crispy-forms
crispy-bootstrap5 # https://github.com/django-crispy-forms/crispy-bootstrap5
-django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.25
+django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
# Simple history - model history tracking
django-simple-history
From 8c4c6ab35d4117e5d474acbbabbd4afc627a3659 Mon Sep 17 00:00:00 2001
From: amstilp <3944584+amstilp@users.noreply.github.com>
Date: Tue, 12 Nov 2024 19:04:23 +0000
Subject: [PATCH 20/49] Compile requirements files
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index cac76c2f..0939fc4d 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -52,7 +52,7 @@ django==4.2.16
# django-tables2
django-allauth==65.1.0
# via -r requirements/requirements.in
-django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.25
+django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
# via -r requirements/requirements.in
django-autocomplete-light==3.11.0
# via django-anvil-consortium-manager
From 5fcdcf806fa1b9dd808ee272f0bc513b1d582b48 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 12 Nov 2024 11:48:38 -0800
Subject: [PATCH 21/49] Move account related settings into adapter
This was a change in ACM v0.26.
---
config/settings/base.py | 6 ------
gregor_django/gregor_anvil/adapters.py | 3 +++
2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/config/settings/base.py b/config/settings/base.py
index f33bb9ec..f62767cc 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -388,12 +388,6 @@
ANVIL_ACCOUNT_ADAPTER = "gregor_django.gregor_anvil.adapters.AccountAdapter"
ANVIL_MANAGED_GROUP_ADAPTER = "gregor_django.gregor_anvil.adapters.ManagedGroupAdapter"
-# Specify the URL name that AccountLink and AccountLinkVerify redirect to.
-ANVIL_ACCOUNT_LINK_REDIRECT = "users:redirect"
-# Specify the subject for AnVIL account verification emails.
-ANVIL_ACCOUNT_LINK_EMAIL_SUBJECT = "Verify your AnVIL account email"
-ANVIL_ACCOUNT_VERIFY_NOTIFICATION_EMAIL = "gregorconsortium@uw.edu"
-
DRUPAL_API_CLIENT_ID = env("DRUPAL_API_CLIENT_ID", default="")
DRUPAL_API_CLIENT_SECRET = env("DRUPAL_API_CLIENT_SECRET", default="")
DRUPAL_API_REL_PATH = env("DRUPAL_API_REL_PATH", default="mockapi")
diff --git a/gregor_django/gregor_anvil/adapters.py b/gregor_django/gregor_anvil/adapters.py
index 8cf97765..1583d234 100644
--- a/gregor_django/gregor_anvil/adapters.py
+++ b/gregor_django/gregor_anvil/adapters.py
@@ -67,6 +67,9 @@ class AccountAdapter(BaseAccountAdapter):
list_table_class = tables.AccountTable
list_filterset_class = filters.AccountListFilter
+ # account_link_verify_redirect = "users:redirect"
+ # account_link_email_subject = "Verify your AnVIL account email"
+ # account_verify_notification_email = "gregorconsortium@uw.edu"
def get_autocomplete_queryset(self, queryset, q):
"""Filter to Accounts where the email or the associated user name matches the query `q`."""
From 2bc9f018e53df56c38387984371fe5d7876eeb12 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 12 Nov 2024 12:01:30 -0800
Subject: [PATCH 22/49] Uncomment lines in account adapter
---
gregor_django/gregor_anvil/adapters.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/gregor_django/gregor_anvil/adapters.py b/gregor_django/gregor_anvil/adapters.py
index 1583d234..894542fd 100644
--- a/gregor_django/gregor_anvil/adapters.py
+++ b/gregor_django/gregor_anvil/adapters.py
@@ -67,9 +67,9 @@ class AccountAdapter(BaseAccountAdapter):
list_table_class = tables.AccountTable
list_filterset_class = filters.AccountListFilter
- # account_link_verify_redirect = "users:redirect"
- # account_link_email_subject = "Verify your AnVIL account email"
- # account_verify_notification_email = "gregorconsortium@uw.edu"
+ account_link_verify_redirect = "users:redirect"
+ account_link_email_subject = "Verify your AnVIL account email"
+ account_verify_notification_email = "gregorconsortium@uw.edu"
def get_autocomplete_queryset(self, queryset, q):
"""Filter to Accounts where the email or the associated user name matches the query `q`."""
From b07e1fb2d28ae725cc89f31453632cf7dfc4ccd6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 12 Nov 2024 20:28:06 +0000
Subject: [PATCH 23/49] Bump django-allauth from 65.1.0 to 65.2.0
Bumps [django-allauth](https://github.com/sponsors/pennersr) from 65.1.0 to 65.2.0.
- [Commits](https://github.com/sponsors/pennersr/commits)
---
updated-dependencies:
- dependency-name: django-allauth
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 0939fc4d..664ccaea 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -50,7 +50,7 @@ django==4.2.16
# django-picklefield
# django-simple-history
# django-tables2
-django-allauth==65.1.0
+django-allauth==65.2.0
# via -r requirements/requirements.in
django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
# via -r requirements/requirements.in
From aeda04230d09f3cf72ecdcb798679d4575c9096f Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 12 Nov 2024 13:24:44 -0800
Subject: [PATCH 24/49] Update text on home page
---
gregor_django/templates/pages/home.html | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/gregor_django/templates/pages/home.html b/gregor_django/templates/pages/home.html
index 8687c2b9..5cb63ad8 100644
--- a/gregor_django/templates/pages/home.html
+++ b/gregor_django/templates/pages/home.html
@@ -7,13 +7,12 @@
GREGoR AnVIL app
- Data for the GREGoR consortium is stored in workspaces on the AnVIL platform .
- Data are added to the workspaces during "upload cycles" that occur every 3 months.
- After the upload cycle is complete, the DCC performs QC, creates a combined data workspace, and shares it with the consortium.
- More information can be found in the Consortium Data page on the main GREGoR consortium website.
- This app facilitates the creation and sharing of workspaces for GREGoR.
+ The GREGoR Consortium leverages the NHGRI Analysis Visualization and Informatics Lab (AnVIL) for rapid Consortium data sharing and release to the broader scientific community.
+ Consortium members upload data to workspaces on the AnVIL platform every calendar quarter (“upload cycle”).
+ Uploaded data are combined into a Consortium dataset after each upload cycle, and the dataset is shared with Consortium members.
+ The Data Coordinating Center (DCC) developed and utilizes this app, the AnVIL Consortium Manager, to manage various workspace types that facilitate the data uploading process, as well as subsequent data processing and synthesis procedures.
+ More information about Consortium data, including how to access and how to get started with working with the data, can be found on the GREGoR website .
-
From 54de6ef41bb0e6ac108c107674f908363ba8128c Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 12 Nov 2024 13:32:37 -0800
Subject: [PATCH 25/49] Add custom text to UploadWorkspace list page
---
gregor_django/gregor_anvil/adapters.py | 1 +
.../gregor_anvil/uploadworkspace_list.html | 42 +++++++++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 gregor_django/templates/gregor_anvil/uploadworkspace_list.html
diff --git a/gregor_django/gregor_anvil/adapters.py b/gregor_django/gregor_anvil/adapters.py
index 894542fd..1c207087 100644
--- a/gregor_django/gregor_anvil/adapters.py
+++ b/gregor_django/gregor_anvil/adapters.py
@@ -118,6 +118,7 @@ class UploadWorkspaceAdapter(WorkspaceAdminSharingAdapterMixin, BaseWorkspaceAda
workspace_data_form_class = forms.UploadWorkspaceForm
workspace_form_class = WorkspaceForm
workspace_detail_template_name = "gregor_anvil/uploadworkspace_detail.html"
+ workspace_list_template_name = "gregor_anvil/uploadworkspace_list.html"
def get_autocomplete_queryset(self, queryset, q, forwarded={}):
"""Filter to Accounts where the email or the associated user name matches the query `q`."""
diff --git a/gregor_django/templates/gregor_anvil/uploadworkspace_list.html b/gregor_django/templates/gregor_anvil/uploadworkspace_list.html
new file mode 100644
index 00000000..4c4b0a91
--- /dev/null
+++ b/gregor_django/templates/gregor_anvil/uploadworkspace_list.html
@@ -0,0 +1,42 @@
+{% extends "anvil_consortium_manager/base.html" %}
+{% load static %}
+
+{% load render_table from django_tables2 %}
+{% load crispy_forms_tags %}
+
+{% block title %}{{workspace_type_display_name}}s{% endblock %}
+
+{% block content %}
+
+
+
+
+
{{workspace_type_display_name}}s
+
+
+
+ This page lists all available workspaces that contain data uploaded by Research Centers (RCs) in a given upload cycle.
+ Upload workspaces are unique to an RC, consent group (GRU or HMB), and upload cycle.
+
+
+ Current upload cycle workspaces are accessible to an RC's members who are approved by their PI for uploader and/or reader access.
+ Previous upload cycles workspaces are accessible to all GREGoR members who are approved for reader access.
+
+
+ Learn more about Accessing Consortium Data .
+
+
+
+
+
+ {% crispy filter.form %}
+
+
+ {% render_table table %}
+
+
+
+
+
+
+{% endblock content %}
From 38bfe8a3b75f58b39c2aee73a948cc1b235f81a3 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 12 Nov 2024 13:34:39 -0800
Subject: [PATCH 26/49] Add custom text to combined workspace page
---
gregor_django/gregor_anvil/adapters.py | 1 +
.../combinedconsortiumdataworkspace_list.html | 39 +++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_list.html
diff --git a/gregor_django/gregor_anvil/adapters.py b/gregor_django/gregor_anvil/adapters.py
index 1c207087..0f1fa645 100644
--- a/gregor_django/gregor_anvil/adapters.py
+++ b/gregor_django/gregor_anvil/adapters.py
@@ -193,6 +193,7 @@ class CombinedConsortiumDataWorkspaceAdapter(WorkspaceAdminSharingAdapterMixin,
workspace_data_form_class = forms.CombinedConsortiumDataWorkspaceForm
workspace_detail_template_name = "gregor_anvil/combinedconsortiumdataworkspace_detail.html"
workspace_form_class = WorkspaceForm
+ workspace_list_template_name = "gregor_anvil/combinedconsortiumdataworkspace_list.html"
class ReleaseWorkspaceAdapter(WorkspaceAdminSharingAdapterMixin, BaseWorkspaceAdapter):
diff --git a/gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_list.html b/gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_list.html
new file mode 100644
index 00000000..d03c8687
--- /dev/null
+++ b/gregor_django/templates/gregor_anvil/combinedconsortiumdataworkspace_list.html
@@ -0,0 +1,39 @@
+{% extends "anvil_consortium_manager/base.html" %}
+{% load static %}
+
+{% load render_table from django_tables2 %}
+{% load crispy_forms_tags %}
+
+{% block title %}{{workspace_type_display_name}}s{% endblock %}
+
+{% block content %}
+
+
+
+
+
{{workspace_type_display_name}}s
+
+
+
+ This page lists all available workspaces that contain data tables combined across upload workspaces up to a given upload cycle.
+ Combined consortium data workspaces are accessible to all GREGoR members who are approved for reader access.
+ The most recent combined workspace is a good place to begin working with GREGoR data on AnVIL!
+
+
+ Learn more about Accessing Consortium Data .
+
+
+
+
+
+ {% crispy filter.form %}
+
+
+ {% render_table table %}
+
+
+
+
+
+
+{% endblock content %}
From fe2536eba16b3b1673593e52da9c9352da9f3ae0 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 12 Nov 2024 13:36:21 -0800
Subject: [PATCH 27/49] Add custom text to exchange workspace template
---
gregor_django/gregor_anvil/adapters.py | 1 +
.../gregor_anvil/exchangeworkspace_list.html | 38 +++++++++++++++++++
2 files changed, 39 insertions(+)
create mode 100644 gregor_django/templates/gregor_anvil/exchangeworkspace_list.html
diff --git a/gregor_django/gregor_anvil/adapters.py b/gregor_django/gregor_anvil/adapters.py
index 0f1fa645..f0192b27 100644
--- a/gregor_django/gregor_anvil/adapters.py
+++ b/gregor_django/gregor_anvil/adapters.py
@@ -250,3 +250,4 @@ class ExchangeWorkspaceAdapter(WorkspaceAdminSharingAdapterMixin, BaseWorkspaceA
workspace_data_form_class = forms.ExchangeWorkspaceForm
workspace_form_class = WorkspaceForm
workspace_detail_template_name = "gregor_anvil/exchangeworkspace_detail.html"
+ workspace_list_template_name = "gregor_anvil/exchangeworkspace_list.html"
diff --git a/gregor_django/templates/gregor_anvil/exchangeworkspace_list.html b/gregor_django/templates/gregor_anvil/exchangeworkspace_list.html
new file mode 100644
index 00000000..5baa5ea5
--- /dev/null
+++ b/gregor_django/templates/gregor_anvil/exchangeworkspace_list.html
@@ -0,0 +1,38 @@
+{% extends "anvil_consortium_manager/base.html" %}
+{% load static %}
+
+{% load render_table from django_tables2 %}
+{% load crispy_forms_tags %}
+
+{% block title %}{{workspace_type_display_name}}s{% endblock %}
+
+{% block content %}
+
+
+
+
+
{{workspace_type_display_name}}s
+
+
+
+ This page lists workspaces that facilitate data exchange between the Data Coordinating Center and a Research Center (RC) independent of the upload cycle.
+ Each exchange workspace is only accessible to the RC's members who are approved by their PI approved for uploader and/or reader access.
+
+
+ Learn more about Accessing Consortium Data .
+
+
+
+
+
+ {% crispy filter.form %}
+
+
+ {% render_table table %}
+
+
+
+
+
+
+{% endblock content %}
From 0fb96c60994a141cb9296a68e710313e520b929e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 13 Nov 2024 19:41:39 +0000
Subject: [PATCH 28/49] Bump mysqlclient from 2.2.5 to 2.2.6
Bumps [mysqlclient](https://github.com/PyMySQL/mysqlclient) from 2.2.5 to 2.2.6.
- [Release notes](https://github.com/PyMySQL/mysqlclient/releases)
- [Changelog](https://github.com/PyMySQL/mysqlclient/blob/main/HISTORY.rst)
- [Commits](https://github.com/PyMySQL/mysqlclient/commits)
---
updated-dependencies:
- dependency-name: mysqlclient
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 0939fc4d..7125851e 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -97,7 +97,7 @@ idna==3.7
# via requests
jsonapi-requests==0.8.0
# via -r requirements/requirements.in
-mysqlclient==2.2.5
+mysqlclient==2.2.6
# via -r requirements/requirements.in
networkx==3.1
# via django-anvil-consortium-manager
From 37d365c2af5fdada4d0a2d5fe2e192f744f63e8d Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 13 Nov 2024 16:03:52 -0800
Subject: [PATCH 29/49] Reorder registered workspace types
Put the workspaces that investigators would be most interested in
at the beginning.
---
config/settings/base.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/config/settings/base.py b/config/settings/base.py
index a6a62ccd..68e9478c 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -380,15 +380,15 @@
# django-anvil-consortium-manager
# ------------------------------------------------------------------------------
ANVIL_WORKSPACE_ADAPTERS = [
- "gregor_django.gregor_anvil.adapters.ResourceWorkspaceAdapter",
- "gregor_django.gregor_anvil.adapters.TemplateWorkspaceAdapter",
+ "gregor_django.gregor_anvil.adapters.CombinedConsortiumDataWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.UploadWorkspaceAdapter",
+ "gregor_django.gregor_anvil.adapters.ResourceWorkspaceAdapter",
+ "gregor_django.gregor_anvil.adapters.ExchangeWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.PartnerUploadWorkspaceAdapter",
- "gregor_django.gregor_anvil.adapters.CombinedConsortiumDataWorkspaceAdapter",
- "gregor_django.gregor_anvil.adapters.ReleaseWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.DCCProcessingWorkspaceAdapter",
"gregor_django.gregor_anvil.adapters.DCCProcessedDataWorkspaceAdapter",
- "gregor_django.gregor_anvil.adapters.ExchangeWorkspaceAdapter",
+ "gregor_django.gregor_anvil.adapters.ReleaseWorkspaceAdapter",
+ "gregor_django.gregor_anvil.adapters.TemplateWorkspaceAdapter",
]
ANVIL_ACCOUNT_ADAPTER = "gregor_django.gregor_anvil.adapters.AccountAdapter"
ANVIL_MANAGED_GROUP_ADAPTER = "gregor_django.gregor_anvil.adapters.ManagedGroupAdapter"
From 8522653dbae61fc1a210c6dc6b1bfa611738e7e3 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Wed, 13 Nov 2024 16:15:16 -0800
Subject: [PATCH 30/49] Allow only 4 maximum processes for pytest
This means it won't eat up all my CPUs locally.
---
pytest.ini | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pytest.ini b/pytest.ini
index 3b3a2e8c..d954c9a2 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --ds=config.settings.test --reuse-db -n auto
+addopts = --ds=config.settings.test --reuse-db -n auto --maxprocesses 4
python_files = tests.py test_*.py
filterwarnings =
# Convert all warnings to errors.
From ab6dcf2290608140424e333762568fddb368cfac Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 15 Nov 2024 19:06:59 +0000
Subject: [PATCH 31/49] Bump ruff from 0.7.2 to 0.7.4
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.7.2 to 0.7.4.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.7.2...0.7.4)
---
updated-dependencies:
- dependency-name: ruff
dependency-type: direct:development
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
requirements/dev-requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/dev-requirements.txt b/requirements/dev-requirements.txt
index 21e1b81e..55ff72e1 100644
--- a/requirements/dev-requirements.txt
+++ b/requirements/dev-requirements.txt
@@ -150,7 +150,7 @@ requests==2.32.3
# -c requirements/requirements.txt
# -c requirements/test-requirements.txt
# sphinx
-ruff==0.7.2
+ruff==0.7.4
# via -r requirements/dev-requirements.in
six==1.16.0
# via
From 62ae5db50a5a12187307c5702b9f5aa828869899 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 21 Nov 2024 19:44:31 +0000
Subject: [PATCH 32/49] Bump codecov/codecov-action from 4.6.0 to 5.0.7
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4.6.0 to 5.0.7.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4.6.0...v5.0.7)
---
updated-dependencies:
- dependency-name: codecov/codecov-action
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
---
.github/workflows/ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 97f12a24..620c4ed7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -140,6 +140,6 @@ jobs:
python -m coverage report
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@v4.6.0
+ uses: codecov/codecov-action@v5.0.7
with:
token: ${{ secrets.CODECOV_TOKEN }}
From 777a730d9fb98299f90641db5256cd3bc35a68a1 Mon Sep 17 00:00:00 2001
From: Jonas Carson
Date: Thu, 21 Nov 2024 12:39:40 -0800
Subject: [PATCH 33/49] Add redirectview for favicon.ico to our custom favicon.
Make redirect view not login protected
---
config/settings/base.py | 1 +
config/urls.py | 3 +++
2 files changed, 4 insertions(+)
diff --git a/config/settings/base.py b/config/settings/base.py
index f62767cc..6dc1850a 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -298,6 +298,7 @@
"socialaccount_signup",
"admin:index",
"admin:login",
+ "favicon"
]
# django-dbbackup
diff --git a/config/urls.py b/config/urls.py
index c5982f85..28948cce 100644
--- a/config/urls.py
+++ b/config/urls.py
@@ -1,9 +1,11 @@
from django.conf import settings
from django.conf.urls.static import static
+from django.templatetags.static import static as static_url_tag
from django.contrib import admin
from django.urls import include, path
from django.views import defaults as default_views
from django.views.generic import TemplateView
+from django.views.generic.base import RedirectView
urlpatterns = [
path("", TemplateView.as_view(template_name="pages/home.html"), name="home"),
@@ -22,6 +24,7 @@
"gregor_anvil/",
include("gregor_django.gregor_anvil.urls", namespace="gregor_anvil"),
),
+ path("favicon.ico", RedirectView.as_view(url=static_url_tag("images/favicons/favicon_1.jpg"), permanent=True), name="favicon"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
From a381456229f015fc5a407bcddcc89ea5d8aff213 Mon Sep 17 00:00:00 2001
From: Jonas Carson
Date: Thu, 21 Nov 2024 12:43:24 -0800
Subject: [PATCH 34/49] Minor linting changes
---
config/settings/base.py | 2 +-
config/urls.py | 8 ++++++--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/config/settings/base.py b/config/settings/base.py
index 6dc1850a..08ed3bcf 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -298,7 +298,7 @@
"socialaccount_signup",
"admin:index",
"admin:login",
- "favicon"
+ "favicon",
]
# django-dbbackup
diff --git a/config/urls.py b/config/urls.py
index 28948cce..df1659ca 100644
--- a/config/urls.py
+++ b/config/urls.py
@@ -1,7 +1,7 @@
from django.conf import settings
from django.conf.urls.static import static
-from django.templatetags.static import static as static_url_tag
from django.contrib import admin
+from django.templatetags.static import static as static_url_tag
from django.urls import include, path
from django.views import defaults as default_views
from django.views.generic import TemplateView
@@ -24,7 +24,11 @@
"gregor_anvil/",
include("gregor_django.gregor_anvil.urls", namespace="gregor_anvil"),
),
- path("favicon.ico", RedirectView.as_view(url=static_url_tag("images/favicons/favicon_1.jpg"), permanent=True), name="favicon"),
+ path(
+ "favicon.ico",
+ RedirectView.as_view(url=static_url_tag("images/favicons/favicon_1.jpg"), permanent=True),
+ name="favicon",
+ ),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
From 9e0958e8370d27e9c5eba2715860366f2861d8ff Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 22 Nov 2024 00:24:37 +0000
Subject: [PATCH 35/49] Bump pyjwt from 2.9.0 to 2.10.0
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.9.0 to 2.10.0.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/compare/2.9.0...2.10.0)
---
updated-dependencies:
- dependency-name: pyjwt
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 59a8dfac..a5c98273 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -123,7 +123,7 @@ pyasn1-modules==0.3.0
# via google-auth
pycparser==2.21
# via cffi
-pyjwt==2.9.0
+pyjwt==2.10.0
# via -r requirements/requirements.in
pyproject-hooks==1.0.0
# via
From c25a2a6f91cdbc7141d3667308ca00db367181c9 Mon Sep 17 00:00:00 2001
From: Jonas Carson
Date: Fri, 22 Nov 2024 08:51:50 -0800
Subject: [PATCH 36/49] Fix breaking change in 2.10 - sub must be a string - to
align with JWT spec
---
gregor_django/drupal_oauth_provider/tests.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gregor_django/drupal_oauth_provider/tests.py b/gregor_django/drupal_oauth_provider/tests.py
index ca2b598d..b133227b 100644
--- a/gregor_django/drupal_oauth_provider/tests.py
+++ b/gregor_django/drupal_oauth_provider/tests.py
@@ -116,7 +116,7 @@ def get_mocked_response(self):
"name": "testmaster",
"email": "test@testmaster.net",
"email_verified": "True",
- "sub": 20122
+ "sub": "20122"
}""",
),
]
@@ -184,7 +184,7 @@ def get_id_token(self):
"iat": self.setup_time,
"aud": allowed_audience,
"scope": ["authenticated", "oauth_client_user"],
- "sub": 20122,
+ "sub": "20122",
}
)
From fd36515016830c5372748952f7eb82448f24631c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 27 Nov 2024 19:05:36 +0000
Subject: [PATCH 37/49] Bump cryptography from 43.0.3 to 44.0.0
Bumps [cryptography](https://github.com/pyca/cryptography) from 43.0.3 to 44.0.0.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/43.0.3...44.0.0)
---
updated-dependencies:
- dependency-name: cryptography
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index a5c98273..9d398406 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -32,7 +32,7 @@ crispy-bootstrap5==2024.10
# via
# -r requirements/requirements.in
# django-anvil-consortium-manager
-cryptography==43.0.3
+cryptography==44.0.0
# via -r requirements/requirements.in
django==4.2.16
# via
From 0f2db2872afbbce8bda3267fac84e536a0dd467c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 28 Nov 2024 19:41:38 +0000
Subject: [PATCH 38/49] Bump pyjwt from 2.10.0 to 2.10.1
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.10.0 to 2.10.1.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/compare/2.10.0...2.10.1)
---
updated-dependencies:
- dependency-name: pyjwt
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index a5c98273..61a9a546 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -123,7 +123,7 @@ pyasn1-modules==0.3.0
# via google-auth
pycparser==2.21
# via cffi
-pyjwt==2.10.0
+pyjwt==2.10.1
# via -r requirements/requirements.in
pyproject-hooks==1.0.0
# via
From 90c51da2ba92327a7a816ee1e786d76a934a83df Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 29 Nov 2024 19:42:34 +0000
Subject: [PATCH 39/49] Bump ruff from 0.7.4 to 0.8.1
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.7.4 to 0.8.1.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.7.4...0.8.1)
---
updated-dependencies:
- dependency-name: ruff
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
requirements/dev-requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/dev-requirements.txt b/requirements/dev-requirements.txt
index 3df2ab06..ca4dd453 100644
--- a/requirements/dev-requirements.txt
+++ b/requirements/dev-requirements.txt
@@ -150,7 +150,7 @@ requests==2.32.3
# -c requirements/requirements.txt
# -c requirements/test-requirements.txt
# sphinx
-ruff==0.7.4
+ruff==0.8.1
# via -r requirements/dev-requirements.in
six==1.16.0
# via
From 7bfad31aa7a5026c936f81af2865106cab804483 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 2 Dec 2024 16:25:41 +0000
Subject: [PATCH 40/49] [pre-commit.ci] pre-commit autoupdate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.7.0 → v0.8.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.0...v0.8.1)
- [github.com/gitleaks/gitleaks: v8.21.1 → v8.21.2](https://github.com/gitleaks/gitleaks/compare/v8.21.1...v8.21.2)
---
.pre-commit-config.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 34714409..9c8f14bf 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -12,7 +12,7 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
- rev: v0.7.0
+ rev: v0.8.1
hooks:
# Run the linter.
- id: ruff
@@ -21,7 +21,7 @@ repos:
- id: ruff-format
- repo: https://github.com/gitleaks/gitleaks
- rev: v8.21.1
+ rev: v8.21.2
hooks:
- id: gitleaks
From 1bb11305f6b08631c4e9be6b3cf12253f0c294cc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Dec 2024 18:44:32 +0000
Subject: [PATCH 41/49] Bump pyjwt from 2.10.0 to 2.10.1 in /requirements
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.10.0 to 2.10.1.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/compare/2.10.0...2.10.1)
---
updated-dependencies:
- dependency-name: pyjwt
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
requirements/requirements.txt | 54 +++++++++++++++++------------------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index a5c98273..d159b267 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -5,12 +5,12 @@
# pip-compile requirements/requirements.in
#
argon2-cffi==23.1.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
argon2-cffi-bindings==21.2.0
# via argon2-cffi
asgiref==3.8.1
# via
- # -r requirements/requirements.in
+ # -r requirements.in
# django
# django-allauth
# django-htmx
@@ -30,13 +30,13 @@ click==8.1.7
# via pip-tools
crispy-bootstrap5==2024.10
# via
- # -r requirements/requirements.in
+ # -r requirements.in
# django-anvil-consortium-manager
cryptography==43.0.3
- # via -r requirements/requirements.in
+ # via -r requirements.in
django==4.2.16
# via
- # -r requirements/requirements.in
+ # -r requirements.in
# crispy-bootstrap5
# django-allauth
# django-anvil-consortium-manager
@@ -51,41 +51,41 @@ django==4.2.16
# django-simple-history
# django-tables2
django-allauth==65.2.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-autocomplete-light==3.11.0
# via django-anvil-consortium-manager
django-constance==4.1.3
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-crispy-forms==2.3
# via
- # -r requirements/requirements.in
+ # -r requirements.in
# crispy-bootstrap5
# django-anvil-consortium-manager
django-dbbackup==4.2.1
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-environ==0.10.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-extensions==3.2.1
# via
- # -r requirements/requirements.in
+ # -r requirements.in
# django-anvil-consortium-manager
django-filter==23.5
# via django-anvil-consortium-manager
django-htmx==1.21.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-login-required-middleware==0.9.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-maintenance-mode==0.21.1
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-model-utils==5.0.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-picklefield==3.2
- # via -r requirements/requirements.in
+ # via -r requirements.in
django-simple-history==3.7.0
# via
- # -r requirements/requirements.in
+ # -r requirements.in
# django-anvil-consortium-manager
django-tables2==2.7.0
# via django-anvil-consortium-manager
@@ -96,23 +96,23 @@ google-auth==2.11.0
idna==3.7
# via requests
jsonapi-requests==0.8.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
mysqlclient==2.2.6
- # via -r requirements/requirements.in
+ # via -r requirements.in
networkx==3.1
# via django-anvil-consortium-manager
numpy==1.24.4
# via django-anvil-consortium-manager
oauthlib==3.2.2
# via
- # -r requirements/requirements.in
+ # -r requirements.in
# requests-oauthlib
packaging==23.2
# via
# build
# plotly
pip-tools==7.4.1
- # via -r requirements/requirements.in
+ # via -r requirements.in
plotly==5.19.0
# via django-anvil-consortium-manager
pyasn1==0.4.8
@@ -123,8 +123,8 @@ pyasn1-modules==0.3.0
# via google-auth
pycparser==2.21
# via cffi
-pyjwt==2.10.0
- # via -r requirements/requirements.in
+pyjwt==2.10.1
+ # via -r requirements.in
pyproject-hooks==1.0.0
# via
# build
@@ -141,7 +141,7 @@ requests==2.32.3
# jsonapi-requests
# requests-oauthlib
requests-oauthlib==2.0.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
rsa==4.9
# via google-auth
six==1.16.0
@@ -149,7 +149,7 @@ six==1.16.0
sqlparse==0.5.1
# via django
tablib==3.7.0
- # via -r requirements/requirements.in
+ # via -r requirements.in
tenacity==8.2.3
# via
# jsonapi-requests
@@ -166,7 +166,7 @@ urllib3==2.2.2
wheel==0.42.0
# via pip-tools
whitenoise==6.8.2
- # via -r requirements/requirements.in
+ # via -r requirements.in
# The following packages are considered to be unsafe in a requirements file:
# pip
From 5f2fc748cbe2c50bb26c1ceee04898762c39ef1a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Dec 2024 18:45:11 +0000
Subject: [PATCH 42/49] Compile requirements files
---
requirements/requirements.txt | 52 +++++++++++++++++------------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index d159b267..61a9a546 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -5,12 +5,12 @@
# pip-compile requirements/requirements.in
#
argon2-cffi==23.1.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
argon2-cffi-bindings==21.2.0
# via argon2-cffi
asgiref==3.8.1
# via
- # -r requirements.in
+ # -r requirements/requirements.in
# django
# django-allauth
# django-htmx
@@ -30,13 +30,13 @@ click==8.1.7
# via pip-tools
crispy-bootstrap5==2024.10
# via
- # -r requirements.in
+ # -r requirements/requirements.in
# django-anvil-consortium-manager
cryptography==43.0.3
- # via -r requirements.in
+ # via -r requirements/requirements.in
django==4.2.16
# via
- # -r requirements.in
+ # -r requirements/requirements.in
# crispy-bootstrap5
# django-allauth
# django-anvil-consortium-manager
@@ -51,41 +51,41 @@ django==4.2.16
# django-simple-history
# django-tables2
django-allauth==65.2.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-autocomplete-light==3.11.0
# via django-anvil-consortium-manager
django-constance==4.1.3
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-crispy-forms==2.3
# via
- # -r requirements.in
+ # -r requirements/requirements.in
# crispy-bootstrap5
# django-anvil-consortium-manager
django-dbbackup==4.2.1
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-environ==0.10.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-extensions==3.2.1
# via
- # -r requirements.in
+ # -r requirements/requirements.in
# django-anvil-consortium-manager
django-filter==23.5
# via django-anvil-consortium-manager
django-htmx==1.21.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-login-required-middleware==0.9.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-maintenance-mode==0.21.1
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-model-utils==5.0.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-picklefield==3.2
- # via -r requirements.in
+ # via -r requirements/requirements.in
django-simple-history==3.7.0
# via
- # -r requirements.in
+ # -r requirements/requirements.in
# django-anvil-consortium-manager
django-tables2==2.7.0
# via django-anvil-consortium-manager
@@ -96,23 +96,23 @@ google-auth==2.11.0
idna==3.7
# via requests
jsonapi-requests==0.8.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
mysqlclient==2.2.6
- # via -r requirements.in
+ # via -r requirements/requirements.in
networkx==3.1
# via django-anvil-consortium-manager
numpy==1.24.4
# via django-anvil-consortium-manager
oauthlib==3.2.2
# via
- # -r requirements.in
+ # -r requirements/requirements.in
# requests-oauthlib
packaging==23.2
# via
# build
# plotly
pip-tools==7.4.1
- # via -r requirements.in
+ # via -r requirements/requirements.in
plotly==5.19.0
# via django-anvil-consortium-manager
pyasn1==0.4.8
@@ -124,7 +124,7 @@ pyasn1-modules==0.3.0
pycparser==2.21
# via cffi
pyjwt==2.10.1
- # via -r requirements.in
+ # via -r requirements/requirements.in
pyproject-hooks==1.0.0
# via
# build
@@ -141,7 +141,7 @@ requests==2.32.3
# jsonapi-requests
# requests-oauthlib
requests-oauthlib==2.0.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
rsa==4.9
# via google-auth
six==1.16.0
@@ -149,7 +149,7 @@ six==1.16.0
sqlparse==0.5.1
# via django
tablib==3.7.0
- # via -r requirements.in
+ # via -r requirements/requirements.in
tenacity==8.2.3
# via
# jsonapi-requests
@@ -166,7 +166,7 @@ urllib3==2.2.2
wheel==0.42.0
# via pip-tools
whitenoise==6.8.2
- # via -r requirements.in
+ # via -r requirements/requirements.in
# The following packages are considered to be unsafe in a requirements file:
# pip
From cbaa6963987ba5eb37c725487fb11c868da78ca4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Dec 2024 20:21:39 +0000
Subject: [PATCH 43/49] Bump django-allauth from 65.2.0 to 65.3.0
Bumps [django-allauth](https://github.com/sponsors/pennersr) from 65.2.0 to 65.3.0.
- [Commits](https://github.com/sponsors/pennersr/commits)
---
updated-dependencies:
- dependency-name: django-allauth
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index a5c98273..2338105c 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -50,7 +50,7 @@ django==4.2.16
# django-picklefield
# django-simple-history
# django-tables2
-django-allauth==65.2.0
+django-allauth==65.3.0
# via -r requirements/requirements.in
django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
# via -r requirements/requirements.in
From 2a62ad673a16fc1e43cbf9c8e59d73a1abe96df7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Dec 2024 20:21:55 +0000
Subject: [PATCH 44/49] Bump pytest from 8.3.3 to 8.3.4
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.3 to 8.3.4.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.3...8.3.4)
---
updated-dependencies:
- dependency-name: pytest
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
requirements/test-requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/test-requirements.txt b/requirements/test-requirements.txt
index 2f6f4a10..52cbfef8 100644
--- a/requirements/test-requirements.txt
+++ b/requirements/test-requirements.txt
@@ -49,7 +49,7 @@ packaging==23.2
# pytest-sugar
pluggy==1.5.0
# via pytest
-pytest==8.3.3
+pytest==8.3.4
# via
# -r requirements/test-requirements.in
# pytest-cov
From 0891a0f8065d02a3ccad2ee3acb31e0c806835f3 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Mon, 2 Dec 2024 15:10:24 -0800
Subject: [PATCH 45/49] Split some tables into staff vs. regular user tables
Also add tests for the tables and for the views using those tables
(WorkspaceList).
---
gregor_django/gregor_anvil/adapters.py | 6 +-
gregor_django/gregor_anvil/tables.py | 43 +++-
.../gregor_anvil/tests/test_tables.py | 131 ++++++++--
.../gregor_anvil/tests/test_views.py | 242 +++++++++++++++++-
4 files changed, 384 insertions(+), 38 deletions(-)
diff --git a/gregor_django/gregor_anvil/adapters.py b/gregor_django/gregor_anvil/adapters.py
index f0192b27..f6939c8a 100644
--- a/gregor_django/gregor_anvil/adapters.py
+++ b/gregor_django/gregor_anvil/adapters.py
@@ -143,7 +143,7 @@ class PartnerUploadWorkspaceAdapter(WorkspaceAdminSharingAdapterMixin, BaseWorks
name = "Partner upload workspace"
description = "Workspaces that contain data uploaded by a Partner Group "
list_table_class_view = tables.PartnerUploadWorkspaceTable
- list_table_class_staff_view = tables.PartnerUploadWorkspaceTable
+ list_table_class_staff_view = tables.PartnerUploadWorkspaceStaffTable
workspace_data_model = models.PartnerUploadWorkspace
workspace_data_form_class = forms.PartnerUploadWorkspaceForm
@@ -160,7 +160,7 @@ class ResourceWorkspaceAdapter(WorkspaceAdminSharingAdapterMixin, BaseWorkspaceA
"Workspaces that contain general Consortium resources (e.g., examples of using AnVIL, working with data, etc.)" # noqa: E501
)
list_table_class_view = tables.DefaultWorkspaceTable
- list_table_class_staff_view = tables.DefaultWorkspaceTable
+ list_table_class_staff_view = tables.DefaultWorkspaceStaffTable
workspace_data_model = models.ResourceWorkspace
workspace_data_form_class = forms.ResourceWorkspaceForm
workspace_detail_template_name = "gregor_anvil/resourceworkspace_detail.html"
@@ -245,7 +245,7 @@ class ExchangeWorkspaceAdapter(WorkspaceAdminSharingAdapterMixin, BaseWorkspaceA
name = "Exchange workspace"
description = "Workspaces for exchanging data with a Research Center outside of an upload cycle"
list_table_class_view = tables.ExchangeWorkspaceTable
- list_table_class_staff_view = tables.ExchangeWorkspaceTable
+ list_table_class_staff_view = tables.ExchangeWorkspaceStaffTable
workspace_data_model = models.ExchangeWorkspace
workspace_data_form_class = forms.ExchangeWorkspaceForm
workspace_form_class = WorkspaceForm
diff --git a/gregor_django/gregor_anvil/tables.py b/gregor_django/gregor_anvil/tables.py
index 23ac7857..d35922cf 100644
--- a/gregor_django/gregor_anvil/tables.py
+++ b/gregor_django/gregor_anvil/tables.py
@@ -154,9 +154,24 @@ def render_consortium_access(self, record):
class DefaultWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
- """Class to use for default workspace tables in GREGoR."""
+ """Class to use for default workspace tables in GREGoR for view users."""
name = tables.Column(linkify=True, verbose_name="Workspace")
+ billing_project = tables.Column()
+
+ class Meta:
+ model = Workspace
+ fields = (
+ "name",
+ "billing_project",
+ "consortium_access",
+ )
+ order_by = ("name",)
+
+
+class DefaultWorkspaceStaffTable(DefaultWorkspaceTable):
+ """Class to use for default workspace tables in GREGoR for staff users."""
+
billing_project = tables.Column(linkify=True)
number_groups = tables.Column(
verbose_name="Number of groups shared with",
@@ -165,15 +180,13 @@ class DefaultWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
accessor="workspacegroupsharing_set__count",
)
- class Meta:
- model = Workspace
+ class Meta(DefaultWorkspaceTable.Meta):
fields = (
"name",
"billing_project",
"number_groups",
"consortium_access",
)
- order_by = ("name",)
class UploadWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
@@ -198,7 +211,7 @@ class PartnerUploadWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
"""A table for Workspaces that includes fields from PartnerUploadWorkspace."""
name = tables.columns.Column(linkify=True)
- partneruploadworkspace__partner_group = tables.columns.Column(linkify=True)
+ partneruploadworkspace__partner_group = tables.columns.Column()
class Meta:
model = Workspace
@@ -212,6 +225,12 @@ class Meta:
)
+class PartnerUploadWorkspaceStaffTable(PartnerUploadWorkspaceTable):
+ """A table for Workspaces that includes fields from PartnerUploadWorkspace."""
+
+ partneruploadworkspace__partner_group = tables.columns.Column(linkify=True)
+
+
class TemplateWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
"""A table for Workspaces that includes fields from TemplateWorkspace."""
@@ -279,6 +298,7 @@ class DCCProcessingWorkspaceTable(tables.Table):
"""A table for Workspaces that includes fields from DCCProcessingWorkspace."""
name = tables.columns.Column(linkify=True)
+ dccprocessingworkspace__upload_cycle = tables.columns.Column(linkify=True)
class Meta:
model = Workspace
@@ -293,7 +313,7 @@ class DCCProcessedDataWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Tabl
"""A table for Workspaces that includes fields from DCCProcessedDataWorkspace."""
name = tables.columns.Column(linkify=True)
- dccprocesseddataworkspace__consent_group = tables.columns.Column(linkify=True)
+ dccprocesseddataworkspace__upload_cycle = tables.columns.Column(linkify=True)
class Meta:
model = Workspace
@@ -309,10 +329,17 @@ class ExchangeWorkspaceTable(tables.Table):
"""Class to use for ExchangeWorkspace tables."""
name = tables.Column(linkify=True, verbose_name="Workspace")
- billing_project = tables.Column(linkify=True)
- exchangeworkspace__research_center = tables.Column(linkify=True)
+ billing_project = tables.Column()
+ exchangeworkspace__research_center = tables.Column()
class Meta:
model = Workspace
fields = ("name", "billing_project", "exchangeworkspace__research_center")
order_by = ("name",)
+
+
+class ExchangeWorkspaceStaffTable(ExchangeWorkspaceTable):
+ """Class to use for ExchangeWorkspace tables."""
+
+ billing_project = tables.Column(linkify=True)
+ exchangeworkspace__research_center = tables.Column(linkify=True)
diff --git a/gregor_django/gregor_anvil/tests/test_tables.py b/gregor_django/gregor_anvil/tests/test_tables.py
index fb5d90c4..01a8434f 100644
--- a/gregor_django/gregor_anvil/tests/test_tables.py
+++ b/gregor_django/gregor_anvil/tests/test_tables.py
@@ -268,10 +268,10 @@ def test_is_shared_one_auth_domain_shared_with_different_group_in_auth_domain(se
self.assertNotIn("check-circle-fill", table.render_consortium_access(workspace))
-class UploadWorkspaceTableTest(TestCase):
+class DefaultWorkspaceTableTest(TestCase):
model = Workspace
- model_factory = factories.UploadWorkspaceFactory
- table_class = tables.UploadWorkspaceTable
+ model_factory = factories.WorkspaceFactory
+ table_class = tables.DefaultWorkspaceTable
def test_row_count_with_no_objects(self):
table = self.table_class(self.model.objects.all())
@@ -289,10 +289,10 @@ def test_row_count_with_two_objects(self):
self.assertEqual(len(table.rows), 2)
-class PartnerUploadWorkspaceTableTest(TestCase):
+class DefaultWorkspaceStaffTableTest(TestCase):
model = Workspace
- model_factory = factories.PartnerUploadWorkspaceFactory
- table_class = tables.PartnerUploadWorkspaceTable
+ model_factory = factories.WorkspaceFactory
+ table_class = tables.DefaultWorkspaceStaffTable
def test_row_count_with_no_objects(self):
table = self.table_class(self.model.objects.all())
@@ -309,11 +309,22 @@ def test_row_count_with_two_objects(self):
table = self.table_class(self.model.objects.all())
self.assertEqual(len(table.rows), 2)
+ def test_number_groups(self):
+ self.model_factory.create(name="aaa")
+ workspace_2 = self.model_factory.create(name="bbb")
+ workspace_3 = self.model_factory.create(name="ccc")
+ WorkspaceGroupSharingFactory.create_batch(1, workspace=workspace_2)
+ WorkspaceGroupSharingFactory.create_batch(2, workspace=workspace_3)
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(table.rows[0].get_cell("number_groups"), 0)
+ self.assertEqual(table.rows[1].get_cell("number_groups"), 1)
+ self.assertEqual(table.rows[2].get_cell("number_groups"), 2)
-class TemplateWorkspaceTableTest(TestCase):
+
+class UploadWorkspaceTableTest(TestCase):
model = Workspace
- model_factory = factories.TemplateWorkspaceFactory
- table_class = tables.TemplateWorkspaceTable
+ model_factory = factories.UploadWorkspaceFactory
+ table_class = tables.UploadWorkspaceTable
def test_row_count_with_no_objects(self):
table = self.table_class(self.model.objects.all())
@@ -331,12 +342,10 @@ def test_row_count_with_two_objects(self):
self.assertEqual(len(table.rows), 2)
-class CombinedConsortiumDataWorkspaceTableTest(TestCase):
- """Tests for the AccountTable in this app."""
-
+class PartnerUploadWorkspaceTableTest(TestCase):
model = Workspace
- model_factory = factories.CombinedConsortiumDataWorkspaceFactory
- table_class = tables.CombinedConsortiumDataWorkspaceTable
+ model_factory = factories.PartnerUploadWorkspaceFactory
+ table_class = tables.PartnerUploadWorkspaceTable
def test_row_count_with_no_objects(self):
table = self.table_class(self.model.objects.all())
@@ -348,17 +357,37 @@ def test_row_count_with_one_object(self):
self.assertEqual(len(table.rows), 1)
def test_row_count_with_two_objects(self):
+ # These values are coded into the model, so need to create separately.
self.model_factory.create_batch(2)
table = self.table_class(self.model.objects.all())
self.assertEqual(len(table.rows), 2)
-class ReleaseWorkspaceTableTest(TestCase):
- """Tests for the AccountTable in this app."""
+class PartnerUploadWorkspaceStaffTableTest(TestCase):
+ model = Workspace
+ model_factory = factories.PartnerUploadWorkspaceFactory
+ table_class = tables.PartnerUploadWorkspaceStaffTable
+
+ def test_row_count_with_no_objects(self):
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 0)
+ def test_row_count_with_one_object(self):
+ self.model_factory.create()
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 1)
+
+ def test_row_count_with_two_objects(self):
+ # These values are coded into the model, so need to create separately.
+ self.model_factory.create_batch(2)
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 2)
+
+
+class TemplateWorkspaceTableTest(TestCase):
model = Workspace
- model_factory = factories.ReleaseWorkspaceFactory
- table_class = tables.ReleaseWorkspaceTable
+ model_factory = factories.TemplateWorkspaceFactory
+ table_class = tables.TemplateWorkspaceTable
def test_row_count_with_no_objects(self):
table = self.table_class(self.model.objects.all())
@@ -370,6 +399,7 @@ def test_row_count_with_one_object(self):
self.assertEqual(len(table.rows), 1)
def test_row_count_with_two_objects(self):
+ # These values are coded into the model, so need to create separately.
self.model_factory.create_batch(2)
table = self.table_class(self.model.objects.all())
self.assertEqual(len(table.rows), 2)
@@ -411,6 +441,50 @@ def test_row_count_with_two_workspace_types(self):
self.assertEqual(len(table.rows), 2)
+class CombinedConsortiumDataWorkspaceTableTest(TestCase):
+ """Tests for the AccountTable in this app."""
+
+ model = Workspace
+ model_factory = factories.CombinedConsortiumDataWorkspaceFactory
+ table_class = tables.CombinedConsortiumDataWorkspaceTable
+
+ def test_row_count_with_no_objects(self):
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 0)
+
+ def test_row_count_with_one_object(self):
+ self.model_factory.create()
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 1)
+
+ def test_row_count_with_two_objects(self):
+ self.model_factory.create_batch(2)
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 2)
+
+
+class ReleaseWorkspaceTableTest(TestCase):
+ """Tests for the AccountTable in this app."""
+
+ model = Workspace
+ model_factory = factories.ReleaseWorkspaceFactory
+ table_class = tables.ReleaseWorkspaceTable
+
+ def test_row_count_with_no_objects(self):
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 0)
+
+ def test_row_count_with_one_object(self):
+ self.model_factory.create()
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 1)
+
+ def test_row_count_with_two_objects(self):
+ self.model_factory.create_batch(2)
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 2)
+
+
class DCCProcessingWorkspaceTableTest(TestCase):
model = Workspace
model_factory = factories.DCCProcessingWorkspaceFactory
@@ -472,3 +546,24 @@ def test_row_count_with_two_objects(self):
self.model_factory.create_batch(2)
table = self.table_class(self.model.objects.all())
self.assertEqual(len(table.rows), 2)
+
+
+class ExchangeWorkspaceStaffTableTest(TestCase):
+ model = Workspace
+ model_factory = factories.ExchangeWorkspaceFactory
+ table_class = tables.ExchangeWorkspaceStaffTable
+
+ def test_row_count_with_no_objects(self):
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 0)
+
+ def test_row_count_with_one_object(self):
+ self.model_factory.create()
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 1)
+
+ def test_row_count_with_two_objects(self):
+ # These values are coded into the model, so need to create separately.
+ self.model_factory.create_batch(2)
+ table = self.table_class(self.model.objects.all())
+ self.assertEqual(len(table.rows), 2)
diff --git a/gregor_django/gregor_anvil/tests/test_views.py b/gregor_django/gregor_anvil/tests/test_views.py
index 01e9d227..5621418b 100644
--- a/gregor_django/gregor_anvil/tests/test_views.py
+++ b/gregor_django/gregor_anvil/tests/test_views.py
@@ -24,7 +24,7 @@
from gregor_django.users.tables import UserTable
from gregor_django.users.tests.factories import UserFactory
-from .. import forms, models, tables, views
+from .. import adapters, forms, models, tables, views
from ..audit import (
combined_workspace_audit,
upload_workspace_audit,
@@ -1493,12 +1493,23 @@ def get_url(self, *args):
"""Get the url for the view being tested."""
return reverse("anvil_consortium_manager:workspaces:list", args=args)
- def test_view_has_correct_table_class(self):
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.UploadWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
"""The view has the correct table class in the context."""
self.client.force_login(self.user)
response = self.client.get(self.get_url(self.workspace_type))
self.assertIn("table", response.context_data)
- self.assertIsInstance(response.context_data["table"], tables.UploadWorkspaceTable)
+ self.assertIs(type(response.context_data["table"]), tables.UploadWorkspaceTable)
class UploadWorkspaceCreateTest(AnVILAPIMockTestMixin, TestCase):
@@ -1752,12 +1763,23 @@ def get_url(self, *args):
"""Get the url for the view being tested."""
return reverse("anvil_consortium_manager:workspaces:list", args=args)
- def test_view_has_correct_table_class(self):
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.DefaultWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
"""The view has the correct table class in the context."""
self.client.force_login(self.user)
response = self.client.get(self.get_url(self.workspace_type))
self.assertIn("table", response.context_data)
- self.assertIsInstance(response.context_data["table"], tables.DefaultWorkspaceTable)
+ self.assertIs(type(response.context_data["table"]), tables.DefaultWorkspaceStaffTable)
class ResourceWorkspaceCreateTest(AnVILAPIMockTestMixin, TestCase):
@@ -1882,12 +1904,23 @@ def get_url(self, *args):
"""Get the url for the view being tested."""
return reverse("anvil_consortium_manager:workspaces:list", args=args)
- def test_view_has_correct_table_class(self):
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.TemplateWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
"""The view has the correct table class in the context."""
self.client.force_login(self.user)
response = self.client.get(self.get_url(self.workspace_type))
self.assertIn("table", response.context_data)
- self.assertIsInstance(response.context_data["table"], tables.TemplateWorkspaceTable)
+ self.assertIs(type(response.context_data["table"]), tables.TemplateWorkspaceTable)
class TemplateWorkspaceCreateTest(AnVILAPIMockTestMixin, TestCase):
@@ -1971,6 +2004,42 @@ def test_creates_upload_workspace(self):
self.assertEqual(new_workspace_data.intended_use, "foo bar")
+class ConsortiumCombinedDataWorkspaceListTest(TestCase):
+ """Tests of the anvil_consortium_manager WorkspaceList view using this app's adapter."""
+
+ def setUp(self):
+ """Set up test class."""
+ self.factory = RequestFactory()
+ # Create a user with both view and edit permission.
+ self.user = User.objects.create_user(username="test", password="test")
+ self.user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.workspace_type = "combined_consortium"
+
+ def get_url(self, *args):
+ """Get the url for the view being tested."""
+ return reverse("anvil_consortium_manager:workspaces:list", args=args)
+
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.CombinedConsortiumDataWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
+ """The view has the correct table class in the context."""
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.CombinedConsortiumDataWorkspaceTable)
+
+
class ConsortiumCombinedDataWorkspaceDetailTest(TestCase):
"""Tests of the anvil_consortium_manager WorkspaceDetail view using the CombinedConsortiumDataWorkspace adapter."""
@@ -2108,6 +2177,42 @@ def test_links_staff_edit_user(self):
self.assertContains(response, url)
+class ReleaseWorkspaceListTest(TestCase):
+ """Tests of the anvil_consortium_manager WorkspaceList view using this app's adapter."""
+
+ def setUp(self):
+ """Set up test class."""
+ self.factory = RequestFactory()
+ # Create a user with both view and edit permission.
+ self.user = User.objects.create_user(username="test", password="test")
+ self.user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.workspace_type = "release"
+
+ def get_url(self, *args):
+ """Get the url for the view being tested."""
+ return reverse("anvil_consortium_manager:workspaces:list", args=args)
+
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.ReleaseWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
+ """The view has the correct table class in the context."""
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.ReleaseWorkspaceTable)
+
+
class ReleaseWorkspaceDetailTest(TestCase):
"""Tests of the anvil_consortium_manager WorkspaceDetail view using the ReleaseWorkspaceAdapter."""
@@ -2335,6 +2440,42 @@ def test_correct_count_consortium_members_with_access_to_workspaces_in_context(
self.assertEqual(response.context_data["verified_linked_accounts"], 1)
+class DCCProcessingWorkspaceListTest(TestCase):
+ """Tests of the anvil_consortium_manager WorkspaceList view using this app's adapter."""
+
+ def setUp(self):
+ """Set up test class."""
+ self.factory = RequestFactory()
+ # Create a user with both view and edit permission.
+ self.user = User.objects.create_user(username="test", password="test")
+ self.user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.workspace_type = "dcc_processing"
+
+ def get_url(self, *args):
+ """Get the url for the view being tested."""
+ return reverse("anvil_consortium_manager:workspaces:list", args=args)
+
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.DCCProcessingWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
+ """The view has the correct table class in the context."""
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.DCCProcessingWorkspaceTable)
+
+
class DCCProcessingWorkspaceDetailTest(TestCase):
"""Tests of the anvil_consortium_manager WorkspaceDetail view using the DCCProcessingWorkspace adapter."""
@@ -2359,6 +2500,42 @@ def test_status_code(self):
self.assertEqual(response.status_code, 200)
+class DCCProcessedDataWorkspaceListTest(TestCase):
+ """Tests of the anvil_consortium_manager WorkspaceList view using this app's adapter."""
+
+ def setUp(self):
+ """Set up test class."""
+ self.factory = RequestFactory()
+ # Create a user with both view and edit permission.
+ self.user = User.objects.create_user(username="test", password="test")
+ self.user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.workspace_type = "dcc_processed_data"
+
+ def get_url(self, *args):
+ """Get the url for the view being tested."""
+ return reverse("anvil_consortium_manager:workspaces:list", args=args)
+
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.DCCProcessedDataWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
+ """The view has the correct table class in the context."""
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.DCCProcessedDataWorkspaceTable)
+
+
class DCCProcessedDataWorkspaceDetailTest(TestCase):
"""Tests of the anvil_consortium_manager WorkspaceDetail view using the DCCProcessedDataWorkspace adapter."""
@@ -2492,12 +2669,23 @@ def get_url(self, *args):
"""Get the url for the view being tested."""
return reverse("anvil_consortium_manager:workspaces:list", args=args)
- def test_view_has_correct_table_class(self):
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.ExchangeWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
"""The view has the correct table class in the context."""
self.client.force_login(self.user)
response = self.client.get(self.get_url(self.workspace_type))
self.assertIn("table", response.context_data)
- self.assertIsInstance(response.context_data["table"], tables.ExchangeWorkspaceTable)
+ self.assertIs(type(response.context_data["table"]), tables.ExchangeWorkspaceStaffTable)
class ExchangeWorkspaceCreateTest(AnVILAPIMockTestMixin, TestCase):
@@ -2649,6 +2837,42 @@ def test_links_staff_edit_user(self):
)
+class PartnerUploadWorkspaceListTest(TestCase):
+ """Tests of the anvil_consortium_manager WorkspaceList view using this app's adapter."""
+
+ def setUp(self):
+ """Set up test class."""
+ self.factory = RequestFactory()
+ # Create a user with both view and edit permission.
+ self.user = User.objects.create_user(username="test", password="test")
+ self.user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.workspace_type = adapters.PartnerUploadWorkspaceAdapter().get_type()
+
+ def get_url(self, *args):
+ """Get the url for the view being tested."""
+ return reverse("anvil_consortium_manager:workspaces:list", args=args)
+
+ def test_view_has_correct_table_class_view_user(self):
+ """The view has the correct table class in the context."""
+ user = User.objects.create_user(username="test-view", password="test-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.PartnerUploadWorkspaceTable)
+
+ def test_view_has_correct_table_class_staff_view_user(self):
+ """The view has the correct table class in the context."""
+ self.client.force_login(self.user)
+ response = self.client.get(self.get_url(self.workspace_type))
+ self.assertIn("table", response.context_data)
+ self.assertIs(type(response.context_data["table"]), tables.PartnerUploadWorkspaceStaffTable)
+
+
class ManagedGroupCreateTest(AnVILAPIMockTestMixin, TestCase):
"""Tests for custom ManagedGroup behavior."""
From 5397ce4c5e8df420ff1439a63b14766a54a581da Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Mon, 2 Dec 2024 16:08:55 -0800
Subject: [PATCH 46/49] Clean up coverage and add more tests for links in
detail views
---
.../gregor_anvil/tests/test_views.py | 92 ++++++++++++++++++-
1 file changed, 90 insertions(+), 2 deletions(-)
diff --git a/gregor_django/gregor_anvil/tests/test_views.py b/gregor_django/gregor_anvil/tests/test_views.py
index 5621418b..512183e1 100644
--- a/gregor_django/gregor_anvil/tests/test_views.py
+++ b/gregor_django/gregor_anvil/tests/test_views.py
@@ -1872,7 +1872,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
self.object = factories.TemplateWorkspaceFactory.create()
@@ -2222,7 +2222,7 @@ def setUp(self):
# Create a user with both view and edit permission.
self.user = User.objects.create_user(username="test", password="test")
self.user.user_permissions.add(
- Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.VIEW_PERMISSION_CODENAME)
)
self.object = factories.ReleaseWorkspaceFactory.create()
@@ -2278,6 +2278,50 @@ def test_contains_upload_workspaces_from_previous_cycles(self):
response.context_data["included_workspace_table"].data,
)
+ def test_links_view_user(self):
+ user = self.user
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
+ self.assertNotContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
+ def test_links_staff_view_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
+ self.assertContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
+ def test_links_staff_edit_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
+ self.assertContains(
+ response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
+ )
+
class WorkspaceReportTest(TestCase):
def setUp(self):
@@ -2499,6 +2543,41 @@ def test_status_code(self):
response = self.client.get(self.get_url(self.object.workspace.billing_project.name, self.object.workspace.name))
self.assertEqual(response.status_code, 200)
+ def test_links_view_user(self):
+ user = self.user
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
+
+ def test_links_staff_view_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
+
+ def test_links_staff_edit_user(self):
+ user = User.objects.create_user(username="test-staff-view", password="test-staff-view")
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_VIEW_PERMISSION_CODENAME)
+ )
+ user.user_permissions.add(
+ Permission.objects.get(codename=acm_models.AnVILProjectManagerAccess.STAFF_EDIT_PERMISSION_CODENAME)
+ )
+ self.client.force_login(user)
+ response = self.client.get(self.object.get_absolute_url())
+ # Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
+
class DCCProcessedDataWorkspaceListTest(TestCase):
"""Tests of the anvil_consortium_manager WorkspaceList view using this app's adapter."""
@@ -2563,6 +2642,9 @@ def test_links_view_user(self):
user = self.user
self.client.force_login(user)
response = self.client.get(self.object.get_absolute_url())
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
self.assertNotContains(
response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
)
@@ -2575,6 +2657,9 @@ def test_links_staff_view_user(self):
self.client.force_login(user)
response = self.client.get(self.object.get_absolute_url())
# Links to other resources
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
self.assertContains(
response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
)
@@ -2589,6 +2674,9 @@ def test_links_staff_edit_user(self):
)
self.client.force_login(user)
response = self.client.get(self.object.get_absolute_url())
+ self.assertContains(
+ response, reverse("gregor_anvil:upload_cycles:detail", args=[self.object.upload_cycle.cycle])
+ )
self.assertContains(
response, reverse("gregor_anvil:consent_groups:detail", args=[self.object.consent_group.pk])
)
From 7e42195754bfec6ff50e33affdab7fb8de0c065f Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Tue, 3 Dec 2024 10:35:55 -0800
Subject: [PATCH 47/49] Update ACM version in requirements.in file
---
requirements/requirements.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.in b/requirements/requirements.in
index ad7b93f0..25aa98f9 100644
--- a/requirements/requirements.in
+++ b/requirements/requirements.in
@@ -35,7 +35,7 @@ django-extensions # https://github.com/django-extensions/django-extensions
# Bootstrap5 templates for crispy-forms
crispy-bootstrap5 # https://github.com/django-crispy-forms/crispy-bootstrap5
-django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
+django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26.1
# Simple history - model history tracking
django-simple-history
From 0e87cc3469b79cce236a4e8da46dc39f9be1d768 Mon Sep 17 00:00:00 2001
From: amstilp <3944584+amstilp@users.noreply.github.com>
Date: Tue, 3 Dec 2024 18:36:57 +0000
Subject: [PATCH 48/49] Compile requirements files
---
requirements/requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index be24e83d..e1600082 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -52,7 +52,7 @@ django==4.2.16
# django-tables2
django-allauth==65.3.0
# via -r requirements/requirements.in
-django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26
+django-anvil-consortium-manager @ git+https://github.com/UW-GAC/django-anvil-consortium-manager.git@v0.26.1
# via -r requirements/requirements.in
django-autocomplete-light==3.11.0
# via django-anvil-consortium-manager
From 7a095a0ae9b772c526ef516724fdb79b97f99a32 Mon Sep 17 00:00:00 2001
From: Adrienne Stilp
Date: Thu, 5 Dec 2024 16:09:59 -0800
Subject: [PATCH 49/49] Use release-drafter action draft releases and notes
Upon a commit/merge to deploy/production, this action drafts a new
release (but does not release it) and tag name (but does not tag it).
Both the release and the tag are set to the current date, or the
current date with a -1, -2 appended if a release with the current
date already exists. The release notes drafted by the action separate
out dependency updates from other changes, which will help us sort
through the release notes to see what of note has changed.
---
.github/release-drafter.yml | 13 +++
.github/workflows/release-drafter.yml | 114 ++++++++++++++++++++++++++
2 files changed, 127 insertions(+)
create mode 100644 .github/release-drafter.yml
create mode 100644 .github/workflows/release-drafter.yml
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
new file mode 100644
index 00000000..09dd06d8
--- /dev/null
+++ b/.github/release-drafter.yml
@@ -0,0 +1,13 @@
+sort-direction: ascending
+
+categories:
+ - title: "⬆️ Dependencies"
+ labels:
+ - "dependencies"
+ - "update-requirements-files"
+ - "combined-pr"
+
+template: |
+ ## What’s Changed
+
+ $CHANGES
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
new file mode 100644
index 00000000..beb61166
--- /dev/null
+++ b/.github/workflows/release-drafter.yml
@@ -0,0 +1,114 @@
+name: Release Drafter
+
+on:
+ push:
+ # branches to consider in the event; optional, defaults to all
+ branches:
+ - deploy/production
+
+permissions:
+ contents: read
+
+jobs:
+ update_release_draft:
+ permissions:
+ # write permission is required to create a github release
+ contents: write
+ # write permission is required for autolabeler
+ # otherwise, read permission is required at least
+ pull-requests: read
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: Get current date
+ id: get-date
+ run: |
+ export CURRENT_DATE=$(TZ=":America/Los_Angeles" date "+%Y-%m-%d")
+ echo "current_date=${CURRENT_DATE}" >> $GITHUB_OUTPUT
+ echo "Current date set to ${CURRENT_DATE}"
+
+ - name: Get number of releases for the current date
+ id: get-release-count
+ run: |
+ export RELEASE_COUNT=$(gh release list \
+ --repo ${{ github.repository }} \
+ --json tagName \
+ --exclude-drafts \
+ --jq "map(select(.tagName | startswith(\"${CURRENT_DATE}\")))|length" \
+ )
+ echo "release_count=${RELEASE_COUNT}" >> $GITHUB_OUTPUT
+ echo "Found ${RELEASE_COUNT} releases"
+ env:
+ CURRENT_DATE: ${{ steps.get-date.outputs.current_date }}
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Prepare release version
+ id: get-version
+ run: |
+ export VERSION="${CURRENT_DATE}"
+
+ if [ $RELEASE_COUNT -gt 0 ]; then
+ echo "Release already exists for version ${VERSION}"
+ echo "Appending release count to version"
+ export VERSION="${CURRENT_DATE}-${RELEASE_COUNT}"
+ fi
+
+ echo "version=${VERSION}" >> $GITHUB_OUTPUT
+ echo "Version set to ${VERSION}"
+ env:
+ CURRENT_DATE: ${{ steps.get-date.outputs.current_date }}
+ RELEASE_COUNT: ${{ steps.get-release-count.outputs.release_count }}
+
+
+ - name: Check that version doesn't exist
+ id: check-release
+ run: |
+ echo "Checking version ${VERSION}"
+
+ export CHECK=$(gh release list \
+ --repo ${{ github.repository }} \
+ --json tagName \
+ --exclude-drafts \
+ --jq "map(select(.tagName == \"${VERSION}\"))|length" \
+ )
+ echo "Found ${CHECK} releases"
+
+ if [ $CHECK -gt 0 ]; then
+ echo "Release already exists for version ${VERSION}"
+ exit 1
+ fi
+ env:
+ VERSION: ${{ steps.get-version.outputs.version }}
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Check that tag doesn't exist
+ id: check-tag
+ run: |
+ echo "Checking tag for version ${VERSION}"
+
+ # Query the API for this tag.
+ export CHECK=$(gh api \
+ -H "Accept: application/vnd.github+json" \
+ -H "X-GitHub-Api-Version: 2022-11-28" \
+ /repos/${{ github.repository }}/tags \
+ --jq "map(select(.name == \"${VERSION}\"))|length" \
+ )
+ echo "Found ${CHECK} tags"
+
+ if [ $CHECK -gt 0 ]; then
+ echo "Tag already exists for version ${VERSION}"
+ exit 1
+ fi
+ env:
+ VERSION: ${{ steps.get-version.outputs.version }}
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+
+ - uses: release-drafter/release-drafter@v6
+ with:
+ commitish: deploy/production
+ tag: ${{ steps.get-version.outputs.version }}
+ name: ${{ steps.get-version.outputs.version }}
+ version: ${{ steps.get-version.outputs.version }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}