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();