56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
from fastapi import APIRouter, Depends
|
|
from sqlalchemy import func
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..auth import verify_token
|
|
from ..database import get_db
|
|
from ..models import NodeType, RequirementNode
|
|
from ..schemas import StatsResponse
|
|
|
|
router = APIRouter(prefix="/api/stats", tags=["stats"], dependencies=[Depends(verify_token)])
|
|
|
|
|
|
@router.get("", response_model=StatsResponse)
|
|
def get_stats(project_id: int | None = None, db: Session = Depends(get_db)):
|
|
query = db.query(RequirementNode)
|
|
if project_id is not None:
|
|
query = query.filter(RequirementNode.project_id == project_id)
|
|
|
|
nodes = query.all()
|
|
total = len(nodes)
|
|
|
|
by_type = {}
|
|
by_status: dict[str, int] = {}
|
|
by_priority: dict[str, int] = {}
|
|
quality_passing = 0
|
|
leaves_with_tests = 0
|
|
total_leaves = 0
|
|
|
|
for n in nodes:
|
|
by_type[n.node_type.value] = by_type.get(n.node_type.value, 0) + 1
|
|
by_status[n.status.value] = by_status.get(n.status.value, 0) + 1
|
|
by_priority[n.priority.value] = by_priority.get(n.priority.value, 0) + 1
|
|
|
|
if n.traceable and n.measurable and n.consistent and n.single_purpose:
|
|
quality_passing += 1
|
|
|
|
if n.node_type == NodeType.leaf:
|
|
total_leaves += 1
|
|
if n.test_spec:
|
|
leaves_with_tests += 1
|
|
|
|
coverage = (leaves_with_tests / total_leaves * 100) if total_leaves > 0 else 0.0
|
|
|
|
return StatsResponse(
|
|
total_nodes=total,
|
|
pillars=by_type.get("pillar", 0),
|
|
requirements=by_type.get("requirement", 0),
|
|
sub_requirements=by_type.get("sub_requirement", 0),
|
|
leaves=by_type.get("leaf", 0),
|
|
by_status=by_status,
|
|
by_priority=by_priority,
|
|
quality_passing=quality_passing,
|
|
quality_failing=total - quality_passing,
|
|
coverage_percent=round(coverage, 1),
|
|
)
|