feat: Add dashboard API endpoints and service for sound statistics
This commit is contained in:
@@ -5,6 +5,7 @@ from fastapi import APIRouter
|
|||||||
from app.api.v1 import (
|
from app.api.v1 import (
|
||||||
admin,
|
admin,
|
||||||
auth,
|
auth,
|
||||||
|
dashboard,
|
||||||
extractions,
|
extractions,
|
||||||
files,
|
files,
|
||||||
main,
|
main,
|
||||||
@@ -19,6 +20,7 @@ api_router = APIRouter(prefix="/v1")
|
|||||||
|
|
||||||
# Include all route modules
|
# Include all route modules
|
||||||
api_router.include_router(auth.router, tags=["authentication"])
|
api_router.include_router(auth.router, tags=["authentication"])
|
||||||
|
api_router.include_router(dashboard.router, tags=["dashboard"])
|
||||||
api_router.include_router(extractions.router, tags=["extractions"])
|
api_router.include_router(extractions.router, tags=["extractions"])
|
||||||
api_router.include_router(files.router, tags=["files"])
|
api_router.include_router(files.router, tags=["files"])
|
||||||
api_router.include_router(main.router, tags=["main"])
|
api_router.include_router(main.router, tags=["main"])
|
||||||
|
|||||||
29
app/api/v1/dashboard.py
Normal file
29
app/api/v1/dashboard.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
"""Dashboard API endpoints."""
|
||||||
|
|
||||||
|
from typing import Annotated, Any
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
|
from app.core.dependencies import get_current_user, get_dashboard_service
|
||||||
|
from app.models.user import User
|
||||||
|
from app.services.dashboard import DashboardService
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/dashboard", tags=["dashboard"])
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/soundboard-statistics")
|
||||||
|
async def get_soundboard_statistics(
|
||||||
|
_current_user: Annotated[User, Depends(get_current_user)],
|
||||||
|
dashboard_service: Annotated[DashboardService, Depends(get_dashboard_service)],
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Get soundboard statistics."""
|
||||||
|
return await dashboard_service.get_soundboard_statistics()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/track-statistics")
|
||||||
|
async def get_track_statistics(
|
||||||
|
_current_user: Annotated[User, Depends(get_current_user)],
|
||||||
|
dashboard_service: Annotated[DashboardService, Depends(get_dashboard_service)],
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Get track statistics."""
|
||||||
|
return await dashboard_service.get_track_statistics()
|
||||||
@@ -9,7 +9,9 @@ from app.core.database import get_db
|
|||||||
from app.core.logging import get_logger
|
from app.core.logging import get_logger
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.services.auth import AuthService
|
from app.services.auth import AuthService
|
||||||
|
from app.services.dashboard import DashboardService
|
||||||
from app.services.oauth import OAuthService
|
from app.services.oauth import OAuthService
|
||||||
|
from app.repositories.sound import SoundRepository
|
||||||
from app.utils.auth import JWTUtils, TokenUtils
|
from app.utils.auth import JWTUtils, TokenUtils
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
@@ -184,3 +186,11 @@ async def get_admin_user(
|
|||||||
detail="Not enough permissions",
|
detail="Not enough permissions",
|
||||||
)
|
)
|
||||||
return current_user
|
return current_user
|
||||||
|
|
||||||
|
|
||||||
|
async def get_dashboard_service(
|
||||||
|
session: Annotated[AsyncSession, Depends(get_db)],
|
||||||
|
) -> DashboardService:
|
||||||
|
"""Get the dashboard service."""
|
||||||
|
sound_repository = SoundRepository(session)
|
||||||
|
return DashboardService(sound_repository)
|
||||||
|
|||||||
@@ -178,3 +178,49 @@ class SoundRepository(BaseRepository[Sound]):
|
|||||||
search_query, sound_types, sort_by, sort_order
|
search_query, sound_types, sort_by, sort_order
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
async def get_soundboard_statistics(self) -> dict[str, int | float]:
|
||||||
|
"""Get statistics for SDB type sounds."""
|
||||||
|
try:
|
||||||
|
statement = select(
|
||||||
|
func.count(Sound.id).label("count"),
|
||||||
|
func.sum(Sound.play_count).label("total_plays"),
|
||||||
|
func.sum(Sound.duration).label("total_duration"),
|
||||||
|
func.sum(Sound.size + func.coalesce(Sound.normalized_size, 0)).label("total_size")
|
||||||
|
).where(Sound.type == "SDB")
|
||||||
|
|
||||||
|
result = await self.session.exec(statement)
|
||||||
|
row = result.first()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"count": row.count if row.count is not None else 0,
|
||||||
|
"total_plays": row.total_plays if row.total_plays is not None else 0,
|
||||||
|
"total_duration": row.total_duration if row.total_duration is not None else 0,
|
||||||
|
"total_size": row.total_size if row.total_size is not None else 0
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to get soundboard statistics")
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def get_track_statistics(self) -> dict[str, int | float]:
|
||||||
|
"""Get statistics for EXT type sounds."""
|
||||||
|
try:
|
||||||
|
statement = select(
|
||||||
|
func.count(Sound.id).label("count"),
|
||||||
|
func.sum(Sound.play_count).label("total_plays"),
|
||||||
|
func.sum(Sound.duration).label("total_duration"),
|
||||||
|
func.sum(Sound.size + func.coalesce(Sound.normalized_size, 0)).label("total_size")
|
||||||
|
).where(Sound.type == "EXT")
|
||||||
|
|
||||||
|
result = await self.session.exec(statement)
|
||||||
|
row = result.first()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"count": row.count if row.count is not None else 0,
|
||||||
|
"total_plays": row.total_plays if row.total_plays is not None else 0,
|
||||||
|
"total_duration": row.total_duration if row.total_duration is not None else 0,
|
||||||
|
"total_size": row.total_size if row.total_size is not None else 0
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to get track statistics")
|
||||||
|
raise
|
||||||
|
|||||||
46
app/services/dashboard.py
Normal file
46
app/services/dashboard.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""Dashboard service for statistics and analytics."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from app.core.logging import get_logger
|
||||||
|
from app.repositories.sound import SoundRepository
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DashboardService:
|
||||||
|
"""Service for dashboard statistics and analytics."""
|
||||||
|
|
||||||
|
def __init__(self, sound_repository: SoundRepository) -> None:
|
||||||
|
"""Initialize the dashboard service."""
|
||||||
|
self.sound_repository = sound_repository
|
||||||
|
|
||||||
|
async def get_soundboard_statistics(self) -> dict[str, Any]:
|
||||||
|
"""Get comprehensive soundboard statistics."""
|
||||||
|
try:
|
||||||
|
stats = await self.sound_repository.get_soundboard_statistics()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"sound_count": stats["count"],
|
||||||
|
"total_play_count": stats["total_plays"],
|
||||||
|
"total_duration": stats["total_duration"],
|
||||||
|
"total_size": stats["total_size"],
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to get soundboard statistics")
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def get_track_statistics(self) -> dict[str, Any]:
|
||||||
|
"""Get comprehensive track statistics."""
|
||||||
|
try:
|
||||||
|
stats = await self.sound_repository.get_track_statistics()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"track_count": stats["count"],
|
||||||
|
"total_play_count": stats["total_plays"],
|
||||||
|
"total_duration": stats["total_duration"],
|
||||||
|
"total_size": stats["total_size"],
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to get track statistics")
|
||||||
|
raise
|
||||||
Reference in New Issue
Block a user