Files
TaskMate/backend/routes/labels.js
Claude Project Manager ab1e5be9a9 Initial commit
2025-12-28 21:36:45 +00:00

203 Zeilen
5.6 KiB
JavaScript

/**
* TASKMATE - Label Routes
* =======================
* CRUD für Labels/Tags
*/
const express = require('express');
const router = express.Router();
const { getDb } = require('../database');
const logger = require('../utils/logger');
const { validators } = require('../middleware/validation');
/**
* GET /api/labels/:projectId
* Alle Labels eines Projekts
*/
router.get('/:projectId', (req, res) => {
try {
const db = getDb();
const labels = db.prepare(`
SELECT l.*,
(SELECT COUNT(*) FROM task_labels tl WHERE tl.label_id = l.id) as task_count
FROM labels l
WHERE l.project_id = ?
ORDER BY l.name
`).all(req.params.projectId);
res.json(labels.map(l => ({
id: l.id,
projectId: l.project_id,
name: l.name,
color: l.color,
taskCount: l.task_count
})));
} catch (error) {
logger.error('Fehler beim Abrufen der Labels:', { error: error.message });
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
/**
* POST /api/labels
* Neues Label erstellen
*/
router.post('/', (req, res) => {
try {
const { projectId, name, color } = req.body;
// Validierung
const errors = [];
errors.push(validators.required(projectId, 'Projekt-ID'));
errors.push(validators.required(name, 'Name'));
errors.push(validators.maxLength(name, 30, 'Name'));
errors.push(validators.required(color, 'Farbe'));
errors.push(validators.hexColor(color, 'Farbe'));
const firstError = errors.find(e => e !== null);
if (firstError) {
return res.status(400).json({ error: firstError });
}
const db = getDb();
// Prüfen ob Label-Name bereits existiert
const existing = db.prepare(
'SELECT id FROM labels WHERE project_id = ? AND LOWER(name) = LOWER(?)'
).get(projectId, name);
if (existing) {
return res.status(400).json({ error: 'Ein Label mit diesem Namen existiert bereits' });
}
const result = db.prepare(`
INSERT INTO labels (project_id, name, color)
VALUES (?, ?, ?)
`).run(projectId, name, color);
const label = db.prepare('SELECT * FROM labels WHERE id = ?').get(result.lastInsertRowid);
logger.info(`Label erstellt: ${name} in Projekt ${projectId}`);
// WebSocket
const io = req.app.get('io');
io.to(`project:${projectId}`).emit('label:created', {
id: label.id,
projectId: label.project_id,
name: label.name,
color: label.color
});
res.status(201).json({
id: label.id,
projectId: label.project_id,
name: label.name,
color: label.color,
taskCount: 0
});
} catch (error) {
logger.error('Fehler beim Erstellen des Labels:', { error: error.message });
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
/**
* PUT /api/labels/:id
* Label aktualisieren
*/
router.put('/:id', (req, res) => {
try {
const labelId = req.params.id;
const { name, color } = req.body;
// Validierung
if (name) {
const nameError = validators.maxLength(name, 30, 'Name');
if (nameError) return res.status(400).json({ error: nameError });
}
if (color) {
const colorError = validators.hexColor(color, 'Farbe');
if (colorError) return res.status(400).json({ error: colorError });
}
const db = getDb();
const existing = db.prepare('SELECT * FROM labels WHERE id = ?').get(labelId);
if (!existing) {
return res.status(404).json({ error: 'Label nicht gefunden' });
}
// Prüfen ob neuer Name bereits existiert
if (name && name.toLowerCase() !== existing.name.toLowerCase()) {
const duplicate = db.prepare(
'SELECT id FROM labels WHERE project_id = ? AND LOWER(name) = LOWER(?) AND id != ?'
).get(existing.project_id, name, labelId);
if (duplicate) {
return res.status(400).json({ error: 'Ein Label mit diesem Namen existiert bereits' });
}
}
db.prepare(`
UPDATE labels SET
name = COALESCE(?, name),
color = COALESCE(?, color)
WHERE id = ?
`).run(name || null, color || null, labelId);
const label = db.prepare('SELECT * FROM labels WHERE id = ?').get(labelId);
logger.info(`Label aktualisiert: ${label.name} (ID: ${labelId})`);
// WebSocket
const io = req.app.get('io');
io.to(`project:${label.project_id}`).emit('label:updated', {
id: label.id,
name: label.name,
color: label.color
});
res.json({
id: label.id,
projectId: label.project_id,
name: label.name,
color: label.color
});
} catch (error) {
logger.error('Fehler beim Aktualisieren des Labels:', { error: error.message });
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
/**
* DELETE /api/labels/:id
* Label löschen
*/
router.delete('/:id', (req, res) => {
try {
const labelId = req.params.id;
const db = getDb();
const label = db.prepare('SELECT * FROM labels WHERE id = ?').get(labelId);
if (!label) {
return res.status(404).json({ error: 'Label nicht gefunden' });
}
// Label wird von task_labels durch CASCADE gelöscht
db.prepare('DELETE FROM labels WHERE id = ?').run(labelId);
logger.info(`Label gelöscht: ${label.name} (ID: ${labelId})`);
// WebSocket
const io = req.app.get('io');
io.to(`project:${label.project_id}`).emit('label:deleted', { id: labelId });
res.json({ message: 'Label gelöscht' });
} catch (error) {
logger.error('Fehler beim Löschen des Labels:', { error: error.message });
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
module.exports = router;