File size: 2,422 Bytes
732b14f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Resolve report section photo paths under ``settings.upload_dir``."""

from __future__ import annotations

from pathlib import Path

from app.config import settings

_PHOTO_EXTENSIONS = ("jpg", "jpeg", "png", "webp")


def report_photo_relpath(
    tenant_id: str,
    report_id: str,
    section_code: str,
    photo_id: str,
    ext: str,
) -> str:
    """Relative path stored in ``ReportSectionPhoto.file_path`` (POSIX-style)."""
    ext_norm = ext.lower().lstrip(".")
    if ext_norm == "jpeg":
        ext_norm = "jpg"
    return "/".join(
        (
            tenant_id,
            "report_photos",
            str(report_id),
            str(section_code),
            f"{photo_id}.{ext_norm}",
        )
    )


def resolve_report_photo_path(
    file_path: str,
    *,
    tenant_id: str | None = None,
    report_id: str | None = None,
    section_code: str | None = None,
    photo_id: str | None = None,
) -> str | None:
    """Return an on-disk path for python-docx / FileResponse, or ``None``."""
    raw = (file_path or "").strip()
    if not raw:
        return None

    upload_root = settings.upload_dir.resolve()

    candidate = Path(raw)
    if candidate.is_file():
        return str(candidate.resolve())

    # Path stored relative to upload_dir (preferred).
    rel = Path(raw.replace("\\", "/"))
    if not rel.is_absolute():
        under = (upload_root / rel).resolve()
        if under.is_file():
            return str(under)

    # Absolute path from another host/container — re-root under upload_dir when possible.
    parts = tuple(Path(raw).parts)
    if "report_photos" in parts:
        idx = parts.index("report_photos")
        if idx >= 1:
            suffix = Path(*parts[idx - 1 :])
            under = (upload_root / suffix).resolve()
            if under.is_file():
                return str(under)

    if tenant_id and report_id and section_code and photo_id:
        section_dir = upload_root / tenant_id / "report_photos" / str(report_id) / str(section_code)
        if section_dir.is_dir():
            for ext in _PHOTO_EXTENSIONS:
                cand = section_dir / f"{photo_id}.{ext}"
                if cand.is_file():
                    return str(cand.resolve())
            name = Path(raw).name
            if name:
                cand = section_dir / name
                if cand.is_file():
                    return str(cand.resolve())

    return None