- 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
208 lines
7.3 KiB
JavaScript
208 lines
7.3 KiB
JavaScript
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(); |