Files
2026-10-03 09:44:11 +03:00

348 lines
8.2 KiB
Python

from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
# ============================================================
# AUTH / USERS
# ============================================================
class UserCreate(BaseModel):
username: str
password: str
display_name: Optional[str] = ""
role: Optional[str] = "personal"
class UserLogin(BaseModel):
username: str
password: str
class UserOut(BaseModel):
id: int
username: str
display_name: str
role: str
created_at: str
class Config:
from_attributes = True
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
user: UserOut
# ============================================================
# WORKOUT TYPES
# ============================================================
class WorkoutTypeBase(BaseModel):
name: str
sort_order: Optional[int] = 0
class WorkoutTypeCreate(WorkoutTypeBase):
sync_id: Optional[str] = None
class WorkoutTypeOut(WorkoutTypeBase):
id: int
sync_id: str
created_at: str
class Config:
from_attributes = True
# ============================================================
# METRIC TYPES
# ============================================================
class MetricTypeBase(BaseModel):
name: str
unit: Optional[str] = "см"
category: Optional[str] = "body"
sort_order: Optional[int] = 0
class MetricTypeCreate(MetricTypeBase):
sync_id: Optional[str] = None
class MetricTypeOut(MetricTypeBase):
id: int
sync_id: str
created_at: str
class Config:
from_attributes = True
# ============================================================
# CLIENTS
# ============================================================
class ClientBase(BaseModel):
full_name: str
birth_date: Optional[str] = None
goal: Optional[str] = ""
notes: Optional[str] = ""
color: Optional[str] = None
is_active: Optional[int] = 1
class ClientCreate(ClientBase):
sync_id: Optional[str] = None
class ClientUpdate(BaseModel):
full_name: Optional[str] = None
birth_date: Optional[str] = None
goal: Optional[str] = None
notes: Optional[str] = None
color: Optional[str] = None
is_active: Optional[int] = None
class ClientOut(ClientBase):
id: int
sync_id: str
owner_id: Optional[int] = None
created_at: str
updated_at: str
class Config:
from_attributes = True
# ============================================================
# EXERCISES
# ============================================================
class ExerciseBase(BaseModel):
name: str
workout_type_id: Optional[int] = None
class ExerciseCreate(ExerciseBase):
sync_id: Optional[str] = None
class ExerciseUpdate(BaseModel):
name: Optional[str] = None
workout_type_id: Optional[int] = None
class ExerciseOut(ExerciseBase):
id: int
sync_id: str
owner_id: Optional[int] = None
created_at: str
updated_at: str
class Config:
from_attributes = True
# ============================================================
# DROPSET ITEMS
# ============================================================
class DropsetItemBase(BaseModel):
weight: float = Field(gt=0)
reps: int = Field(gt=0)
sort_order: int = 0
class DropsetItemCreate(DropsetItemBase):
pass
class DropsetItemOut(DropsetItemBase):
id: int
class Config:
from_attributes = True
# ============================================================
# SETS
# ============================================================
class SetBase(BaseModel):
is_dropset: int = 0
weight: Optional[float] = None
reps: Optional[int] = None
rating: Optional[int] = Field(None, ge=1, le=5)
notes: Optional[str] = ""
sort_order: int = 0
timestamp: str
class SetCreate(SetBase):
sync_id: Optional[str] = None
dropset_items: List[DropsetItemCreate] = Field(default_factory=list)
class SetOut(SetBase):
id: int
sync_id: str
created_at: str
dropset_items: List[DropsetItemOut] = Field(default_factory=list)
class Config:
from_attributes = True
# ============================================================
# WORKOUT EXERCISES
# ============================================================
class WorkoutExerciseBase(BaseModel):
exercise_name: str
exercise_id: Optional[int] = None
exercise_sync_id: Optional[str] = None
sort_order: int = 0
class WorkoutExerciseCreate(WorkoutExerciseBase):
sync_id: Optional[str] = None
sets: List[SetCreate] = Field(default_factory=list)
class WorkoutExerciseOut(WorkoutExerciseBase):
id: int
sync_id: str
created_at: str
sets: List[SetOut] = Field(default_factory=list)
class Config:
from_attributes = True
# ============================================================
# CARDIO
# ============================================================
class CardioBase(BaseModel):
cardio_type: str
purpose: str
duration: Optional[int] = None
distance: Optional[float] = None
speed: Optional[float] = None
incline: Optional[float] = None
resistance: Optional[int] = None
notes: Optional[str] = ""
sort_order: int = 0
class CardioCreate(CardioBase):
sync_id: Optional[str] = None
class CardioOut(CardioBase):
id: int
sync_id: str
created_at: str
class Config:
from_attributes = True
# ============================================================
# WORKOUTS
# ============================================================
class WorkoutBase(BaseModel):
start_time: str
end_time: Optional[str] = None
notes: Optional[str] = ""
workout_type_id: Optional[int] = None
class WorkoutCreate(WorkoutBase):
sync_id: Optional[str] = None
client_id: Optional[int] = None
client_sync_id: Optional[str] = None
workout_exercises: List[WorkoutExerciseCreate] = Field(default_factory=list)
cardio_sessions: List[CardioCreate] = Field(default_factory=list)
class WorkoutUpdate(BaseModel):
workout_type_id: Optional[int] = None
end_time: Optional[str] = None
notes: Optional[str] = None
synced: Optional[int] = None
class WorkoutOut(WorkoutBase):
id: int
sync_id: str
owner_id: Optional[int] = None
client_id: Optional[int] = None
synced: int
created_at: str
updated_at: str
workout_exercises: List[WorkoutExerciseOut] = Field(default_factory=list)
cardio_sessions: List[CardioOut] = Field(default_factory=list)
class Config:
from_attributes = True
# ============================================================
# BODY METRIC VALUES
# ============================================================
class BodyMetricValueBase(BaseModel):
value: float
class BodyMetricValueCreate(BodyMetricValueBase):
metric_type_id: Optional[int] = None
metric_type_sync_id: Optional[str] = None
class BodyMetricValueOut(BodyMetricValueBase):
id: int
metric_type_id: int
class Config:
from_attributes = True
# ============================================================
# BODY METRICS
# ============================================================
class BodyMetricBase(BaseModel):
metric_date: str
notes: Optional[str] = ""
class BodyMetricCreate(BodyMetricBase):
sync_id: Optional[str] = None
client_id: Optional[int] = None
client_sync_id: Optional[str] = None
values: List[BodyMetricValueCreate] = Field(default_factory=list)
class BodyMetricOut(BodyMetricBase):
id: int
sync_id: str
owner_id: Optional[int] = None
client_id: Optional[int] = None
created_at: str
values: List[BodyMetricValueOut] = Field(default_factory=list)
class Config:
from_attributes = True
# ============================================================
# SYNC
# ============================================================
class SyncPayload(BaseModel):
clients: List[ClientCreate] = Field(default_factory=list)
exercises: List[ExerciseCreate] = Field(default_factory=list)
workouts: List[WorkoutCreate] = Field(default_factory=list)
body_metrics: List[BodyMetricCreate] = Field(default_factory=list)
class SyncResponse(BaseModel):
status: str
created: Dict[str, int]
updated: Dict[str, int]
warnings: List[str] = Field(default_factory=list)