Backend:
- New endpoint: POST /api/auth/register
- New endpoint: GET /api/auth/verify/{token}
- Migration: Add email_verified, verification_token, verification_expires
- Helper: send_email() for reusable SMTP
- Validation: email format, password length (min 8), name
- Auto-login after verification (returns session token)
- Rate limit: 3 registrations per hour per IP
Features:
- Verification token valid for 24h
- Existing users marked as verified (grandfather clause)
- SMTP configured via .env (SMTP_HOST, SMTP_USER, SMTP_PASS)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
126 lines
3.7 KiB
Python
126 lines
3.7 KiB
Python
"""
|
|
Pydantic Models for Mitai Jinkendo API
|
|
|
|
Data validation schemas for request/response bodies.
|
|
"""
|
|
from typing import Optional
|
|
from pydantic import BaseModel
|
|
|
|
|
|
# ── Profile Models ────────────────────────────────────────────────────────────
|
|
|
|
class ProfileCreate(BaseModel):
|
|
name: str
|
|
avatar_color: Optional[str] = '#1D9E75'
|
|
sex: Optional[str] = 'm'
|
|
dob: Optional[str] = None
|
|
height: Optional[float] = 178
|
|
goal_weight: Optional[float] = None
|
|
goal_bf_pct: Optional[float] = None
|
|
|
|
|
|
class ProfileUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
avatar_color: Optional[str] = None
|
|
sex: Optional[str] = None
|
|
dob: Optional[str] = None
|
|
height: Optional[float] = None
|
|
goal_weight: Optional[float] = None
|
|
goal_bf_pct: Optional[float] = None
|
|
|
|
|
|
# ── Tracking Models ───────────────────────────────────────────────────────────
|
|
|
|
class WeightEntry(BaseModel):
|
|
date: str
|
|
weight: float
|
|
note: Optional[str] = None
|
|
|
|
|
|
class CircumferenceEntry(BaseModel):
|
|
date: str
|
|
c_neck: Optional[float] = None
|
|
c_chest: Optional[float] = None
|
|
c_waist: Optional[float] = None
|
|
c_belly: Optional[float] = None
|
|
c_hip: Optional[float] = None
|
|
c_thigh: Optional[float] = None
|
|
c_calf: Optional[float] = None
|
|
c_arm: Optional[float] = None
|
|
notes: Optional[str] = None
|
|
photo_id: Optional[str] = None
|
|
|
|
|
|
class CaliperEntry(BaseModel):
|
|
date: str
|
|
sf_method: Optional[str] = 'jackson3'
|
|
sf_chest: Optional[float] = None
|
|
sf_axilla: Optional[float] = None
|
|
sf_triceps: Optional[float] = None
|
|
sf_subscap: Optional[float] = None
|
|
sf_suprailiac: Optional[float] = None
|
|
sf_abdomen: Optional[float] = None
|
|
sf_thigh: Optional[float] = None
|
|
sf_calf_med: Optional[float] = None
|
|
sf_lowerback: Optional[float] = None
|
|
sf_biceps: Optional[float] = None
|
|
body_fat_pct: Optional[float] = None
|
|
lean_mass: Optional[float] = None
|
|
fat_mass: Optional[float] = None
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class ActivityEntry(BaseModel):
|
|
date: str
|
|
start_time: Optional[str] = None
|
|
end_time: Optional[str] = None
|
|
activity_type: str
|
|
duration_min: Optional[float] = None
|
|
kcal_active: Optional[float] = None
|
|
kcal_resting: Optional[float] = None
|
|
hr_avg: Optional[float] = None
|
|
hr_max: Optional[float] = None
|
|
distance_km: Optional[float] = None
|
|
rpe: Optional[int] = None
|
|
source: Optional[str] = 'manual'
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class NutritionDay(BaseModel):
|
|
date: str
|
|
kcal: Optional[float] = None
|
|
protein_g: Optional[float] = None
|
|
fat_g: Optional[float] = None
|
|
carbs_g: Optional[float] = None
|
|
|
|
|
|
# ── Auth Models ───────────────────────────────────────────────────────────────
|
|
|
|
class LoginRequest(BaseModel):
|
|
email: str
|
|
password: str
|
|
|
|
|
|
class PasswordResetRequest(BaseModel):
|
|
email: str
|
|
|
|
|
|
class PasswordResetConfirm(BaseModel):
|
|
token: str
|
|
new_password: str
|
|
|
|
|
|
class RegisterRequest(BaseModel):
|
|
name: str
|
|
email: str
|
|
password: str
|
|
|
|
|
|
# ── Admin Models ──────────────────────────────────────────────────────────────
|
|
|
|
class AdminProfileUpdate(BaseModel):
|
|
role: Optional[str] = None
|
|
ai_enabled: Optional[int] = None
|
|
ai_limit_day: Optional[int] = None
|
|
export_enabled: Optional[int] = None
|