Dieser Commit ist enthalten in:
Claude Project Manager
2025-12-28 21:36:45 +00:00
Commit ab1e5be9a9
146 geänderte Dateien mit 65525 neuen und 0 gelöschten Zeilen

230
backend/routes/export.js Normale Datei
Datei anzeigen

@ -0,0 +1,230 @@
/**
* TASKMATE - Export Routes
* ========================
* Export in JSON und CSV
*/
const express = require('express');
const router = express.Router();
const { getDb } = require('../database');
const logger = require('../utils/logger');
/**
* GET /api/export/project/:id/json
* Projekt als JSON exportieren
*/
router.get('/project/:id/json', (req, res) => {
try {
const projectId = req.params.id;
const db = getDb();
// Projekt
const project = db.prepare('SELECT * FROM projects WHERE id = ?').get(projectId);
if (!project) {
return res.status(404).json({ error: 'Projekt nicht gefunden' });
}
// Spalten
const columns = db.prepare('SELECT * FROM columns WHERE project_id = ? ORDER BY position').all(projectId);
// Labels
const labels = db.prepare('SELECT * FROM labels WHERE project_id = ?').all(projectId);
// Aufgaben mit allen Details
const tasks = db.prepare('SELECT * FROM tasks WHERE project_id = ?').all(projectId);
const tasksWithDetails = tasks.map(task => {
const taskLabels = db.prepare(`
SELECT l.* FROM labels l
JOIN task_labels tl ON l.id = tl.label_id
WHERE tl.task_id = ?
`).all(task.id);
const subtasks = db.prepare('SELECT * FROM subtasks WHERE task_id = ? ORDER BY position').all(task.id);
const comments = db.prepare(`
SELECT c.*, u.display_name FROM comments c
LEFT JOIN users u ON c.user_id = u.id
WHERE c.task_id = ?
`).all(task.id);
const attachments = db.prepare('SELECT * FROM attachments WHERE task_id = ?').all(task.id);
const links = db.prepare('SELECT * FROM links WHERE task_id = ?').all(task.id);
return {
...task,
labels: taskLabels,
subtasks,
comments,
attachments,
links
};
});
// Vorlagen
const templates = db.prepare('SELECT * FROM task_templates WHERE project_id = ?').all(projectId);
const exportData = {
exportedAt: new Date().toISOString(),
exportedBy: req.user.username,
version: '1.0',
project: {
id: project.id,
name: project.name,
description: project.description,
createdAt: project.created_at
},
columns: columns.map(c => ({
id: c.id,
name: c.name,
position: c.position,
color: c.color
})),
labels: labels.map(l => ({
id: l.id,
name: l.name,
color: l.color
})),
tasks: tasksWithDetails,
templates
};
logger.info(`Projekt exportiert als JSON: ${project.name}`);
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Disposition', `attachment; filename="${project.name.replace(/[^a-z0-9]/gi, '_')}_export.json"`);
res.json(exportData);
} catch (error) {
logger.error('Fehler beim JSON-Export:', { error: error.message });
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
/**
* GET /api/export/project/:id/csv
* Aufgaben als CSV exportieren
*/
router.get('/project/:id/csv', (req, res) => {
try {
const projectId = req.params.id;
const db = getDb();
const project = db.prepare('SELECT * FROM projects WHERE id = ?').get(projectId);
if (!project) {
return res.status(404).json({ error: 'Projekt nicht gefunden' });
}
const tasks = db.prepare(`
SELECT
t.*,
c.name as column_name,
u.display_name as assigned_name
FROM tasks t
LEFT JOIN columns c ON t.column_id = c.id
LEFT JOIN users u ON t.assigned_to = u.id
WHERE t.project_id = ?
ORDER BY c.position, t.position
`).all(projectId);
// CSV Header
const headers = [
'ID', 'Titel', 'Beschreibung', 'Status', 'Priorität',
'Fälligkeitsdatum', 'Zugewiesen an', 'Zeitschätzung (Min)',
'Erstellt am', 'Archiviert'
];
// CSV Zeilen
const rows = tasks.map(task => [
task.id,
escapeCsvField(task.title),
escapeCsvField(task.description || ''),
task.column_name,
task.priority,
task.due_date || '',
task.assigned_name || '',
task.time_estimate_min || '',
task.created_at,
task.archived ? 'Ja' : 'Nein'
]);
// CSV zusammenbauen
const csv = [
headers.join(';'),
...rows.map(row => row.join(';'))
].join('\n');
logger.info(`Projekt exportiert als CSV: ${project.name}`);
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
res.setHeader('Content-Disposition', `attachment; filename="${project.name.replace(/[^a-z0-9]/gi, '_')}_export.csv"`);
// BOM für Excel UTF-8 Erkennung
res.send('\ufeff' + csv);
} catch (error) {
logger.error('Fehler beim CSV-Export:', { error: error.message });
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
/**
* GET /api/export/all/json
* Alle Daten exportieren (Backup)
*/
router.get('/all/json', (req, res) => {
try {
const db = getDb();
const projects = db.prepare('SELECT * FROM projects').all();
const columns = db.prepare('SELECT * FROM columns').all();
const labels = db.prepare('SELECT * FROM labels').all();
const tasks = db.prepare('SELECT * FROM tasks').all();
const subtasks = db.prepare('SELECT * FROM subtasks').all();
const comments = db.prepare('SELECT * FROM comments').all();
const taskLabels = db.prepare('SELECT * FROM task_labels').all();
const attachments = db.prepare('SELECT * FROM attachments').all();
const links = db.prepare('SELECT * FROM links').all();
const templates = db.prepare('SELECT * FROM task_templates').all();
const history = db.prepare('SELECT * FROM history').all();
const exportData = {
exportedAt: new Date().toISOString(),
exportedBy: req.user.username,
version: '1.0',
data: {
projects,
columns,
labels,
tasks,
subtasks,
comments,
taskLabels,
attachments,
links,
templates,
history
}
};
logger.info('Vollständiger Export durchgeführt');
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Disposition', `attachment; filename="taskmate_backup_${Date.now()}.json"`);
res.json(exportData);
} catch (error) {
logger.error('Fehler beim Voll-Export:', { error: error.message });
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
/**
* Hilfsfunktion: CSV-Feld escapen
*/
function escapeCsvField(field) {
if (typeof field !== 'string') return field;
// Wenn Feld Semikolon, Anführungszeichen oder Zeilenumbruch enthält
if (field.includes(';') || field.includes('"') || field.includes('\n')) {
// Anführungszeichen verdoppeln und in Anführungszeichen setzen
return '"' + field.replace(/"/g, '""') + '"';
}
return field;
}
module.exports = router;