fix(fns): queue uploads from worker-visible path
This commit is contained in:
@@ -137,6 +137,55 @@ class FNSUploadService:
|
||||
|
||||
return FNSUploadResult(queued=1, skipped=0, invalid=0, task_ids=[task.id])
|
||||
|
||||
@classmethod
|
||||
def queue_server_path(
|
||||
cls,
|
||||
*,
|
||||
server_path: str,
|
||||
requested_by_id: int | None,
|
||||
) -> FNSUploadResult:
|
||||
"""Queue an FNS file that already exists on the worker-visible disk."""
|
||||
from apps.parsers.tasks import process_fns_zip_archive
|
||||
|
||||
path = cls._validate_server_path(server_path)
|
||||
if path.suffix.lower() == ".zip":
|
||||
task_name = "apps.parsers.tasks.process_fns_zip_archive"
|
||||
task = process_fns_zip_archive
|
||||
upload_type = "zip_server_path"
|
||||
else:
|
||||
task_name = "apps.parsers.tasks.process_fns_file"
|
||||
task = process_fns_file
|
||||
upload_type = "file_server_path"
|
||||
|
||||
task_id = str(uuid.uuid4())
|
||||
try:
|
||||
BackgroundJobService.create_job(
|
||||
task_id=task_id,
|
||||
task_name=task_name,
|
||||
user_id=requested_by_id,
|
||||
meta={
|
||||
"source": ParserLoadLog.Source.FNS_REPORTS,
|
||||
"file": path.name,
|
||||
"server_path": str(path),
|
||||
"upload_type": upload_type,
|
||||
},
|
||||
)
|
||||
async_result = task.apply_async(
|
||||
args=[str(path)],
|
||||
kwargs={"requested_by_id": requested_by_id},
|
||||
task_id=task_id,
|
||||
)
|
||||
except Exception:
|
||||
BackgroundJob.objects.filter(task_id=task_id).delete()
|
||||
raise
|
||||
|
||||
return FNSUploadResult(
|
||||
queued=1,
|
||||
skipped=0,
|
||||
invalid=0,
|
||||
task_ids=[async_result.id],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def queue_zip_archive_path(
|
||||
cls,
|
||||
@@ -240,6 +289,50 @@ class FNSUploadService:
|
||||
archive_file.seek(0)
|
||||
return archive_path
|
||||
|
||||
@classmethod
|
||||
def _validate_server_path(cls, server_path: str) -> Path:
|
||||
raw_path = Path(server_path)
|
||||
if not raw_path.is_absolute():
|
||||
raise ValueError("Путь к файлу должен быть абсолютным")
|
||||
|
||||
path = raw_path.resolve(strict=False)
|
||||
allowed_roots = cls._allowed_server_path_roots()
|
||||
if not any(cls._is_relative_to(path, root) for root in allowed_roots):
|
||||
allowed = ", ".join(str(root) for root in allowed_roots)
|
||||
raise ValueError(f"Путь должен находиться внутри: {allowed}")
|
||||
|
||||
suffix = path.suffix.lower()
|
||||
if suffix == ".zip":
|
||||
return path
|
||||
if suffix in {".xlsx", ".xlsm"} and FNS_XLSX_FILENAME_RE.match(path.name):
|
||||
return path
|
||||
raise ValueError(
|
||||
"Поддерживаются ZIP архивы или Excel файлы формата " "fin_{id}_{ogrn}.xlsx"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _allowed_server_path_roots() -> list[Path]:
|
||||
roots = [
|
||||
Path(settings.FNS_WATCH_DIRECTORY),
|
||||
Path(settings.FNS_WATCH_DIRECTORY) / "archives",
|
||||
]
|
||||
configured_archive_dir = getattr(
|
||||
settings,
|
||||
"FNS_ARCHIVE_UPLOAD_DIRECTORY",
|
||||
None,
|
||||
)
|
||||
if configured_archive_dir:
|
||||
roots.append(Path(configured_archive_dir))
|
||||
return list(dict.fromkeys(root.resolve(strict=False) for root in roots))
|
||||
|
||||
@staticmethod
|
||||
def _is_relative_to(path: Path, root: Path) -> bool:
|
||||
try:
|
||||
path.relative_to(root)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _queue_file_bytes(
|
||||
cls,
|
||||
|
||||
Reference in New Issue
Block a user