diff --git a/src/backend/InvenTree/InvenTree/helpers.py b/src/backend/InvenTree/InvenTree/helpers.py index c3e53f15a1..3acf31c67d 100644 --- a/src/backend/InvenTree/InvenTree/helpers.py +++ b/src/backend/InvenTree/InvenTree/helpers.py @@ -16,7 +16,7 @@ from django.conf import settings from django.contrib.staticfiles.storage import StaticFilesStorage from django.core.exceptions import FieldError, ValidationError from django.core.files.storage import default_storage -from django.db.models.fields.files import ImageFieldFile +from django.db.models.fields.files import FieldFile, ImageFieldFile from django.http import StreamingHttpResponse from django.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -176,10 +176,14 @@ def constructPathString(path: list[str], max_chars: int = 250) -> str: return pathstring -def getMediaUrl(file: StdImageFieldFile | ImageFieldFile, name: str | None = None): +def getMediaUrl( + file: FieldFile | ImageFieldFile | StdImageFieldFile, name: str | None = None +): """Return the qualified access path for the given file, under the media directory.""" - if not isinstance(file, StdImageFieldFile): - raise ValueError('file_obj must be an instance of StdImageFieldFile') + if not isinstance(file, (FieldFile, ImageFieldFile, StdImageFieldFile)): + raise TypeError( + 'file must be one of FileField, ImageFileField, StdImageFieldFile' + ) if name is not None: file = regenerate_imagefile(file, name) if settings.STORAGE_TARGET == StorageBackends.S3: diff --git a/src/backend/InvenTree/InvenTree/tests.py b/src/backend/InvenTree/InvenTree/tests.py index e84dc6a48e..a28aad7313 100644 --- a/src/backend/InvenTree/InvenTree/tests.py +++ b/src/backend/InvenTree/InvenTree/tests.py @@ -702,7 +702,7 @@ class TestHelpers(TestCase): def testMediaUrl(self): """Test getMediaUrl.""" # Str should not work - with self.assertRaises(ValueError): + with self.assertRaises(TypeError): helpers.getMediaUrl('xx/yy.png') # type: ignore # Correct usage diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index 763865248a..a5671cfa77 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -2034,7 +2034,7 @@ class Attachment(InvenTree.models.MetadataMixin, InvenTree.models.InvenTreeModel if self.attachment: import InvenTree.helpers_model - media_url = InvenTree.helpers.getMediaUrl(self.attachment.url) + media_url = InvenTree.helpers.getMediaUrl(self.attachment) return InvenTree.helpers_model.construct_absolute_url(media_url) return '' diff --git a/src/backend/InvenTree/common/tests.py b/src/backend/InvenTree/common/tests.py index e2e1d4cef2..52a1eeca95 100644 --- a/src/backend/InvenTree/common/tests.py +++ b/src/backend/InvenTree/common/tests.py @@ -202,6 +202,21 @@ class AttachmentTest(InvenTreeAPITestCase): self.assignRole('part.delete') self.delete(url, expected_code=204) + def test_fully_qualified_url(self): + """Test that the fully qualified URL is returned correctly.""" + part = Part.objects.first() + + attachment = Attachment.objects.create( + attachment=self.generate_file('test.txt'), + comment='Testing filename: test.txt', + model_type='part', + model_id=part.pk, + ) + + url = attachment.fully_qualified_url() + self.assertIs(type(url), str) + self.assertIn(f'/media/attachments/part/{part.pk}/test', url) + class SettingsTest(InvenTreeTestCase): """Tests for the 'settings' model."""