initial commit - LeDiscord plateforme des copains
This commit is contained in:
314
backend/api/routers/stats.py
Normal file
314
backend/api/routers/stats.py
Normal file
@@ -0,0 +1,314 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user