added setup files

This commit is contained in:
2025-10-09 00:47:56 +02:00
parent 79b3658c5e
commit 6052a600dd
6 changed files with 109 additions and 70 deletions

View File

@@ -6,17 +6,31 @@ import { db } from '../services/databaseService.js';
export const checkSetupStatus = async (req: Request, res: Response): Promise<void> => { export const checkSetupStatus = async (req: Request, res: Response): Promise<void> => {
try { try {
const adminExists = await db.get<{ count: number }>( // First, ensure database is properly initialized
'SELECT COUNT(*) as count FROM users WHERE role = ?', try {
['admin'] const adminExists = await db.get<{ count: number }>(
); 'SELECT COUNT(*) as count FROM users WHERE role = ?',
['admin']
);
res.json({ res.json({
needsSetup: !adminExists || adminExists.count === 0 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) { } catch (error) {
console.error('Error checking setup status:', 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<void> =>
res.status(201).json({ res.status(201).json({
message: 'Admin user created successfully', message: 'Admin user created successfully',
userId: adminId userId: adminId,
email: email
}); });
} catch (error) { } catch (error) {
console.error('Error in setup:', error); console.error('Error in setup:', error);

View File

@@ -1,5 +1,6 @@
// backend/src/routes/setup.ts // backend/src/routes/setup.ts
import express from 'express'; import express from 'express';
import bcrypt from 'bcryptjs';
import { checkSetupStatus, setupAdmin } from '../controllers/setupController.js'; import { checkSetupStatus, setupAdmin } from '../controllers/setupController.js';
const router = express.Router(); const router = express.Router();

View File

@@ -1,3 +1,4 @@
// backend/src/scripts/initializeDatabase.ts
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
@@ -14,6 +15,20 @@ export async function initializeDatabase(): Promise<void> {
try { try {
console.log('Starting database initialization...'); 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 // Get list of existing tables
interface TableInfo { interface TableInfo {
name: string; name: string;
@@ -26,7 +41,7 @@ export async function initializeDatabase(): Promise<void> {
console.log('Existing tables found:', existingTables.map(t => t.name).join(', ') || 'none'); 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 = [ const tablesToDrop = [
'employee_availabilities', 'employee_availabilities',
'assigned_shifts', 'assigned_shifts',
@@ -77,54 +92,13 @@ export async function initializeDatabase(): Promise<void> {
} }
await db.run('COMMIT'); 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 // Give a small delay to ensure all transactions are properly closed
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 100));
// Create default template
await setupDefaultTemplate();
} catch (error) { } catch (error) {
console.error('Fehler bei der Datenbankinitialisierung:', error); console.error('Error during database initialization:', error);
throw error;
}
}
async function createAdminUser(): Promise<void> {
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);
throw error; throw error;
} }
} }

View File

@@ -1,7 +1,6 @@
// backend/src/server.ts - Login für alle Benutzer // backend/src/server.ts
import express from 'express'; import express from 'express';
import cors from 'cors'; import cors from 'cors';
import { v4 as uuidv4 } from 'uuid';
import { setupDefaultTemplate } from './scripts/setupDefaultTemplate.js'; import { setupDefaultTemplate } from './scripts/setupDefaultTemplate.js';
import { initializeDatabase } from './scripts/initializeDatabase.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<AdminCountResult>(
'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 // Start server
app.listen(PORT, async () => { app.listen(PORT, async () => {
@@ -47,13 +69,15 @@ app.listen(PORT, async () => {
try { try {
await initializeDatabase(); await initializeDatabase();
console.log('✅ Database initialized successfully');
await setupDefaultTemplate(); await setupDefaultTemplate();
console.log('✅ Standard-Vorlage überprüft/erstellt'); console.log('✅ Default template checked/created');
} catch (error) { } catch (error) {
console.error('❌ Fehler bei der Initialisierung:', error); console.error('❌ Error during initialization:', error);
} }
console.log(''); 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'); console.log('📝 Create your admin account on first launch');
}); });

View File

@@ -1,4 +1,4 @@
// frontend/src/contexts/AuthContext.tsx - KORRIGIERT // frontend/src/contexts/AuthContext.tsx
import React, { createContext, useContext, useState, useEffect } from 'react'; import React, { createContext, useContext, useState, useEffect } from 'react';
import { authService, User, LoginRequest } from '../services/authService'; import { authService, User, LoginRequest } from '../services/authService';
@@ -8,7 +8,7 @@ interface AuthContextType {
logout: () => void; logout: () => void;
hasRole: (roles: string[]) => boolean; hasRole: (roles: string[]) => boolean;
loading: boolean; loading: boolean;
refreshUser: () => void; // NEU: Force refresh refreshUser: () => void;
needsSetup: boolean; needsSetup: boolean;
checkSetupStatus: () => Promise<void>; checkSetupStatus: () => Promise<void>;
} }
@@ -19,15 +19,20 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const [user, setUser] = useState<User | null>(null); const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [needsSetup, setNeedsSetup] = useState(false); const [needsSetup, setNeedsSetup] = useState(false);
const [refreshTrigger, setRefreshTrigger] = useState(0); // NEU: Refresh trigger const [refreshTrigger, setRefreshTrigger] = useState(0);
const checkSetupStatus = async () => { const checkSetupStatus = async () => {
try { try {
const response = await fetch('/api/setup/status'); const response = await fetch('/api/setup/status');
if (!response.ok) {
throw new Error('Failed to check setup status');
}
const data = await response.json(); const data = await response.json();
setNeedsSetup(data.needsSetup); setNeedsSetup(data.needsSetup);
} catch (error) { } catch (error) {
console.error('Error checking setup status:', 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(() => { useEffect(() => {
const initializeApp = async () => { const initializeApp = async () => {
await checkSetupStatus(); await checkSetupStatus();
const savedUser = authService.getCurrentUser();
if (savedUser) { // Only try to load user if setup is not needed
setUser(savedUser); if (!needsSetup) {
console.log('✅ User from localStorage:', savedUser.email); const savedUser = authService.getCurrentUser();
if (savedUser) {
setUser(savedUser);
console.log('✅ User from localStorage:', savedUser.email);
}
} }
setLoading(false); setLoading(false);
}; };
initializeApp(); initializeApp();
}, []); }, []);
// NEU: User vom Server laden wenn nötig // Update needsSetup when it changes
useEffect(() => { 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 loadUserFromServer = async () => {
const serverUser = await authService.fetchCurrentUser(); const serverUser = await authService.fetchCurrentUser();
if (serverUser) { if (serverUser) {
@@ -57,7 +78,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
}; };
loadUserFromServer(); loadUserFromServer();
} }
}, [refreshTrigger]); }, [refreshTrigger, needsSetup]);
const login = async (credentials: LoginRequest) => { const login = async (credentials: LoginRequest) => {
try { try {

View File

@@ -1,3 +1,4 @@
// frontend/src/pages/Setup/Setup.tsx
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext'; import { useAuth } from '../../contexts/AuthContext';
@@ -14,7 +15,7 @@ const Setup: React.FC = () => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState(''); const [error, setError] = useState('');
const navigate = useNavigate(); const navigate = useNavigate();
const { login } = useAuth(); const { login, checkSetupStatus } = useAuth();
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target; const { name, value } = e.target;
@@ -81,6 +82,9 @@ const Setup: React.FC = () => {
throw new Error(data.error || 'Setup fehlgeschlagen'); throw new Error(data.error || 'Setup fehlgeschlagen');
} }
// Re-check setup status after successful setup
await checkSetupStatus();
// Automatically log in after setup // Automatically log in after setup
await login({ email: adminEmail, password: formData.password }); await login({ email: adminEmail, password: formData.password });
navigate('/'); navigate('/');