1
0

Add complete ai.card Rust implementation

- Implement complete Rust API server with axum framework
- Add database abstraction supporting PostgreSQL and SQLite
- Implement comprehensive gacha system with probability calculations
- Add JWT authentication with atproto DID integration
- Create card master data system with rarities (Normal, Rare, SuperRare, Kira, Unique)
- Implement draw history tracking and collection management
- Add API endpoints for authentication, card drawing, and collection viewing
- Include database migrations for both PostgreSQL and SQLite
- Maintain full compatibility with Python API implementation
- Add comprehensive documentation and development guide

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-06-07 17:43:10 +09:00
parent ef907660cc
commit 0b34568585
57 changed files with 3469 additions and 422 deletions

View File

@ -0,0 +1,152 @@
"""Synchronization routes for atproto"""
from typing import Optional
from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel
from app.auth.dependencies import require_user, AuthUser
from app.db.base import get_session
from app.services.card_sync import CardSyncService
from app.repositories.user import UserRepository
router = APIRouter(prefix="/sync", tags=["sync"])
class SyncRequest(BaseModel):
"""Sync request model"""
atproto_session: str # Session string from atproto login
class SyncResponse(BaseModel):
"""Sync response model"""
synced_to_pds: int = 0
imported_from_pds: int = 0
message: str
@router.post("/cards", response_model=SyncResponse)
async def sync_cards(
request: SyncRequest,
current_user: AuthUser = Depends(require_user),
db: AsyncSession = Depends(get_session)
):
"""
Sync cards between database and atproto PDS
- **atproto_session**: Session string from atproto login
"""
try:
# Get user from database
user_repo = UserRepository(db)
user = await user_repo.get_by_did(current_user.did)
if not user:
raise HTTPException(status_code=404, detail="User not found")
# Create sync service
sync_service = CardSyncService(db, request.atproto_session)
# Import from PDS first
imported = await sync_service.import_cards_from_pds(current_user.did)
# Then sync all cards to PDS
synced = await sync_service.sync_all_user_cards(user.id, current_user.did)
await db.commit()
return SyncResponse(
synced_to_pds=synced,
imported_from_pds=imported,
message=f"Successfully synced {synced} cards to PDS and imported {imported} cards from PDS"
)
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=str(e))
@router.post("/export")
async def export_to_pds(
request: SyncRequest,
current_user: AuthUser = Depends(require_user),
db: AsyncSession = Depends(get_session)
):
"""
Export all cards to atproto PDS
- **atproto_session**: Session string from atproto login
"""
try:
user_repo = UserRepository(db)
user = await user_repo.get_by_did(current_user.did)
if not user:
raise HTTPException(status_code=404, detail="User not found")
sync_service = CardSyncService(db, request.atproto_session)
synced = await sync_service.sync_all_user_cards(user.id, current_user.did)
return {
"exported": synced,
"message": f"Successfully exported {synced} cards to PDS"
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/import")
async def import_from_pds(
request: SyncRequest,
current_user: AuthUser = Depends(require_user),
db: AsyncSession = Depends(get_session)
):
"""
Import cards from atproto PDS
- **atproto_session**: Session string from atproto login
"""
try:
sync_service = CardSyncService(db, request.atproto_session)
imported = await sync_service.import_cards_from_pds(current_user.did)
await db.commit()
return {
"imported": imported,
"message": f"Successfully imported {imported} cards from PDS"
}
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=str(e))
@router.get("/verify/{card_id}")
async def verify_card_ownership(
card_id: int,
unique_id: Optional[str] = None,
current_user: AuthUser = Depends(require_user),
db: AsyncSession = Depends(get_session)
):
"""
Verify user owns a specific card
- **card_id**: Card type ID (0-15)
- **unique_id**: Unique ID for unique cards
"""
sync_service = CardSyncService(db)
owns_card = await sync_service.verify_card_ownership(
current_user.did,
card_id,
unique_id
)
return {
"card_id": card_id,
"unique_id": unique_id,
"owned": owns_card
}
# Import Optional
from typing import Optional