diff --git a/libs/shared/shared/django_apps/upload_breadcrumbs/admin.py b/libs/shared/shared/django_apps/upload_breadcrumbs/admin.py index 00f0310f7..859d9bc00 100644 --- a/libs/shared/shared/django_apps/upload_breadcrumbs/admin.py +++ b/libs/shared/shared/django_apps/upload_breadcrumbs/admin.py @@ -560,9 +560,6 @@ def get_urls(self): @admin.display(description="Actions", ordering=None) def resend_upload_button(self, obj: UploadBreadcrumb) -> str: """Display resend button in the list view for failed uploads.""" - if not self._is_failed_upload(obj): - return "-" - resend_url = reverse( "admin:upload_breadcrumbs_uploadbreadcrumb_resend_upload", args=[obj.id] ) @@ -577,24 +574,16 @@ def resend_upload_action(self, obj: UploadBreadcrumb) -> str: if not obj.pk: # New object return "-" - html_parts = [] - - if self._is_failed_upload(obj): - resend_url = reverse( - "admin:upload_breadcrumbs_uploadbreadcrumb_resend_upload", args=[obj.id] - ) - html_parts.append( - f'🔄 Resend Upload" - "

" - "
⚠️ Note: This will create a new upload task for the same commit and repository. " - "The original upload data may no longer be available in storage.
" - ) - else: - html_parts.append( - "
✅ This upload does not appear to have failed. Resend option is not available.
" - ) - + resend_url = reverse( + "admin:upload_breadcrumbs_uploadbreadcrumb_resend_upload", args=[obj.id] + ) + html_parts = [ + f'🔄 Resend Upload" + "

" + "
⚠️ Note: This will create a new upload task for the same commit and repository. " + "The original upload data may no longer be available in storage.
" + ] return format_html("".join(html_parts)) def _is_failed_upload(self, obj: UploadBreadcrumb) -> bool: @@ -624,10 +613,6 @@ def resend_upload_view(self, request, object_id): messages.error(request, "Upload breadcrumb not found.") return redirect("admin:upload_breadcrumbs_uploadbreadcrumb_changelist") - if not self._is_failed_upload(breadcrumb): - messages.error(request, "This upload does not appear to have failed.") - return redirect("admin:upload_breadcrumbs_uploadbreadcrumb_changelist") - success, error_message = self._resend_upload(breadcrumb, request.user) if success: @@ -706,6 +691,17 @@ def _resend_upload( "resend_timestamp": timezone.now().isoformat(), } + # Check if upload_ids is None + if breadcrumb.upload_ids is None: + log.error( + "Cannot resend upload - breadcrumb has no upload IDs", + extra={"breadcrumb_id": breadcrumb.id}, + ) + return ( + False, + "This breadcrumb has no associated upload IDs. It may be a resend breadcrumb that hasn't been processed yet.", + ) + log.info( f"Collecting upload data for {len(breadcrumb.upload_ids)} uploads", extra={"upload_ids": breadcrumb.upload_ids}, diff --git a/libs/shared/shared/django_apps/upload_breadcrumbs/tests/test_admin.py b/libs/shared/shared/django_apps/upload_breadcrumbs/tests/test_admin.py index eb017960f..44ab1afe2 100644 --- a/libs/shared/shared/django_apps/upload_breadcrumbs/tests/test_admin.py +++ b/libs/shared/shared/django_apps/upload_breadcrumbs/tests/test_admin.py @@ -1063,8 +1063,8 @@ def test_resend_upload_button_scenarios(self): { "milestone": Milestones.UPLOAD_COMPLETE.value, }, - None, - str, + ["🔄 Resend", 'class="button"', "onclick="], + SafeString, "successful upload", ), ] @@ -1079,16 +1079,13 @@ def test_resend_upload_button_scenarios(self): breadcrumb = UploadBreadcrumbFactory(breadcrumb_data=breadcrumb_data) result = self.admin.resend_upload_button(breadcrumb) - if expected_contains is None: - self.assertEqual(result, "-", f"Failed for: {description}") - else: - self.assertIsInstance( - result, expected_type, f"Failed for: {description}" + self.assertIsInstance( + result, expected_type, f"Failed for: {description}" + ) + for expected_content in expected_contains: + self.assertIn( + expected_content, result, f"Failed for: {description}" ) - for expected_content in expected_contains: - self.assertIn( - expected_content, result, f"Failed for: {description}" - ) def test_resend_upload_action_scenarios(self): """Test resend_upload_action with various scenarios.""" @@ -1120,10 +1117,7 @@ def test_resend_upload_action_scenarios(self): }, "abcdef1234567890", True, - [ - "✅ This upload does not appear to have failed", - "Resend option is not available", - ], + ["🔄 Resend Upload", 'class="button default"', "abcdef1", "⚠️ Note:"], "successful upload", ), ({}, "abcdef1234567890", False, None, "new object without pk"), @@ -1170,22 +1164,27 @@ def test_resend_upload_view_with_nonexistent_breadcrumb(self, mock_messages_erro request, "Upload breadcrumb not found." ) - @patch("django.contrib.messages.error") - def test_resend_upload_view_with_non_failed_upload(self, mock_messages_error): - """Test resend_upload_view handles non-failed uploads.""" + @patch("django.contrib.messages.success") + def test_resend_upload_view_with_non_failed_upload(self, mock_messages_success): + """Test resend_upload_view allows resending non-failed uploads.""" breadcrumb_data = { "milestone": Milestones.UPLOAD_COMPLETE.value, } - breadcrumb = UploadBreadcrumbFactory(breadcrumb_data=breadcrumb_data) + breadcrumb = UploadBreadcrumbFactory( + breadcrumb_data=breadcrumb_data, commit_sha="abcdef1234567890" + ) request = MagicMock() request.user = self.user - with patch.object(self.admin, "get_object", return_value=breadcrumb): + with ( + patch.object(self.admin, "get_object", return_value=breadcrumb), + patch.object(self.admin, "_resend_upload", return_value=(True, None)), + ): response = self.admin.resend_upload_view(request, str(breadcrumb.id)) - mock_messages_error.assert_called_once_with( - request, "This upload does not appear to have failed." - ) + mock_messages_success.assert_called_once() + success_message = mock_messages_success.call_args[0][1] + self.assertIn("Upload resend triggered successfully", success_message) @patch("django.contrib.messages.success") def test_resend_upload_view_successful_resend(self, mock_messages_success):