Project-Image-Uploader/backend/src/services/MigrationService.js
matthias.lotz 24c1de1666 IMP: Eigene Verzeichnisse für Uploads und Datenbank
- README aktualisiert, um die neuen Verzeichnisse zu reflektieren
- Konstanten für Verzeichnispfade in 'constants.js' hinzugefügt
- 'DatabaseManager.js' angepasst, um die neuen Datenbankverzeichnisse zu verwenden
- Routen für Batch-Upload, Download und Upload aktualisiert, um die neuen Pfade zu berücksichtigen
- 'MigrationService.js' hinzugefügt, um vorhandene Daten in die neuen Verzeichnisse zu migrieren
- Hilfsfunktionen in 'groupStorage.js' und 'initiate-resources.js' angepasst
- 'docker-compose.yml' und 'prod.sh' aktualisiert, um die neuen Verzeichnisse zu berücksichtigen
2025-10-18 14:23:12 +02:00

208 lines
7.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs').promises;
const path = require('path');
const GroupRepository = require('../repositories/GroupRepository');
const dbManager = require('../database/DatabaseManager');
class MigrationService {
constructor() {
// JSON metadata and backups now live under data/db
this.jsonDataPath = path.join(__dirname, '../data/db');
this.backupPath = path.join(__dirname, '../data/db/backup');
}
// Hauptmigration von JSON zu SQLite
async migrateJsonToSqlite() {
console.log('🔄 Starte Migration von JSON zu SQLite...');
try {
// 1. Initialisiere Datenbank
await dbManager.initialize();
// 2. Prüfe ob bereits migriert
const stats = await GroupRepository.getStats();
if (stats.totalGroups > 0) {
console.log(` Datenbank enthält bereits ${stats.totalGroups} Gruppen. Migration wird übersprungen.`);
return { success: true, message: 'Already migrated', stats };
}
// 3. Lade JSON-Gruppen
const jsonGroups = await this.loadJsonGroups();
if (jsonGroups.length === 0) {
console.log(' Keine JSON-Gruppen zum Migrieren gefunden.');
return { success: true, message: 'No JSON data found', migrated: 0 };
}
// 4. Erstelle Backup
await this.createBackup();
// 5. Migriere Gruppen
let migratedCount = 0;
let errorCount = 0;
for (const jsonGroup of jsonGroups) {
try {
await this.migrateGroup(jsonGroup);
migratedCount++;
console.log(`✓ Gruppe ${jsonGroup.groupId} migriert`);
} catch (error) {
errorCount++;
console.error(`✗ Fehler bei Gruppe ${jsonGroup.groupId}:`, error.message);
}
}
console.log(`🎉 Migration abgeschlossen: ${migratedCount} erfolgreich, ${errorCount} Fehler`);
return {
success: true,
migrated: migratedCount,
errors: errorCount,
total: jsonGroups.length
};
} catch (error) {
console.error('💥 Migration fehlgeschlagen:', error);
throw error;
}
}
// Lade alle JSON-Gruppendateien
async loadJsonGroups() {
const groups = [];
try {
const files = await fs.readdir(this.jsonDataPath);
const jsonFiles = files.filter(file => file.endsWith('.json') && file !== 'groups.json');
for (const file of jsonFiles) {
try {
const filePath = path.join(this.jsonDataPath, file);
const content = await fs.readFile(filePath, 'utf8');
const group = JSON.parse(content);
// Validiere Gruppenstruktur
if (this.validateGroup(group)) {
groups.push(this.normalizeGroup(group));
} else {
console.warn(`⚠️ Ungültige Gruppenstruktur in ${file}`);
}
} catch (error) {
console.error(`✗ Fehler beim Laden von ${file}:`, error.message);
}
}
} catch (error) {
console.error('Fehler beim Lesen des data-Verzeichnisses:', error);
}
return groups;
}
// Validiere JSON-Gruppenstruktur
validateGroup(group) {
return group &&
group.groupId &&
group.uploadDate &&
Array.isArray(group.images);
}
// Normalisiere Gruppendaten für SQLite
normalizeGroup(jsonGroup) {
return {
groupId: jsonGroup.groupId,
year: jsonGroup.year || new Date(jsonGroup.uploadDate).getFullYear(),
title: jsonGroup.title || 'Migriertes Projekt',
description: jsonGroup.description || '',
name: jsonGroup.name || '',
uploadDate: jsonGroup.uploadDate,
images: jsonGroup.images.map((img, index) => ({
fileName: img.fileName,
originalName: img.originalName,
filePath: img.filePath,
uploadOrder: img.uploadOrder || index + 1,
fileSize: img.fileSize || null,
mimeType: img.mimeType || null
}))
};
}
// Migriere einzelne Gruppe
async migrateGroup(group) {
await GroupRepository.createGroup(group);
}
// Erstelle Backup der JSON-Dateien
async createBackup() {
try {
// Erstelle backup-Verzeichnis
await fs.mkdir(this.backupPath, { recursive: true });
const files = await fs.readdir(this.jsonDataPath);
const jsonFiles = files.filter(file => file.endsWith('.json'));
for (const file of jsonFiles) {
const sourcePath = path.join(this.jsonDataPath, file);
const backupPath = path.join(this.backupPath, `${Date.now()}_${file}`);
await fs.copyFile(sourcePath, backupPath);
}
console.log(`✓ Backup erstellt: ${jsonFiles.length} Dateien`);
} catch (error) {
console.error('Fehler beim Erstellen des Backups:', error);
throw error;
}
}
// Rollback zur JSON-Struktur (falls nötig)
async rollbackToJson() {
console.log('🔄 Starte Rollback zu JSON...');
try {
const groups = await GroupRepository.getAllGroupsWithImages();
for (const group of groups) {
const fileName = `${group.groupId}.json`;
const filePath = path.join(this.jsonDataPath, fileName);
await fs.writeFile(filePath, JSON.stringify(group, null, 2));
}
console.log(`✓ Rollback abgeschlossen: ${groups.length} Gruppen`);
return { success: true, exported: groups.length };
} catch (error) {
console.error('Rollback fehlgeschlagen:', error);
throw error;
}
}
// Migrationsstatus prüfen
async getMigrationStatus() {
try {
const dbStats = await GroupRepository.getStats();
// Zähle JSON-Dateien
const files = await fs.readdir(this.jsonDataPath);
const jsonFileCount = files.filter(file => file.endsWith('.json') && file !== 'groups.json').length;
return {
database: {
initialized: dbStats.totalGroups >= 0,
groups: dbStats.totalGroups,
images: dbStats.totalImages,
latestUpload: dbStats.latestUpload
},
json: {
files: jsonFileCount
},
migrated: dbStats.totalGroups > 0,
needsMigration: jsonFileCount > 0 && dbStats.totalGroups === 0
};
} catch (error) {
return {
database: { initialized: false, error: error.message },
json: { files: 0 },
migrated: false,
needsMigration: false
};
}
}
}
module.exports = new MigrationService();