Code Splitting Results: - goals.py: 1339 → 655 lines (-684 lines, -51%) - Created 4 new routers: * goal_types.py (426 lines) - Goal Type Definitions CRUD * goal_progress.py (155 lines) - Progress tracking * training_phases.py (107 lines) - Training phases * fitness_tests.py (94 lines) - Fitness tests Benefits: ✅ Improved maintainability (smaller, focused files) ✅ Better context window efficiency for AI tools ✅ Clearer separation of concerns ✅ Easier testing and debugging All routers registered in main.py. Backward compatible - no API changes.
95 lines
2.9 KiB
Python
95 lines
2.9 KiB
Python
"""
|
|
Fitness Tests Router - Fitness Test Recording & Norm Tracking
|
|
|
|
Endpoints for managing fitness tests:
|
|
- List fitness tests
|
|
- Record fitness test results
|
|
- Calculate norm categories
|
|
|
|
Part of v9h Goal System.
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel
|
|
from typing import Optional
|
|
from datetime import date
|
|
|
|
from db import get_db, get_cursor, r2d
|
|
from auth import require_auth
|
|
|
|
router = APIRouter(prefix="/api/goals", tags=["fitness-tests"])
|
|
|
|
# ============================================================================
|
|
# Pydantic Models
|
|
# ============================================================================
|
|
|
|
class FitnessTestCreate(BaseModel):
|
|
"""Record fitness test result"""
|
|
test_type: str
|
|
result_value: float
|
|
result_unit: str
|
|
test_date: date
|
|
test_conditions: Optional[str] = None
|
|
|
|
# ============================================================================
|
|
# Endpoints
|
|
# ============================================================================
|
|
|
|
@router.get("/tests")
|
|
def list_fitness_tests(session: dict = Depends(require_auth)):
|
|
"""List all fitness tests"""
|
|
pid = session['profile_id']
|
|
|
|
with get_db() as conn:
|
|
cur = get_cursor(conn)
|
|
cur.execute("""
|
|
SELECT id, test_type, result_value, result_unit,
|
|
test_date, test_conditions, norm_category, created_at
|
|
FROM fitness_tests
|
|
WHERE profile_id = %s
|
|
ORDER BY test_date DESC
|
|
""", (pid,))
|
|
|
|
return [r2d(row) for row in cur.fetchall()]
|
|
|
|
@router.post("/tests")
|
|
def create_fitness_test(data: FitnessTestCreate, session: dict = Depends(require_auth)):
|
|
"""Record fitness test result"""
|
|
pid = session['profile_id']
|
|
|
|
with get_db() as conn:
|
|
cur = get_cursor(conn)
|
|
|
|
# Calculate norm category (simplified for now)
|
|
norm_category = _calculate_norm_category(
|
|
data.test_type,
|
|
data.result_value,
|
|
data.result_unit
|
|
)
|
|
|
|
cur.execute("""
|
|
INSERT INTO fitness_tests (
|
|
profile_id, test_type, result_value, result_unit,
|
|
test_date, test_conditions, norm_category
|
|
) VALUES (%s, %s, %s, %s, %s, %s, %s)
|
|
RETURNING id
|
|
""", (
|
|
pid, data.test_type, data.result_value, data.result_unit,
|
|
data.test_date, data.test_conditions, norm_category
|
|
))
|
|
|
|
test_id = cur.fetchone()['id']
|
|
|
|
return {"id": test_id, "norm_category": norm_category}
|
|
|
|
# ============================================================================
|
|
# Helper Functions
|
|
# ============================================================================
|
|
|
|
def _calculate_norm_category(test_type: str, value: float, unit: str) -> Optional[str]:
|
|
"""
|
|
Calculate norm category for fitness test
|
|
(Simplified - would need age/gender-specific norms)
|
|
"""
|
|
# Placeholder - should use proper norm tables
|
|
return None
|