@@ -98,6 +98,7 @@ async def lifespan(app: FastAPI): # pylint: disable=redefined-outer-name
9898
9999metrics = Metrics ()
100100app = FastAPI (lifespan = lifespan , debug = True , docs_url = None , redoc_url = None )
101+
101102db = Database (service = (os .getenv ('MONGO_SERVICE' ) or 'mongodb://db:27017' ))
102103auth = Authentication (token_url = "user/login" )
103104pubsub = None # pylint: disable=invalid-name
@@ -1456,6 +1457,72 @@ async def icons(icon_name: str):
14561457 return FileResponse (icon_path )
14571458
14581459
1460+ @app .get ('/static/css/{filename}' )
1461+ async def serve_css (filename : str ):
1462+ """Serve CSS files from api/static/css/"""
1463+ metrics .add ('http_requests_total' , 1 )
1464+ root_dir = os .path .dirname (os .path .abspath (__file__ ))
1465+ print (f"[CSS] Request for: { filename } " )
1466+ print (f"[CSS] root_dir: { root_dir } " )
1467+ # Security: only allow safe filenames
1468+ if not re .match (r'^[A-Za-z0-9_.-]+\.css$' , filename ):
1469+ print (f"[CSS] Invalid filename pattern: { filename } " )
1470+ raise HTTPException (
1471+ status_code = status .HTTP_400_BAD_REQUEST ,
1472+ detail = "Invalid filename"
1473+ )
1474+ file_path = os .path .join (root_dir , 'static' , 'css' , filename )
1475+ print (f"[CSS] Looking for file at: { file_path } " )
1476+ print (f"[CSS] File exists: { os .path .isfile (file_path )} " )
1477+ if not os .path .isfile (file_path ):
1478+ print (f"[CSS] File not found: { file_path } " )
1479+ raise HTTPException (
1480+ status_code = status .HTTP_404_NOT_FOUND ,
1481+ detail = "File not found"
1482+ )
1483+ print (f"[CSS] Serving file: { file_path } " )
1484+ return FileResponse (
1485+ file_path ,
1486+ media_type = "text/css" ,
1487+ headers = {
1488+ 'Cache-Control' : 'public, max-age=3600' , # Cache for 1 hour
1489+ }
1490+ )
1491+
1492+
1493+ @app .get ('/static/js/{filename}' )
1494+ async def serve_js (filename : str ):
1495+ """Serve JavaScript files from api/static/js/"""
1496+ metrics .add ('http_requests_total' , 1 )
1497+ root_dir = os .path .dirname (os .path .abspath (__file__ ))
1498+ print (f"[JS] Request for: { filename } " )
1499+ print (f"[JS] root_dir: { root_dir } " )
1500+ # Security: only allow safe filenames
1501+ if not re .match (r'^[A-Za-z0-9_.-]+\.js$' , filename ):
1502+ print (f"[JS] Invalid filename pattern: { filename } " )
1503+ raise HTTPException (
1504+ status_code = status .HTTP_400_BAD_REQUEST ,
1505+ detail = "Invalid filename"
1506+ )
1507+ file_path = os .path .join (root_dir , 'static' , 'js' , filename )
1508+ print (f"[JS] Looking for file at: { file_path } " )
1509+ print (f"[JS] File exists: { os .path .isfile (file_path )} " )
1510+ if not os .path .isfile (file_path ):
1511+ print (f"[JS] File not found: { file_path } " )
1512+ raise HTTPException (
1513+ status_code = status .HTTP_404_NOT_FOUND ,
1514+ detail = "File not found"
1515+ )
1516+ print (f"[JS] Serving file: { file_path } " )
1517+ return FileResponse (
1518+ file_path ,
1519+ media_type = "application/javascript" ,
1520+ headers = {
1521+ 'Cache-Control' : 'public, max-age=3600' , # Cache for 1 hour
1522+ }
1523+ )
1524+
1525+
14591526@app .get ('/metrics' )
14601527async def get_metrics ():
14611528 """Get metrics"""
0 commit comments