feat: Add endpoint and service method to retrieve top users by various metrics
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"""User repository."""
|
||||
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
@@ -11,6 +12,11 @@ from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
from app.core.logging import get_logger
|
||||
from app.models.plan import Plan
|
||||
from app.models.user import User
|
||||
from app.models.sound_played import SoundPlayed
|
||||
from app.models.credit_transaction import CreditTransaction
|
||||
from app.models.playlist import Playlist
|
||||
from app.models.sound import Sound
|
||||
from app.models.tts import TTS
|
||||
from app.repositories.base import BaseRepository
|
||||
|
||||
logger = get_logger(__name__)
|
||||
@@ -217,3 +223,110 @@ class UserRepository(BaseRepository[User]):
|
||||
except Exception:
|
||||
logger.exception("Failed to check if email exists: %s", email)
|
||||
raise
|
||||
|
||||
async def get_top_users(
|
||||
self,
|
||||
metric_type: str,
|
||||
date_filter: datetime | None = None,
|
||||
limit: int = 10,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Get top users by different metrics."""
|
||||
try:
|
||||
if metric_type == "sounds_played":
|
||||
# Get users with most sounds played
|
||||
query = (
|
||||
select(
|
||||
User.id,
|
||||
User.name,
|
||||
func.count(SoundPlayed.id).label("count")
|
||||
)
|
||||
.join(SoundPlayed, User.id == SoundPlayed.user_id)
|
||||
.group_by(User.id, User.name)
|
||||
)
|
||||
if date_filter:
|
||||
query = query.where(SoundPlayed.created_at >= date_filter)
|
||||
|
||||
elif metric_type == "credits_used":
|
||||
# Get users with most credits used (negative transactions)
|
||||
query = (
|
||||
select(
|
||||
User.id,
|
||||
User.name,
|
||||
func.sum(func.abs(CreditTransaction.amount)).label("count")
|
||||
)
|
||||
.join(CreditTransaction, User.id == CreditTransaction.user_id)
|
||||
.where(CreditTransaction.amount < 0)
|
||||
.group_by(User.id, User.name)
|
||||
)
|
||||
if date_filter:
|
||||
query = query.where(CreditTransaction.created_at >= date_filter)
|
||||
|
||||
elif metric_type == "tracks_added":
|
||||
# Get users with most EXT sounds added
|
||||
query = (
|
||||
select(
|
||||
User.id,
|
||||
User.name,
|
||||
func.count(Sound.id).label("count")
|
||||
)
|
||||
.join(Sound, User.id == Sound.user_id)
|
||||
.where(Sound.type == "EXT")
|
||||
.group_by(User.id, User.name)
|
||||
)
|
||||
if date_filter:
|
||||
query = query.where(Sound.created_at >= date_filter)
|
||||
|
||||
elif metric_type == "tts_added":
|
||||
# Get users with most TTS sounds added
|
||||
query = (
|
||||
select(
|
||||
User.id,
|
||||
User.name,
|
||||
func.count(TTS.id).label("count")
|
||||
)
|
||||
.join(TTS, User.id == TTS.user_id)
|
||||
.group_by(User.id, User.name)
|
||||
)
|
||||
if date_filter:
|
||||
query = query.where(TTS.created_at >= date_filter)
|
||||
|
||||
elif metric_type == "playlists_created":
|
||||
# Get users with most playlists created
|
||||
query = (
|
||||
select(
|
||||
User.id,
|
||||
User.name,
|
||||
func.count(Playlist.id).label("count")
|
||||
)
|
||||
.join(Playlist, User.id == Playlist.user_id)
|
||||
.group_by(User.id, User.name)
|
||||
)
|
||||
if date_filter:
|
||||
query = query.where(Playlist.created_at >= date_filter)
|
||||
|
||||
else:
|
||||
msg = f"Unknown metric type: {metric_type}"
|
||||
raise ValueError(msg)
|
||||
|
||||
# Add ordering and limit
|
||||
query = query.order_by(func.count().desc()).limit(limit)
|
||||
|
||||
result = await self.session.exec(query)
|
||||
rows = result.all()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": row[0],
|
||||
"name": row[1],
|
||||
"count": int(row[2]),
|
||||
}
|
||||
for row in rows
|
||||
]
|
||||
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Failed to get top users for metric=%s, date_filter=%s",
|
||||
metric_type,
|
||||
date_filter,
|
||||
)
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user