Files
HabitForge/backend/api/v1/challenges.py
T
2026-07-30 23:25:20 -04:00

119 lines
3.8 KiB
Python

"""Challenge endpoints for API v1."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import func
from typing import List, Optional
import datetime
from backend.models.challenge import Challenge
from backend.models.tracking import Tracking
from backend.models.user import User
from backend import auth
from backend.schemas.challenge import ChallengeCreate, ChallengeResponse
from backend.schemas.tracking import TrackingCreate, TrackingResponse
from backend.database import get_db
router = APIRouter(prefix="/api/challenges", tags=["challenges"])
@router.post("", response_model=ChallengeResponse, status_code=status.HTTP_201_CREATED)
def create_challenge(
challenge: ChallengeCreate,
db: Session = Depends(get_db),
current_user: User = Depends(auth.get_current_user)
):
"""Create a new challenge."""
# Calculate next display_order for THIS user
max_order = db.query(func.max(Challenge.display_order)).filter(
Challenge.user_id == current_user.id
).scalar()
new_order = (max_order if max_order is not None else -1) + 1
db_challenge = Challenge(**challenge.dict(), display_order=new_order, user_id=current_user.id)
db.add(db_challenge)
db.commit()
db.refresh(db_challenge)
return db_challenge
@router.get("", response_model=List[ChallengeResponse])
def read_challenges(
db: Session = Depends(get_db),
current_user: User = Depends(auth.get_current_user)
):
"""Get all challenges for the current user."""
challenges = db.query(Challenge).filter(
Challenge.user_id == current_user.id
).order_by(Challenge.display_order.asc()).all()
return challenges
@router.put("/reorder", status_code=status.HTTP_204_NO_CONTENT)
def reorder_challenges(
ordered_ids: List[int],
db: Session = Depends(get_db),
current_user: User = Depends(auth.get_current_user)
):
"""Reorder challenges."""
# Sanity check: ensure these challenges belong to user
for index, challenge_id in enumerate(ordered_ids):
db.query(Challenge).filter(
Challenge.id == challenge_id,
Challenge.user_id == current_user.id
).update({"display_order": index})
db.commit()
return None
@router.delete("/{challenge_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_challenge(
challenge_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(auth.get_current_user)
):
"""Delete a challenge."""
db_challenge = db.query(Challenge).filter(
Challenge.id == challenge_id,
Challenge.user_id == current_user.id
).first()
if not db_challenge:
raise HTTPException(status_code=404, detail="Challenge not found")
db.delete(db_challenge)
db.commit()
return None
@router.post("/{challenge_id}/tracking", response_model=TrackingResponse)
def log_tracking(
challenge_id: int,
tracking: TrackingCreate,
db: Session = Depends(get_db),
current_user: User = Depends(auth.get_current_user)
):
"""Log tracking for a challenge."""
# Verify challenge belongs to user
challenge = db.query(Challenge).filter(
Challenge.id == challenge_id,
Challenge.user_id == current_user.id
).first()
if not challenge:
raise HTTPException(status_code=404, detail="Challenge not found")
# Check if tracking exists for this date and challenge
db_tracking = db.query(Tracking).filter(
Tracking.challenge_id == challenge_id,
Tracking.date == tracking.date
).first()
if db_tracking:
db_tracking.reps = tracking.reps
db_tracking.completed = tracking.completed
db_tracking.notes = tracking.notes
else:
db_tracking = Tracking(**tracking.dict())
db.add(db_tracking)
db.commit()
db.refresh(db_tracking)
return db_tracking