Files
leocrm/app/routes/dashboard.py
T

101 lines
3.5 KiB
Python

"""Dashboard routes — list available widgets from active plugins (Task 5.25)."""
from __future__ import annotations
import uuid
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.db import get_db
from app.core.visibility import apply_visibility_filter
from app.deps import require_permission
from app.models.contact import Contact
from app.plugins.registry import get_registry
router = APIRouter(prefix="/api/v1/dashboard", tags=["dashboard"])
@router.get("/widgets")
async def list_dashboard_widgets(
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(require_permission("dashboard:read")),
):
"""List all available dashboard widgets from active plugins.
Returns a flat list of widget definitions contributed by active plugins,
sorted by their order field. Each widget includes the contributing plugin name.
"""
registry = get_registry()
manifests = await registry.get_active_manifests(db)
widgets: list[dict] = []
for manifest in manifests:
for widget in manifest.get("dashboard_widgets", []):
widget_copy = dict(widget)
widget_copy["plugin_name"] = manifest["name"]
widgets.append(widget_copy)
# Sort by order field
widgets.sort(key=lambda w: w.get("order", 100))
return {"items": widgets, "total": len(widgets)}
@router.get("/counts")
async def get_dashboard_counts(
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(require_permission("dashboard:read")),
):
"""Get dashboard count statistics filtered by user visibility.
Returns counts for contacts and companies that the current user
is allowed to see based on ownership and sharing permissions.
"""
tenant_id = uuid.UUID(current_user["tenant_id"])
user_id = uuid.UUID(current_user["user_id"])
is_system_admin = current_user.get("is_system_admin", False)
# Contact count with visibility filter
contact_query = select(func.count(Contact.id)).where(
Contact.tenant_id == tenant_id,
Contact.deleted_at.is_(None),
)
contact_query = await apply_visibility_filter(
db, contact_query, "contact", Contact, user_id, tenant_id, is_system_admin
)
contact_result = await db.execute(contact_query)
contact_count = contact_result.scalar() or 0
# Company count (Contact.type == 'company') with visibility filter
company_query = select(func.count(Contact.id)).where(
Contact.tenant_id == tenant_id,
Contact.deleted_at.is_(None),
Contact.type == "company",
)
company_query = await apply_visibility_filter(
db, company_query, "contact", Contact, user_id, tenant_id, is_system_admin
)
company_result = await db.execute(company_query)
company_count = company_result.scalar() or 0
# Person count (Contact.type == 'person') with visibility filter
person_query = select(func.count(Contact.id)).where(
Contact.tenant_id == tenant_id,
Contact.deleted_at.is_(None),
Contact.type == "person",
)
person_query = await apply_visibility_filter(
db, person_query, "contact", Contact, user_id, tenant_id, is_system_admin
)
person_result = await db.execute(person_query)
person_count = person_result.scalar() or 0
return {
"contacts": contact_count,
"companies": company_count,
"persons": person_count,
"total": contact_count,
}