173 lines
5.3 KiB
Python
173 lines
5.3 KiB
Python
"""Card-related API routes"""
|
||
from typing import List, Dict
|
||
from fastapi import APIRouter, HTTPException, Depends
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from app.models.card import Card, CardDraw, CardDrawResult
|
||
from app.services.gacha import GachaService
|
||
from app.services.card_master import card_master_service
|
||
from app.repositories.user import UserRepository
|
||
from app.repositories.card import CardRepository, UniqueCardRepository
|
||
from app.db.base import get_session
|
||
|
||
router = APIRouter(prefix="/cards", tags=["cards"])
|
||
|
||
|
||
@router.post("/draw", response_model=CardDrawResult)
|
||
async def draw_card(
|
||
draw_request: CardDraw,
|
||
db: AsyncSession = Depends(get_session)
|
||
):
|
||
"""
|
||
カードを抽選する
|
||
|
||
- **user_did**: ユーザーのatproto DID
|
||
- **is_paid**: 課金ガチャかどうか
|
||
"""
|
||
try:
|
||
gacha_service = GachaService(db)
|
||
card, is_unique = await gacha_service.draw_card(
|
||
user_did=draw_request.user_did,
|
||
is_paid=draw_request.is_paid
|
||
)
|
||
|
||
# 演出タイプを決定
|
||
animation_type = "normal"
|
||
if is_unique:
|
||
animation_type = "unique"
|
||
elif card.status.value == "kira":
|
||
animation_type = "kira"
|
||
elif card.status.value in ["super_rare", "rare"]:
|
||
animation_type = "rare"
|
||
|
||
# 新規取得かチェック
|
||
user_repo = UserRepository(db)
|
||
card_repo = CardRepository(db)
|
||
user = await user_repo.get_by_did(draw_request.user_did)
|
||
count = await card_repo.count_user_cards(user.id, card.id)
|
||
is_new = count == 1 # 今引いたカードが初めてなら1枚
|
||
|
||
result = CardDrawResult(
|
||
card=card,
|
||
is_new=is_new,
|
||
animation_type=animation_type
|
||
)
|
||
|
||
await db.commit()
|
||
return result
|
||
|
||
except Exception as e:
|
||
await db.rollback()
|
||
raise HTTPException(status_code=500, detail=str(e))
|
||
|
||
|
||
@router.get("/user/{user_did}", response_model=List[Card])
|
||
async def get_user_cards(
|
||
user_did: str,
|
||
skip: int = 0,
|
||
limit: int = 100,
|
||
db: AsyncSession = Depends(get_session)
|
||
):
|
||
"""
|
||
ユーザーの所有カード一覧を取得
|
||
|
||
- **user_did**: ユーザーのatproto DID
|
||
"""
|
||
user_repo = UserRepository(db)
|
||
card_repo = CardRepository(db)
|
||
|
||
user = await user_repo.get_by_did(user_did)
|
||
if not user:
|
||
raise HTTPException(status_code=404, detail="User not found")
|
||
|
||
user_cards = await card_repo.get_user_cards(user.id, skip=skip, limit=limit)
|
||
|
||
# Convert to API model
|
||
cards = []
|
||
for uc in user_cards:
|
||
card = Card(
|
||
id=uc.card_id,
|
||
cp=uc.cp,
|
||
status=uc.status,
|
||
skill=uc.skill,
|
||
owner_did=user_did,
|
||
obtained_at=uc.obtained_at,
|
||
is_unique=uc.is_unique,
|
||
unique_id=str(uc.unique_id) if uc.unique_id else None
|
||
)
|
||
cards.append(card)
|
||
|
||
return cards
|
||
|
||
|
||
@router.get("/unique")
|
||
async def get_unique_cards(db: AsyncSession = Depends(get_session)):
|
||
"""
|
||
全てのuniqueカード一覧を取得(所有者情報付き)
|
||
"""
|
||
unique_repo = UniqueCardRepository(db)
|
||
unique_cards = await unique_repo.get_all_unique_cards()
|
||
|
||
return [
|
||
{
|
||
"card_id": uc.card_id,
|
||
"owner_did": uc.owner_did,
|
||
"obtained_at": uc.obtained_at,
|
||
"unique_id": str(uc.unique_id)
|
||
}
|
||
for uc in unique_cards
|
||
]
|
||
|
||
|
||
@router.get("/stats")
|
||
async def get_gacha_stats(db: AsyncSession = Depends(get_session)):
|
||
"""
|
||
ガチャ統計情報を取得
|
||
"""
|
||
try:
|
||
card_repo = CardRepository(db)
|
||
|
||
# 総ガチャ実行数
|
||
total_draws = await card_repo.get_total_card_count()
|
||
|
||
# レアリティ別カード数
|
||
cards_by_rarity = await card_repo.get_cards_by_rarity()
|
||
|
||
# 成功率計算(簡易版)
|
||
success_rates = {}
|
||
if total_draws > 0:
|
||
for rarity, count in cards_by_rarity.items():
|
||
success_rates[rarity] = count / total_draws
|
||
|
||
# 最近の活動(最新10件)
|
||
recent_cards = await card_repo.get_recent_cards(limit=10)
|
||
recent_activity = []
|
||
for card_data in recent_cards:
|
||
recent_activity.append({
|
||
"timestamp": card_data.get("obtained_at", "").isoformat() if card_data.get("obtained_at") else "",
|
||
"user_did": card_data.get("owner_did", "unknown"),
|
||
"card_name": f"Card #{card_data.get('card_id', 0)}",
|
||
"rarity": card_data.get("status", "common")
|
||
})
|
||
|
||
return {
|
||
"total_draws": total_draws,
|
||
"cards_by_rarity": cards_by_rarity,
|
||
"success_rates": success_rates,
|
||
"recent_activity": recent_activity
|
||
}
|
||
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=f"Statistics error: {str(e)}")
|
||
|
||
|
||
@router.get("/master", response_model=List[Dict])
|
||
async def get_card_master_data():
|
||
"""
|
||
全カードマスターデータを取得(ai.jsonから)
|
||
"""
|
||
try:
|
||
cards = card_master_service.get_all_cards()
|
||
return cards
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=f"Failed to get card master data: {str(e)}") |