elmeg-demo/backend/routers/reviews.py
fullsizemalt bc804a666b feat: Gamification sprint complete
XP System:
- XP now awarded for attendance (+25), ratings (+10), reviews (+50)
- First-time bonuses for first rating (+25) and first review (+50)
- Streak bonuses (+10 per day, capped at 7x)
- Badge awards automatically grant XP

User Titles & Flair System (Tracker-style):
- Level-based free titles: Rookie → Immortal
- Purchasable titles with XP: Jam Connoisseur, Setlist Savant, etc.
- Username colors purchasable with XP (6 colors + Rainbow)
- Emoji flairs purchasable with XP
- Early adopter perks: exclusive titles, colors, 10% XP bonus

New Fields on User:
- custom_title, title_color, flair
- is_early_adopter, is_supporter
- joined_at

Shop API Endpoints:
- GET /gamification/shop/titles
- POST /gamification/shop/titles/purchase
- GET/POST for colors and flairs
- GET /gamification/user/{id}/display
- GET /gamification/early-adopter-perks

Frontend:
- XP Leaderboard added to home page
- LevelProgressCard shows on profile
2025-12-21 19:21:20 -08:00

67 lines
2.2 KiB
Python

from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlmodel import Session, select, func
from database import get_session
from models import Review, User
from schemas import ReviewCreate, ReviewRead
from auth import get_current_user
from services.gamification import award_xp, check_and_award_badges, update_streak, XP_REWARDS
router = APIRouter(prefix="/reviews", tags=["reviews"])
@router.post("/", response_model=ReviewRead)
def create_review(
review: ReviewCreate,
session: Session = Depends(get_session),
current_user: User = Depends(get_current_user)
):
db_review = Review.model_validate(review)
db_review.user_id = current_user.id
session.add(db_review)
# Check if this is user's first review for bonus XP
review_count = session.exec(
select(func.count(Review.id)).where(Review.user_id == current_user.id)
).one() or 0
# Award XP
xp_amount = XP_REWARDS["review_write"]
if review_count == 0:
xp_amount += XP_REWARDS["first_review"] # Bonus for first review
award_xp(session, current_user, xp_amount, "review")
update_streak(session, current_user)
check_and_award_badges(session, current_user)
session.commit()
session.refresh(db_review)
return db_review
@router.get("/", response_model=List[ReviewRead])
def read_reviews(
show_id: Optional[int] = None,
venue_id: Optional[int] = None,
song_id: Optional[int] = None,
performance_id: Optional[int] = None,
tour_id: Optional[int] = None,
year: Optional[int] = None,
offset: int = 0,
limit: int = Query(default=100, le=100),
session: Session = Depends(get_session)
):
query = select(Review)
if show_id:
query = query.where(Review.show_id == show_id)
if venue_id:
query = query.where(Review.venue_id == venue_id)
if song_id:
query = query.where(Review.song_id == song_id)
if performance_id:
query = query.where(Review.performance_id == performance_id)
if tour_id:
query = query.where(Review.tour_id == tour_id)
if year:
query = query.where(Review.year == year)
reviews = session.exec(query.offset(offset).limit(limit)).all()
return reviews