feat(platform): ship AI fallback stack and entity-scoped course planning
Unifies the new LangGraph-driven course-plan/media flow with robust provider fallbacks, admin AI provider settings, editable book-style materials, and strict entity isolation across LMS/course-plan APIs. Adds admin-only entity membership management in the Entities UI so users can switch linked entities directly from the platform. Made-with: Cursor
This commit is contained in:
@@ -94,12 +94,39 @@ def _get_jwt_secret():
|
||||
return secret
|
||||
|
||||
|
||||
def validate_token():
|
||||
"""Decode JWT Bearer token and return the corresponding ``res.users`` record or None."""
|
||||
def _extract_bearer_token(allow_query_param: bool = False) -> str | None:
|
||||
"""Pull a JWT off the current request.
|
||||
|
||||
By default we only honour the ``Authorization: Bearer …`` header. Some
|
||||
endpoints (notably media streams that get embedded in ``<img>`` /
|
||||
``<audio>`` / ``<video>`` tags, where the browser cannot attach custom
|
||||
headers) opt in to ``allow_query_param=True`` so callers can send the
|
||||
token via ``?token=<jwt>`` or ``?access_token=<jwt>``. We deliberately
|
||||
keep this off by default so a leaked URL never gives access to JSON
|
||||
APIs — only to the specific raw-media route that opts in.
|
||||
"""
|
||||
auth_header = request.httprequest.headers.get("Authorization", "")
|
||||
if not auth_header.startswith("Bearer "):
|
||||
if auth_header.startswith("Bearer "):
|
||||
return auth_header[7:].strip() or None
|
||||
if allow_query_param:
|
||||
try:
|
||||
args = request.httprequest.args
|
||||
except Exception:
|
||||
args = {}
|
||||
token = (args.get("token") or args.get("access_token") or "").strip()
|
||||
if token:
|
||||
return token
|
||||
return None
|
||||
|
||||
|
||||
def validate_token(allow_query_param: bool = False):
|
||||
"""Decode JWT Bearer token and return the corresponding ``res.users`` record or None.
|
||||
|
||||
See :func:`_extract_bearer_token` for the ``allow_query_param`` flag.
|
||||
"""
|
||||
token = _extract_bearer_token(allow_query_param=allow_query_param)
|
||||
if not token:
|
||||
return None
|
||||
token = auth_header[7:]
|
||||
secret = _get_jwt_secret()
|
||||
if not secret:
|
||||
_logger.error("System parameter 'encoach.jwt_secret' is not configured")
|
||||
|
||||
Reference in New Issue
Block a user