From 87c21ce335d4caeb2c15955eab2b0590b4b695d0 Mon Sep 17 00:00:00 2001 From: Sajid Ali Date: Mon, 15 Dec 2025 18:02:26 -0500 Subject: [PATCH 1/3] project managers should be able to see allocations Signed-off-by: Sajid Ali modified: coldfront/core/project/views.py modified: coldfront/core/project/views.py --- coldfront/core/project/views.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/coldfront/core/project/views.py b/coldfront/core/project/views.py index def15489b3..ed0e6a7625 100644 --- a/coldfront/core/project/views.py +++ b/coldfront/core/project/views.py @@ -203,12 +203,11 @@ def get_context_data(self, **kwargs): "Active", ] ) - & Q(allocationuser__user=self.request.user) - & Q( - allocationuser__status__name__in=[ - "Active", - ] + & ( + Q(allocationuser__user=self.request.user) + & Q(allocationuser__status__name__in=["Active", "PendingEULA"]) ) + | Q(project__projectuser__role__name="Manager") ) .distinct() .order_by("-end_date") From ea481c869eed74ca1c70dc50b364be7766c4d650 Mon Sep 17 00:00:00 2001 From: Sajid Ali Date: Mon, 5 Jan 2026 12:31:30 -0500 Subject: [PATCH 2/3] minor formatting change --- coldfront/core/project/tests/test_views.py | 61 ++++++---------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/coldfront/core/project/tests/test_views.py b/coldfront/core/project/tests/test_views.py index 1661a7f8c7..5cf18064ea 100644 --- a/coldfront/core/project/tests/test_views.py +++ b/coldfront/core/project/tests/test_views.py @@ -32,17 +32,13 @@ def setUpTestData(cls): cls.project_user = project_user.user manager_role = ProjectUserRoleChoiceFactory(name="Manager") - pi_user = ProjectUserFactory( - project=cls.project, role=manager_role, user=cls.project.pi - ) + pi_user = ProjectUserFactory(project=cls.project, role=manager_role, user=cls.project.pi) cls.pi_user = pi_user.user cls.admin_user = UserFactory(is_staff=True, is_superuser=True) cls.nonproject_user = UserFactory(is_staff=False, is_superuser=False) attributetype = PAttributeTypeFactory(name="string") - cls.projectattributetype = ProjectAttributeTypeFactory( - attribute_type=attributetype - ) + cls.projectattributetype = ProjectAttributeTypeFactory(attribute_type=attributetype) def project_access_tstbase(self, url): """Test basic access control for project views. For all project views: @@ -94,9 +90,7 @@ def test_projectdetail_request_allocation_button_visibility(self): # pi can see request allocation button utils.page_contains_for_user(self, self.pi_user, self.url, button_text) # non-manager user cannot see request allocation button - utils.page_does_not_contain_for_user( - self, self.project_user, self.url, button_text - ) + utils.page_does_not_contain_for_user(self, self.project_user, self.url, button_text) def test_projectdetail_edituser_button_visibility(self): """Test visibility of projectdetail edit button across user levels""" @@ -105,24 +99,16 @@ def test_projectdetail_edituser_button_visibility(self): # pi can see edit button utils.page_contains_for_user(self, self.pi_user, self.url, "fa-user-edit") # non-manager user cannot see edit button - utils.page_does_not_contain_for_user( - self, self.project_user, self.url, "fa-user-edit" - ) + utils.page_does_not_contain_for_user(self, self.project_user, self.url, "fa-user-edit") def test_projectdetail_addnotification_button_visibility(self): """Test visibility of projectdetail add notification button across user levels""" # admin can see add notification button - utils.page_contains_for_user( - self, self.admin_user, self.url, "Add Notification" - ) + utils.page_contains_for_user(self, self.admin_user, self.url, "Add Notification") # pi cannot see add notification button - utils.page_does_not_contain_for_user( - self, self.pi_user, self.url, "Add Notification" - ) + utils.page_does_not_contain_for_user(self, self.pi_user, self.url, "Add Notification") # non-manager user cannot see add notification button - utils.page_does_not_contain_for_user( - self, self.project_user, self.url, "Add Notification" - ) + utils.page_does_not_contain_for_user(self, self.project_user, self.url, "Add Notification") class ProjectCreateTest(ProjectViewTestBase): @@ -152,9 +138,7 @@ def setUpTestData(cls): """Set up users and project for testing""" super(ProjectAttributeCreateTest, cls).setUpTestData() int_attributetype = PAttributeTypeFactory(name="Int") - cls.int_projectattributetype = ProjectAttributeTypeFactory( - attribute_type=int_attributetype - ) + cls.int_projectattributetype = ProjectAttributeTypeFactory(attribute_type=int_attributetype) cls.url = f"/project/{cls.project.pk}/project-attribute-create/" def test_project_access(self): @@ -180,9 +164,7 @@ def test_project_attribute_create_post(self): }, ) redirect_url = f"/project/{self.project.pk}/" - self.assertRedirects( - response, redirect_url, status_code=302, target_status_code=200 - ) + self.assertRedirects(response, redirect_url, status_code=302, target_status_code=200) def test_project_attribute_create_post_required_values(self): """ProjectAttributeCreate correctly flags missing project or value""" @@ -195,9 +177,7 @@ def test_project_attribute_create_post_required_values(self): "value": "test_value", }, ) - self.assertFormError( - response.context["form"], "project", "This field is required." - ) + self.assertFormError(response.context["form"], "project", "This field is required.") # missing value response = self.client.post( self.url, @@ -206,9 +186,7 @@ def test_project_attribute_create_post_required_values(self): "project": self.project.pk, }, ) - self.assertFormError( - response.context["form"], "value", "This field is required." - ) + self.assertFormError(response.context["form"], "value", "This field is required.") def test_project_attribute_create_value_type_match(self): """ProjectAttributeCreate correctly flags value-type mismatch""" @@ -223,9 +201,7 @@ def test_project_attribute_create_value_type_match(self): "project": self.project.pk, }, ) - self.assertFormError( - response.context["form"], None, "Invalid Value True. Value must be an int." - ) + self.assertFormError(response.context["form"], None, "Invalid Value True. Value must be an int.") class ProjectAttributeUpdateTest(ProjectViewTestBase): @@ -281,9 +257,7 @@ def setUpTestData(cls): super(ProjectListViewTest, cls).setUpTestData() # add 100 projects to test pagination, permissions, search functionality additional_projects = [ProjectFactory() for i in list(range(100))] - cls.additional_projects = [ - p for p in additional_projects if p.pi.last_name != cls.project.pi.last_name - ] + cls.additional_projects = [p for p in additional_projects if p.pi.last_name != cls.project.pi.last_name] cls.url = "/project/" ### ProjectListView access tests ### @@ -305,9 +279,7 @@ def test_project_list_display_members(self): response = utils.login_and_get_page(self.client, self.project_user, self.url) self.assertEqual(len(response.context["object_list"]), 1) proj_user = self.project.projectuser_set.get(user=self.project_user) - proj_user.status, _ = ProjectUserStatusChoice.objects.get_or_create( - name="Removed" - ) + proj_user.status, _ = ProjectUserStatusChoice.objects.get_or_create(name="Removed") proj_user.save() response = utils.login_and_get_page(self.client, self.project_user, self.url) self.assertEqual(len(response.context["object_list"]), 0) @@ -335,10 +307,7 @@ def test_project_list_displayall_permission_project_user(self): def test_project_list_search(self): """Test that project list search works.""" url_base = self.url + "?show_all_projects=on" - url = ( - f"{url_base}&last_name={self.project.pi.last_name}" - + f"&school={self.project.school.description}" - ) + url = f"{url_base}&last_name={self.project.pi.last_name}" + f"&school={self.project.school.description}" # search by project project_title response = utils.login_and_get_page(self.client, self.admin_user, url) self.assertEqual(len(response.context["object_list"]), 1) From 5ae1c573215fe2174aa58babf2ca6482550109f6 Mon Sep 17 00:00:00 2001 From: Sajid Ali Date: Mon, 5 Jan 2026 12:33:52 -0500 Subject: [PATCH 3/3] add test --- coldfront/core/project/tests/test_views.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/coldfront/core/project/tests/test_views.py b/coldfront/core/project/tests/test_views.py index 5cf18064ea..872b872ccc 100644 --- a/coldfront/core/project/tests/test_views.py +++ b/coldfront/core/project/tests/test_views.py @@ -4,6 +4,10 @@ from coldfront.core.test_helpers import utils from coldfront.core.test_helpers.factories import ( + AllocationFactory, + AllocationStatusChoiceFactory, + AllocationUserFactory, + AllocationUserStatusChoiceFactory, UserFactory, ProjectFactory, ProjectUserFactory, @@ -34,12 +38,17 @@ def setUpTestData(cls): manager_role = ProjectUserRoleChoiceFactory(name="Manager") pi_user = ProjectUserFactory(project=cls.project, role=manager_role, user=cls.project.pi) cls.pi_user = pi_user.user + cls.manager_user = ProjectUserFactory(project=cls.project, role=manager_role) cls.admin_user = UserFactory(is_staff=True, is_superuser=True) cls.nonproject_user = UserFactory(is_staff=False, is_superuser=False) attributetype = PAttributeTypeFactory(name="string") cls.projectattributetype = ProjectAttributeTypeFactory(attribute_type=attributetype) + cls.allocation = AllocationFactory(status=AllocationStatusChoiceFactory(name="active"), project=cls.project) + active_ausc = AllocationUserStatusChoiceFactory(name="Active") + cls.pi_as_alloc_user = AllocationUserFactory(allocation=cls.allocation, status=active_ausc) + def project_access_tstbase(self, url): """Test basic access control for project views. For all project views: - if not logged in, redirect to login page @@ -110,6 +119,12 @@ def test_projectdetail_addnotification_button_visibility(self): # non-manager user cannot see add notification button utils.page_does_not_contain_for_user(self, self.project_user, self.url, "Add Notification") + def test_manager_can_view_allocations(self): + """Project Manager should be able to view allocations on the project + without being a user on the Allocation""" + response = utils.login_and_get_page(self.client, self.manager_user.user, self.url) + self.assertEqual(len(response.context["allocations"]), 1) + class ProjectCreateTest(ProjectViewTestBase): """Tests for project create view"""