mirror of
https://github.com/skoelle/calender_sync.git
synced 2026-09-17 18:20:24 +00:00
fix: Error Handling + Context Manager für DB-Verbindungen
- try/finally für Connection/Cleanup in allen Endpunkten - fetch_events() Helper-Funktion reduziert Code-Duplikation - Exception Logging bei DB-Fehlern - HTTPException 500 bei Datenbankfehlern
This commit is contained in:
+51
-67
@@ -1,17 +1,22 @@
|
|||||||
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from fastapi import FastAPI, Query
|
from fastapi import FastAPI, HTTPException, Query
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from api.database import get_connection
|
from api.database import get_connection
|
||||||
|
|
||||||
|
log = logging.getLogger("calendar-api")
|
||||||
|
|
||||||
app = FastAPI(title="Calendar Sync API")
|
app = FastAPI(title="Calendar Sync API")
|
||||||
|
|
||||||
templates = Jinja2Templates(directory=Path(__file__).parent / "templates")
|
templates = Jinja2Templates(directory=Path(__file__).parent / "templates")
|
||||||
|
|
||||||
|
SELECT_COLUMNS = "id, summary, description, location, start_at, end_at, all_day, status"
|
||||||
|
|
||||||
|
|
||||||
class EventResponse(BaseModel):
|
class EventResponse(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
@@ -43,6 +48,32 @@ def row_to_event(row) -> EventResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_events(limit: int = 10, search: str | None = None) -> list[dict]:
|
||||||
|
conn = get_connection()
|
||||||
|
try:
|
||||||
|
cur = conn.cursor()
|
||||||
|
try:
|
||||||
|
if search:
|
||||||
|
cur.execute(
|
||||||
|
f"SELECT {SELECT_COLUMNS} FROM calendar_events "
|
||||||
|
"WHERE deleted = 0 AND start_at >= NOW() AND summary LIKE %s "
|
||||||
|
"ORDER BY start_at ASC LIMIT %s",
|
||||||
|
(f"%{search}%", limit),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cur.execute(
|
||||||
|
f"SELECT {SELECT_COLUMNS} FROM calendar_events "
|
||||||
|
"WHERE deleted = 0 AND start_at >= NOW() "
|
||||||
|
"ORDER BY start_at ASC LIMIT %s",
|
||||||
|
(limit,),
|
||||||
|
)
|
||||||
|
return cur.fetchall()
|
||||||
|
finally:
|
||||||
|
cur.close()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/health")
|
@app.get("/api/health")
|
||||||
def health():
|
def health():
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
@@ -53,35 +84,11 @@ def get_events(
|
|||||||
limit: int = Query(default=10, ge=1, le=50),
|
limit: int = Query(default=10, ge=1, le=50),
|
||||||
search: str | None = Query(default=None),
|
search: str | None = Query(default=None),
|
||||||
):
|
):
|
||||||
conn = get_connection()
|
try:
|
||||||
cur = conn.cursor()
|
rows = fetch_events(limit=limit, search=search)
|
||||||
|
except Exception:
|
||||||
if search:
|
log.exception("DB-Fehler bei /api/events")
|
||||||
cur.execute(
|
raise HTTPException(status_code=500, detail="Database error")
|
||||||
"""
|
|
||||||
SELECT id, summary, description, location, start_at, end_at, all_day, status
|
|
||||||
FROM calendar_events
|
|
||||||
WHERE deleted = 0 AND start_at >= NOW() AND summary LIKE %s
|
|
||||||
ORDER BY start_at ASC
|
|
||||||
LIMIT %s
|
|
||||||
""",
|
|
||||||
(f"%{search}%", limit),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
SELECT id, summary, description, location, start_at, end_at, all_day, status
|
|
||||||
FROM calendar_events
|
|
||||||
WHERE deleted = 0 AND start_at >= NOW()
|
|
||||||
ORDER BY start_at ASC
|
|
||||||
LIMIT %s
|
|
||||||
""",
|
|
||||||
(limit,),
|
|
||||||
)
|
|
||||||
|
|
||||||
rows = cur.fetchall()
|
|
||||||
cur.close()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
events = [row_to_event(row) for row in rows]
|
events = [row_to_event(row) for row in rows]
|
||||||
|
|
||||||
@@ -95,23 +102,24 @@ def get_events(
|
|||||||
@app.get("/api/events/{event_id}", response_model=EventResponse)
|
@app.get("/api/events/{event_id}", response_model=EventResponse)
|
||||||
def get_event(event_id: int):
|
def get_event(event_id: int):
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
|
try:
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
try:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
f"SELECT {SELECT_COLUMNS} FROM calendar_events "
|
||||||
SELECT id, summary, description, location, start_at, end_at, all_day, status
|
"WHERE id = %s AND deleted = 0",
|
||||||
FROM calendar_events
|
|
||||||
WHERE id = %s AND deleted = 0
|
|
||||||
""",
|
|
||||||
(event_id,),
|
(event_id,),
|
||||||
)
|
)
|
||||||
|
|
||||||
row = cur.fetchone()
|
row = cur.fetchone()
|
||||||
|
finally:
|
||||||
cur.close()
|
cur.close()
|
||||||
|
except Exception:
|
||||||
|
log.exception("DB-Fehler bei /api/events/%d", event_id)
|
||||||
|
raise HTTPException(status_code=500, detail="Database error")
|
||||||
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if not row:
|
if not row:
|
||||||
from fastapi import HTTPException
|
|
||||||
raise HTTPException(status_code=404, detail="Event not found")
|
raise HTTPException(status_code=404, detail="Event not found")
|
||||||
|
|
||||||
return row_to_event(row)
|
return row_to_event(row)
|
||||||
@@ -122,35 +130,11 @@ def index(
|
|||||||
search: str | None = Query(default=None),
|
search: str | None = Query(default=None),
|
||||||
limit: int = Query(default=10, ge=1, le=50),
|
limit: int = Query(default=10, ge=1, le=50),
|
||||||
):
|
):
|
||||||
conn = get_connection()
|
try:
|
||||||
cur = conn.cursor()
|
rows = fetch_events(limit=limit, search=search)
|
||||||
|
except Exception:
|
||||||
if search:
|
log.exception("DB-Fehler bei /")
|
||||||
cur.execute(
|
raise HTTPException(status_code=500, detail="Database error")
|
||||||
"""
|
|
||||||
SELECT id, summary, description, location, start_at, end_at, all_day, status
|
|
||||||
FROM calendar_events
|
|
||||||
WHERE deleted = 0 AND start_at >= NOW() AND summary LIKE %s
|
|
||||||
ORDER BY start_at ASC
|
|
||||||
LIMIT %s
|
|
||||||
""",
|
|
||||||
(f"%{search}%", limit),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
SELECT id, summary, description, location, start_at, end_at, all_day, status
|
|
||||||
FROM calendar_events
|
|
||||||
WHERE deleted = 0 AND start_at >= NOW()
|
|
||||||
ORDER BY start_at ASC
|
|
||||||
LIMIT %s
|
|
||||||
""",
|
|
||||||
(limit,),
|
|
||||||
)
|
|
||||||
|
|
||||||
rows = cur.fetchall()
|
|
||||||
cur.close()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
events = []
|
events = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
|||||||
Reference in New Issue
Block a user