a8d44b189c
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
73 lines
2.4 KiB
Python
73 lines
2.4 KiB
Python
"""
|
|
User-scoping utilities for multi-user document isolation.
|
|
|
|
When ``multi_user_enabled`` is ``True`` in settings, every document query
|
|
is filtered by the authenticated user's identifier so that each user sees
|
|
only their own documents. When the flag is ``False`` (default), all
|
|
documents are visible to all users (single-user / shared mode).
|
|
"""
|
|
|
|
import logging
|
|
|
|
from fastapi import Request
|
|
from sqlalchemy.orm import Query
|
|
from sqlalchemy.sql import false
|
|
|
|
from app.config import settings
|
|
from app.models import FileRecord
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_current_owner_id(request: Request) -> str | None:
|
|
"""Extract the owner identifier for the current authenticated user.
|
|
|
|
The owner ID is derived from the user's session data. It uses the
|
|
``sub`` claim (OAuth subject) when available, falling back to
|
|
``preferred_username`` or ``email``. Returns ``None`` when no user
|
|
is authenticated.
|
|
|
|
Args:
|
|
request: The current FastAPI request with session data.
|
|
|
|
Returns:
|
|
A stable string identifier for the user, or ``None``.
|
|
"""
|
|
user = request.session.get("user")
|
|
if not user or not isinstance(user, dict):
|
|
return None
|
|
# Prefer 'sub' (OAuth subject), then 'preferred_username', then 'email', then 'id'
|
|
return user.get("sub") or user.get("preferred_username") or user.get("email") or user.get("id")
|
|
|
|
|
|
def apply_owner_filter(query: Query, request: Request) -> Query:
|
|
"""Conditionally filter a ``FileRecord`` query by the current user.
|
|
|
|
When multi-user mode is enabled, only files whose ``owner_id``
|
|
matches the authenticated user are returned. Admin users bypass
|
|
the filter and see all documents.
|
|
|
|
When multi-user mode is disabled the query is returned unchanged.
|
|
|
|
Args:
|
|
query: A SQLAlchemy query selecting ``FileRecord`` rows.
|
|
request: The current FastAPI request (for session inspection).
|
|
|
|
Returns:
|
|
The (possibly filtered) query.
|
|
"""
|
|
if not settings.multi_user_enabled:
|
|
return query
|
|
|
|
user = request.session.get("user")
|
|
if isinstance(user, dict) and user.get("is_admin"):
|
|
# Admins see all documents in multi-user mode
|
|
return query
|
|
|
|
owner_id = get_current_owner_id(request)
|
|
if owner_id is None:
|
|
# No authenticated user — return empty result set
|
|
return query.filter(false())
|
|
|
|
return query.filter(FileRecord.owner_id == owner_id)
|