Files
md2vk/app/main.py
T

83 lines
2.6 KiB
Python

"""md2vk — FastAPI приложение."""
from __future__ import annotations
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
from app.database import init_db
from app.api.v1 import router as api_v1_router
from app.api.audit import AuditMiddleware
from pathlib import Path
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s")
logger = logging.getLogger("md2vk")
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Инициализация при старте."""
logger.info("Initializing database...")
await init_db()
logger.info("Database ready. Starting md2vk...")
yield
logger.info("Shutting down...")
app = FastAPI(
title="md2vk",
description="Сервис публикации Markdown на стене VK",
version="0.1.0",
lifespan=lifespan,
)
# Аудит-лог авторизации/запросов API (JSONL, ротация по дням)
app.add_middleware(AuditMiddleware)
app.include_router(api_v1_router)
STATIC_DIR = Path(__file__).resolve().parent.parent / "static"
@app.get("/favicon.ico", include_in_schema=False)
async def favicon() -> FileResponse:
"""Favicon (SVG-бренд)."""
return FileResponse(STATIC_DIR / "favicon.svg", media_type="image/svg+xml")
@app.get("/", response_class=HTMLResponse, include_in_schema=False)
async def index() -> HTMLResponse:
"""Стартовая страница сервиса."""
return HTMLResponse(
"""<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>md2vk</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 640px; margin: 80px auto; padding: 0 20px;
background: #0d1117; color: #e6edf3; }
h1 { color: #58a6ff; }
code { background: #1f2630; padding: 2px 6px; border-radius: 4px; }
</style>
</head>
<body>
<h1>md2vk</h1>
<p>Сервис публикации Markdown на стену ВКонтакте.</p>
<p>API: <code>/api/v1</code> · <a href="/docs" style="color:#58a6ff">Swagger UI</a> · <a href="/redoc" style="color:#58a6ff">ReDoc</a></p>
</body>
</html>"""
)
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
logger.error(f"Unhandled error: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={"detail": f"Internal server error: {str(exc)}"},
)