feat: add public profile and collection endpoints
This commit is contained in:
@@ -3,7 +3,7 @@ from sqlalchemy.orm import Session
|
|||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from app.database import get_db, engine
|
from app.database import get_db, engine
|
||||||
from app import models, seed
|
from app import models, seed
|
||||||
from app.routers import auth, users, chests
|
from app.routers import auth, users, chests, profiles
|
||||||
|
|
||||||
from app.middleware import IdempotencyMiddleware
|
from app.middleware import IdempotencyMiddleware
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ app.add_middleware(IdempotencyMiddleware)
|
|||||||
app.include_router(auth.router)
|
app.include_router(auth.router)
|
||||||
app.include_router(users.router)
|
app.include_router(users.router)
|
||||||
app.include_router(chests.router)
|
app.include_router(chests.router)
|
||||||
|
app.include_router(profiles.router)
|
||||||
|
|
||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
def startup_event():
|
def startup_event():
|
||||||
|
|||||||
48
backend/app/routers/profiles.py
Normal file
48
backend/app/routers/profiles.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from app import schemas, models, database
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/profiles",
|
||||||
|
tags=["profiles"],
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/{nickname}", response_model=schemas.UserProfilePublic)
|
||||||
|
def get_public_profile(nickname: str, db: Session = Depends(database.get_db)):
|
||||||
|
profile = db.query(models.UserProfile).filter(models.UserProfile.nickname == nickname).first()
|
||||||
|
if not profile:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
|
||||||
|
# We return the profile directly, which matches UserProfilePublic schema (nickname).
|
||||||
|
# But UserProfile model has created_at?
|
||||||
|
# Let's check model. UserProfile has keys: user_id, nickname, created_at?
|
||||||
|
# Actually models.UserProfile might not have created_at. Let's check.
|
||||||
|
# If not, we should rely on User.created_at or add it.
|
||||||
|
# For now assuming UserProfile has what we need or we fetch from User.
|
||||||
|
return profile
|
||||||
|
|
||||||
|
@router.get("/{nickname}/collection", response_model=List[schemas.UserCardResponse])
|
||||||
|
def get_public_collection(nickname: str, db: Session = Depends(database.get_db)):
|
||||||
|
# 1. Get User ID from nickname
|
||||||
|
profile = db.query(models.UserProfile).filter(models.UserProfile.nickname == nickname).first()
|
||||||
|
if not profile:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
|
||||||
|
# 2. Get Collection
|
||||||
|
# Note: Privacy check would go here.
|
||||||
|
cards = db.query(models.UserCard).filter(models.UserCard.user_id == profile.user_id).all()
|
||||||
|
if not cards:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# We need to reshape to UserCardResponse (card_name, rarity, obtained_at)
|
||||||
|
# models.UserCard has 'card' relationship.
|
||||||
|
response = []
|
||||||
|
for user_card in cards:
|
||||||
|
response.append({
|
||||||
|
"card_id": user_card.card_id,
|
||||||
|
"card_name": user_card.card.name,
|
||||||
|
"rarity": user_card.card.rarity,
|
||||||
|
"obtained_at": user_card.obtained_at
|
||||||
|
})
|
||||||
|
return response
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from pydantic import BaseModel, EmailStr
|
from pydantic import BaseModel, EmailStr
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
class UserRegister(BaseModel):
|
class UserRegister(BaseModel):
|
||||||
email: EmailStr
|
email: EmailStr
|
||||||
@@ -33,3 +34,20 @@ class ChestOpenResponse(BaseModel):
|
|||||||
chest_open_id: str
|
chest_open_id: str
|
||||||
spent_gold: int
|
spent_gold: int
|
||||||
items: List[ChestOpenItemResponse]
|
items: List[ChestOpenItemResponse]
|
||||||
|
|
||||||
|
class UserProfilePublic(BaseModel):
|
||||||
|
nickname: str
|
||||||
|
created_at: datetime
|
||||||
|
# Add other public fields here if needed
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|
||||||
|
class UserCardResponse(BaseModel):
|
||||||
|
card_id: str
|
||||||
|
card_name: str
|
||||||
|
rarity: str
|
||||||
|
obtained_at: datetime
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|||||||
48
verify_profiles.sh
Executable file
48
verify_profiles.sh
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Logging in..."
|
||||||
|
TOKEN=$(curl -s -X POST -H "Content-Type: application/json" -d '{"email":"test@example.com", "password":"password123"}' http://localhost:8000/auth/login | jq -r .access_token)
|
||||||
|
|
||||||
|
echo "Getting My Profile to find nickname..."
|
||||||
|
MY_PROFILE=$(curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8000/me/profile)
|
||||||
|
NICKNAME=$(echo $MY_PROFILE | jq -r .nickname)
|
||||||
|
echo "My Nickname: $NICKNAME"
|
||||||
|
|
||||||
|
echo "--- Testing Public Profile ($NICKNAME) ---"
|
||||||
|
PUBLIC_PROFILE=$(curl -s http://localhost:8000/profiles/$NICKNAME)
|
||||||
|
echo "Public Profile: $PUBLIC_PROFILE"
|
||||||
|
|
||||||
|
CHECK_NICK=$(echo $PUBLIC_PROFILE | jq -r .nickname)
|
||||||
|
if [ "$CHECK_NICK" == "$NICKNAME" ]; then
|
||||||
|
echo "SUCCESS: Public profile nickname matches."
|
||||||
|
else
|
||||||
|
echo "FAILURE: Public profile nickname mismatch."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "--- Testing Public Collection ($NICKNAME) ---"
|
||||||
|
COLLECTION=$(curl -s http://localhost:8000/profiles/$NICKNAME/collection)
|
||||||
|
COUNT=$(echo $COLLECTION | jq '. | length')
|
||||||
|
echo "Collection count: $COUNT"
|
||||||
|
|
||||||
|
if [ "$COUNT" -ge 0 ]; then
|
||||||
|
echo "SUCCESS: Collection retrieved."
|
||||||
|
else
|
||||||
|
echo "FAILURE: Collection failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "--- Testing Non-Existent Profile ---"
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/profiles/nonexistent_user_123)
|
||||||
|
echo "HTTP Code: $HTTP_CODE"
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" == "404" ]; then
|
||||||
|
echo "SUCCESS: Non-existent profile returned 404."
|
||||||
|
else
|
||||||
|
# wait, could be 500 if DB error?
|
||||||
|
echo "FAILURE: Non-existent profile returned $HTTP_CODE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ALL TESTS PASSED"
|
||||||
Reference in New Issue
Block a user