Automated Action c5e673d2ea Implement complete beat marketplace API with FastAPI
- 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
2025-07-06 17:42:23 +00:00

138 lines
4.5 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
from sqlalchemy.orm import Session
from typing import List, Optional
from app.db.session import get_db
from app.models.beat import Beat
from app.models.user import User
from app.schemas.beat import BeatCreate, BeatUpdate, BeatResponse
from app.services.auth import get_current_producer
import shutil
from pathlib import Path
router = APIRouter()
@router.get("/", response_model=List[BeatResponse])
async def get_beats(
skip: int = 0,
limit: int = 100,
genre: Optional[str] = None,
producer_id: Optional[int] = None,
db: Session = Depends(get_db)
):
query = db.query(Beat).filter(Beat.is_available)
if genre:
query = query.filter(Beat.genre == genre)
if producer_id:
query = query.filter(Beat.producer_id == producer_id)
beats = query.offset(skip).limit(limit).all()
return beats
@router.get("/{beat_id}", response_model=BeatResponse)
async def get_beat(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")
return beat
@router.post("/", response_model=BeatResponse)
async def create_beat(
beat: BeatCreate,
current_user: User = Depends(get_current_producer),
db: Session = Depends(get_db)
):
db_beat = Beat(
**beat.dict(),
producer_id=current_user.id,
file_path="", # Will be set when file is uploaded
)
db.add(db_beat)
db.commit()
db.refresh(db_beat)
return db_beat
@router.put("/{beat_id}", response_model=BeatResponse)
async def update_beat(
beat_id: int,
beat_update: BeatUpdate,
current_user: User = Depends(get_current_producer),
db: Session = Depends(get_db)
):
beat = db.query(Beat).filter(Beat.id == beat_id, Beat.producer_id == current_user.id).first()
if not beat:
raise HTTPException(status_code=404, detail="Beat not found")
update_data = beat_update.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(beat, field, value)
db.commit()
db.refresh(beat)
return beat
@router.delete("/{beat_id}")
async def delete_beat(
beat_id: int,
current_user: User = Depends(get_current_producer),
db: Session = Depends(get_db)
):
beat = db.query(Beat).filter(Beat.id == beat_id, Beat.producer_id == current_user.id).first()
if not beat:
raise HTTPException(status_code=404, detail="Beat not found")
beat.is_available = False
db.commit()
return {"message": "Beat deleted successfully"}
@router.post("/{beat_id}/upload-file")
async def upload_beat_file(
beat_id: int,
file: UploadFile = File(...),
current_user: User = Depends(get_current_producer),
db: Session = Depends(get_db)
):
beat = db.query(Beat).filter(Beat.id == beat_id, Beat.producer_id == current_user.id).first()
if not beat:
raise HTTPException(status_code=404, detail="Beat not found")
if not file.filename.endswith(('.mp3', '.wav', '.flac')):
raise HTTPException(status_code=400, detail="Invalid file format")
storage_dir = Path("/app/storage/beats")
storage_dir.mkdir(parents=True, exist_ok=True)
file_path = storage_dir / f"{beat_id}_{file.filename}"
with open(file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
beat.file_path = str(file_path)
db.commit()
return {"message": "File uploaded successfully", "file_path": str(file_path)}
@router.post("/{beat_id}/upload-preview")
async def upload_beat_preview(
beat_id: int,
file: UploadFile = File(...),
current_user: User = Depends(get_current_producer),
db: Session = Depends(get_db)
):
beat = db.query(Beat).filter(Beat.id == beat_id, Beat.producer_id == current_user.id).first()
if not beat:
raise HTTPException(status_code=404, detail="Beat not found")
if not file.filename.endswith(('.mp3', '.wav')):
raise HTTPException(status_code=400, detail="Invalid file format")
storage_dir = Path("/app/storage/beats/previews")
storage_dir.mkdir(parents=True, exist_ok=True)
file_path = storage_dir / f"{beat_id}_preview_{file.filename}"
with open(file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
beat.preview_path = str(file_path)
db.commit()
return {"message": "Preview uploaded successfully", "preview_path": str(file_path)}