diff --git a/app/cabinet/routes/branding.py b/app/cabinet/routes/branding.py index 14c9dc0e..63e6b745 100644 --- a/app/cabinet/routes/branding.py +++ b/app/cabinet/routes/branding.py @@ -31,6 +31,7 @@ BRANDING_LOGO_KEY = "CABINET_BRANDING_LOGO" # Stores "custom" or "default" THEME_COLORS_KEY = "CABINET_THEME_COLORS" # Stores JSON with theme colors ENABLED_THEMES_KEY = "CABINET_ENABLED_THEMES" # Stores JSON with enabled themes {"dark": true, "light": false} ANIMATION_ENABLED_KEY = "CABINET_ANIMATION_ENABLED" # Stores "true" or "false" +FULLSCREEN_ENABLED_KEY = "CABINET_FULLSCREEN_ENABLED" # Stores "true" or "false" # Allowed image types ALLOWED_CONTENT_TYPES = {"image/png", "image/jpeg", "image/jpg", "image/webp", "image/svg+xml"} @@ -106,6 +107,16 @@ class AnimationEnabledUpdate(BaseModel): enabled: bool +class FullscreenEnabledResponse(BaseModel): + """Fullscreen enabled setting.""" + enabled: bool = False + + +class FullscreenEnabledUpdate(BaseModel): + """Request to update fullscreen setting.""" + enabled: bool + + # Default theme colors DEFAULT_THEME_COLORS = { "accent": "#3b82f6", @@ -549,3 +560,37 @@ async def update_animation_enabled( logger.info(f"Admin {admin.telegram_id} set animation enabled: {payload.enabled}") return AnimationEnabledResponse(enabled=payload.enabled) + + +# ============ Fullscreen Routes ============ + +@router.get("/fullscreen", response_model=FullscreenEnabledResponse) +async def get_fullscreen_enabled( + db: AsyncSession = Depends(get_cabinet_db), +): + """ + Get fullscreen enabled setting. + This is a public endpoint - no authentication required. + """ + fullscreen_value = await get_setting_value(db, FULLSCREEN_ENABLED_KEY) + + if fullscreen_value is not None: + enabled = fullscreen_value.lower() == "true" + return FullscreenEnabledResponse(enabled=enabled) + + # Default: disabled + return FullscreenEnabledResponse(enabled=False) + + +@router.patch("/fullscreen", response_model=FullscreenEnabledResponse) +async def update_fullscreen_enabled( + payload: FullscreenEnabledUpdate, + admin: User = Depends(get_current_admin_user), + db: AsyncSession = Depends(get_cabinet_db), +): + """Update fullscreen enabled setting. Admin only.""" + await set_setting_value(db, FULLSCREEN_ENABLED_KEY, str(payload.enabled).lower()) + + logger.info(f"Admin {admin.telegram_id} set fullscreen enabled: {payload.enabled}") + + return FullscreenEnabledResponse(enabled=payload.enabled) diff --git a/app/webapi/server.py b/app/webapi/server.py index 00bc2a3c..863ec5e2 100644 --- a/app/webapi/server.py +++ b/app/webapi/server.py @@ -25,14 +25,45 @@ class WebAPIServer: logger.warning("WEB_API_WORKERS > 1 не поддерживается в embed-режиме, используем 1") workers = 1 + # Кастомный конфиг логирования - скрываем спам от WebSocket + log_config = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "default": { + "()": "uvicorn.logging.DefaultFormatter", + "fmt": "%(levelprefix)s %(message)s", + "use_colors": None, + }, + }, + "handlers": { + "default": { + "formatter": "default", + "class": "logging.StreamHandler", + "stream": "ext://sys.stderr", + }, + }, + "loggers": { + "uvicorn": {"handlers": ["default"], "level": "WARNING", "propagate": False}, + "uvicorn.error": {"level": "WARNING", "propagate": False}, + "uvicorn.access": {"level": "ERROR", "propagate": False}, + "uvicorn.protocols": {"level": "WARNING", "propagate": False}, + "uvicorn.protocols.websockets": {"level": "WARNING", "propagate": False}, + "uvicorn.protocols.websockets.websockets_impl": {"level": "WARNING", "propagate": False}, + "websockets": {"level": "WARNING", "propagate": False}, + "websockets.server": {"level": "WARNING", "propagate": False}, + }, + } + self._config = uvicorn.Config( app=self._app, host=settings.WEB_API_HOST, port=int(settings.WEB_API_PORT or 8080), - log_level=settings.LOG_LEVEL.lower(), + log_level="warning", workers=workers, lifespan="on", access_log=False, + log_config=log_config, ) self._server = uvicorn.Server(self._config) self._task: Optional[asyncio.Task[None]] = None