/
DemienMedich
/
BodyweightBase
Обзор
Документация
Войти
/
DemienMedich
/
BodyweightBase
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
core/src/legacy_migrator.cpp
217 строк
8 KB
DemienMedich
Add adaptive training and health analytics core
09 июл 2026, 11:27
09 июл 2026, 11:27
487c3ec
Код
Авторство
О чём код?
#include "bodyweight/legacy_migrator.h" #include <QDateTime> #include <QDir> #include <QFile> #include <QJsonArray> #include <QJsonDocument> #include <QJsonParseError> namespace bodyweight { namespace { QJsonObject migrateStep(const QJsonObject &legacy) { return { {"exerciseId", legacy.value("ExerciseId")}, {"targetOverride", legacy.value("TargetOverride")}, {"restSecondsOverride", legacy.value("RestSecondsOverride")}, {"coachNote", legacy.value("CoachNote")} }; } QJsonObject migratePlan(const QJsonObject &legacy) { QJsonArray steps; for (const QJsonValue &value : legacy.value("Steps").toArray()) { if (value.isObject()) steps.append(migrateStep(value.toObject())); } return { {"id", legacy.value("Id")}, {"basePlanId", legacy.value("BasePlanId")}, {"name", legacy.value("Name")}, {"goal", legacy.value("Goal")}, {"description", legacy.value("Description")}, {"variantId", legacy.value("VariantId")}, {"roundCount", legacy.value("RoundCount")}, {"warmupIncluded", legacy.value("WarmupIncluded")}, {"warmupStepCount", legacy.value("WarmupStepCount")}, {"roundStepCount", legacy.value("RoundStepCount")}, {"recommendedRoundsText", legacy.value("RecommendedRoundsText")}, {"dayOfWeek", inferPlanDayOfWeek(legacy.value("Name").toString())}, {"steps", steps} }; } QJsonObject migrateCompletedStep(const QJsonObject &legacy) { return { {"exerciseId", legacy.value("ExerciseId")}, {"exerciseName", legacy.value("ExerciseName")}, {"metric", legacy.value("Metric").toInt() == 1 ? "seconds" : "repetitions"}, {"targetValue", legacy.value("TargetValue")}, {"actualValue", legacy.value("ActualValue")}, {"workSeconds", legacy.value("WorkSeconds")}, {"restSeconds", legacy.value("RestSeconds")}, {"completed", legacy.value("Completed")}, {"loadNote", legacy.value("LoadNote")} }; } QJsonObject migrateSession(const QJsonObject &legacy) { QJsonArray steps; for (const QJsonValue &value : legacy.value("Steps").toArray()) { if (value.isObject()) steps.append(migrateCompletedStep(value.toObject())); } return { {"id", legacy.value("SessionId")}, {"planId", legacy.value("PlanId")}, {"planName", legacy.value("PlanName")}, {"startedAt", legacy.value("StartedAtLocal")}, {"endedAt", legacy.value("EndedAtLocal")}, {"totalWorkSeconds", legacy.value("TotalWorkSeconds")}, {"totalRestSeconds", legacy.value("TotalRestSeconds")}, {"completedAll", legacy.value("CompletedAll")}, {"feedback", legacy.value("FeedbackLabel")}, {"steps", steps} }; } QJsonObject migrateBodyweightEntry(const QJsonObject &legacy) { return { {"loggedAt", legacy.value("LoggedAtLocal")}, {"weightKg", legacy.value("WeightKg")} }; } QJsonObject migrateBodyMeasurementEntry(const QJsonObject &legacy) { return { {"loggedAt", legacy.value("LoggedAtLocal")}, {"waistCm", legacy.value("WaistCm")}, {"shouldersCm", legacy.value("ShouldersCm")}, {"chestCm", legacy.value("ChestCm")}, {"armCm", legacy.value("ArmCm")} }; } QJsonObject migrateNutritionAdherenceEntry(const QJsonObject &legacy) { return { {"date", legacy.value("DateLocal")}, {"statusId", legacy.value("StatusId")} }; } QJsonObject migratePhotoProgressEntry(const QJsonObject &legacy) { return { {"loggedAt", legacy.value("LoggedAtLocal")}, {"imagePath", legacy.value("ImagePath")} }; } QJsonObject migrateRecoveryCheckInEntry(const QJsonObject &legacy) { return { {"sessionId", legacy.value("SessionId")}, {"planName", legacy.value("PlanName")}, {"loggedAt", legacy.value("LoggedAtLocal")}, {"energyScore", legacy.value("EnergyScore")}, {"sleepScore", legacy.value("SleepScore")}, {"jointScore", legacy.value("JointScore")}, {"note", legacy.value("Note")} }; } QJsonArray migrateArray(const QJsonArray &legacyArray, QJsonObject (*migrator)(const QJsonObject &)) { QJsonArray result; for (const QJsonValue &value : legacyArray) { if (value.isObject()) result.append(migrator(value.toObject())); } return result; } } // namespace int inferPlanDayOfWeek(const QString &planName) { const QString dayToken = planName.section(QChar(0x2022), 0, 0).trimmed(); static const struct { const char *shortName; const char *fullName; int day; } days[] = { {"Пн", "Понедельник", 1}, {"Вт", "Вторник", 2}, {"Ср", "Среда", 3}, {"Чт", "Четверг", 4}, {"Пт", "Пятница", 5}, {"Сб", "Суббота", 6}, {"Вс", "Воскресенье", 7}, }; for (const auto &entry : days) { if (dayToken.compare(QString::fromUtf8(entry.shortName), Qt::CaseInsensitive) == 0 || dayToken.compare(QString::fromUtf8(entry.fullName), Qt::CaseInsensitive) == 0) { return entry.day; } } return 0; } QJsonObject migrateLegacyRoot(const QJsonObject &legacyRoot) { QJsonArray plans; for (const QJsonValue &value : legacyRoot.value("WorkoutPlans").toArray()) { if (value.isObject()) plans.append(migratePlan(value.toObject())); } QJsonArray sessions; for (const QJsonValue &value : legacyRoot.value("SessionHistory").toArray()) { if (value.isObject()) sessions.append(migrateSession(value.toObject())); } return { {"schemaVersion", 1}, {"libraryVersion", legacyRoot.value("LibraryVersion")}, {"selectedPlanId", legacyRoot.value("SelectedPlanId")}, {"selectedPlanVariantId", legacyRoot.value("SelectedPlanVariantId")}, {"selectedRoundCount", legacyRoot.value("SelectedRoundCount")}, {"currentBodyWeightKg", legacyRoot.value("CurrentBodyWeightKg")}, {"nutritionPresetId", legacyRoot.value("NutritionPresetId").toString("balanced")}, {"bodyweightHistory", migrateArray(legacyRoot.value("BodyweightHistory").toArray(), migrateBodyweightEntry)}, {"bodyMeasurementHistory", migrateArray(legacyRoot.value("BodyMeasurementHistory").toArray(), migrateBodyMeasurementEntry)}, {"nutritionAdherenceHistory", migrateArray(legacyRoot.value("NutritionAdherenceHistory").toArray(), migrateNutritionAdherenceEntry)}, {"photoProgressHistory", migrateArray(legacyRoot.value("PhotoProgressHistory").toArray(), migratePhotoProgressEntry)}, {"recoveryCheckInHistory", migrateArray(legacyRoot.value("RecoveryCheckInHistory").toArray(), migrateRecoveryCheckInEntry)}, {"plans", plans}, {"sessions", sessions}, {"pendingDraft", QJsonValue::Null}, {"legacyArchive", QJsonObject{ {"importedAt", QDateTime::currentDateTime().toString(Qt::ISODateWithMs)}, {"sessionCount", legacyRoot.value("SessionHistory").toArray().size()} }} }; } LegacyMigrationResult migrateLegacyStateFile(const QString &legacyPath, const QString &archiveDirectory) { LegacyMigrationResult result; QFile file(legacyPath); if (!file.open(QIODevice::ReadOnly)) { result.error = file.errorString(); return result; } const QByteArray bytes = file.readAll(); QJsonParseError parseError; const QJsonDocument document = QJsonDocument::fromJson(bytes, &parseError); if (parseError.error != QJsonParseError::NoError || !document.isObject()) { result.error = QStringLiteral("Legacy state is invalid: %1").arg(parseError.errorString()); return result; } QDir directory; if (!directory.mkpath(archiveDirectory)) { result.error = QStringLiteral("Could not create legacy archive directory."); return result; } result.archivedLegacyPath = QDir(archiveDirectory).filePath( QStringLiteral("legacy-state.%1.json").arg(QDateTime::currentDateTime().toString("yyyyMMdd-HHmmss"))); QFile archive(result.archivedLegacyPath); if (!archive.open(QIODevice::WriteOnly) || archive.write(bytes) != bytes.size()) { result.error = QStringLiteral("Could not archive legacy state."); result.archivedLegacyPath.clear(); return result; } result.nativeRoot = migrateLegacyRoot(document.object()); result.ok = true; return result; } } // namespace bodyweight