from fastapi import FastAPI, HTTPException, Request from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse import traceback import os import locales import config from routers import auth, orders, catalog, portfolio, files, chat, blog, admin app = FastAPI(title="Radionica 3D API") # Configure CORS origins = [ "http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:5000", "https://radionica3d.me", "https://www.radionica3d.me", ] extra_origins = os.getenv("CORS_ORIGINS") if extra_origins: origins.extend(extra_origins.split(",")) app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.exception_handler(RequestValidationError) async def validation_exception_handler(request: Request, exc: RequestValidationError): lang = request.query_params.get("lang", "en") errors = [] for error in exc.errors(): error_type = error.get("type", "unknown") ctx = error.get("ctx", {}) translated_msg = locales.translate_error(error_type, lang, **ctx) loc = ".".join(str(l) for l in error.get("loc", [])[1:]) errors.append({ "loc": error.get("loc"), "msg": f"{loc}: {translated_msg}" if loc else translated_msg, "type": error_type }) return JSONResponse(status_code=422, content={"detail": errors}) @app.exception_handler(Exception) async def all_exception_handler(request: Request, exc: Exception): print(f"ERROR: {exc}") traceback.print_exc() if config.DEBUG: return JSONResponse( status_code=500, content={"detail": str(exc), "traceback": traceback.format_exc()} ) return JSONResponse(status_code=500, content={"detail": "Internal server error"}) # Add custom exception logging or other middleware here if needed # Include Routers app.include_router(auth.router) app.include_router(orders.router) app.include_router(catalog.router) app.include_router(portfolio.router) app.include_router(files.router) app.include_router(chat.router) app.include_router(blog.router) app.include_router(admin.router) # Mount Static Files if not os.path.exists("uploads"): os.makedirs("uploads") # Mount static files for uploads and previews with caching app.mount("/uploads", StaticFiles(directory="uploads", html=False), name="uploads") @app.middleware("http") async def add_cache_control_header(request, call_next): response = await call_next(request) if request.url.path.startswith("/uploads"): response.headers["Cache-Control"] = "public, max-age=604800, immutable" return response if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)