FastAPI + SQLAlchemy/Alembic + MariaDB backend with Jinja2/htmx/Alpine server-rendered frontend. Multi-user via Google OAuth, daily habit tracking, monthly/weekly history views, Web Push reminders via APScheduler, and PWA support (manifest, service worker, offline caching). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
82 lines
3.2 KiB
Python
82 lines
3.2 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.database import get_db
|
|
from app.models.habit import HabitStatus, HabitType
|
|
from app.models.user import User
|
|
from app.schemas.habit import HabitCreate, HabitOut, HabitReorderRequest, HabitUpdate
|
|
from app.schemas.habit_log import HabitStats
|
|
from app.security import require_login
|
|
from app.services import habit_service, log_service
|
|
|
|
router = APIRouter(prefix="/api/habits", tags=["habits"], dependencies=[Depends(require_login)])
|
|
|
|
|
|
def _get_habit_or_404(db: Session, habit_id: int, user_id: int):
|
|
habit = habit_service.get_habit(db, habit_id, user_id)
|
|
if habit is None:
|
|
raise HTTPException(status_code=404, detail="습관을 찾을 수 없습니다")
|
|
return habit
|
|
|
|
|
|
@router.get("", response_model=list[HabitOut])
|
|
def list_habits(
|
|
type: HabitType | None = None,
|
|
status: HabitStatus | None = None,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_login),
|
|
):
|
|
return habit_service.list_habits(db, current_user.id, habit_type=type, status=status)
|
|
|
|
|
|
@router.post("", response_model=HabitOut, status_code=201)
|
|
def create_habit(
|
|
data: HabitCreate, db: Session = Depends(get_db), current_user: User = Depends(require_login)
|
|
):
|
|
return habit_service.create_habit(db, current_user.id, data)
|
|
|
|
|
|
@router.post("/reorder")
|
|
def reorder_habits(
|
|
data: HabitReorderRequest, db: Session = Depends(get_db), current_user: User = Depends(require_login)
|
|
):
|
|
habit_service.reorder_habits(db, current_user.id, data.habit_ids)
|
|
return {"ok": True}
|
|
|
|
|
|
@router.get("/{habit_id}", response_model=HabitOut)
|
|
def get_habit(habit_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_login)):
|
|
return _get_habit_or_404(db, habit_id, current_user.id)
|
|
|
|
|
|
@router.put("/{habit_id}", response_model=HabitOut)
|
|
def update_habit(
|
|
habit_id: int, data: HabitUpdate, db: Session = Depends(get_db), current_user: User = Depends(require_login)
|
|
):
|
|
habit = _get_habit_or_404(db, habit_id, current_user.id)
|
|
return habit_service.update_habit(db, habit, data)
|
|
|
|
|
|
@router.delete("/{habit_id}", status_code=204)
|
|
def delete_habit(habit_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_login)):
|
|
habit = _get_habit_or_404(db, habit_id, current_user.id)
|
|
habit_service.delete_habit(db, habit)
|
|
|
|
|
|
@router.post("/{habit_id}/complete", response_model=HabitOut)
|
|
def complete_habit(habit_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_login)):
|
|
habit = _get_habit_or_404(db, habit_id, current_user.id)
|
|
return habit_service.complete_habit(db, habit)
|
|
|
|
|
|
@router.post("/{habit_id}/reactivate", response_model=HabitOut)
|
|
def reactivate_habit(habit_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_login)):
|
|
habit = _get_habit_or_404(db, habit_id, current_user.id)
|
|
return habit_service.reactivate_habit(db, habit)
|
|
|
|
|
|
@router.get("/{habit_id}/stats", response_model=HabitStats)
|
|
def get_habit_stats(habit_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_login)):
|
|
habit = _get_habit_or_404(db, habit_id, current_user.id)
|
|
return log_service.get_habit_stats(db, habit)
|