From 6a8eb826a69cbb9b43312d150190007a52b42203 Mon Sep 17 00:00:00 2001 From: abhiramtx <7253115-abhiramtx@users.noreply.replit.com> Date: Sat, 13 Dec 2025 21:34:03 +0000 Subject: [PATCH] Add persistent file storage and improve error handling Refactor object storage initialization to use a dedicated function and add error handling for uploads, including a fallback to local storage. Replit-Commit-Author: Agent Replit-Commit-Session-Id: cd9a7d26-a4e5-4215-975c-c59f4ed1f06d Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 127466ff-4d39-4e2e-bc28-80d552851c25 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/d0a1d46d-d203-4308-bc6a-312ac7c0243b/cd9a7d26-a4e5-4215-975c-c59f4ed1f06d/05bPjFc --- .replit | 4 ---- app.py | 18 +++++++++++++++--- object_storage.py | 45 +++++++++++++++++++++++++-------------------- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/.replit b/.replit index 3b5a64a..a77bab0 100644 --- a/.replit +++ b/.replit @@ -12,10 +12,6 @@ deploymentTarget = "cloudrun" localPort = 5000 externalPort = 80 -[[ports]] -localPort = 37833 -externalPort = 3000 - [agent] expertMode = true diff --git a/app.py b/app.py index ec16ddb..0074c4b 100644 --- a/app.py +++ b/app.py @@ -17,11 +17,16 @@ ADMIN_PASSWORD = 'techturb123' try: storage_service = ObjectStorageService() USING_OBJECT_STORAGE = True + print(f"Object Storage initialized successfully - using bucket: {storage_service.bucket_name}") except ValueError as e: print(f"Warning: Object Storage not configured - {e}") print("Files will be saved locally (ephemeral storage)") storage_service = None USING_OBJECT_STORAGE = False +except Exception as e: + print(f"Error initializing Object Storage: {e}") + storage_service = None + USING_OBJECT_STORAGE = False def get_db_connection(): conn = psycopg2.connect(os.environ['DATABASE_URL']) @@ -36,10 +41,17 @@ def upload_file_to_storage(file, folder='uploads'): return None if USING_OBJECT_STORAGE and storage_service: - # Upload to persistent object storage - return storage_service.upload_file(file, folder) + try: + result = storage_service.upload_file(file, folder) + print(f"File uploaded to object storage: {result}") + return result + except Exception as e: + print(f"Error uploading to object storage: {e}") + filename = secure_filename(file.filename) + filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) + file.save(filepath) + return f'images/{filename}' else: - # Fallback to local storage (ephemeral) filename = secure_filename(file.filename) filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(filepath) diff --git a/object_storage.py b/object_storage.py index 1d0723c..0a1d963 100644 --- a/object_storage.py +++ b/object_storage.py @@ -4,35 +4,45 @@ Handles persistent file uploads using Google Cloud Storage (Replit Object Storag """ from google.cloud import storage +from google.auth import identity_pool import os +import json from uuid import uuid4 from werkzeug.utils import secure_filename REPLIT_SIDECAR_ENDPOINT = "http://127.0.0.1:1106" +def get_replit_credentials(): + """Create proper credentials for Replit Object Storage""" + credentials_config = { + "audience": "replit", + "subject_token_type": "access_token", + "token_url": f"{REPLIT_SIDECAR_ENDPOINT}/token", + "type": "external_account", + "credential_source": { + "url": f"{REPLIT_SIDECAR_ENDPOINT}/credential", + "format": { + "type": "json", + "subject_token_field_name": "access_token", + }, + }, + "universe_domain": "googleapis.com", + } + + credentials = identity_pool.Credentials.from_info(credentials_config) + return credentials + + class ObjectStorageService: def __init__(self): """Initialize the object storage client with Replit credentials""" + credentials = get_replit_credentials() self.client = storage.Client( - credentials={ - "audience": "replit", - "subject_token_type": "access_token", - "token_url": f"{REPLIT_SIDECAR_ENDPOINT}/token", - "type": "external_account", - "credential_source": { - "url": f"{REPLIT_SIDECAR_ENDPOINT}/credential", - "format": { - "type": "json", - "subject_token_field_name": "access_token", - }, - }, - "universe_domain": "googleapis.com", - }, + credentials=credentials, project="", ) - # Get bucket name from environment variable self.bucket_name = os.environ.get('OBJECT_STORAGE_BUCKET') if not self.bucket_name: raise ValueError( @@ -56,23 +66,19 @@ class ObjectStorageService: if not file or not file.filename: return None - # Generate unique filename original_filename = secure_filename(file.filename) file_extension = os.path.splitext(original_filename)[1] unique_filename = f"{uuid4()}{file_extension}" object_name = f"{folder}/{unique_filename}" - # Upload to bucket blob = self.bucket.blob(object_name) blob.upload_from_file( file.stream, content_type=file.content_type or 'application/octet-stream' ) - # Make the blob publicly accessible blob.make_public() - # Return the public URL return blob.public_url def get_blob(self, url): @@ -80,7 +86,6 @@ class ObjectStorageService: if not url or not url.startswith('https://storage.googleapis.com/'): return None - # Extract blob name from URL parts = url.replace(f'https://storage.googleapis.com/{self.bucket_name}/', '') return self.bucket.blob(parts)