From 42f9e4670cf5f88e09f720b3c19e85aeb62d3a7a Mon Sep 17 00:00:00 2001 From: NguyenND Date: Tue, 14 Jul 2026 11:33:17 -0400 Subject: [PATCH] Jul 14 - Preparation for using CDN - fix issue --- CLAUDE.md | 5 +++-- scripts/audit_photos.py | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index b02d8c9..8b21089 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1327,8 +1327,9 @@ timeout = 30 1. `Issue.photo_path` (string) 2. `Issue.mobile_photo_paths[]` (JSON list — iPad evidence) 3. `Issue.result_photos[]` (JSON list — web resolution photos) -4. `Inspection.photo_path` (string) -5. `Inspection.form_data{}` — any `uploads/...` string (image fields; walk nested) +4. `Inspection.form_data{}` — any `uploads/...` string (image fields; walk nested) +5. `InspectionResult.photo_path` (string — per checklist-item result photo) + - `Inspection` itself has **no** `photo_path` column (the `photo_path` at inspection.py:103 belongs to `InspectionResult`, not `Inspection`). - Signatures are inline `data:` base64 in the DB, **not files** → correctly ignored. **Zero-loss invariants (non-negotiable):** diff --git a/scripts/audit_photos.py b/scripts/audit_photos.py index 01231cb..162e9d3 100644 --- a/scripts/audit_photos.py +++ b/scripts/audit_photos.py @@ -9,11 +9,11 @@ database and NOTHING to the uploads tree. It only reads, and emits a report. What it does ------------ 1. Collects every photo path REFERENCED by the database, across all 5 sources: - - Issue.photo_path (string) - - Issue.mobile_photo_paths[] (JSON list — iPad evidence) - - Issue.result_photos[] (JSON list — web resolution photos) - - Inspection.photo_path (string) - - Inspection.form_data{} (any 'uploads/...' string, incl. nested — image fields) + - Issue.photo_path (string) + - Issue.mobile_photo_paths[] (JSON list — iPad evidence) + - Issue.result_photos[] (JSON list — web resolution photos) + - Inspection.form_data{} (any 'uploads/...' string, incl. nested — image fields) + - InspectionResult.photo_path (string — per checklist-item result photo) (Signatures are stored inline as 'data:' base64, NOT files — correctly ignored.) 2. Checks each referenced path against the file actually on disk. 3. Walks the uploads tree and finds files NOT referenced by any record (orphans). @@ -44,9 +44,9 @@ from datetime import datetime # Make the app package importable when run from the repo root. sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -from app import create_app, db # noqa: E402 -from app.models.issue import Issue # noqa: E402 -from app.models.inspection import Inspection # noqa: E402 +from app import create_app, db # noqa: E402 +from app.models.issue import Issue # noqa: E402 +from app.models.inspection import Inspection, InspectionResult # noqa: E402 # ── Path helpers ────────────────────────────────────────────────────────────── @@ -113,14 +113,18 @@ def collect_referenced(): for pth in (iss.result_photos or []): add(pth, f'issue:{iss.id}:result_photos', 'issue.result_photos') - # --- Inspections --- + # --- Inspections: form_data image fields (Inspection has NO photo_path) --- for insp in Inspection.query.yield_per(500): - add(insp.photo_path, f'inspection:{insp.id}:photo_path', 'inspection.photo_path') fd = insp.form_data or {} for s in walk_strings(fd): # Any 'uploads/...' string inside form_data is an uploaded image value. add(s, f'inspection:{insp.id}:form_data', 'inspection.form_data(image)') + # --- InspectionResult: per checklist-item result photo --- + for res in InspectionResult.query.yield_per(500): + add(res.photo_path, f'inspection_result:{res.id}:photo_path', + 'inspection_result.photo_path') + return referenced, by_source