148 lines
4.5 KiB
Python
148 lines
4.5 KiB
Python
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],
|
|
}
|