mirror of
https://github.com/donpat1to/Schichtenplaner.git
synced 2025-11-30 22:45:46 +01:00
added admin setup
This commit is contained in:
@@ -1,63 +1,20 @@
|
||||
// backend/src/server.ts - Login für alle Benutzer
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { setupDefaultTemplate } from './scripts/setupDefaultTemplate.js';
|
||||
import { initializeDatabase } from './scripts/initializeDatabase.js';
|
||||
|
||||
// Route imports
|
||||
import authRoutes from './routes/auth.js';
|
||||
import employeeRoutes from './routes/employees.js';
|
||||
import shiftPlanRoutes from './routes/shiftPlans.js';
|
||||
import shiftTemplateRoutes from './routes/shiftTemplates.js';
|
||||
import setupRoutes from './routes/setup.js';
|
||||
|
||||
const app = express();
|
||||
const PORT = 3002;
|
||||
|
||||
// IN-MEMORY STORE für Mitarbeiter
|
||||
let employees = [
|
||||
{
|
||||
id: '1',
|
||||
email: 'admin@schichtplan.de',
|
||||
password: 'admin123', // Klartext für Test
|
||||
name: 'Admin User',
|
||||
role: 'admin',
|
||||
isActive: true,
|
||||
phone: '+49 123 456789',
|
||||
department: 'IT',
|
||||
createdAt: new Date().toISOString(),
|
||||
lastLogin: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
email: 'instandhalter@schichtplan.de',
|
||||
password: 'instandhalter123',
|
||||
name: 'Max Instandhalter',
|
||||
role: 'instandhalter',
|
||||
isActive: true,
|
||||
phone: '+49 123 456790',
|
||||
department: 'Produktion',
|
||||
createdAt: new Date().toISOString(),
|
||||
lastLogin: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
email: 'mitarbeiter1@schichtplan.de',
|
||||
password: 'user123',
|
||||
name: 'Anna Müller',
|
||||
role: 'user',
|
||||
isActive: true,
|
||||
phone: '+49 123 456791',
|
||||
department: 'Logistik',
|
||||
createdAt: new Date().toISOString(),
|
||||
lastLogin: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
email: 'mitarbeiter2@schichtplan.de',
|
||||
password: 'user123',
|
||||
name: 'Tom Schmidt',
|
||||
role: 'user',
|
||||
isActive: true,
|
||||
phone: '+49 123 456792',
|
||||
department: 'Produktion',
|
||||
createdAt: new Date().toISOString(),
|
||||
lastLogin: new Date().toISOString()
|
||||
}
|
||||
];
|
||||
|
||||
// CORS und Middleware
|
||||
app.use(cors({
|
||||
origin: 'http://localhost:3000',
|
||||
@@ -65,6 +22,13 @@ app.use(cors({
|
||||
}));
|
||||
app.use(express.json());
|
||||
|
||||
// API Routes
|
||||
app.use('/api/setup', setupRoutes);
|
||||
app.use('/api/auth', authRoutes);
|
||||
app.use('/api/employees', employeeRoutes);
|
||||
app.use('/api/shift-plans', shiftPlanRoutes);
|
||||
app.use('/api/shift-templates', shiftTemplateRoutes);
|
||||
|
||||
// Health route
|
||||
app.get('/api/health', (req: any, res: any) => {
|
||||
res.json({
|
||||
@@ -74,263 +38,22 @@ app.get('/api/health', (req: any, res: any) => {
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/api/auth/login', async (req: any, res: any) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
console.log('🔐 Login attempt for:', email);
|
||||
console.log('📧 Email:', email);
|
||||
console.log('🔑 Password length:', password?.length);
|
||||
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({ error: 'Email and password are required' });
|
||||
}
|
||||
|
||||
// Benutzer suchen
|
||||
const user = employees.find(emp => emp.email === email && emp.isActive);
|
||||
|
||||
if (!user) {
|
||||
console.log('❌ User not found or inactive:', email);
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
console.log('🔍 User found:', user.email);
|
||||
console.log('💾 Stored password:', user.password);
|
||||
console.log('↔️ Password match:', password === user.password);
|
||||
|
||||
// Passwort-Überprüfung
|
||||
const isPasswordValid = password === user.password;
|
||||
|
||||
if (!isPasswordValid) {
|
||||
console.log('❌ Password invalid for:', email);
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
// Last Login aktualisieren
|
||||
user.lastLogin = new Date().toISOString();
|
||||
|
||||
console.log('✅ Login successful for:', email);
|
||||
|
||||
// User ohne Passwort zurückgeben
|
||||
const { password: _, ...userWithoutPassword } = user;
|
||||
|
||||
res.json({
|
||||
user: userWithoutPassword,
|
||||
token: 'jwt-token-' + Date.now() + '-' + user.id,
|
||||
expiresIn: '7d'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// EMPLOYEE ROUTES
|
||||
app.get('/api/employees', async (req: any, res: any) => {
|
||||
try {
|
||||
console.log('📋 Fetching employees - Total:', employees.length);
|
||||
|
||||
// Passwörter ausblenden
|
||||
const employeesWithoutPasswords = employees.map(emp => {
|
||||
const { password, ...empWithoutPassword } = emp;
|
||||
return empWithoutPassword;
|
||||
});
|
||||
|
||||
res.json(employeesWithoutPasswords);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/employees', async (req: any, res: any) => {
|
||||
try {
|
||||
const { email, password, name, role, phone, department } = req.body;
|
||||
|
||||
console.log('👤 Creating employee:', { email, name, role });
|
||||
|
||||
// Validierung
|
||||
if (!email || !password || !name || !role) {
|
||||
return res.status(400).json({ error: 'Email, password, name and role are required' });
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
return res.status(400).json({ error: 'Password must be at least 6 characters long' });
|
||||
}
|
||||
|
||||
// Rollen-Validierung
|
||||
const validRoles = ['admin', 'instandhalter', 'user'];
|
||||
if (!validRoles.includes(role)) {
|
||||
return res.status(400).json({ error: 'Ungültige Rolle' });
|
||||
}
|
||||
|
||||
// Check if email already exists
|
||||
if (employees.find(emp => emp.email === email)) {
|
||||
return res.status(409).json({ error: 'Email already exists' });
|
||||
}
|
||||
|
||||
// NEUEN Benutzer erstellen
|
||||
const newEmployee = {
|
||||
id: uuidv4(),
|
||||
email,
|
||||
password: password, // Klartext speichern für einfachen Test
|
||||
name,
|
||||
role,
|
||||
isActive: true,
|
||||
phone: phone || '',
|
||||
department: department || '',
|
||||
createdAt: new Date().toISOString(),
|
||||
lastLogin: ''
|
||||
};
|
||||
|
||||
employees.push(newEmployee);
|
||||
|
||||
console.log('✅ Employee created:', {
|
||||
email: newEmployee.email,
|
||||
name: newEmployee.name,
|
||||
role: newEmployee.role
|
||||
});
|
||||
console.log('📊 Total employees:', employees.length);
|
||||
|
||||
// Response ohne Passwort
|
||||
const { password: _, ...employeeWithoutPassword } = newEmployee;
|
||||
res.status(201).json(employeeWithoutPassword);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating employee:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/employees/:id', async (req: any, res: any) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { name, role, isActive, phone, department } = req.body;
|
||||
|
||||
console.log('✏️ Updating employee:', id);
|
||||
|
||||
// Mitarbeiter finden
|
||||
const employeeIndex = employees.findIndex(emp => emp.id === id);
|
||||
if (employeeIndex === -1) {
|
||||
return res.status(404).json({ error: 'Employee not found' });
|
||||
}
|
||||
|
||||
// Mitarbeiter aktualisieren
|
||||
employees[employeeIndex] = {
|
||||
...employees[employeeIndex],
|
||||
name: name || employees[employeeIndex].name,
|
||||
role: role || employees[employeeIndex].role,
|
||||
isActive: isActive !== undefined ? isActive : employees[employeeIndex].isActive,
|
||||
phone: phone || employees[employeeIndex].phone,
|
||||
department: department || employees[employeeIndex].department
|
||||
};
|
||||
|
||||
console.log('✅ Employee updated:', employees[employeeIndex].name);
|
||||
|
||||
// Response ohne Passwort
|
||||
const { password, ...employeeWithoutPassword } = employees[employeeIndex];
|
||||
res.json(employeeWithoutPassword);
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/employees/:id', async (req: any, res: any) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
console.log('🗑️ Deleting employee:', id);
|
||||
|
||||
const employeeIndex = employees.findIndex(emp => emp.id === id);
|
||||
if (employeeIndex === -1) {
|
||||
return res.status(404).json({ error: 'Employee not found' });
|
||||
}
|
||||
|
||||
const employeeToDelete = employees[employeeIndex];
|
||||
|
||||
// Admin-Check
|
||||
if (employeeToDelete.role === 'admin') {
|
||||
const adminCount = employees.filter(emp =>
|
||||
emp.role === 'admin' && emp.isActive
|
||||
).length;
|
||||
|
||||
if (adminCount <= 1) {
|
||||
return res.status(400).json({
|
||||
error: 'Mindestens ein Administrator muss im System verbleiben'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Perform hard delete
|
||||
employees.splice(employeeIndex, 1);
|
||||
console.log('✅ Employee permanently deleted:', employeeToDelete.name);
|
||||
|
||||
res.status(204).send();
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Availability Routes
|
||||
app.get('/api/employees/:employeeId/availabilities', async (req: any, res: any) => {
|
||||
try {
|
||||
const { employeeId } = req.params;
|
||||
console.log('📅 Fetching availabilities for:', employeeId);
|
||||
|
||||
// Mock Verfügbarkeiten
|
||||
const daysOfWeek = [0, 1, 2, 3, 4, 5, 6];
|
||||
const timeSlots = [
|
||||
{ name: 'Vormittag', start: '08:00', end: '12:00' },
|
||||
{ name: 'Nachmittag', start: '12:00', end: '16:00' },
|
||||
{ name: 'Abend', start: '16:00', end: '20:00' }
|
||||
];
|
||||
|
||||
const mockAvailabilities = daysOfWeek.flatMap(day =>
|
||||
timeSlots.map((slot, index) => ({
|
||||
id: `avail-${employeeId}-${day}-${index}`,
|
||||
employeeId,
|
||||
dayOfWeek: day,
|
||||
startTime: slot.start,
|
||||
endTime: slot.end,
|
||||
isAvailable: day >= 1 && day <= 5
|
||||
}))
|
||||
);
|
||||
|
||||
res.json(mockAvailabilities);
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/employees/:employeeId/availabilities', async (req: any, res: any) => {
|
||||
try {
|
||||
const { employeeId } = req.params;
|
||||
const availabilities = req.body;
|
||||
|
||||
console.log('💾 Saving availabilities for:', employeeId);
|
||||
|
||||
// Mock erfolgreiches Speichern
|
||||
res.json(availabilities);
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Start server
|
||||
app.listen(PORT, () => {
|
||||
app.listen(PORT, async () => {
|
||||
console.log('🎉 BACKEND STARTED SUCCESSFULLY!');
|
||||
console.log(`📍 Port: ${PORT}`);
|
||||
console.log(`📍 Health: http://localhost:${PORT}/api/health`);
|
||||
|
||||
try {
|
||||
await initializeDatabase();
|
||||
await setupDefaultTemplate();
|
||||
console.log('✅ Standard-Vorlage überprüft/erstellt');
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler bei der Initialisierung:', error);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('🔐 SIMPLE LOGIN READY - Plain text passwords for testing!');
|
||||
console.log('');
|
||||
console.log('📋 TEST ACCOUNTS:');
|
||||
console.log(' 👑 Admin: admin@schichtplan.de / admin123');
|
||||
console.log(' 🔧 Instandhalter: instandhalter@schichtplan.de / instandhalter123');
|
||||
console.log(' 👤 User1: mitarbeiter1@schichtplan.de / user123');
|
||||
console.log(' 👤 User2: mitarbeiter2@schichtplan.de / user123');
|
||||
console.log(' 👤 Patrick: patrick@patrick.de / 12345678');
|
||||
});
|
||||
console.log('🔧 Setup ready at: http://localhost:${PORT}/api/setup/status');
|
||||
console.log('📝 Create your admin account on first launch');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user