diff --git a/openedx/core/djangoapps/content_libraries/api/libraries.py b/openedx/core/djangoapps/content_libraries/api/libraries.py index 8ad0930660..0d07889fab 100644 --- a/openedx/core/djangoapps/content_libraries/api/libraries.py +++ b/openedx/core/djangoapps/content_libraries/api/libraries.py @@ -681,7 +681,7 @@ def get_backup_task_status( Returns a dictionary with the following keys: - state: One of "Pending", "Exporting", "Succeeded", "Failed" - - url: If state is "Succeeded", the URL where the exported .zip file can be downloaded. Otherwise, None. + - file: If state is "Succeeded", the FileField of the exported .zip. Otherwise, None. If no task is found, returns None. """ @@ -690,10 +690,10 @@ def get_backup_task_status( except UserTaskStatus.DoesNotExist: return None - result = {'state': task_status.state, 'url': None} + result = {'state': task_status.state, 'file': None} if task_status.state == UserTaskStatus.SUCCEEDED: artifact = UserTaskArtifact.objects.get(status=task_status, name='Output') - result['url'] = artifact.file.storage.url(artifact.file.name) + result['file'] = artifact.file return result diff --git a/openedx/core/djangoapps/content_libraries/rest_api/libraries.py b/openedx/core/djangoapps/content_libraries/rest_api/libraries.py index 1acdf7bb11..28329cbe77 100644 --- a/openedx/core/djangoapps/content_libraries/rest_api/libraries.py +++ b/openedx/core/djangoapps/content_libraries/rest_api/libraries.py @@ -786,8 +786,8 @@ class LibraryBackupView(APIView): if not result: raise NotFound(detail="No backup found for this library.") - - return Response(LibraryBackupTaskStatusSerializer(result).data) + # Passing request context to the serializer so the url absolute path is correctly generated + return Response(LibraryBackupTaskStatusSerializer(result, context={'request': request}).data) # LTI 1.3 Views diff --git a/openedx/core/djangoapps/content_libraries/rest_api/serializers.py b/openedx/core/djangoapps/content_libraries/rest_api/serializers.py index 56b8963b71..5f816d16e4 100644 --- a/openedx/core/djangoapps/content_libraries/rest_api/serializers.py +++ b/openedx/core/djangoapps/content_libraries/rest_api/serializers.py @@ -425,4 +425,4 @@ class LibraryBackupTaskStatusSerializer(serializers.Serializer): Serializer for checking the status of a library backup task. """ state = serializers.CharField() - url = serializers.URLField(allow_null=True) + url = serializers.FileField(source='file', allow_null=True, use_url=True) diff --git a/openedx/core/djangoapps/content_libraries/tests/test_api.py b/openedx/core/djangoapps/content_libraries/tests/test_api.py index 611f06871c..670d630e5a 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_api.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_api.py @@ -1430,7 +1430,7 @@ class ContentLibraryExportTest(ContentLibrariesRestApiTest): status = api.get_backup_task_status(self.user.id, task_id=task_id) assert status is not None assert status['state'] == UserTaskStatus.IN_PROGRESS - assert status['url'] is None + assert status['file'] is None def test_get_backup_task_status_succeeded(self) -> None: # Create a mock UserTaskStatus in SUCCEEDED state @@ -1444,7 +1444,7 @@ class ContentLibraryExportTest(ContentLibrariesRestApiTest): # Create a mock UserTaskArtifact mock_artifact = mock.Mock() - mock_artifact.file.storage.url.return_value = "/media/user_tasks/2025/10/01/library-libOEXCSPROB_mOw1rPL.zip" + mock_artifact.file.url = "/media/user_tasks/2025/10/01/library-libOEXCSPROB_mOw1rPL.zip" with mock.patch( 'openedx.core.djangoapps.content_libraries.api.libraries.UserTaskStatus.objects.get' @@ -1458,7 +1458,7 @@ class ContentLibraryExportTest(ContentLibrariesRestApiTest): status = api.get_backup_task_status(self.user.id, task_id=task_id) assert status is not None assert status['state'] == UserTaskStatus.SUCCEEDED - assert status['url'] == "/media/user_tasks/2025/10/01/library-libOEXCSPROB_mOw1rPL.zip" + assert status['file'].url == "/media/user_tasks/2025/10/01/library-libOEXCSPROB_mOw1rPL.zip" def test_get_backup_task_status_failed(self) -> None: # Create a mock UserTaskStatus in FAILED state @@ -1478,4 +1478,4 @@ class ContentLibraryExportTest(ContentLibrariesRestApiTest): status = api.get_backup_task_status(self.user.id, task_id=task_id) assert status is not None assert status['state'] == UserTaskStatus.FAILED - assert status['url'] is None + assert status['file'] is None