Recherche partout (#68) : routes /recherche + /api/search, draco sur /api/search, CORS bornée
CI / test (push) Failing after 1s
CI / test (push) Failing after 1s
This commit is contained in:
+68
@@ -390,6 +390,19 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
||||
if (path.startswith("/mcp") or path.startswith("/api/")) \
|
||||
and _bearer_user(request) is not None:
|
||||
return await call_next(request)
|
||||
# Recherche partout (#68) : /api/search accepte aussi le jeton
|
||||
# SSO draco_session (mono-utilisateur : un jeton valide désigne
|
||||
# l'opérateur), comme les API de recherche des sœurs. Les
|
||||
# preflights OPTIONS ne portent jamais de cookies : ils sont
|
||||
# répondus par RechercheCorsMiddleware avant d'arriver ici.
|
||||
if path == "/api/search":
|
||||
try:
|
||||
from app import draco
|
||||
|
||||
if draco.claims_for(request) is not None:
|
||||
return await call_next(request)
|
||||
except Exception:
|
||||
pass
|
||||
# API consumers get a plain 401 (no browser prompt, no
|
||||
# redirect they cannot follow); browsers get the login page.
|
||||
if path.startswith("/api/") or "text/html" not in request.headers.get(
|
||||
@@ -408,6 +421,15 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
||||
app.add_middleware(AuthMiddleware)
|
||||
|
||||
|
||||
# Recherche partout (#68) : CORS bornée pour GET /api/search — ajouté
|
||||
# après AuthMiddleware donc exécuté avant lui (dernier ajouté = le
|
||||
# plus externe) : les preflights OPTIONS sont répondus ici, avant
|
||||
# tout refus d'authentification.
|
||||
from app.recherche import RechercheCorsMiddleware
|
||||
|
||||
app.add_middleware(RechercheCorsMiddleware)
|
||||
|
||||
|
||||
def _safe_next(raw: str) -> str:
|
||||
"""Only local paths may be a post-login destination."""
|
||||
if raw.startswith("/") and not raw.startswith("//") and "://" not in raw:
|
||||
@@ -4311,6 +4333,51 @@ async def search_page(request: Request, q: str = ""):
|
||||
)
|
||||
|
||||
|
||||
@app.get("/recherche", response_class=HTMLResponse)
|
||||
async def recherche_page(request: Request, q: str = ""):
|
||||
"""Page de résultats unifiée « Rechercher partout » (fusion #68).
|
||||
|
||||
Coquille seule : les résultats sont chargés côté client par
|
||||
static/js/recherche.js. La page /search native reste inchangée.
|
||||
"""
|
||||
return render(request, "recherche.html", q=q.strip())
|
||||
|
||||
|
||||
@app.get("/api/search")
|
||||
async def recherche_api(request: Request, q: str = "", limit: int = 20):
|
||||
"""Recherche JSON pour la page « Rechercher partout » (fusion #68).
|
||||
|
||||
Même source que la page /search : recherche Gitea (titres + corps,
|
||||
tous états, tous projets du workspace), groupée par dépôt avec la
|
||||
colonne du tableau. Auth : voir AuthMiddleware (session, Basic,
|
||||
jeton API, ou jeton SSO draco_session pour ce chemin). Les corps
|
||||
sont tronqués à 160 caractères ; seuls les champs utiles sont
|
||||
exposés (voir app/recherche.py).
|
||||
"""
|
||||
from app.recherche import groupes_vers_json
|
||||
|
||||
q = q.strip()
|
||||
limit = max(1, min(limit, 50))
|
||||
if not q:
|
||||
return {"query": q, "groups": [], "total": 0}
|
||||
workspace, _role = _current_workspace(request)
|
||||
conn_ids = (
|
||||
models.workspace_connection_ids(workspace["id"])
|
||||
if workspace
|
||||
else [registry.default_id]
|
||||
)
|
||||
results: list[dict] = []
|
||||
for cid in conn_ids:
|
||||
try:
|
||||
found = await _forge_client(cid).search_issues(q=q, state="all")
|
||||
results.extend(found)
|
||||
except Exception as exc:
|
||||
logger.debug("search failed for conn %s: %s", cid, exc)
|
||||
groups = _group_issue_results(results)
|
||||
data, total = groupes_vers_json(groups, limit)
|
||||
return {"query": q, "groups": data, "total": total}
|
||||
|
||||
|
||||
@app.get("/my", response_class=HTMLResponse)
|
||||
async def my_issues(request: Request):
|
||||
"""Open issues assigned to the token owner, per connection."""
|
||||
@@ -6914,3 +6981,4 @@ async def readiness():
|
||||
},
|
||||
status_code=200 if ready else 503,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user