From 8069c3638d6fb8021d58e1e93987916d796f707e Mon Sep 17 00:00:00 2001 From: Dahye Kim Date: Fri, 12 Dec 2025 15:25:09 -0500 Subject: [PATCH 1/2] allocation with unique (project, resource) is created --- coldfront/core/allocation/views.py | 9 +++ .../management/commands/load_test_data.py | 68 +------------------ 2 files changed, 11 insertions(+), 66 deletions(-) diff --git a/coldfront/core/allocation/views.py b/coldfront/core/allocation/views.py index 48e7312804..cd473c92c2 100644 --- a/coldfront/core/allocation/views.py +++ b/coldfront/core/allocation/views.py @@ -80,6 +80,7 @@ import plotly.express as px from plotly.offline import plot from django.http import HttpResponse, HttpResponseBadRequest +from django.db import IntegrityError, transaction ALLOCATION_ENABLE_ALLOCATION_RENEWAL = import_from_settings( "ALLOCATION_ENABLE_ALLOCATION_RENEWAL", True @@ -690,6 +691,14 @@ def form_valid(self, form): ) return self.form_invalid(form) + # Prevent duplicate allocation for same (project, resource) + if Allocation.objects.filter(project=project_obj, resources=resource_obj).exists(): + form.add_error( + "resource", + "An allocation for this project and resource already exists.", + ) + return self.form_invalid(form) + usernames = form_data.get("users") usernames.append(project_obj.pi.username) usernames = list(set(usernames)) diff --git a/coldfront/core/utils/management/commands/load_test_data.py b/coldfront/core/utils/management/commands/load_test_data.py index 99f26d01c0..4cdb77ec0b 100644 --- a/coldfront/core/utils/management/commands/load_test_data.py +++ b/coldfront/core/utils/management/commands/load_test_data.py @@ -269,43 +269,7 @@ def handle(self, *args, **options): start_date = datetime.datetime.now() end_date = datetime.datetime.now() + relativedelta(days=365) - # Add PI cluster - allocation_obj, _ = Allocation.objects.get_or_create( - project=project_obj, - status=AllocationStatusChoice.objects.get(name="Active"), - start_date=start_date, - end_date=end_date, - is_changeable=True, - justification="I need access to my nodes.", - ) - - allocation_obj.resources.add(Resource.objects.get(name="Tandon")) - allocation_obj.save() - - allocation_attribute_type_obj = AllocationAttributeType.objects.get( - name="slurm_account_name" - ) - AllocationAttribute.objects.get_or_create( - allocation_attribute_type=allocation_attribute_type_obj, - allocation=allocation_obj, - value=f"torch_pr_{allocation_obj.project.pk}_Tandon", - ) - - allocation_attribute_type_obj = AllocationAttributeType.objects.get( - name="slurm_user_specs" - ) - AllocationAttribute.objects.get_or_create( - allocation_attribute_type=allocation_attribute_type_obj, - allocation=allocation_obj, - value="Fairshare=parent", - ) - - allocation_user_obj = AllocationUser.objects.create( - allocation=allocation_obj, - user=pi1, - status=AllocationUserStatusChoice.objects.get(name="Active"), - ) - # Add university cluster + # Add university allocation allocation_obj, _ = Allocation.objects.get_or_create( project=project_obj, status=AllocationStatusChoice.objects.get(name="Active"), @@ -363,41 +327,13 @@ def handle(self, *args, **options): value="2022-01-01", ) - allocation_user_obj = AllocationUser.objects.create( - allocation=allocation_obj, - user=pi1, - status=AllocationUserStatusChoice.objects.get(name="Active"), - ) - # Add project storage - allocation_obj, _ = Allocation.objects.get_or_create( - project=project_obj, - status=AllocationStatusChoice.objects.get(name="Active"), - start_date=start_date, - end_date=end_date, - quantity=10, - is_changeable=True, - justification="I need extra storage.", - ) - - allocation_obj.resources.add(Resource.objects.get(name="Tandon")) - allocation_obj.save() - - allocation_attribute_type_obj = AllocationAttributeType.objects.get( - name="slurm_account_name" - ) - AllocationAttribute.objects.get_or_create( - allocation_attribute_type=allocation_attribute_type_obj, - allocation=allocation_obj, - value=f"torch_pr_{allocation_obj.project.pk}_Tandon", - ) - allocation_user_obj = AllocationUser.objects.create( allocation=allocation_obj, user=pi1, status=AllocationUserStatusChoice.objects.get(name="Active"), ) - # Add metered allocation + # Add Tandon allocation allocation_obj, _ = Allocation.objects.get_or_create( project=project_obj, status=AllocationStatusChoice.objects.get(name="Active"), From 331678e8ac5fcd99cbcd971d3ade61214cda8959 Mon Sep 17 00:00:00 2001 From: Dahye Kim Date: Fri, 12 Dec 2025 15:25:44 -0500 Subject: [PATCH 2/2] test for checking duplicate allocation (project, resource) creation --- coldfront/core/allocation/test_views.py | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/coldfront/core/allocation/test_views.py b/coldfront/core/allocation/test_views.py index bbd8eb4958..441134e187 100644 --- a/coldfront/core/allocation/test_views.py +++ b/coldfront/core/allocation/test_views.py @@ -590,6 +590,32 @@ def test_allocationcreateview_post_zeroquantity(self): self.assertContains(response, "Allocation requested.") self.assertEqual(len(self.project.allocation_set.all()), 2) + def test_allocationcreateview_post_duplicate_project_resource_shows_error(self): + """Posting an allocation for same project+resource should show error and not create a new allocation""" + self.post_data["resource"] = str(self.resource_tandon.pk) + + # Create an existing allocation for (project, resource_tandon) + existing = Allocation.objects.create( + project=self.project, + justification="existing", + quantity=1, + status=AllocationStatusChoice.objects.get(name="New"), + ) + existing.resources.add(self.resource_tandon) + + initial_count = self.project.allocation_set.count() + + response = self.client.post(self.url, data=self.post_data, follow=True) + + self.assertEqual(response.status_code, 200) + # Should not create a new allocation + self.assertEqual(self.project.allocation_set.count(), initial_count) + + # Should show the friendly error message you added in form_valid + self.assertContains( + response, + "An allocation for this project and resource already exists.", + ) class AllocationAddUsersViewTest(AllocationViewBaseTest): """Tests for the AllocationAddUsersView"""