Newer
Older
navi-1 / navi / api / routes / admin / sessions.py
"""Admin view over every user's sessions."""

from typing import Annotated

from fastapi import Depends, HTTPException

from navi.api.deps import get_session_store, require_admin
from navi.auth import User
from navi.config import settings
from navi.core import SessionStore

from ._router import router


@router.get("/sessions")
async def admin_list_sessions(
    store: Annotated[SessionStore, Depends(get_session_store)],
    user: Annotated[User, Depends(require_admin)],
    limit: int = 50,
    offset: int = 0,
    search: str | None = None,
    sort_by: str = "last_active",
    sort_order: str = "desc",
):
    """Return all sessions across all users with pagination, search and sorting."""
    sessions = await store.search_list(
        limit=limit,
        offset=offset,
        user_id=user.id,
        is_admin=True,
        search=search or None,
        sort_by=sort_by,
        sort_order=sort_order,
    )
    total = await store.count_all(user_id=user.id, is_admin=True, search=search or None)
    return {
        "total": total,
        "limit": limit,
        "offset": offset,
        "items": [
            {
                "session_id": s.id,
                "profile_id": s.profile_id,
                "user_id": s.user_id,
                "name": s.name,
                "message_count": s.display_count,
                "pinned": s.pinned,
                "created_at": s.created_at.isoformat(),
                "last_active": s.last_active.isoformat(),
            }
            for s in sessions
        ],
    }


@router.get("/sessions/{session_id}")
async def admin_get_session(
    session_id: str,
    store: Annotated[SessionStore, Depends(get_session_store)],
    user: Annotated[User, Depends(require_admin)],
) -> dict:
    """Return full session details including messages."""
    session = await store.get(session_id)
    if session is None:
        raise HTTPException(status_code=404, detail="Session not found")
    return {
        "session_id": session.id,
        "profile_id": session.profile_id,
        "user_id": session.user_id,
        "name": session.name,
        "messages": [m.model_dump(mode="json", exclude_none=True) for m in session.messages],
        "context_token_count": session.context_token_count,
        "max_context_tokens": settings.ollama_num_ctx,
        "pinned": session.pinned,
        "created_at": session.created_at.isoformat(),
        "last_active": session.last_active.isoformat(),
    }


@router.delete("/sessions/{session_id}", status_code=204)
async def admin_delete_session(
    session_id: str,
    store: Annotated[SessionStore, Depends(get_session_store)],
    user: Annotated[User, Depends(require_admin)],
) -> None:
    """Delete any session (bypass ownership)."""
    from navi.session_files import delete_session_dir

    deleted = await store.delete(session_id)
    if not deleted:
        raise HTTPException(status_code=404, detail="Session not found")
    await delete_session_dir(session_id)