Skip to content

Commit c89b375

Browse files
committed
fix(backend): avoid error if s3 url pre-signing fails on project get
1 parent 4c903b3 commit c89b375

File tree

1 file changed

+52
-20
lines changed

1 file changed

+52
-20
lines changed

src/backend/app/projects/project_schemas.py

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import uuid
33
from datetime import date, datetime
4+
from urllib.parse import urlparse
45
from typing import Annotated, List, Optional, Union
56

67
import geojson
@@ -624,6 +625,25 @@ def calculate_pagination(cls, values):
624625
return values
625626

626627

628+
def safe_url(callable_fn, *, label: str):
629+
"""
630+
Check if a URL is valid & also avoid error if S3 pre-sign fails.
631+
"""
632+
try:
633+
url = callable_fn()
634+
if not url:
635+
return None
636+
637+
parsed = urlparse(url)
638+
if parsed.scheme not in {"http", "https"}:
639+
raise ValueError(f"Invalid URL scheme: {url}")
640+
641+
return url
642+
except Exception as e:
643+
log.warning(f"Failed to generate {label} URL: {e}")
644+
return None
645+
646+
627647
class ProjectInfo(BaseModel):
628648
"""Out model for the project endpoint."""
629649

@@ -659,37 +679,49 @@ class ProjectInfo(BaseModel):
659679

660680
@model_validator(mode="after")
661681
def set_image_url(cls, values):
662-
"""Set image_url before rendering the model."""
663682
project_id = values.id
664-
if project_id:
665-
image_dir = f"dtm-data/projects/{project_id}/map_screenshot.png"
666-
values.image_url = generate_presigned_download_url(
667-
settings.S3_BUCKET_NAME, image_dir, 5
668-
)
683+
if not project_id:
684+
return values
685+
686+
image_dir = f"dtm-data/projects/{project_id}/map_screenshot.png"
687+
688+
values.image_url = safe_url(
689+
lambda: generate_presigned_download_url(
690+
settings.S3_BUCKET_NAME,
691+
image_dir,
692+
5,
693+
),
694+
label="image_url",
695+
)
696+
669697
return values
670698

671699
@model_validator(mode="after")
672700
def set_assets_url(cls, values):
673-
"""Set assets_url before rendering the model."""
674701
project_id = values.id
675-
if project_id:
676-
values.assets_url = (
677-
get_assets_url_for_project(project_id)
678-
if values.image_processing_status == "SUCCESS"
679-
else None
680-
)
702+
if not project_id or values.image_processing_status != "SUCCESS":
703+
values.assets_url = None
704+
return values
705+
706+
values.assets_url = safe_url(
707+
lambda: get_assets_url_for_project(project_id),
708+
label="assets_url",
709+
)
710+
681711
return values
682712

683713
@model_validator(mode="after")
684714
def set_orthophoto_url(cls, values):
685-
"""Set orthophoto_url before rendering the model."""
686715
project_id = values.id
687-
if project_id:
688-
values.orthophoto_url = (
689-
get_orthophoto_url_for_project(project_id)
690-
if values.image_processing_status == "SUCCESS"
691-
else None
692-
)
716+
if not project_id or values.image_processing_status != "SUCCESS":
717+
values.orthophoto_url = None
718+
return values
719+
720+
values.orthophoto_url = safe_url(
721+
lambda: get_orthophoto_url_for_project(project_id),
722+
label="orthophoto_url",
723+
)
724+
693725
return values
694726

695727
@model_validator(mode="after")

0 commit comments

Comments
 (0)