Stats and error handling
This commit is contained in:
@ -124,7 +124,7 @@ class ClientOperations:
|
||||
existing_id = await self.get_client_id(FlexID.name(create_model.name))
|
||||
if existing_id:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Error: A client already exists with this name."
|
||||
status_code=400, detail="A client already exists with this name.", headers={"X-Model-Field": "name"}
|
||||
)
|
||||
deleted_id = await resolve_client_id(
|
||||
self.session, create_model.name, include_deleted=True
|
||||
|
||||
@ -8,6 +8,8 @@ from typing import Annotated
|
||||
from fastapi import APIRouter, Depends, Query, Request
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from sshecret_backend.api.common import get_system_stats
|
||||
from sshecret_backend.api.schemas import SystemStats
|
||||
from sshecret_backend.types import AsyncDBSessionDep
|
||||
from sshecret_backend.api.clients.schemas import (
|
||||
ClientCreate,
|
||||
@ -149,4 +151,11 @@ def create_client_router(get_db_session: AsyncDBSessionDep) -> APIRouter:
|
||||
client_op = ClientOperations(session, request)
|
||||
return await client_op.update_client_policies(client_id, policy_update)
|
||||
|
||||
@router.get("/stats")
|
||||
async def get_stats(
|
||||
session: Annotated[AsyncSession, Depends(get_db_session)],
|
||||
) -> SystemStats:
|
||||
"""Get system stats."""
|
||||
return await get_system_stats(session)
|
||||
|
||||
return router
|
||||
|
||||
@ -6,11 +6,12 @@ import uuid
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
import bcrypt
|
||||
from sqlalchemy import Select
|
||||
from sqlalchemy import Select, distinct, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.future import select
|
||||
from sqlalchemy.orm import selectinload
|
||||
from sshecret_backend.models import Client, ClientAccessPolicy
|
||||
from sshecret_backend.api.schemas import SystemStats
|
||||
from sshecret_backend.models import AuditLog, Client, ClientAccessPolicy, ClientSecret
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
RE_UUID = re.compile(
|
||||
@ -137,3 +138,24 @@ async def create_new_client_version(
|
||||
await session.flush()
|
||||
await refresh_client(session, new_client)
|
||||
return new_client
|
||||
|
||||
|
||||
async def get_system_stats(session: AsyncSession) -> SystemStats:
|
||||
"""Get system stats."""
|
||||
client_count_expr = (
|
||||
select(func.count("*"))
|
||||
.select_from(Client)
|
||||
.where(Client.is_deleted.is_not(True))
|
||||
.where(Client.is_active.is_not(False))
|
||||
.where(Client.is_system.is_not(True))
|
||||
)
|
||||
client_count = (await session.scalars(client_count_expr)).one()
|
||||
secret_count_expr = select(func.count(distinct(ClientSecret.name))).where(
|
||||
ClientSecret.deleted.is_not(True)
|
||||
)
|
||||
secret_count = (await session.scalars(secret_count_expr)).one()
|
||||
audit_count_expr = select(func.count("*")).select_from(AuditLog)
|
||||
audit_count = (await session.scalars(audit_count_expr)).one()
|
||||
return SystemStats(
|
||||
clients=client_count, secrets=secret_count, audit_events=audit_count
|
||||
)
|
||||
|
||||
@ -7,3 +7,11 @@ class BodyValue(BaseModel):
|
||||
"""A generic model with just a value parameter."""
|
||||
|
||||
value: str
|
||||
|
||||
|
||||
class SystemStats(BaseModel):
|
||||
"""Generic system stats."""
|
||||
|
||||
clients: int
|
||||
secrets: int
|
||||
audit_events: int
|
||||
|
||||
@ -146,6 +146,7 @@ class ClientSecretOperations:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Cannot add a secret. A different secret with the same name already exists.",
|
||||
headers={"X-Model-Field": "name"},
|
||||
)
|
||||
secret = ClientSecret(
|
||||
name=name,
|
||||
|
||||
Reference in New Issue
Block a user