fix(api): file upload with library (#3213)
Some checks failed
Container / meta (analyzer) (push) Waiting to run
Container / meta (api) (push) Waiting to run
Container / meta (legacy) (push) Waiting to run
Container / meta (nginx) (push) Waiting to run
Container / meta (playout) (push) Waiting to run
Container / meta (worker) (push) Waiting to run
Container / build (push) Blocked by required conditions
Project / pre-commit (push) Waiting to run
Project / test-tools (push) Waiting to run
Release-Please / release-please (push) Waiting to run
API schema / check (push) Has been cancelled
API schema / dispatch (push) Has been cancelled
API / lint (push) Has been cancelled
API / test-with-database (bullseye) (push) Has been cancelled
API / test-with-database (focal) (push) Has been cancelled
API / test-with-database (jammy) (push) Has been cancelled
Legacy / lint (7.4) (push) Has been cancelled
Legacy / test (7.4) (push) Has been cancelled
Legacy / locale (push) Has been cancelled
Some checks failed
Container / meta (analyzer) (push) Waiting to run
Container / meta (api) (push) Waiting to run
Container / meta (legacy) (push) Waiting to run
Container / meta (nginx) (push) Waiting to run
Container / meta (playout) (push) Waiting to run
Container / meta (worker) (push) Waiting to run
Container / build (push) Blocked by required conditions
Project / pre-commit (push) Waiting to run
Project / test-tools (push) Waiting to run
Release-Please / release-please (push) Waiting to run
API schema / check (push) Has been cancelled
API schema / dispatch (push) Has been cancelled
API / lint (push) Has been cancelled
API / test-with-database (bullseye) (push) Has been cancelled
API / test-with-database (focal) (push) Has been cancelled
API / test-with-database (jammy) (push) Has been cancelled
Legacy / lint (7.4) (push) Has been cancelled
Legacy / test (7.4) (push) Has been cancelled
Legacy / locale (push) Has been cancelled
### Description Uploads with bulk_import defining --library fail with error 400 in the REST API The primary key of the track_type was changed from chars to a numerical ID, and the data model expects this now in the REST endpoint. However the bulk import still populates this field with the Char Tag. ### Testing Notes **What I did:** `libretime-api bulk_import --path /home/libretime/upload/ --library POD --allowed-extensions mp3` **How you can replicate my testing:** see above --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
6ff6de7124
commit
643504edc9
@ -85,7 +85,7 @@ class Importer:
|
|||||||
|
|
||||||
return File.objects.filter(md5=file_md5).exists()
|
return File.objects.filter(md5=file_md5).exists()
|
||||||
|
|
||||||
def _upload_file(self, filepath: Path, library: Optional[str]) -> None:
|
def _upload_file(self, filepath: Path, library_id: Optional[int]) -> None:
|
||||||
try:
|
try:
|
||||||
resp = requests.post(
|
resp = requests.post(
|
||||||
f"{self.url}/rest/media",
|
f"{self.url}/rest/media",
|
||||||
@ -94,7 +94,11 @@ class Importer:
|
|||||||
("file", (filepath.name, filepath.open("rb"))),
|
("file", (filepath.name, filepath.open("rb"))),
|
||||||
],
|
],
|
||||||
timeout=30,
|
timeout=30,
|
||||||
cookies={"tt_upload": library} if library is not None else {},
|
cookies=(
|
||||||
|
{"tt_upload": str(library_id)}
|
||||||
|
if library_id not in (None, 0)
|
||||||
|
else {}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|
||||||
@ -105,7 +109,7 @@ class Importer:
|
|||||||
logger.info("deleting %s", filepath)
|
logger.info("deleting %s", filepath)
|
||||||
filepath.unlink()
|
filepath.unlink()
|
||||||
|
|
||||||
def _handle_file(self, filepath: Path, library: Optional[str]) -> None:
|
def _handle_file(self, filepath: Path, library_id: Optional[int]) -> None:
|
||||||
logger.debug("handling file %s", filepath)
|
logger.debug("handling file %s", filepath)
|
||||||
|
|
||||||
if not filepath.is_file():
|
if not filepath.is_file():
|
||||||
@ -117,7 +121,7 @@ class Importer:
|
|||||||
self._delete_file(filepath)
|
self._delete_file(filepath)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._upload_file(filepath, library)
|
self._upload_file(filepath, library_id)
|
||||||
|
|
||||||
if self.delete_after_upload:
|
if self.delete_after_upload:
|
||||||
self._delete_file(filepath)
|
self._delete_file(filepath)
|
||||||
@ -125,7 +129,7 @@ class Importer:
|
|||||||
def _walk_dir(
|
def _walk_dir(
|
||||||
self,
|
self,
|
||||||
path: Path,
|
path: Path,
|
||||||
library: Optional[str],
|
library_id: Optional[int],
|
||||||
allowed_extensions: List[str],
|
allowed_extensions: List[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
if not path.is_dir():
|
if not path.is_dir():
|
||||||
@ -133,13 +137,13 @@ class Importer:
|
|||||||
|
|
||||||
for sub_path in path.iterdir():
|
for sub_path in path.iterdir():
|
||||||
if sub_path.is_dir():
|
if sub_path.is_dir():
|
||||||
self._walk_dir(sub_path, library, allowed_extensions)
|
self._walk_dir(sub_path, library_id, allowed_extensions)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if sub_path.suffix.lower() not in allowed_extensions:
|
if sub_path.suffix.lower() not in allowed_extensions:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._handle_file(sub_path.resolve(), library)
|
self._handle_file(sub_path.resolve(), library_id)
|
||||||
|
|
||||||
def _check_library(self, library: str) -> bool:
|
def _check_library(self, library: str) -> bool:
|
||||||
return Library.objects.filter(code=library).exists()
|
return Library.objects.filter(code=library).exists()
|
||||||
@ -153,8 +157,16 @@ class Importer:
|
|||||||
if library is not None and not self._check_library(library):
|
if library is not None and not self._check_library(library):
|
||||||
raise ValueError(f"provided library {library} does not exist")
|
raise ValueError(f"provided library {library} does not exist")
|
||||||
|
|
||||||
|
if library:
|
||||||
|
try:
|
||||||
|
library_id = Library.objects.get(code=library).id
|
||||||
|
except Library.DoesNotExist as exc:
|
||||||
|
raise ValueError(f"provided library {library} does not exist") from exc
|
||||||
|
else:
|
||||||
|
library_id = 0
|
||||||
|
|
||||||
allowed_extensions = [
|
allowed_extensions = [
|
||||||
(x if x.startswith(".") else "." + x) for x in allowed_extensions
|
(x if x.startswith(".") else "." + x) for x in allowed_extensions
|
||||||
]
|
]
|
||||||
|
|
||||||
self._walk_dir(path, library, allowed_extensions)
|
self._walk_dir(path, library_id, allowed_extensions)
|
||||||
|
|||||||
@ -22,6 +22,8 @@ class Library(models.Model):
|
|||||||
db_column="analyze_cue_points",
|
db_column="analyze_cue_points",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
id = models.AutoField(primary_key=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
managed = False
|
managed = False
|
||||||
db_table = "cc_track_types"
|
db_table = "cc_track_types"
|
||||||
|
|||||||
@ -30,6 +30,7 @@ def _import_paths(tmp_path: Path):
|
|||||||
def _library():
|
def _library():
|
||||||
return baker.make(
|
return baker.make(
|
||||||
"storage.Library",
|
"storage.Library",
|
||||||
|
id=1,
|
||||||
code="MUS",
|
code="MUS",
|
||||||
name="Music",
|
name="Music",
|
||||||
description="Some music",
|
description="Some music",
|
||||||
@ -62,8 +63,8 @@ def test_importer(
|
|||||||
):
|
):
|
||||||
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
||||||
|
|
||||||
importer._handle_file.assert_called_with(import_paths[1], library.code)
|
importer._handle_file.assert_called_with(import_paths[1], library.id)
|
||||||
importer._upload_file.assert_called_with(import_paths[1], library.code)
|
importer._upload_file.assert_called_with(import_paths[1], library.id)
|
||||||
importer._delete_file.assert_not_called()
|
importer._delete_file.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@ -76,8 +77,8 @@ def test_importer_and_delete(
|
|||||||
importer.delete_after_upload = True
|
importer.delete_after_upload = True
|
||||||
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
||||||
|
|
||||||
importer._handle_file.assert_called_with(import_paths[1], library.code)
|
importer._handle_file.assert_called_with(import_paths[1], library.id)
|
||||||
importer._upload_file.assert_called_with(import_paths[1], library.code)
|
importer._upload_file.assert_called_with(import_paths[1], library.id)
|
||||||
importer._delete_file.assert_called_with(import_paths[1])
|
importer._delete_file.assert_called_with(import_paths[1])
|
||||||
|
|
||||||
|
|
||||||
@ -87,11 +88,11 @@ def test_importer_existing_file(
|
|||||||
importer: MockImporter,
|
importer: MockImporter,
|
||||||
library,
|
library,
|
||||||
):
|
):
|
||||||
baker.make("storage.File", md5="46305a7cf42ee53976c88d337e47e940")
|
baker.make("storage.File", id=1, md5="46305a7cf42ee53976c88d337e47e940")
|
||||||
|
|
||||||
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
||||||
|
|
||||||
importer._handle_file.assert_called_with(import_paths[1], library.code)
|
importer._handle_file.assert_called_with(import_paths[1], library.id)
|
||||||
importer._upload_file.assert_not_called()
|
importer._upload_file.assert_not_called()
|
||||||
importer._delete_file.assert_not_called()
|
importer._delete_file.assert_not_called()
|
||||||
|
|
||||||
@ -102,12 +103,12 @@ def test_importer_existing_file_and_delete(
|
|||||||
importer: MockImporter,
|
importer: MockImporter,
|
||||||
library,
|
library,
|
||||||
):
|
):
|
||||||
baker.make("storage.File", md5="46305a7cf42ee53976c88d337e47e940")
|
baker.make("storage.File", id=1, md5="46305a7cf42ee53976c88d337e47e940")
|
||||||
|
|
||||||
importer.delete_if_exists = True
|
importer.delete_if_exists = True
|
||||||
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
importer.import_dir(import_paths[0], library.code, [".mp3"])
|
||||||
|
|
||||||
importer._handle_file.assert_called_with(import_paths[1], library.code)
|
importer._handle_file.assert_called_with(import_paths[1], library.id)
|
||||||
importer._upload_file.assert_not_called()
|
importer._upload_file.assert_not_called()
|
||||||
importer._delete_file.assert_called_with(import_paths[1])
|
importer._delete_file.assert_called_with(import_paths[1])
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user