From 6052a600dd5571a9fc3c5159b8ecc17c16f0dcb9 Mon Sep 17 00:00:00 2001 From: donpat1to Date: Thu, 9 Oct 2025 00:47:56 +0200 Subject: [PATCH] added setup files --- backend/src/controllers/setupController.ts | 33 ++++++++---- backend/src/routes/setup.ts | 1 + backend/src/scripts/initializeDatabase.ts | 62 +++++++--------------- backend/src/server.ts | 36 ++++++++++--- frontend/src/contexts/AuthContext.tsx | 41 ++++++++++---- frontend/src/pages/Setup/Setup.tsx | 6 ++- 6 files changed, 109 insertions(+), 70 deletions(-) diff --git a/backend/src/controllers/setupController.ts b/backend/src/controllers/setupController.ts index 8d604c7..8c0f2c5 100644 --- a/backend/src/controllers/setupController.ts +++ b/backend/src/controllers/setupController.ts @@ -6,17 +6,31 @@ import { db } from '../services/databaseService.js'; export const checkSetupStatus = async (req: Request, res: Response): Promise => { try { - const adminExists = await db.get<{ count: number }>( - 'SELECT COUNT(*) as count FROM users WHERE role = ?', - ['admin'] - ); + // First, ensure database is properly initialized + try { + const adminExists = await db.get<{ count: number }>( + 'SELECT COUNT(*) as count FROM users WHERE role = ?', + ['admin'] + ); - res.json({ - needsSetup: !adminExists || adminExists.count === 0 - }); + res.json({ + needsSetup: !adminExists || adminExists.count === 0, + message: adminExists && adminExists.count > 0 ? 'Admin user exists' : 'No admin user found' + }); + } catch (dbError) { + console.error('Database error in checkSetupStatus:', dbError); + // If there's a database error, assume setup is needed + res.json({ + needsSetup: true, + message: 'Database not ready, setup required' + }); + } } catch (error) { console.error('Error checking setup status:', error); - res.status(500).json({ error: 'Internal server error' }); + res.status(500).json({ + error: 'Internal server error', + needsSetup: true + }); } }; @@ -78,7 +92,8 @@ export const setupAdmin = async (req: Request, res: Response): Promise => res.status(201).json({ message: 'Admin user created successfully', - userId: adminId + userId: adminId, + email: email }); } catch (error) { console.error('Error in setup:', error); diff --git a/backend/src/routes/setup.ts b/backend/src/routes/setup.ts index 22281c5..da4d842 100644 --- a/backend/src/routes/setup.ts +++ b/backend/src/routes/setup.ts @@ -1,5 +1,6 @@ // backend/src/routes/setup.ts import express from 'express'; +import bcrypt from 'bcryptjs'; import { checkSetupStatus, setupAdmin } from '../controllers/setupController.js'; const router = express.Router(); diff --git a/backend/src/scripts/initializeDatabase.ts b/backend/src/scripts/initializeDatabase.ts index dcda674..f40e756 100644 --- a/backend/src/scripts/initializeDatabase.ts +++ b/backend/src/scripts/initializeDatabase.ts @@ -1,3 +1,4 @@ +// backend/src/scripts/initializeDatabase.ts import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; @@ -14,6 +15,20 @@ export async function initializeDatabase(): Promise { try { console.log('Starting database initialization...'); + // Check if users table exists and has data + try { + const existingAdmin = await db.get<{ count: number }>( + "SELECT COUNT(*) as count FROM users WHERE role = 'admin'" + ); + + if (existingAdmin && existingAdmin.count > 0) { + console.log('✅ Database already initialized with admin user'); + return; + } + } catch (error) { + console.log('ℹ️ Database tables might not exist yet, creating schema...'); + } + // Get list of existing tables interface TableInfo { name: string; @@ -26,7 +41,7 @@ export async function initializeDatabase(): Promise { console.log('Existing tables found:', existingTables.map(t => t.name).join(', ') || 'none'); - // Drop existing tables in reverse order of dependencies + // Drop existing tables in reverse order of dependencies if they exist const tablesToDrop = [ 'employee_availabilities', 'assigned_shifts', @@ -77,54 +92,13 @@ export async function initializeDatabase(): Promise { } await db.run('COMMIT'); - console.log('✅ Datenbankschema erfolgreich initialisiert'); + console.log('✅ Database schema successfully initialized'); // Give a small delay to ensure all transactions are properly closed await new Promise(resolve => setTimeout(resolve, 100)); - // Create default template - await setupDefaultTemplate(); } catch (error) { - console.error('Fehler bei der Datenbankinitialisierung:', error); - throw error; - } -} - -async function createAdminUser(): Promise { - try { - await db.run('BEGIN TRANSACTION'); - - try { - // Erstelle Admin-Benutzer, wenn noch keiner existiert - const admin = await db.get('SELECT id FROM users WHERE role = ?', ['admin']); - - if (!admin) { - await db.run( - `INSERT INTO users (id, email, password, name, role, phone, department, is_active) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - [ - 'admin-' + Math.random().toString(36).substring(2), - 'admin@schichtplan.de', - 'admin123', - 'Administrator', - 'admin', - '+49 123 456789', - 'IT', - true - ] - ); - console.log('✅ Admin-Benutzer erstellt'); - } else { - console.log('ℹ️ Admin-Benutzer existiert bereits'); - } - - await db.run('COMMIT'); - } catch (error) { - await db.run('ROLLBACK'); - throw error; - } - } catch (error) { - console.error('Fehler beim Erstellen des Admin-Benutzers:', error); + console.error('Error during database initialization:', error); throw error; } } \ No newline at end of file diff --git a/backend/src/server.ts b/backend/src/server.ts index 4206868..96959bc 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -1,7 +1,6 @@ -// backend/src/server.ts - Login für alle Benutzer +// backend/src/server.ts 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'; @@ -38,6 +37,29 @@ app.get('/api/health', (req: any, res: any) => { }); }); +// Setup status route (additional endpoint for clarity) +app.get('/api/initial-setup', async (req: any, res: any) => { + try { + const { db } = await import('./services/databaseService.js'); + + // Define proper interface for the result + interface AdminCountResult { + count: number; + } + + const adminExists = await db.get( + 'SELECT COUNT(*) as count FROM users WHERE role = ?', + ['admin'] + ); + + res.json({ + needsInitialSetup: !adminExists || adminExists.count === 0 + }); + } catch (error) { + console.error('Error checking initial setup:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}); // Start server app.listen(PORT, async () => { @@ -47,13 +69,15 @@ app.listen(PORT, async () => { try { await initializeDatabase(); + console.log('✅ Database initialized successfully'); + await setupDefaultTemplate(); - console.log('✅ Standard-Vorlage überprüft/erstellt'); + console.log('✅ Default template checked/created'); } catch (error) { - console.error('❌ Fehler bei der Initialisierung:', error); + console.error('❌ Error during initialization:', error); } console.log(''); - console.log('🔧 Setup ready at: http://localhost:${PORT}/api/setup/status'); + console.log(`🔧 Setup ready at: http://localhost:${PORT}/api/setup/status`); console.log('📝 Create your admin account on first launch'); -}); +}); \ No newline at end of file diff --git a/frontend/src/contexts/AuthContext.tsx b/frontend/src/contexts/AuthContext.tsx index 7d83cc4..6edbaf8 100644 --- a/frontend/src/contexts/AuthContext.tsx +++ b/frontend/src/contexts/AuthContext.tsx @@ -1,4 +1,4 @@ -// frontend/src/contexts/AuthContext.tsx - KORRIGIERT +// frontend/src/contexts/AuthContext.tsx import React, { createContext, useContext, useState, useEffect } from 'react'; import { authService, User, LoginRequest } from '../services/authService'; @@ -8,7 +8,7 @@ interface AuthContextType { logout: () => void; hasRole: (roles: string[]) => boolean; loading: boolean; - refreshUser: () => void; // NEU: Force refresh + refreshUser: () => void; needsSetup: boolean; checkSetupStatus: () => Promise; } @@ -19,15 +19,20 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [needsSetup, setNeedsSetup] = useState(false); - const [refreshTrigger, setRefreshTrigger] = useState(0); // NEU: Refresh trigger + const [refreshTrigger, setRefreshTrigger] = useState(0); const checkSetupStatus = async () => { try { const response = await fetch('/api/setup/status'); + if (!response.ok) { + throw new Error('Failed to check setup status'); + } const data = await response.json(); setNeedsSetup(data.needsSetup); } catch (error) { console.error('Error checking setup status:', error); + // If we can't reach the server, assume setup is needed + setNeedsSetup(true); } }; @@ -35,19 +40,35 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children useEffect(() => { const initializeApp = async () => { await checkSetupStatus(); - const savedUser = authService.getCurrentUser(); - if (savedUser) { - setUser(savedUser); - console.log('✅ User from localStorage:', savedUser.email); + + // Only try to load user if setup is not needed + if (!needsSetup) { + const savedUser = authService.getCurrentUser(); + if (savedUser) { + setUser(savedUser); + console.log('✅ User from localStorage:', savedUser.email); + } } + setLoading(false); }; initializeApp(); }, []); - // NEU: User vom Server laden wenn nötig + // Update needsSetup when it changes useEffect(() => { - if (refreshTrigger > 0) { + if (!needsSetup && !user) { + // If setup is complete but no user is loaded, try to load from localStorage + const savedUser = authService.getCurrentUser(); + if (savedUser) { + setUser(savedUser); + } + } + }, [needsSetup, user]); + + // User vom Server laden wenn nötig + useEffect(() => { + if (refreshTrigger > 0 && !needsSetup) { const loadUserFromServer = async () => { const serverUser = await authService.fetchCurrentUser(); if (serverUser) { @@ -57,7 +78,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }; loadUserFromServer(); } - }, [refreshTrigger]); + }, [refreshTrigger, needsSetup]); const login = async (credentials: LoginRequest) => { try { diff --git a/frontend/src/pages/Setup/Setup.tsx b/frontend/src/pages/Setup/Setup.tsx index e00ddcd..960f964 100644 --- a/frontend/src/pages/Setup/Setup.tsx +++ b/frontend/src/pages/Setup/Setup.tsx @@ -1,3 +1,4 @@ +// frontend/src/pages/Setup/Setup.tsx import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '../../contexts/AuthContext'; @@ -14,7 +15,7 @@ const Setup: React.FC = () => { const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const navigate = useNavigate(); - const { login } = useAuth(); + const { login, checkSetupStatus } = useAuth(); const handleInputChange = (e: React.ChangeEvent) => { const { name, value } = e.target; @@ -81,6 +82,9 @@ const Setup: React.FC = () => { throw new Error(data.error || 'Setup fehlgeschlagen'); } + // Re-check setup status after successful setup + await checkSetupStatus(); + // Automatically log in after setup await login({ email: adminEmail, password: formData.password }); navigate('/');