Spaces:
Running
Running
| from __future__ import annotations | |
| import time | |
| from typing import List, Optional | |
| from fastapi import APIRouter, HTTPException, Query | |
| from app.models.schemas import GoogleScopeMapResponse | |
| from app.services.google_scope_map import CATEGORY_ORDER, SCOPE_MAP | |
| router = APIRouter() | |
| async def get_scope_map( | |
| category: Optional[str] = Query(None, description="Return a single category only (e.g. gmail)"), | |
| search: Optional[str] = Query(None, description="Free-text search across aliases and scope URIs"), | |
| ) -> GoogleScopeMapResponse: | |
| """Return the friendly scope alias -> full URI mapping. | |
| Clients can read this map to pick short aliases (e.g. ``gmail_full``, | |
| ``sheets_readonly``) and then pass them as a list in | |
| ``POST /google/oauth/auth-url`` instead of pasting long scope URLs. | |
| """ | |
| started = time.perf_counter() | |
| def _matches(alias: str, uri: str, needle: Optional[str]) -> bool: | |
| if not needle: | |
| return True | |
| needle_l = needle.lower() | |
| return needle_l in alias.lower() or needle_l in uri.lower() | |
| if category: | |
| if category not in SCOPE_MAP: | |
| valid = ", ".join(CATEGORY_ORDER) | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"Unknown category '{category}'. Valid categories: {valid}", | |
| ) | |
| selected: dict = {category: SCOPE_MAP[category]} | |
| else: | |
| selected = dict(SCOPE_MAP) | |
| if search: | |
| selected = { | |
| cat: { | |
| alias: uri | |
| for alias, uri in entries.items() | |
| if _matches(alias, uri, search) | |
| } | |
| for cat, entries in selected.items() | |
| if any(_matches(a, u, search) for a, u in entries.items()) | |
| } | |
| total_aliases = sum(len(entries) for entries in selected.values()) | |
| return GoogleScopeMapResponse( | |
| success=True, | |
| time_ms=round((time.perf_counter() - started) * 1000, 3), | |
| count=total_aliases, | |
| categories=list(selected.keys()), | |
| map=selected, | |
| ) | |