fix: dashboard endpoint and SSH key Fernet key generation
- Create missing /dashboard/summary endpoint that frontend expects - Fix SSH key Fernet key generation to use proper base64 encoding (was using raw session secret slice which failed validation)
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
import uuid
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
from sqlalchemy import func, select
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from src.auth.dependencies import get_current_user_id, get_db_session
|
||||||
|
from src.models.git_repository import GitRepository
|
||||||
|
from src.models.project import Project
|
||||||
|
from src.models.ssh_key import SSHKey
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/dashboard", tags=["dashboard"])
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/summary")
|
||||||
|
async def get_dashboard_summary(
|
||||||
|
user_id: uuid.UUID = Depends(get_current_user_id),
|
||||||
|
session: AsyncSession = Depends(get_db_session),
|
||||||
|
) -> dict:
|
||||||
|
# Count user's projects
|
||||||
|
projects_result = await session.execute(
|
||||||
|
select(func.count()).select_from(Project).where(Project.owner_id == user_id)
|
||||||
|
)
|
||||||
|
projects_count = projects_result.scalar() or 0
|
||||||
|
|
||||||
|
# Count user's repositories
|
||||||
|
repos_result = await session.execute(
|
||||||
|
select(func.count()).select_from(GitRepository).where(GitRepository.owner_id == user_id)
|
||||||
|
)
|
||||||
|
repos_count = repos_result.scalar() or 0
|
||||||
|
|
||||||
|
# Count user's SSH keys
|
||||||
|
ssh_keys_result = await session.execute(
|
||||||
|
select(func.count()).select_from(SSHKey).where(SSHKey.user_id == user_id)
|
||||||
|
)
|
||||||
|
ssh_keys_count = ssh_keys_result.scalar() or 0
|
||||||
|
|
||||||
|
# Get recent activity (latest 5 projects)
|
||||||
|
recent_projects = await session.execute(
|
||||||
|
select(Project)
|
||||||
|
.where(Project.owner_id == user_id)
|
||||||
|
.order_by(Project.created_at.desc())
|
||||||
|
.limit(5)
|
||||||
|
)
|
||||||
|
recent_activity = [f"Created project: {p.name}" for p in recent_projects.scalars().all()]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"projects": projects_count,
|
||||||
|
"repositories": repos_count,
|
||||||
|
"sshKeys": ssh_keys_count,
|
||||||
|
"recentActivity": recent_activity,
|
||||||
|
}
|
||||||
@@ -25,9 +25,16 @@ async def _get_user(session: AsyncSession, user_id: uuid.UUID) -> User:
|
|||||||
|
|
||||||
|
|
||||||
def _get_fernet() -> Fernet:
|
def _get_fernet() -> Fernet:
|
||||||
|
"""Generate a valid Fernet key from the session secret."""
|
||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
key = settings.session_secret[:32].ljust(32, "=")
|
# Derive a 32-byte key from the session secret using SHA256
|
||||||
return Fernet(key.encode())
|
key_bytes = hashlib.sha256(settings.session_secret.encode()).digest()
|
||||||
|
# Base64 encode it for Fernet (must be 32 url-safe base64-encoded bytes)
|
||||||
|
key = base64.urlsafe_b64encode(key_bytes)
|
||||||
|
return Fernet(key)
|
||||||
|
|
||||||
|
|
||||||
def generate_ssh_key_pair() -> tuple[str, str]:
|
def generate_ssh_key_pair() -> tuple[str, str]:
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from fastapi.staticfiles import StaticFiles
|
|||||||
from sqlalchemy import select, text
|
from sqlalchemy import select, text
|
||||||
|
|
||||||
from src.api.auth import router as auth_router
|
from src.api.auth import router as auth_router
|
||||||
|
from src.api.dashboard import router as dashboard_router
|
||||||
from src.api.git_repositories import router as git_repositories_router
|
from src.api.git_repositories import router as git_repositories_router
|
||||||
from src.api.projects import router as projects_router
|
from src.api.projects import router as projects_router
|
||||||
from src.api.ssh_keys import router as ssh_keys_router
|
from src.api.ssh_keys import router as ssh_keys_router
|
||||||
@@ -156,6 +157,7 @@ async def health_check():
|
|||||||
return {"status": "unhealthy", "database": "disconnected", "error": str(exc)}
|
return {"status": "unhealthy", "database": "disconnected", "error": str(exc)}
|
||||||
|
|
||||||
app.include_router(auth_router)
|
app.include_router(auth_router)
|
||||||
|
app.include_router(dashboard_router)
|
||||||
app.include_router(projects_router)
|
app.include_router(projects_router)
|
||||||
app.include_router(users_router)
|
app.include_router(users_router)
|
||||||
app.include_router(ssh_keys_router)
|
app.include_router(ssh_keys_router)
|
||||||
|
|||||||
Reference in New Issue
Block a user