
- Set up FastAPI project structure with main.py and requirements.txt - Created SQLite database models for users, beats, and transactions - Implemented Alembic database migrations - Added user authentication system with JWT tokens - Created beat management endpoints (CRUD operations) - Implemented purchase/transaction system - Added file upload/download functionality for beat files - Created health endpoint and API documentation - Updated README with comprehensive documentation - Fixed all linting issues with Ruff Environment variables needed: - SECRET_KEY: JWT secret key for authentication
66 lines
2.1 KiB
Python
66 lines
2.1 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from fastapi.responses import FileResponse
|
|
from sqlalchemy.orm import Session
|
|
from pathlib import Path
|
|
from app.db.session import get_db
|
|
from app.models.transaction import Transaction, TransactionStatus
|
|
from app.models.beat import Beat
|
|
from app.models.user import User
|
|
from app.services.auth import get_current_active_user
|
|
|
|
router = APIRouter()
|
|
|
|
@router.get("/download/{beat_id}")
|
|
async def download_beat(
|
|
beat_id: int,
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
# Check if user has purchased this beat
|
|
transaction = db.query(Transaction).filter(
|
|
Transaction.buyer_id == current_user.id,
|
|
Transaction.beat_id == beat_id,
|
|
Transaction.status == TransactionStatus.COMPLETED
|
|
).first()
|
|
|
|
if not transaction:
|
|
# Check if user is the producer of this beat
|
|
beat = db.query(Beat).filter(
|
|
Beat.id == beat_id,
|
|
Beat.producer_id == current_user.id
|
|
).first()
|
|
if not beat:
|
|
raise HTTPException(status_code=403, detail="Access denied - beat not purchased")
|
|
else:
|
|
beat = transaction.beat
|
|
|
|
if not beat.file_path or not Path(beat.file_path).exists():
|
|
raise HTTPException(status_code=404, detail="Beat file not found")
|
|
|
|
return FileResponse(
|
|
beat.file_path,
|
|
media_type='application/octet-stream',
|
|
filename=f"{beat.title}.{beat.file_path.split('.')[-1]}"
|
|
)
|
|
|
|
@router.get("/preview/{beat_id}")
|
|
async def get_beat_preview(
|
|
beat_id: int,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
beat = db.query(Beat).filter(
|
|
Beat.id == beat_id,
|
|
Beat.is_available
|
|
).first()
|
|
|
|
if not beat:
|
|
raise HTTPException(status_code=404, detail="Beat not found")
|
|
|
|
if not beat.preview_path or not Path(beat.preview_path).exists():
|
|
raise HTTPException(status_code=404, detail="Preview not available")
|
|
|
|
return FileResponse(
|
|
beat.preview_path,
|
|
media_type='audio/mpeg',
|
|
filename=f"{beat.title}_preview.{beat.preview_path.split('.')[-1]}"
|
|
) |