/** * TASKMATE - Import Routes * ======================== * Import von JSON-Backups */ const express = require('express'); const router = express.Router(); const { getDb } = require('../database'); const logger = require('../utils/logger'); /** * POST /api/import/project * Projekt aus JSON importieren */ router.post('/project', (req, res) => { try { const { data, overwrite = false } = req.body; if (!data || !data.project) { return res.status(400).json({ error: 'Ungültiges Import-Format' }); } const db = getDb(); // Transaktion starten const importProject = db.transaction(() => { const importData = data; // Projekt erstellen const projectResult = db.prepare(` INSERT INTO projects (name, description, created_by) VALUES (?, ?, ?) `).run( importData.project.name + (overwrite ? '' : ' (Import)'), importData.project.description, req.user.id ); const newProjectId = projectResult.lastInsertRowid; // Mapping für alte -> neue IDs const columnMap = new Map(); const labelMap = new Map(); const taskMap = new Map(); // Spalten importieren if (importData.columns) { const insertColumn = db.prepare(` INSERT INTO columns (project_id, name, position, color) VALUES (?, ?, ?, ?) `); importData.columns.forEach(col => { const result = insertColumn.run(newProjectId, col.name, col.position, col.color); columnMap.set(col.id, result.lastInsertRowid); }); } // Labels importieren if (importData.labels) { const insertLabel = db.prepare(` INSERT INTO labels (project_id, name, color) VALUES (?, ?, ?) `); importData.labels.forEach(label => { const result = insertLabel.run(newProjectId, label.name, label.color); labelMap.set(label.id, result.lastInsertRowid); }); } // Aufgaben importieren if (importData.tasks) { const insertTask = db.prepare(` INSERT INTO tasks ( project_id, column_id, title, description, priority, due_date, time_estimate_min, position, created_by ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `); importData.tasks.forEach(task => { const newColumnId = columnMap.get(task.column_id); if (!newColumnId) return; const result = insertTask.run( newProjectId, newColumnId, task.title, task.description, task.priority || 'medium', task.due_date, task.time_estimate_min, task.position, req.user.id ); taskMap.set(task.id, result.lastInsertRowid); // Task-Labels if (task.labels) { const insertTaskLabel = db.prepare( 'INSERT INTO task_labels (task_id, label_id) VALUES (?, ?)' ); task.labels.forEach(label => { const newLabelId = labelMap.get(label.id); if (newLabelId) { try { insertTaskLabel.run(result.lastInsertRowid, newLabelId); } catch (e) { /* Ignorieren */ } } }); } // Subtasks if (task.subtasks) { const insertSubtask = db.prepare( 'INSERT INTO subtasks (task_id, title, completed, position) VALUES (?, ?, ?, ?)' ); task.subtasks.forEach(st => { insertSubtask.run( result.lastInsertRowid, st.title, st.completed ? 1 : 0, st.position ); }); } // Links if (task.links) { const insertLink = db.prepare( 'INSERT INTO links (task_id, title, url, created_by) VALUES (?, ?, ?, ?)' ); task.links.forEach(link => { insertLink.run(result.lastInsertRowid, link.title, link.url, req.user.id); }); } }); } // Vorlagen importieren if (importData.templates) { const insertTemplate = db.prepare(` INSERT INTO task_templates ( project_id, name, title_template, description, priority, labels, subtasks, time_estimate_min ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `); importData.templates.forEach(tmpl => { // Labels-IDs mappen let newLabels = null; if (tmpl.labels) { const oldLabels = typeof tmpl.labels === 'string' ? JSON.parse(tmpl.labels) : tmpl.labels; const mappedLabels = oldLabels.map(id => labelMap.get(id)).filter(id => id); newLabels = JSON.stringify(mappedLabels); } insertTemplate.run( newProjectId, tmpl.name, tmpl.title_template, tmpl.description, tmpl.priority, newLabels, tmpl.subtasks, tmpl.time_estimate_min ); }); } return { projectId: newProjectId, columnsImported: columnMap.size, labelsImported: labelMap.size, tasksImported: taskMap.size }; }); const result = importProject(); logger.info(`Projekt importiert: ID ${result.projectId} (${result.tasksImported} Aufgaben)`); res.status(201).json({ message: 'Import erfolgreich', ...result }); } catch (error) { logger.error('Fehler beim Import:', { error: error.message }); res.status(500).json({ error: 'Import fehlgeschlagen: ' + error.message }); } }); /** * POST /api/import/validate * Import-Datei validieren */ router.post('/validate', (req, res) => { try { const { data } = req.body; const errors = []; const warnings = []; if (!data) { errors.push('Keine Daten vorhanden'); return res.json({ valid: false, errors, warnings }); } // Version prüfen if (!data.version) { warnings.push('Keine Versionsangabe gefunden'); } // Projekt prüfen if (!data.project) { errors.push('Kein Projekt in den Daten gefunden'); } else { if (!data.project.name) { errors.push('Projektname fehlt'); } } // Spalten prüfen if (!data.columns || data.columns.length === 0) { errors.push('Keine Spalten in den Daten gefunden'); } // Aufgaben prüfen if (data.tasks) { data.tasks.forEach((task, idx) => { if (!task.title) { warnings.push(`Aufgabe ${idx + 1} hat keinen Titel`); } if (!task.column_id) { warnings.push(`Aufgabe "${task.title || idx + 1}" hat keine Spalten-ID`); } }); } // Statistiken const stats = { projectName: data.project?.name || 'Unbekannt', columns: data.columns?.length || 0, labels: data.labels?.length || 0, tasks: data.tasks?.length || 0, templates: data.templates?.length || 0 }; res.json({ valid: errors.length === 0, errors, warnings, stats }); } catch (error) { logger.error('Fehler bei Import-Validierung:', { error: error.message }); res.status(400).json({ valid: false, errors: ['Ungültiges JSON-Format'], warnings: [] }); } }); module.exports = router;