
- 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
138 lines
4.5 KiB
Python
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)} |