52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
"""Сервисы для операций над заданиями: удаление и чистка артефактов."""
|
|
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from django.conf import settings
|
|
from django.db import transaction
|
|
|
|
from ..models import TimelapseJob
|
|
|
|
logger = logging.getLogger('camlaps')
|
|
|
|
|
|
def _resolve_output_video_path(job: TimelapseJob) -> Path | None:
|
|
"""Возвращает абсолютный путь к mp4 из output_rel_path или None, если видео не задано/путь небезопасен."""
|
|
rel = (job.output_rel_path or '').strip().lstrip('/')
|
|
if not rel:
|
|
return None
|
|
|
|
filename = Path(rel).name
|
|
export_dir = Path(settings.TIMELAPS_EXPORT_DIR).resolve()
|
|
candidate = (export_dir / filename).resolve()
|
|
|
|
if candidate != export_dir and export_dir not in candidate.parents:
|
|
return None
|
|
|
|
return candidate
|
|
|
|
|
|
@transaction.atomic
|
|
def delete_job_and_artifacts(job_id: int) -> bool:
|
|
"""Удаляет задачу и её видеофайл (если существует). Возвращает True, если файл видео был удалён."""
|
|
logger.info('jobs:delete:start job_id=%s', job_id)
|
|
|
|
job = TimelapseJob.objects.select_for_update().filter(pk=job_id).first()
|
|
if not job:
|
|
logger.info('jobs:delete:done job_not_found=true job_id=%s', job_id)
|
|
return False
|
|
|
|
video_path = _resolve_output_video_path(job)
|
|
video_deleted = False
|
|
|
|
if video_path and video_path.exists():
|
|
try:
|
|
video_path.unlink()
|
|
video_deleted = True
|
|
except Exception:
|
|
logger.exception('jobs:delete:video_unlink_error job_id=%s', job_id)
|
|
|
|
job.delete()
|
|
logger.info('jobs:delete:done job_id=%s video_deleted=%s', job_id, video_deleted)
|
|
return video_deleted |