Initial commit
Dieser Commit ist enthalten in:
202
backend/routes/labels.js
Normale Datei
202
backend/routes/labels.js
Normale Datei
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* 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;
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren