fix: banner translations and deployment improvements
- Add translateCarName import from i18n.ts for proper multilingual support - Change default API language from 'ko' to 'en' for hero banners - Add checkbox column for Local Cars banner registration - Update Dockerfile with Playwright dependencies - Add PostgreSQL migration script - Add banner translation fix script 🤖 Generated with [Claude Code](https://claude.ai/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,7 @@ def get_localized_field(obj, field: str, lang: str) -> Optional[str]:
|
||||
|
||||
@router.get("/", response_model=List[HeroBannerLocalizedResponse])
|
||||
def get_hero_banners(
|
||||
lang: str = Query("ko", regex="^(ko|en|mn|ru)$"),
|
||||
lang: str = Query("en", regex="^(ko|en|mn|ru)$"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""활성 히어로 배너 목록 조회 (Public)"""
|
||||
|
||||
@@ -64,7 +64,10 @@ class Settings(BaseSettings):
|
||||
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
db_path = os.path.join(base_dir, "autonet.db")
|
||||
return f"sqlite:///{db_path}"
|
||||
return f"postgresql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
||||
# URL-encode password for special characters like @ # etc
|
||||
from urllib.parse import quote_plus
|
||||
encoded_password = quote_plus(self.DB_PASSWORD)
|
||||
return f"postgresql://{self.DB_USER}:{encoded_password}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
||||
|
||||
@property
|
||||
def REDIS_URL(self) -> str:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.responses import RedirectResponse
|
||||
from contextlib import asynccontextmanager
|
||||
import os
|
||||
import asyncio
|
||||
@@ -15,6 +17,42 @@ from datetime import datetime, timedelta
|
||||
|
||||
app_settings = get_settings()
|
||||
|
||||
|
||||
class TrailingSlashMiddleware(BaseHTTPMiddleware):
|
||||
"""
|
||||
Middleware to normalize trailing slashes on API paths.
|
||||
Uses redirect to strip trailing slashes from non-root routes.
|
||||
|
||||
Routes defined with "/" (like /hero-banners/) keep trailing slash.
|
||||
Routes defined without "/" (like /cars) get redirected.
|
||||
"""
|
||||
# Routes that are defined WITH trailing slash (router.get("/"))
|
||||
TRAILING_SLASH_ROUTES = {
|
||||
"/api/hero-banners/",
|
||||
"/api/settings/",
|
||||
"/api/notifications/",
|
||||
"/api/vehicle-requests/",
|
||||
}
|
||||
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
path = request.url.path
|
||||
|
||||
# Skip if it's a known trailing-slash route
|
||||
if path in self.TRAILING_SLASH_ROUTES:
|
||||
return await call_next(request)
|
||||
|
||||
# Redirect trailing slash from other /api/* paths
|
||||
if path.startswith("/api/") and path.endswith("/") and len(path) > 5:
|
||||
new_path = path.rstrip("/")
|
||||
if request.url.query:
|
||||
new_url = f"{new_path}?{request.url.query}"
|
||||
else:
|
||||
new_url = new_path
|
||||
return RedirectResponse(url=new_url, status_code=307)
|
||||
|
||||
return await call_next(request)
|
||||
|
||||
|
||||
# Create tables
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
@@ -118,6 +156,9 @@ app = FastAPI(
|
||||
lifespan=lifespan
|
||||
)
|
||||
|
||||
# Trailing slash middleware (must be added before CORS)
|
||||
app.add_middleware(TrailingSlashMiddleware)
|
||||
|
||||
# CORS - credentials=True requires explicit origins (not "*")
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
@@ -126,6 +167,8 @@ app.add_middleware(
|
||||
"http://127.0.0.1:3000",
|
||||
"http://localhost:8000",
|
||||
"http://192.168.0.202:3000", # Local network
|
||||
"https://autonetsellcar.com", # Production
|
||||
"http://autonetsellcar.com", # Production (HTTP redirect)
|
||||
],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
|
||||
Reference in New Issue
Block a user