Source code for gamesheet_sdk.common.shared.image_upload

# Copyright (c) 2026 bdperkin
# SPDX-License-Identifier: MIT

"""Shared image upload functionality for GameSheet resources."""

from __future__ import annotations

import mimetypes
from pathlib import Path
from typing import Any

from gamesheet_sdk.common import errors
from gamesheet_sdk.common.constants import (
    BFF_API_BASE_URL,
    BFF_ASSETS_UPLOAD_URL,
    CLOUDFLARE_IMAGE_DELIVERY_BASE,
)
from gamesheet_sdk.common.exceptions import AuthenticationError, GameSheetError
from gamesheet_sdk.common.session import Session


[docs] def upload_image(session: Session, image_path: str, image_type: str = "image") -> str: """Upload an image file and return its Cloudflare CDN URL. :param session: An authenticated :class:`Session`. :type session: Session :param image_path: Path to a local image file. :type image_path: str :param image_type: Type of image for error messages (e.g., "photo", "logo"). :type image_type: str :returns: The Cloudflare CDN URL for the uploaded image. :rtype: str :raises GameSheetError: If the file is not found, is not a valid image, or the upload fails. :raises AuthenticationError: If the server returns 401. """ image_file_path = Path(image_path) if not image_file_path.exists(): _err_msg = f"{image_type.capitalize()} file not found: {image_path}" raise GameSheetError(_err_msg) mime_type, _ = mimetypes.guess_type(image_path) if not mime_type or not mime_type.startswith("image/"): _err_msg = f"Invalid image file: {image_path}" raise GameSheetError(_err_msg) upload_url_endpoint = f"{BFF_API_BASE_URL}{BFF_ASSETS_UPLOAD_URL}" upload_url_response = session.post(upload_url_endpoint) if upload_url_response.status_code == 401: raise AuthenticationError(errors.ERROR_MSG_401_EXPIRED) if upload_url_response.status_code >= 400: _err_msg = errors.ERROR_MSG_HTTP_POST.format( endpoint=upload_url_endpoint, status_code=upload_url_response.status_code, text=repr(upload_url_response.text[:200]), ) raise GameSheetError(_err_msg) upload_data: dict[str, Any] = upload_url_response.json() if upload_data.get("status") != "success": _err_msg = f"Failed to get upload URL: {upload_data}" raise GameSheetError(_err_msg) upload_url: str = upload_data["data"]["uploadURL"] image_id: str = upload_data["data"]["id"] with image_file_path.open("rb") as f: upload_response = session.post( upload_url, files={"file": (image_file_path.name, f, mime_type)}, ) if upload_response.status_code >= 400: _err_msg = errors.ERROR_MSG_HTTP_POST.format( endpoint=upload_url, status_code=upload_response.status_code, text=repr(upload_response.text[:200]), ) raise GameSheetError(_err_msg) upload_result: dict[str, Any] = upload_response.json() if not upload_result.get("success"): _err_msg = f"Failed to upload {image_type}: {upload_result}" raise GameSheetError(_err_msg) return f"{CLOUDFLARE_IMAGE_DELIVERY_BASE}/{image_id}"