style: format 9 files with Black
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -91,7 +91,9 @@ class DashboardAuth:
|
||||
|
||||
api_key_clean = api_key.strip()
|
||||
# Check master API key (from env var)
|
||||
if self.master_api_key and secrets.compare_digest(api_key_clean, self.master_api_key.strip()):
|
||||
if self.master_api_key and secrets.compare_digest(
|
||||
api_key_clean, self.master_api_key.strip()
|
||||
):
|
||||
return True, "master", None
|
||||
|
||||
# Check AuthManager's master key (covers auto-generated temp keys)
|
||||
|
||||
@@ -329,9 +329,7 @@ async def get_user_dashboard_stats(user_id: str) -> dict:
|
||||
|
||||
sites = await get_user_sites(user_id)
|
||||
stats["sites_count"] = len(sites)
|
||||
stats["active_sites_count"] = len(
|
||||
[s for s in sites if s.get("status") == "active"]
|
||||
)
|
||||
stats["active_sites_count"] = len([s for s in sites if s.get("status") == "active"])
|
||||
except Exception as e:
|
||||
logger.warning(f"Error getting user sites count: {e}")
|
||||
|
||||
@@ -580,6 +578,7 @@ async def auth_logout(request: Request) -> Response:
|
||||
logger.info(f"Dashboard logout from {client_ip}")
|
||||
return response
|
||||
|
||||
|
||||
# Alias for backwards compatibility with __init__.py and other routes
|
||||
dashboard_logout = auth_logout
|
||||
|
||||
@@ -620,20 +619,24 @@ async def dashboard_home(request: Request) -> Response:
|
||||
projects_by_type = await get_projects_by_type()
|
||||
recent_activity = await get_recent_activity(limit=5)
|
||||
health_summary = await get_health_summary()
|
||||
context.update({
|
||||
"stats": stats,
|
||||
"projects_by_type": projects_by_type,
|
||||
"recent_activity": recent_activity,
|
||||
"health_summary": health_summary,
|
||||
})
|
||||
context.update(
|
||||
{
|
||||
"stats": stats,
|
||||
"projects_by_type": projects_by_type,
|
||||
"recent_activity": recent_activity,
|
||||
"health_summary": health_summary,
|
||||
}
|
||||
)
|
||||
else:
|
||||
# User dashboard — personal stats
|
||||
user_stats = await get_user_dashboard_stats(user_id) if user_id else {}
|
||||
user_sites = await get_user_sites_summary(user_id) if user_id else []
|
||||
context.update({
|
||||
"stats": user_stats,
|
||||
"user_sites": user_sites,
|
||||
})
|
||||
context.update(
|
||||
{
|
||||
"stats": user_stats,
|
||||
"user_sites": user_sites,
|
||||
}
|
||||
)
|
||||
|
||||
return templates.TemplateResponse("dashboard/index.html", context)
|
||||
|
||||
@@ -704,7 +707,7 @@ def get_cached_health_status(project_id: str) -> dict:
|
||||
"status": status,
|
||||
"last_check": latest.last_check.isoformat() if latest.last_check else None,
|
||||
"error_rate": latest.error_rate_percent,
|
||||
"reason": reason
|
||||
"reason": reason,
|
||||
}
|
||||
|
||||
# Fallback to cached metrics (last 24 hours) if no active check exists yet
|
||||
@@ -730,7 +733,12 @@ def get_cached_health_status(project_id: str) -> dict:
|
||||
if history:
|
||||
last_check = history[-1].timestamp.isoformat()
|
||||
|
||||
return {"status": status, "last_check": last_check, "error_rate": error_rate, "reason": None}
|
||||
return {
|
||||
"status": status,
|
||||
"last_check": last_check,
|
||||
"error_rate": error_rate,
|
||||
"reason": None,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning(f"Error getting cached health for {project_id}: {e}")
|
||||
return {"status": "unknown", "last_check": None, "error_rate": 0}
|
||||
@@ -2371,7 +2379,9 @@ async def auth_callback(request: Request) -> Response:
|
||||
user = user_by_email
|
||||
logger.info(
|
||||
"User %s logged in with alternate provider %s (original: %s)",
|
||||
user_info["email"], provider, user_by_email["provider"]
|
||||
user_info["email"],
|
||||
provider,
|
||||
user_by_email["provider"],
|
||||
)
|
||||
else:
|
||||
# New registration -- check rate limit
|
||||
@@ -2386,12 +2396,12 @@ async def auth_callback(request: Request) -> Response:
|
||||
)
|
||||
|
||||
user = await db.create_user(
|
||||
email=user_info["email"],
|
||||
name=user_info.get("name"),
|
||||
provider=user_info["provider"],
|
||||
provider_id=user_info["provider_id"],
|
||||
avatar_url=user_info.get("avatar_url"),
|
||||
)
|
||||
email=user_info["email"],
|
||||
name=user_info.get("name"),
|
||||
provider=user_info["provider"],
|
||||
provider_id=user_info["provider_id"],
|
||||
avatar_url=user_info.get("avatar_url"),
|
||||
)
|
||||
user_auth.record_registration(client_ip)
|
||||
logger.info(
|
||||
"New user registered: %s via %s",
|
||||
|
||||
@@ -260,9 +260,11 @@ class Database:
|
||||
async def _create_schema(self) -> None:
|
||||
"""Create all tables if they do not already exist."""
|
||||
conn = self._require_conn()
|
||||
|
||||
|
||||
# Check if it's a completely fresh DB (no users table)
|
||||
row = await self.fetchone("SELECT name FROM sqlite_master WHERE type='table' AND name='users'")
|
||||
row = await self.fetchone(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='users'"
|
||||
)
|
||||
is_fresh = row is None
|
||||
|
||||
await conn.executescript(_SCHEMA_SQL)
|
||||
@@ -299,7 +301,9 @@ class Database:
|
||||
except Exception as e:
|
||||
if "duplicate column name" not in str(e).lower():
|
||||
raise
|
||||
await self.execute("CREATE INDEX IF NOT EXISTS idx_user_api_keys_prefix ON user_api_keys(key_prefix)")
|
||||
await self.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_user_api_keys_prefix ON user_api_keys(key_prefix)"
|
||||
)
|
||||
else:
|
||||
migration_sql = _MIGRATIONS.get(version)
|
||||
if migration_sql is not None:
|
||||
@@ -307,8 +311,10 @@ class Database:
|
||||
await conn.executescript(migration_sql)
|
||||
logger.info("Migration to version %d applied", version)
|
||||
else:
|
||||
logger.warning("No migration SQL for version %d, recording version only", version)
|
||||
|
||||
logger.warning(
|
||||
"No migration SQL for version %d, recording version only", version
|
||||
)
|
||||
|
||||
# Always record version to avoid infinite retry
|
||||
await self.execute(
|
||||
"INSERT INTO schema_version (version, applied_at) VALUES (?, ?)",
|
||||
|
||||
@@ -774,15 +774,15 @@ class HealthMonitor:
|
||||
self.request_timestamps.clear()
|
||||
self.latest_health_status.clear()
|
||||
logger.warning("All metrics have been reset")
|
||||
|
||||
|
||||
async def start_background_checks(self, interval_seconds: int = 60):
|
||||
"""Start background health checks for all projects."""
|
||||
if self._is_running:
|
||||
return
|
||||
|
||||
|
||||
self._is_running = True
|
||||
logger.info(f"Starting background health checks every {interval_seconds} seconds")
|
||||
|
||||
|
||||
async def _loop():
|
||||
# Initial wait to let server start up fully
|
||||
await asyncio.sleep(5)
|
||||
@@ -791,15 +791,15 @@ class HealthMonitor:
|
||||
await self.check_all_projects_health(include_metrics=True)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in background health check loop: {e}")
|
||||
|
||||
|
||||
# Sleep interval, check _is_running periodically
|
||||
for _ in range(interval_seconds):
|
||||
if not self._is_running:
|
||||
break
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
self._bg_task = asyncio.create_task(_loop())
|
||||
|
||||
|
||||
async def stop_background_checks(self):
|
||||
"""Stop background health checks."""
|
||||
self._is_running = False
|
||||
|
||||
@@ -318,26 +318,25 @@ async def user_mcp_handler(request: Request) -> Response:
|
||||
|
||||
# Check required scope
|
||||
from core.tool_registry import get_tool_registry
|
||||
|
||||
registry = get_tool_registry()
|
||||
tool_def = registry.get_by_name(tool_name)
|
||||
if not tool_def:
|
||||
return JSONResponse(
|
||||
_jsonrpc_error(req_id, -32601, f"Tool '{tool_name}' not found")
|
||||
)
|
||||
return JSONResponse(_jsonrpc_error(req_id, -32601, f"Tool '{tool_name}' not found"))
|
||||
|
||||
required_scope = tool_def.required_scope
|
||||
key_scopes = key_info.get("scopes", "").split()
|
||||
|
||||
|
||||
scope_hierarchy = {"read": 1, "write": 2, "admin": 3}
|
||||
required_level = scope_hierarchy.get(required_scope, 0)
|
||||
key_level = max([scope_hierarchy.get(s, 0) for s in key_scopes] + [0])
|
||||
|
||||
|
||||
if key_level < required_level:
|
||||
return JSONResponse(
|
||||
_jsonrpc_error(
|
||||
req_id,
|
||||
-32600,
|
||||
f"Insufficient scope. Tool '{tool_name}' requires '{required_scope}' scope."
|
||||
req_id,
|
||||
-32600,
|
||||
f"Insufficient scope. Tool '{tool_name}' requires '{required_scope}' scope.",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user