Files
LeDiscord/backend/api/routers/stats.py
2025-08-27 18:34:38 +02:00

315 lines
12 KiB
Python
Executable File

from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from sqlalchemy import func
from datetime import datetime, timedelta
from config.database import get_db
from models.user import User
from models.event import Event, EventParticipation, ParticipationStatus
from models.album import Album, Media
from models.post import Post
from models.vlog import Vlog
from utils.security import get_current_active_user
router = APIRouter()
@router.get("/overview")
async def get_overview_stats(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""Get general overview statistics."""
total_users = db.query(User).filter(User.is_active == True).count()
total_events = db.query(Event).count()
total_albums = db.query(Album).count()
total_posts = db.query(Post).count()
total_vlogs = db.query(Vlog).count()
total_media = db.query(Media).count()
# Recent activity (last 30 days)
thirty_days_ago = datetime.utcnow() - timedelta(days=30)
recent_events = db.query(Event).filter(Event.created_at >= thirty_days_ago).count()
recent_posts = db.query(Post).filter(Post.created_at >= thirty_days_ago).count()
recent_vlogs = db.query(Vlog).filter(Vlog.created_at >= thirty_days_ago).count()
return {
"total_users": total_users,
"total_events": total_events,
"total_albums": total_albums,
"total_posts": total_posts,
"total_vlogs": total_vlogs,
"total_media": total_media,
"recent_events": recent_events,
"recent_posts": recent_posts,
"recent_vlogs": recent_vlogs
}
@router.get("/attendance")
async def get_attendance_stats(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""Get attendance statistics for all users."""
users = db.query(User).filter(User.is_active == True).all()
attendance_stats = []
for user in users:
# Get past events participation
past_participations = db.query(EventParticipation).join(Event).filter(
EventParticipation.user_id == user.id,
Event.date < datetime.utcnow()
).all()
total_past_events = len(past_participations)
present_count = sum(1 for p in past_participations if p.status == ParticipationStatus.PRESENT)
absent_count = sum(1 for p in past_participations if p.status == ParticipationStatus.ABSENT)
# Get upcoming events participation
upcoming_participations = db.query(EventParticipation).join(Event).filter(
EventParticipation.user_id == user.id,
Event.date >= datetime.utcnow()
).all()
upcoming_present = sum(1 for p in upcoming_participations if p.status == ParticipationStatus.PRESENT)
upcoming_maybe = sum(1 for p in upcoming_participations if p.status == ParticipationStatus.MAYBE)
upcoming_pending = sum(1 for p in upcoming_participations if p.status == ParticipationStatus.PENDING)
attendance_stats.append({
"user_id": user.id,
"username": user.username,
"full_name": user.full_name,
"avatar_url": user.avatar_url,
"attendance_rate": user.attendance_rate,
"total_past_events": total_past_events,
"present_count": present_count,
"absent_count": absent_count,
"upcoming_present": upcoming_present,
"upcoming_maybe": upcoming_maybe,
"upcoming_pending": upcoming_pending
})
# Sort by attendance rate
attendance_stats.sort(key=lambda x: x["attendance_rate"], reverse=True)
return {
"attendance_stats": attendance_stats,
"best_attendee": attendance_stats[0] if attendance_stats else None,
"worst_attendee": attendance_stats[-1] if attendance_stats else None
}
@router.get("/fun")
async def get_fun_stats(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""Get fun statistics about the group."""
# Most active poster
post_counts = db.query(
User.id,
User.username,
User.full_name,
func.count(Post.id).label("post_count")
).join(Post).group_by(User.id).order_by(func.count(Post.id).desc()).first()
# Most mentioned user
mention_counts = db.query(
User.id,
User.username,
User.full_name,
func.count().label("mention_count")
).join(Post.mentions).group_by(User.id).order_by(func.count().desc()).first()
# Biggest vlogger
vlog_counts = db.query(
User.id,
User.username,
User.full_name,
func.count(Vlog.id).label("vlog_count")
).join(Vlog).group_by(User.id).order_by(func.count(Vlog.id).desc()).first()
# Photo addict (most albums created)
album_counts = db.query(
User.id,
User.username,
User.full_name,
func.count(Album.id).label("album_count")
).join(Album).group_by(User.id).order_by(func.count(Album.id).desc()).first()
# Event organizer (most events created)
event_counts = db.query(
User.id,
User.username,
User.full_name,
func.count(Event.id).label("event_count")
).join(Event, Event.creator_id == User.id).group_by(User.id).order_by(func.count(Event.id).desc()).first()
# Most viewed vlog
most_viewed_vlog = db.query(Vlog).order_by(Vlog.views_count.desc()).first()
# Longest event streak (consecutive events attended)
# This would require more complex logic to calculate
return {
"most_active_poster": {
"user_id": post_counts[0] if post_counts else None,
"username": post_counts[1] if post_counts else None,
"full_name": post_counts[2] if post_counts else None,
"post_count": post_counts[3] if post_counts else 0
} if post_counts else None,
"most_mentioned": {
"user_id": mention_counts[0] if mention_counts else None,
"username": mention_counts[1] if mention_counts else None,
"full_name": mention_counts[2] if mention_counts else None,
"mention_count": mention_counts[3] if mention_counts else 0
} if mention_counts else None,
"biggest_vlogger": {
"user_id": vlog_counts[0] if vlog_counts else None,
"username": vlog_counts[1] if vlog_counts else None,
"full_name": vlog_counts[2] if vlog_counts else None,
"vlog_count": vlog_counts[3] if vlog_counts else 0
} if vlog_counts else None,
"photo_addict": {
"user_id": album_counts[0] if album_counts else None,
"username": album_counts[1] if album_counts else None,
"full_name": album_counts[2] if album_counts else None,
"album_count": album_counts[3] if album_counts else 0
} if album_counts else None,
"event_organizer": {
"user_id": event_counts[0] if event_counts else None,
"username": event_counts[1] if event_counts else None,
"full_name": event_counts[2] if event_counts else None,
"event_count": event_counts[3] if event_counts else 0
} if event_counts else None,
"most_viewed_vlog": {
"id": most_viewed_vlog.id,
"title": most_viewed_vlog.title,
"author_name": most_viewed_vlog.author.full_name,
"views_count": most_viewed_vlog.views_count
} if most_viewed_vlog else None
}
@router.get("/user/{user_id}")
async def get_user_stats(
user_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""Get statistics for a specific user."""
user = db.query(User).filter(User.id == user_id).first()
if not user:
return {"error": "User not found"}
posts_count = db.query(Post).filter(Post.author_id == user_id).count()
vlogs_count = db.query(Vlog).filter(Vlog.author_id == user_id).count()
albums_count = db.query(Album).filter(Album.creator_id == user_id).count()
events_created = db.query(Event).filter(Event.creator_id == user_id).count()
# Get participation stats
participations = db.query(EventParticipation).filter(EventParticipation.user_id == user_id).all()
present_count = sum(1 for p in participations if p.status == ParticipationStatus.PRESENT)
absent_count = sum(1 for p in participations if p.status == ParticipationStatus.ABSENT)
maybe_count = sum(1 for p in participations if p.status == ParticipationStatus.MAYBE)
# Total views on vlogs
total_vlog_views = db.query(func.sum(Vlog.views_count)).filter(Vlog.author_id == user_id).scalar() or 0
return {
"user": {
"id": user.id,
"username": user.username,
"full_name": user.full_name,
"avatar_url": user.avatar_url,
"attendance_rate": user.attendance_rate,
"member_since": user.created_at
},
"content_stats": {
"posts_count": posts_count,
"vlogs_count": vlogs_count,
"albums_count": albums_count,
"events_created": events_created,
"total_vlog_views": total_vlog_views
},
"participation_stats": {
"total_events": len(participations),
"present_count": present_count,
"absent_count": absent_count,
"maybe_count": maybe_count
}
}
@router.get("/activity/user/{user_id}")
async def get_user_activity(
user_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""Get recent activity for a specific user."""
user = db.query(User).filter(User.id == user_id).first()
if not user:
return {"error": "User not found"}
# Get recent posts
recent_posts = db.query(Post).filter(
Post.author_id == user_id
).order_by(Post.created_at.desc()).limit(5).all()
# Get recent vlogs
recent_vlogs = db.query(Vlog).filter(
Vlog.author_id == user_id
).order_by(Vlog.created_at.desc()).limit(5).all()
# Get recent albums
recent_albums = db.query(Album).filter(
Album.creator_id == user_id
).order_by(Album.created_at.desc()).limit(5).all()
# Get recent events created
recent_events = db.query(Event).filter(
Event.creator_id == user_id
).order_by(Event.created_at.desc()).limit(5).all()
# Combine and sort by date
activities = []
for post in recent_posts:
activities.append({
"id": post.id,
"type": "post",
"description": f"A publié : {post.content[:50]}...",
"created_at": post.created_at,
"link": f"/posts/{post.id}"
})
for vlog in recent_vlogs:
activities.append({
"id": vlog.id,
"type": "vlog",
"description": f"A publié un vlog : {vlog.title}",
"created_at": vlog.created_at,
"link": f"/vlogs/{vlog.id}"
})
for album in recent_albums:
activities.append({
"id": album.id,
"type": "album",
"description": f"A créé un album : {album.title}",
"created_at": album.created_at,
"link": f"/albums/{album.id}"
})
for event in recent_events:
activities.append({
"id": event.id,
"type": "event",
"description": f"A créé un événement : {event.title}",
"created_at": event.created_at,
"link": f"/events/{event.id}"
})
# Sort by creation date (most recent first)
activities.sort(key=lambda x: x["created_at"], reverse=True)
return {
"activity": activities[:10] # Return top 10 most recent activities
}