/** * TASKMATE - Contact Routes * ========================= * CRUD für Kontakte */ const express = require('express'); const router = express.Router(); const { getDb } = require('../database'); const logger = require('../utils/logger'); const { validators } = require('../middleware/validation'); /** * GET /api/contacts * Alle Kontakte abrufen mit optionalem Filter */ router.get('/', (req, res) => { try { const db = getDb(); const { search, tag, sortBy = 'created_at', sortOrder = 'desc' } = req.query; let query = ` SELECT c.*, u.display_name as creator_name FROM contacts c LEFT JOIN users u ON c.created_by = u.id WHERE 1=1 `; const params = []; // Suchfilter if (search) { query += ` AND ( c.first_name LIKE ? OR c.last_name LIKE ? OR c.company LIKE ? OR c.email LIKE ? OR c.phone LIKE ? OR c.mobile LIKE ? )`; const searchParam = `%${search}%`; params.push(searchParam, searchParam, searchParam, searchParam, searchParam, searchParam); } // Tag-Filter if (tag) { query += ` AND c.tags LIKE ?`; params.push(`%${tag}%`); } // Sortierung const validSortFields = ['first_name', 'last_name', 'company', 'created_at', 'updated_at']; const sortField = validSortFields.includes(sortBy) ? sortBy : 'created_at'; const order = sortOrder.toLowerCase() === 'asc' ? 'ASC' : 'DESC'; query += ` ORDER BY c.${sortField} ${order}`; const contacts = db.prepare(query).all(params); res.json(contacts.map(c => ({ id: c.id, firstName: c.first_name, lastName: c.last_name, company: c.company, position: c.position, email: c.email, phone: c.phone, mobile: c.mobile, address: c.address, postalCode: c.postal_code, city: c.city, country: c.country, website: c.website, notes: c.notes, tags: c.tags ? c.tags.split(',').map(t => t.trim()) : [], createdAt: c.created_at, updatedAt: c.updated_at, createdBy: c.created_by, creatorName: c.creator_name }))); } catch (error) { logger.error('Fehler beim Abrufen der Kontakte:', { error: error.message }); res.status(500).json({ error: 'Interner Serverfehler' }); } }); /** * GET /api/contacts/:id * Einzelnen Kontakt abrufen */ router.get('/:id', (req, res) => { try { const db = getDb(); const contactId = req.params.id; const contact = db.prepare(` SELECT c.*, u.display_name as creator_name FROM contacts c LEFT JOIN users u ON c.created_by = u.id WHERE c.id = ? `).get(contactId); if (!contact) { return res.status(404).json({ error: 'Kontakt nicht gefunden' }); } res.json({ id: contact.id, firstName: contact.first_name, lastName: contact.last_name, company: contact.company, position: contact.position, email: contact.email, phone: contact.phone, mobile: contact.mobile, address: contact.address, postalCode: contact.postal_code, city: contact.city, country: contact.country, website: contact.website, notes: contact.notes, tags: contact.tags ? contact.tags.split(',').map(t => t.trim()) : [], createdAt: contact.created_at, updatedAt: contact.updated_at, createdBy: contact.created_by, creatorName: contact.creator_name }); } catch (error) { logger.error('Fehler beim Abrufen des Kontakts:', { error: error.message, contactId: req.params.id }); res.status(500).json({ error: 'Interner Serverfehler' }); } }); /** * POST /api/contacts * Neuen Kontakt erstellen */ router.post('/', validators.contact, (req, res) => { try { const db = getDb(); const userId = req.user.id; const { firstName, lastName, company, position, email, phone, mobile, address, postalCode, city, country, website, notes, tags } = req.body; const result = db.prepare(` INSERT INTO contacts ( first_name, last_name, company, position, email, phone, mobile, address, postal_code, city, country, website, notes, tags, created_by ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).run( firstName || null, lastName || null, company || null, position || null, email || null, phone || null, mobile || null, address || null, postalCode || null, city || null, country || null, website || null, notes || null, Array.isArray(tags) ? tags.join(', ') : null, userId ); const newContact = db.prepare(` SELECT c.*, u.display_name as creator_name FROM contacts c LEFT JOIN users u ON c.created_by = u.id WHERE c.id = ? `).get(result.lastInsertRowid); // Socket.io Event const io = req.app.get('io'); io.emit('contact:created', { contact: { id: newContact.id, firstName: newContact.first_name, lastName: newContact.last_name, company: newContact.company, position: newContact.position, email: newContact.email, phone: newContact.phone, mobile: newContact.mobile, address: newContact.address, postalCode: newContact.postal_code, city: newContact.city, country: newContact.country, website: newContact.website, notes: newContact.notes, tags: newContact.tags ? newContact.tags.split(',').map(t => t.trim()) : [], createdAt: newContact.created_at, updatedAt: newContact.updated_at, createdBy: newContact.created_by, creatorName: newContact.creator_name }, userId }); res.status(201).json({ id: newContact.id, firstName: newContact.first_name, lastName: newContact.last_name, company: newContact.company, position: newContact.position, email: newContact.email, phone: newContact.phone, mobile: newContact.mobile, address: newContact.address, postalCode: newContact.postal_code, city: newContact.city, country: newContact.country, website: newContact.website, notes: newContact.notes, tags: newContact.tags ? newContact.tags.split(',').map(t => t.trim()) : [], createdAt: newContact.created_at, updatedAt: newContact.updated_at, createdBy: newContact.created_by, creatorName: newContact.creator_name }); logger.info('Kontakt erstellt', { contactId: newContact.id, userId }); } catch (error) { logger.error('Fehler beim Erstellen des Kontakts:', { error: error.message, body: req.body }); res.status(500).json({ error: 'Interner Serverfehler' }); } }); /** * PUT /api/contacts/:id * Kontakt aktualisieren */ router.put('/:id', validators.contact, (req, res) => { try { const db = getDb(); const contactId = req.params.id; const userId = req.user.id; const { firstName, lastName, company, position, email, phone, mobile, address, postalCode, city, country, website, notes, tags } = req.body; // Prüfen ob Kontakt existiert const existing = db.prepare('SELECT id FROM contacts WHERE id = ?').get(contactId); if (!existing) { return res.status(404).json({ error: 'Kontakt nicht gefunden' }); } // Update db.prepare(` UPDATE contacts SET first_name = ?, last_name = ?, company = ?, position = ?, email = ?, phone = ?, mobile = ?, address = ?, postal_code = ?, city = ?, country = ?, website = ?, notes = ?, tags = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? `).run( firstName || null, lastName || null, company || null, position || null, email || null, phone || null, mobile || null, address || null, postalCode || null, city || null, country || null, website || null, notes || null, Array.isArray(tags) ? tags.join(', ') : null, contactId ); const updatedContact = db.prepare(` SELECT c.*, u.display_name as creator_name FROM contacts c LEFT JOIN users u ON c.created_by = u.id WHERE c.id = ? `).get(contactId); // Socket.io Event const io = req.app.get('io'); io.emit('contact:updated', { contact: { id: updatedContact.id, firstName: updatedContact.first_name, lastName: updatedContact.last_name, company: updatedContact.company, position: updatedContact.position, email: updatedContact.email, phone: updatedContact.phone, mobile: updatedContact.mobile, address: updatedContact.address, postalCode: updatedContact.postal_code, city: updatedContact.city, country: updatedContact.country, website: updatedContact.website, notes: updatedContact.notes, tags: updatedContact.tags ? updatedContact.tags.split(',').map(t => t.trim()) : [], createdAt: updatedContact.created_at, updatedAt: updatedContact.updated_at, createdBy: updatedContact.created_by, creatorName: updatedContact.creator_name }, userId }); res.json({ id: updatedContact.id, firstName: updatedContact.first_name, lastName: updatedContact.last_name, company: updatedContact.company, position: updatedContact.position, email: updatedContact.email, phone: updatedContact.phone, mobile: updatedContact.mobile, address: updatedContact.address, postalCode: updatedContact.postal_code, city: updatedContact.city, country: updatedContact.country, website: updatedContact.website, notes: updatedContact.notes, tags: updatedContact.tags ? updatedContact.tags.split(',').map(t => t.trim()) : [], createdAt: updatedContact.created_at, updatedAt: updatedContact.updated_at, createdBy: updatedContact.created_by, creatorName: updatedContact.creator_name }); logger.info('Kontakt aktualisiert', { contactId, userId }); } catch (error) { logger.error('Fehler beim Aktualisieren des Kontakts:', { error: error.message, contactId: req.params.id }); res.status(500).json({ error: 'Interner Serverfehler' }); } }); /** * DELETE /api/contacts/:id * Kontakt löschen */ router.delete('/:id', (req, res) => { try { const db = getDb(); const contactId = req.params.id; const userId = req.user.id; // Prüfen ob Kontakt existiert const existing = db.prepare('SELECT id FROM contacts WHERE id = ?').get(contactId); if (!existing) { return res.status(404).json({ error: 'Kontakt nicht gefunden' }); } // Löschen db.prepare('DELETE FROM contacts WHERE id = ?').run(contactId); // Socket.io Event const io = req.app.get('io'); io.emit('contact:deleted', { contactId, userId }); res.json({ success: true }); logger.info('Kontakt gelöscht', { contactId, userId }); } catch (error) { logger.error('Fehler beim Löschen des Kontakts:', { error: error.message, contactId: req.params.id }); res.status(500).json({ error: 'Interner Serverfehler' }); } }); /** * GET /api/contacts/tags * Alle verwendeten Tags abrufen */ router.get('/tags/all', (req, res) => { try { const db = getDb(); const contacts = db.prepare('SELECT DISTINCT tags FROM contacts WHERE tags IS NOT NULL').all(); // Alle Tags sammeln und deduplizieren const allTags = new Set(); contacts.forEach(contact => { if (contact.tags) { contact.tags.split(',').forEach(tag => { const trimmedTag = tag.trim(); if (trimmedTag) { allTags.add(trimmedTag); } }); } }); res.json(Array.from(allTags).sort()); } catch (error) { logger.error('Fehler beim Abrufen der Tags:', { error: error.message }); res.status(500).json({ error: 'Interner Serverfehler' }); } }); module.exports = router;