🐐
This commit is contained in:
147
backend/routers/profile.py
Normal file
147
backend/routers/profile.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from core.database import get_db
|
||||
from core.dependencies import get_current_user
|
||||
from core.models import Card as CardModel
|
||||
from core.models import Deck as DeckModel
|
||||
from core.models import User as UserModel
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def _serialize_card_public(card: CardModel) -> dict:
|
||||
"""Card fields safe to expose on public profiles (no user_id)."""
|
||||
return {
|
||||
"id": str(card.id),
|
||||
"name": card.name,
|
||||
"image_link": card.image_link,
|
||||
"card_rarity": card.card_rarity,
|
||||
"card_type": card.card_type,
|
||||
"text": card.text,
|
||||
"attack": card.attack,
|
||||
"defense": card.defense,
|
||||
"cost": card.cost,
|
||||
"is_favorite": card.is_favorite,
|
||||
"willing_to_trade": card.willing_to_trade,
|
||||
}
|
||||
|
||||
|
||||
class UpdateProfileRequest(BaseModel):
|
||||
trade_wishlist: str
|
||||
|
||||
|
||||
@router.get("/profile")
|
||||
def get_profile(user: UserModel = Depends(get_current_user), db: Session = Depends(get_db)):
|
||||
total_games = user.wins + user.losses
|
||||
|
||||
most_played_deck = (
|
||||
db.query(DeckModel)
|
||||
.filter(DeckModel.user_id == user.id, DeckModel.times_played > 0)
|
||||
.order_by(DeckModel.times_played.desc())
|
||||
.first()
|
||||
)
|
||||
|
||||
most_played_card = (
|
||||
db.query(CardModel)
|
||||
.filter(CardModel.user_id == user.id, CardModel.times_played > 0)
|
||||
.order_by(CardModel.times_played.desc())
|
||||
.first()
|
||||
)
|
||||
|
||||
return {
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"email_verified": user.email_verified,
|
||||
"created_at": user.created_at,
|
||||
"wins": user.wins,
|
||||
"losses": user.losses,
|
||||
"shards": user.shards,
|
||||
"win_rate": round((user.wins / total_games) * 100) if total_games > 0 else None,
|
||||
"trade_wishlist": user.trade_wishlist or "",
|
||||
"most_played_deck": {
|
||||
"name": most_played_deck.name,
|
||||
"times_played": most_played_deck.times_played,
|
||||
} if most_played_deck else None,
|
||||
"most_played_card": {
|
||||
"name": most_played_card.name,
|
||||
"times_played": most_played_card.times_played,
|
||||
"card_type": most_played_card.card_type,
|
||||
"card_rarity": most_played_card.card_rarity,
|
||||
"image_link": most_played_card.image_link,
|
||||
} if most_played_card else None,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/profile/refresh-status")
|
||||
def refresh_status(user: UserModel = Depends(get_current_user)):
|
||||
if not user.last_refresh_at:
|
||||
return {"can_refresh": True, "next_refresh_at": None}
|
||||
next_refresh = user.last_refresh_at + timedelta(minutes=10)
|
||||
can_refresh = datetime.now() >= next_refresh
|
||||
return {
|
||||
"can_refresh": can_refresh,
|
||||
"next_refresh_at": next_refresh.isoformat() if not can_refresh else None,
|
||||
}
|
||||
|
||||
|
||||
@router.patch("/profile")
|
||||
def update_profile(req: UpdateProfileRequest, user: UserModel = Depends(get_current_user), db: Session = Depends(get_db)):
|
||||
user.trade_wishlist = req.trade_wishlist
|
||||
db.commit()
|
||||
return {"trade_wishlist": user.trade_wishlist}
|
||||
|
||||
|
||||
@router.get("/users")
|
||||
def search_users(q: str, current_user: UserModel = Depends(get_current_user), db: Session = Depends(get_db)):
|
||||
# Require auth to prevent scraping
|
||||
if len(q) < 2:
|
||||
return []
|
||||
results = (
|
||||
db.query(UserModel)
|
||||
.filter(UserModel.username.ilike(f"%{q}%"))
|
||||
.limit(20)
|
||||
.all()
|
||||
)
|
||||
return [
|
||||
{
|
||||
"username": u.username,
|
||||
"wins": u.wins,
|
||||
"losses": u.losses,
|
||||
"win_rate": round(u.wins / (u.wins + u.losses) * 100) if (u.wins + u.losses) > 0 else 0,
|
||||
}
|
||||
for u in results
|
||||
]
|
||||
|
||||
|
||||
@router.get("/users/{username}")
|
||||
def get_public_profile(username: str, db: Session = Depends(get_db)):
|
||||
user = db.query(UserModel).filter(UserModel.username == username).first()
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
total_games = user.wins + user.losses
|
||||
favorite_cards = (
|
||||
db.query(CardModel)
|
||||
.filter(CardModel.user_id == user.id, CardModel.is_favorite == True)
|
||||
.order_by(CardModel.received_at.desc())
|
||||
.all()
|
||||
)
|
||||
wtt_cards = (
|
||||
db.query(CardModel)
|
||||
.filter(CardModel.user_id == user.id, CardModel.willing_to_trade == True)
|
||||
.order_by(CardModel.received_at.desc())
|
||||
.all()
|
||||
)
|
||||
return {
|
||||
"username": user.username,
|
||||
"wins": user.wins,
|
||||
"losses": user.losses,
|
||||
"win_rate": round((user.wins / total_games) * 100) if total_games > 0 else None,
|
||||
"trade_wishlist": user.trade_wishlist or "",
|
||||
"last_active_at": user.last_active_at.isoformat() if user.last_active_at else None,
|
||||
"favorite_cards": [_serialize_card_public(c) for c in favorite_cards],
|
||||
"wtt_cards": [_serialize_card_public(c) for c in wtt_cards],
|
||||
}
|
||||
Reference in New Issue
Block a user