#!/usr/bin/env python3 from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session import database import models import schemas from datetime import datetime router = APIRouter(prefix="/sync", tags=["sync"]) def get_current_timestamp(): return datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%fZ') @router.post("/", response_model=schemas.SyncResponse) def sync_data(payload: schemas.SyncPayload, db: Session = Depends(database.get_db)): """ Endpoint для синхронизации офлайн-очереди с клиента. Использует sync_id для идемпотентности — если запись с таким sync_id уже есть, пропускаем. """ timestamp = get_current_timestamp() created = { "clients": 0, "workout_types": 0, "exercises": 0, "workouts": 0, "metric_types": 0, "body_metrics": 0 } updated = {k: 0 for k in created} # Синхронизация клиентов for client_data in payload.clients or []: existing = db.query(models.Client).filter(models.Client.sync_id == client_data.sync_id).first() if not existing: db_client = models.Client( **client_data.dict(), created_at=timestamp, updated_at=timestamp ) db.add(db_client) created["clients"] += 1 # Синхронизация типов тренировок for wt_data in payload.workout_types or []: existing = db.query(models.WorkoutType).filter(models.WorkoutType.sync_id == wt_data.sync_id).first() if not existing: db_wt = models.WorkoutType( **wt_data.dict(), created_at=timestamp ) db.add(db_wt) created["workout_types"] += 1 # Синхронизация упражнений for ex_data in payload.exercises or []: existing = db.query(models.Exercise).filter(models.Exercise.sync_id == ex_data.sync_id).first() if not existing: db_ex = models.Exercise( **ex_data.dict(), created_at=timestamp, updated_at=timestamp ) db.add(db_ex) created["exercises"] += 1 # Синхронизация типов замеров for mt_data in payload.metric_types or []: existing = db.query(models.MetricType).filter(models.MetricType.sync_id == mt_data.sync_id).first() if not existing: db_mt = models.MetricType( **mt_data.dict(), created_at=timestamp ) db.add(db_mt) created["metric_types"] += 1 # Синхронизация тренировок (с упражнениями и подходами) for workout_data in payload.workouts or []: existing = db.query(models.Workout).filter(models.Workout.sync_id == workout_data.sync_id).first() if not existing: db_workout = models.Workout( sync_id=workout_data.sync_id, client_id=workout_data.client_id, workout_type_id=workout_data.workout_type_id, start_time=workout_data.start_time, end_time=workout_data.end_time, notes=workout_data.notes, created_at=timestamp, updated_at=timestamp ) db.add(db_workout) db.flush() # Упражнения for we_data in workout_data.workout_exercises or []: db_we = models.WorkoutExercise( sync_id=we_data.sync_id, workout_id=db_workout.id, exercise_id=we_data.exercise_id, exercise_name=we_data.exercise_name, sort_order=we_data.sort_order, created_at=timestamp ) db.add(db_we) db.flush() # Подходы for set_data in we_data.sets or []: db_set = models.Set( sync_id=set_data.sync_id, workout_exercise_id=db_we.id, is_dropset=set_data.is_dropset, weight=set_data.weight, reps=set_data.reps, rating=set_data.rating, notes=set_data.notes, sort_order=set_data.sort_order, timestamp=set_data.timestamp, created_at=timestamp ) db.add(db_set) db.flush() # Дроп-сет элементы if set_data.is_dropset: for item_data in set_data.dropset_items or []: db_item = models.DropsetItem( set_id=db_set.id, weight=item_data.weight, reps=item_data.reps, sort_order=item_data.sort_order ) db.add(db_item) # Кардио for cardio_data in workout_data.cardio_sessions or []: db_cardio = models.Cardio( sync_id=cardio_data.sync_id, workout_id=db_workout.id, cardio_type=cardio_data.cardio_type, purpose=cardio_data.purpose, duration=cardio_data.duration, distance=cardio_data.distance, speed=cardio_data.speed, incline=cardio_data.incline, resistance=cardio_data.resistance, notes=cardio_data.notes, sort_order=cardio_data.sort_order, created_at=timestamp ) db.add(db_cardio) created["workouts"] += 1 # Синхронизация замеров тела for metric_data in payload.body_metrics or []: existing = db.query(models.BodyMetric).filter(models.BodyMetric.sync_id == metric_data.sync_id).first() if not existing: db_metric = models.BodyMetric( sync_id=metric_data.sync_id, client_id=metric_data.client_id, metric_date=metric_data.metric_date, notes=metric_data.notes, created_at=timestamp ) db.add(db_metric) db.flush() for value_data in metric_data.values or []: db_value = models.BodyMetricValue( body_metric_id=db_metric.id, metric_type_id=value_data.metric_type_id, value=value_data.value ) db.add(db_value) created["body_metrics"] += 1 db.commit() return schemas.SyncResponse( status="success", created=created, updated=updated )