Refine the phase-2 integration spec to reflect implementation details: - Change `resolved_libraries` from `set[str]` to ordered `list[str]` - Document `MCPToken.allowed_libraries` as JSONField (not M2M) since Library lives in Neo4j, not Django's ORM - Clarify that `Library.workspace_id` is a content-routing attribute, not an authorization axis - Describe retirement of the three-branch `_WORKSPACE_SCOPE_CLAUSE` in favor of a single `lib.uid IN $resolved_libraries` check - Specify team JWT resolution via `TeamWorkspaceAssignment` DB join - Note admin UI materializes full Library UID list explicitly
53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
"""
|
|
Utility helpers for the library app.
|
|
"""
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def neo4j_available():
|
|
"""
|
|
Check whether Neo4j is reachable.
|
|
|
|
Returns True if a simple Cypher query succeeds, False otherwise.
|
|
Used to guard views/tests that require Neo4j.
|
|
"""
|
|
try:
|
|
from neomodel import db
|
|
|
|
db.cypher_query("RETURN 1")
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def all_library_uids() -> list[str]:
|
|
"""Return the UIDs of every ``Library`` node in Neo4j.
|
|
|
|
Used by trusted in-process callers — the Django admin HTML search
|
|
page, the ``/library/api/search/`` DRF endpoint (gated by Django
|
|
session auth) and the ``search`` management command — as the
|
|
``resolved_libraries`` argument to :class:`SearchRequest`. These
|
|
callers have already been authenticated/authorized at a coarser
|
|
layer (Django login / DRF session) and the unified auth middleware
|
|
(see ``mcp_server/auth.py``) is the one that resolves narrower
|
|
library sets for MCP bearer tokens.
|
|
|
|
Returns ``[]`` when Neo4j is unreachable. Callers that want the
|
|
unrestricted / "admin sees everything" semantics should feed this
|
|
result directly into ``SearchRequest.resolved_libraries``; callers
|
|
that want to distinguish "unrestricted" from "fail-closed empty"
|
|
must pass ``resolved_libraries=None`` for the former instead.
|
|
"""
|
|
if not neo4j_available():
|
|
return []
|
|
try:
|
|
from .models import Library
|
|
|
|
return [lib.uid for lib in Library.nodes.all() if lib.uid]
|
|
except Exception as exc: # pragma: no cover - Neo4j unreachable paths
|
|
logger.warning("Failed to enumerate library UIDs for search: %s", exc)
|
|
return []
|