Files
gexp/main.py
T

94 lines
3.2 KiB
Python

from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
from starlette.types import Scope
from config import UPLOAD_DIR, ENVIRONMENT
from database.schema import create_tables
from routers import documents, review, search, upload, auth
from services.auth_service import get_session, cleanup_expired_sessions
Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True)
Path("data").mkdir(exist_ok=True)
class CachedStaticFiles(StaticFiles):
"""StaticFiles that sets a long Cache-Control header so browsers
don't re-download the same image on every refresh."""
def __init__(self, *args, max_age: int = 86400, **kwargs):
super().__init__(*args, **kwargs)
self._max_age = max_age
async def get_response(self, path: str, scope: Scope):
response = await super().get_response(path, scope)
if response.status_code == 200:
response.headers["Cache-Control"] = f"public, max-age={self._max_age}"
return response
@asynccontextmanager
async def lifespan(app: FastAPI):
create_tables()
try:
cleanup_expired_sessions()
except Exception:
pass
# Resume any documents that were left in 'pending' state from a previous run
# (e.g. server restart killed the background extraction task).
try:
import asyncio
from database.connection import get_db
from services.extractor import get_default_provider
from routers.upload import _extract_and_save
default_provider = get_default_provider()
with get_db() as conn:
stuck = conn.execute(
"SELECT id, image_path, provider FROM documents WHERE status='pending'"
).fetchall()
for row in stuck:
provider = row["provider"] or default_provider
asyncio.create_task(_extract_and_save(row["id"], row["image_path"], provider))
except Exception:
pass
yield
# Disable docs/openapi in production
if ENVIRONMENT == "production":
app = FastAPI(title="Lebanese Real Estate Registry", docs_url=None, redoc_url=None, openapi_url=None, lifespan=lifespan)
else:
app = FastAPI(title="Lebanese Real Estate Registry", lifespan=lifespan)
@app.middleware("http")
async def check_authentication(request: Request, call_next):
path = request.url.path
allowed_paths = ["/auth/login", "/static"]
is_allowed = any(path.startswith(p) for p in allowed_paths)
request.state.user = None
if not is_allowed:
session_id = request.cookies.get("session_id")
user = get_session(session_id) if session_id else None
if not user:
return RedirectResponse(url="/auth/login", status_code=303)
request.state.user = user
response = await call_next(request)
return response
app.mount("/uploads", CachedStaticFiles(directory=UPLOAD_DIR, max_age=604800), name="uploads")
app.mount("/static", CachedStaticFiles(directory="static", max_age=86400), name="static")
app.include_router(upload.router)
app.include_router(review.router)
app.include_router(search.router)
app.include_router(documents.router)
app.include_router(auth.router, prefix="/auth")