Refactor Dockerfile to use entrypoint script, update requirements for bcrypt, and enhance FastAPI app with optional user retrieval and improved error handling

This commit is contained in:
smueller
2026-07-03 11:48:43 +02:00
parent 995740937e
commit 0d7729287f
6 changed files with 59 additions and 19 deletions

View File

@@ -2,7 +2,7 @@ from pathlib import Path
from fastapi import Depends, FastAPI, Form, HTTPException, Request, Response, status
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from sqlalchemy import inspect, text
@@ -14,7 +14,7 @@ from app.db.session import Base, engine, get_db
from app.models.system import SendLog
from app.models.user import User
from app.schemas.user import UserCreate
from app.services.auth import get_admin_user, get_current_user, require_editor_or_admin
from app.services.auth import get_admin_user, get_current_user, get_optional_user, require_editor_or_admin
from app.services.config_store import get_config, set_config
from app.services.csrf import CSRF_COOKIE_NAME, ensure_csrf_cookie, validate_csrf
from app.services.newsletter import create_html, create_plain_text, filter_articles
@@ -82,21 +82,46 @@ def _bootstrap_admin() -> None:
def _base_context(request: Request, user: User, db: Session) -> dict:
return {
"request": request,
"user": user,
"csrf_token": request.cookies.get(CSRF_COOKIE_NAME) or ensure_csrf_cookie(request),
"smtp": get_smtp_settings(db),
}
def _render(request: Request, name: str, context: dict) -> HTMLResponse:
return templates.TemplateResponse(request=request, name=name, context=context)
def _wants_html(request: Request) -> bool:
accept = request.headers.get("accept", "")
return "text/html" in accept or "*/*" in accept or accept == ""
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
if exc.status_code == status.HTTP_401_UNAUTHORIZED and _wants_html(request):
return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
if exc.status_code == status.HTTP_403_FORBIDDEN and _wants_html(request):
return RedirectResponse(url="/dashboard", status_code=status.HTTP_302_FOUND)
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
@app.get("/", response_class=HTMLResponse)
def index(request: Request):
return RedirectResponse(url="/dashboard", status_code=status.HTTP_302_FOUND)
def index(request: Request, db: Session = Depends(get_db)):
user = get_optional_user(request, db)
target = "/dashboard" if user else "/login"
return RedirectResponse(url=target, status_code=status.HTTP_302_FOUND)
@app.get("/login", response_class=HTMLResponse)
def login_page(request: Request):
return templates.TemplateResponse("login.html", {"request": request, "csrf_token": request.cookies.get(CSRF_COOKIE_NAME) or ensure_csrf_cookie(request)})
def login_page(request: Request, db: Session = Depends(get_db)):
if get_optional_user(request, db):
return RedirectResponse(url="/dashboard", status_code=status.HTTP_302_FOUND)
return _render(
request,
"login.html",
{"csrf_token": request.cookies.get(CSRF_COOKIE_NAME) or ensure_csrf_cookie(request)},
)
@app.post("/login")
@@ -131,7 +156,7 @@ async def dashboard(request: Request, db: Session = Depends(get_db), current_use
context.update({"articles": [], "raw_html": "", "plain_text": "", "filters": {"days": 30, "only_edited": False, "category": ""}})
logs = db.query(SendLog).order_by(SendLog.created_at.desc()).limit(20).all()
context["send_logs"] = logs
return templates.TemplateResponse("dashboard.html", context)
return _render(request, "dashboard.html", context)
@app.post("/dashboard", response_class=HTMLResponse)
@@ -162,7 +187,7 @@ async def dashboard_generate(
"send_logs": db.query(SendLog).order_by(SendLog.created_at.desc()).limit(20).all(),
}
)
return templates.TemplateResponse("dashboard.html", context)
return _render(request, "dashboard.html", context)
@app.post("/newsletter/send-now")
@@ -219,7 +244,7 @@ def update_smtp_settings(
def users_page(request: Request, db: Session = Depends(get_db), admin: User = Depends(get_admin_user)):
context = _base_context(request, admin, db)
context["users"] = db.query(User).order_by(User.created_at.desc()).all()
return templates.TemplateResponse("users.html", context)
return _render(request, "users.html", context)
@app.post("/admin/users")