Merge pull request 'add cors headers in exception handler in cors' (#506) from Mic92-sops-nix into main

This commit is contained in:
clan-bot
2023-11-14 15:42:46 +00:00
4 changed files with 72 additions and 39 deletions

View File

@@ -1,47 +1,24 @@
import logging import logging
import os
from enum import Enum
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.routing import APIRoute from fastapi.routing import APIRoute
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from ..errors import ClanError
from .assets import asset_path from .assets import asset_path
from .error_handlers import clan_error_handler from .error_handlers import clan_error_handler
from .routers import clan_modules, flake, health, machines, root, vms from .routers import clan_modules, flake, health, machines, root, vms
from .settings import settings
from .tags import tags_metadata from .tags import tags_metadata
# Logging setup # Logging setup
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class EnvType(Enum):
production = "production"
development = "development"
@staticmethod
def from_environment() -> "EnvType":
t = os.environ.get("CLAN_WEBUI_ENV", "production")
try:
return EnvType[t]
except KeyError:
log.warning(f"Invalid environment type: {t}, fallback to production")
return EnvType.production
def is_production(self) -> bool:
return self == EnvType.production
def is_development(self) -> bool:
return self == EnvType.development
def setup_app() -> FastAPI: def setup_app() -> FastAPI:
env = EnvType.from_environment()
app = FastAPI() app = FastAPI()
if env.is_development(): if settings.env.is_development():
# Allow CORS in development mode for nextjs dev server # Allow CORS in development mode for nextjs dev server
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
@@ -59,7 +36,7 @@ def setup_app() -> FastAPI:
# Needs to be last in register. Because of wildcard route # Needs to be last in register. Because of wildcard route
app.include_router(root.router) app.include_router(root.router)
app.add_exception_handler(ClanError, clan_error_handler) app.add_exception_handler(Exception, clan_error_handler)
app.mount("/static", StaticFiles(directory=asset_path()), name="static") app.mount("/static", StaticFiles(directory=asset_path()), name="static")

View File

@@ -5,20 +5,44 @@ from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from ..errors import ClanError from ..errors import ClanError
from .settings import settings
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def clan_error_handler(request: Request, exc: Exception) -> JSONResponse: def clan_error_handler(request: Request, exc: Exception) -> JSONResponse:
assert isinstance(exc, ClanError) headers = {}
log.error("ClanError: %s", exc)
detail = [ if settings.env.is_development():
{ headers["Access-Control-Allow-Origin"] = "*"
"loc": [], headers["Access-Control-Allow-Methods"] = "*"
"msg": str(exc),
} if isinstance(exc, ClanError):
] log.error(f"ClanError: {exc}")
return JSONResponse( detail = [
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, {
content=jsonable_encoder(dict(detail=detail)), "loc": [],
) "msg": str(exc),
}
]
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=jsonable_encoder(dict(detail=detail)),
headers=headers,
)
else:
log.exception(f"Unhandled Exception: {exc}")
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=jsonable_encoder(
dict(
detail=[
{
"loc": [],
"msg": str(exc),
}
]
)
),
headers=headers,
)

View File

@@ -0,0 +1,32 @@
import logging
import os
from enum import Enum
log = logging.getLogger(__name__)
class EnvType(Enum):
production = "production"
development = "development"
@staticmethod
def from_environment() -> "EnvType":
t = os.environ.get("CLAN_WEBUI_ENV", "production")
try:
return EnvType[t]
except KeyError:
log.warning(f"Invalid environment type: {t}, fallback to production")
return EnvType.production
def is_production(self) -> bool:
return self == EnvType.production
def is_development(self) -> bool:
return self == EnvType.development
class Settings:
env = EnvType.from_environment()
settings = Settings()

View File

@@ -11,4 +11,4 @@ from clan_cli.webui.app import app
def api() -> TestClient: def api() -> TestClient:
# logging.getLogger("httpx").setLevel(level=logging.WARNING) # logging.getLogger("httpx").setLevel(level=logging.WARNING)
logging.getLogger("asyncio").setLevel(logging.INFO) logging.getLogger("asyncio").setLevel(logging.INFO)
return TestClient(app) return TestClient(app, raise_server_exceptions=False)