diff --git a/backend/src/controllers/authController.ts b/backend/src/controllers/authController.ts index 3b71fea..a25fc9a 100644 --- a/backend/src/controllers/authController.ts +++ b/backend/src/controllers/authController.ts @@ -22,7 +22,7 @@ export interface LoginRequest { } export interface JWTPayload { - id: number; + id: string; // ← VON number ZU string ÄNDERN email: string; role: string; iat?: number; @@ -64,7 +64,7 @@ export const login = async (req: Request, res: Response) => { // Create token payload const tokenPayload: JWTPayload = { - id: user.id, + id: user.id.toString(), // ← Sicherstellen dass es string ist email: user.email, role: user.role }; diff --git a/backend/src/controllers/employeeController.ts b/backend/src/controllers/employeeController.ts index 0ee75d9..481bcba 100644 --- a/backend/src/controllers/employeeController.ts +++ b/backend/src/controllers/employeeController.ts @@ -5,25 +5,6 @@ import bcrypt from 'bcryptjs'; import { db } from '../services/databaseService.js'; import { AuthRequest } from '../middleware/auth.js'; -export const getEmployees = async (req: AuthRequest, res: Response): Promise => { - try { - const employees = await db.all(` - SELECT - id, email, name, role, is_active as isActive, - phone, department, created_at as createdAt, - last_login as lastLogin - FROM users - WHERE is_active = 1 - ORDER BY name - `); - - res.json(employees); - } catch (error) { - console.error('Error fetching employees:', error); - res.status(500).json({ error: 'Internal server error' }); - } -}; - export const getEmployee = async (req: AuthRequest, res: Response): Promise => { try { const { id } = req.params; @@ -56,7 +37,14 @@ export const createEmployee = async (req: AuthRequest, res: Response): Promise(` SELECT id, email, name, is_active, role FROM users @@ -173,137 +161,60 @@ export const deleteEmployee = async (req: AuthRequest, res: Response): Promise( + 'SELECT id, assigned_employees FROM assigned_shifts WHERE json_extract(assigned_employees, "$") LIKE ?', + [`%${id}%`] + ); + + for (const shift of assignedShifts) { + try { + const employeesArray: string[] = JSON.parse(shift.assigned_employees || '[]'); + const filteredEmployees = employeesArray.filter((empId: string) => empId !== id); + await db.run( + 'UPDATE assigned_shifts SET assigned_employees = ? WHERE id = ?', + [JSON.stringify(filteredEmployees), shift.id] + ); + } catch (parseError) { + console.warn(`Could not parse assigned_employees for shift ${shift.id}:`, shift.assigned_employees); + // Falls JSON parsing fehlschlägt, setze leeres Array + await db.run( + 'UPDATE assigned_shifts SET assigned_employees = ? WHERE id = ?', + [JSON.stringify([]), shift.id] + ); } } - // Verify the deletion - const verifyDeletion = await db.get<{count: number}>(` - SELECT - (SELECT COUNT(*) FROM users WHERE id = ?) + - (SELECT COUNT(*) FROM employee_availabilities WHERE employee_id = ?) + - (SELECT COUNT(*) FROM assigned_shifts WHERE json_extract(assigned_employees, '$') LIKE ?) as count - `, [id, id, `%${id}%`]); + // 3. Nullify created_by references + await db.run('UPDATE shift_plans SET created_by = NULL WHERE created_by = ?', [id]); + await db.run('UPDATE shift_templates SET created_by = NULL WHERE created_by = ?', [id]); - if ((verifyDeletion?.count ?? 0) > 0) { - throw new Error('Failed to remove all references to the employee'); - } + // 4. Finally delete the user + await db.run('DELETE FROM users WHERE id = ?', [id]); - // If we got here, everything worked await db.run('COMMIT'); console.log('✅ Successfully deleted employee:', existingEmployee.email); res.status(204).send(); + } catch (error) { - console.error('Error during deletion, rolling back:', error); await db.run('ROLLBACK'); + console.error('Error during deletion transaction:', error); throw error; } - console.log('Attempting to delete employee:', { id, email: existingEmployee.email }); - - try { - // Start a transaction to ensure all deletes succeed or none do - await db.run('BEGIN TRANSACTION'); - - console.log('Starting transaction for deletion of employee:', id); - - // First verify the current state - const beforeState = await db.all(` - SELECT - (SELECT COUNT(*) FROM employee_availabilities WHERE employee_id = ?) as avail_count, - (SELECT COUNT(*) FROM shift_templates WHERE created_by = ?) as template_count, - (SELECT COUNT(*) FROM shift_plans WHERE created_by = ?) as plan_count, - (SELECT COUNT(*) FROM users WHERE id = ?) as user_count - `, [id, id, id, id]); - console.log('Before deletion state:', beforeState[0]); - - // Clear all references first - await db.run(`DELETE FROM employee_availabilities WHERE employee_id = ?`, [id]); - await db.run(`UPDATE shift_plans SET created_by = NULL WHERE created_by = ?`, [id]); - await db.run(`UPDATE shift_templates SET created_by = NULL WHERE created_by = ?`, [id]); - await db.run(`UPDATE assigned_shifts - SET assigned_employees = json_remove(assigned_employees, '$[' || json_each.key || ']') - FROM json_each(assigned_shifts.assigned_employees) - WHERE json_each.value = ?`, [id]); - - // Now delete the user - await db.run('DELETE FROM users WHERE id = ?', [id]); - - // Verify the deletion - const verifyAfterDelete = await db.all(` - SELECT - (SELECT COUNT(*) FROM users WHERE id = ?) as user_exists, - (SELECT COUNT(*) FROM users WHERE email = ?) as email_exists, - (SELECT COUNT(*) FROM users WHERE email = ? AND is_active = 1) as active_email_exists - `, [id, existingEmployee.email, existingEmployee.email]); - - console.log('🔍 Verification after delete:', verifyAfterDelete[0]); - - // Verify the deletion worked - const verifyDeletion = await db.all<{user_count: number, avail_count: number, shift_refs: number}>(` - SELECT - (SELECT COUNT(*) FROM users WHERE id = ?) as user_count, - (SELECT COUNT(*) FROM employee_availabilities WHERE employee_id = ?) as avail_count, - (SELECT COUNT(*) FROM assigned_shifts WHERE json_extract(assigned_employees, '$') LIKE ?) as shift_refs - `, [id, id, `%${id}%`]); - - const counts = verifyDeletion[0]; - if (!counts || counts.user_count > 0 || counts.avail_count > 0 || counts.shift_refs > 0) { - console.error('Deletion verification failed:', counts); - await db.run('ROLLBACK'); - throw new Error('Failed to delete all user data'); - } - - // If we got here, the deletion was successful - await db.run('COMMIT'); - console.log('✅ Deletion committed successfully'); - - // Final verification after commit - const finalCheck = await db.get('SELECT * FROM users WHERE email = ?', [existingEmployee.email]); - console.log('🔍 Final verification - any user with this email:', finalCheck); - } catch (err) { - console.error('Error during deletion transaction:', err); - await db.run('ROLLBACK'); - throw err; - } - - res.status(204).send(); } catch (error) { console.error('Error deleting employee:', error); res.status(500).json({ error: 'Internal server error' }); @@ -344,7 +255,14 @@ export const getAvailabilities = async (req: AuthRequest, res: Response): Promis export const updateAvailabilities = async (req: AuthRequest, res: Response): Promise => { try { const { employeeId } = req.params; - const availabilities = req.body; + const availabilities = req.body as Array<{ + id?: string; + employeeId: string; + dayOfWeek: number; + startTime: string; + endTime: string; + isAvailable: boolean; + }>; // Check if employee exists const existingEmployee = await db.get('SELECT id FROM users WHERE id = ?', [employeeId]); diff --git a/backend/src/controllers/shiftTemplateController.ts b/backend/src/controllers/shiftTemplateController.ts index 08edcbe..f33d071 100644 --- a/backend/src/controllers/shiftTemplateController.ts +++ b/backend/src/controllers/shiftTemplateController.ts @@ -3,6 +3,7 @@ import { Request, Response } from 'express'; import { v4 as uuidv4 } from 'uuid'; import { db } from '../services/databaseService.js'; import { ShiftTemplate, CreateShiftTemplateRequest, UpdateShiftTemplateRequest } from '../models/ShiftTemplate.js'; +import { AuthRequest } from '../middleware/auth.js'; export const getTemplates = async (req: Request, res: Response): Promise => { try { @@ -140,7 +141,7 @@ export const createDefaultTemplate = async (userId: string): Promise => export const createTemplate = async (req: Request, res: Response): Promise => { try { const { name, description, isDefault, shifts }: CreateShiftTemplateRequest = req.body; - const userId = (req as any).user?.userId; // From auth middleware + const userId = (req as AuthRequest).user?.userId; if (!userId) { res.status(401).json({ error: 'Unauthorized' }); diff --git a/backend/src/middleware/auth.ts b/backend/src/middleware/auth.ts index 6b947cb..1a46d37 100644 --- a/backend/src/middleware/auth.ts +++ b/backend/src/middleware/auth.ts @@ -1,6 +1,7 @@ // backend/src/middleware/auth.ts import { Request, Response, NextFunction } from 'express'; import jwt from 'jsonwebtoken'; +import { JWTPayload } from '../controllers/authController.js'; const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key'; @@ -21,8 +22,12 @@ export const authMiddleware = (req: AuthRequest, res: Response, next: NextFuncti } try { - const decoded = jwt.verify(token, JWT_SECRET) as any; - req.user = decoded; + const decoded = jwt.verify(token, JWT_SECRET) as JWTPayload; + req.user = { + userId: decoded.id, + email: decoded.email, + role: decoded.role + }; next(); } catch (error) { res.status(400).json({ error: 'Invalid token.' }); diff --git a/frontend/src/services/employeeService.ts b/frontend/src/services/employeeService.ts index b48884b..63039d9 100644 --- a/frontend/src/services/employeeService.ts +++ b/frontend/src/services/employeeService.ts @@ -4,7 +4,7 @@ import { authService } from './authService'; const API_BASE = 'http://localhost:3002/api/employees'; -export const employeeService = { +export class EmployeeService { // Alle Mitarbeiter abrufen async getEmployees(): Promise { const response = await fetch(`${API_BASE}?_=${Date.now()}`, { @@ -21,7 +21,7 @@ export const employeeService = { } return response.json(); - }, + } // Einzelnen Mitarbeiter abrufen async getEmployee(id: string): Promise { @@ -37,7 +37,7 @@ export const employeeService = { } return response.json(); - }, + } // Neuen Mitarbeiter erstellen async createEmployee(employeeData: CreateEmployeeRequest): Promise { @@ -56,7 +56,7 @@ export const employeeService = { } return response.json(); - }, + } // Mitarbeiter aktualisieren async updateEmployee(id: string, updates: UpdateEmployeeRequest): Promise { @@ -74,7 +74,7 @@ export const employeeService = { } return response.json(); - }, + } // Mitarbeiter permanent löschen async deleteEmployee(id: string): Promise { @@ -89,7 +89,7 @@ export const employeeService = { const error = await response.json().catch(() => ({ error: 'Fehler beim Löschen des Mitarbeiters' })); throw new Error(error.error || 'Fehler beim Löschen des Mitarbeiters'); } - }, + } // Verfügbarkeiten abrufen async getAvailabilities(employeeId: string): Promise { @@ -105,7 +105,7 @@ export const employeeService = { } return response.json(); - }, + } // Verfügbarkeiten aktualisieren async updateAvailabilities(employeeId: string, availabilities: Availability[]): Promise {