mirror of
https://github.com/donpat1to/Schichtenplaner.git
synced 2025-12-01 06:55:45 +01:00
fixed parsing admin setup
This commit is contained in:
2853
backend/package-lock.json
generated
Normal file
2853
backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,20 +9,22 @@
|
|||||||
"start": "node dist/server.js"
|
"start": "node dist/server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
"@types/bcrypt": "^6.0.0",
|
||||||
"cors": "^2.8.5",
|
"bcrypt": "^6.0.0",
|
||||||
"sqlite3": "^5.1.6",
|
|
||||||
"jsonwebtoken": "^9.0.2",
|
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"sqlite3": "^5.1.6",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.17",
|
|
||||||
"@types/cors": "^2.8.13",
|
|
||||||
"@types/jsonwebtoken": "^9.0.2",
|
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
|
"@types/cors": "^2.8.13",
|
||||||
|
"@types/express": "^4.17.17",
|
||||||
|
"@types/jsonwebtoken": "^9.0.2",
|
||||||
"@types/uuid": "^9.0.2",
|
"@types/uuid": "^9.0.2",
|
||||||
"typescript": "^5.0.0",
|
"ts-node": "^10.9.0",
|
||||||
"ts-node": "^10.9.0"
|
"typescript": "^5.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,168 +1,203 @@
|
|||||||
// backend/src/controllers/authController.ts
|
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import bcrypt from 'bcryptjs';
|
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import bcrypt from 'bcrypt';
|
||||||
import { db } from '../services/databaseService.js';
|
import { db } from '../services/databaseService.js';
|
||||||
import { AuthRequest } from '../middleware/auth.js';
|
|
||||||
|
|
||||||
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
|
export interface User {
|
||||||
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d';
|
id: number;
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
phone?: string;
|
||||||
|
department?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const login = async (req: Request, res: Response): Promise<void> => {
|
export interface UserWithPassword extends User {
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginRequest {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JWTPayload {
|
||||||
|
id: number;
|
||||||
|
email: string;
|
||||||
|
role: string;
|
||||||
|
iat?: number;
|
||||||
|
exp?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegisterRequest {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
name: string;
|
||||||
|
phone?: string;
|
||||||
|
department?: string;
|
||||||
|
role?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const login = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { email, password } = req.body;
|
const { email, password } = req.body as LoginRequest;
|
||||||
|
|
||||||
if (!email || !password) {
|
if (!email || !password) {
|
||||||
res.status(400).json({ error: 'Email and password are required' });
|
return res.status(400).json({ error: 'E-Mail und Passwort sind erforderlich' });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User aus Datenbank holen
|
// Get user from database
|
||||||
const user = await db.get<any>(
|
const user = await db.get<UserWithPassword>(
|
||||||
'SELECT * FROM users WHERE email = ?',
|
'SELECT id, email, password, name, role, phone, department FROM users WHERE email = ?',
|
||||||
[email]
|
[email]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
res.status(401).json({ error: 'Invalid credentials' });
|
return res.status(401).json({ error: 'Ungültige Anmeldedaten' });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Passwort vergleichen
|
// Verify password
|
||||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
const validPassword = await bcrypt.compare(password, user.password);
|
||||||
if (!isPasswordValid) {
|
if (!validPassword) {
|
||||||
res.status(401).json({ error: 'Invalid credentials' });
|
return res.status(401).json({ error: 'Ungültige Anmeldedaten' });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JWT Token generieren
|
// Create token payload
|
||||||
|
const tokenPayload: JWTPayload = {
|
||||||
|
id: user.id,
|
||||||
|
email: user.email,
|
||||||
|
role: user.role
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create token
|
||||||
const token = jwt.sign(
|
const token = jwt.sign(
|
||||||
{
|
tokenPayload,
|
||||||
userId: user.id,
|
process.env.JWT_SECRET || 'your-secret-key',
|
||||||
email: user.email,
|
{ expiresIn: '24h' }
|
||||||
role: user.role
|
|
||||||
},
|
|
||||||
JWT_SECRET as jwt.Secret,
|
|
||||||
{ expiresIn: JWT_EXPIRES_IN as jwt.SignOptions['expiresIn'] }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// User ohne Passwort zurückgeben
|
// Remove password from user object
|
||||||
const { password: _, ...userWithoutPassword } = user;
|
const { password: _, ...userWithoutPassword } = user;
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
user: userWithoutPassword,
|
user: userWithoutPassword,
|
||||||
token,
|
token
|
||||||
expiresIn: JWT_EXPIRES_IN
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Login error:', error);
|
console.error('Login error:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Ein Fehler ist beim Login aufgetreten' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const register = async (req: Request, res: Response): Promise<void> => {
|
export const getCurrentUser = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { email, password, name, role = 'user' } = req.body;
|
const jwtUser = (req as any).user as JWTPayload;
|
||||||
|
if (!jwtUser?.id) {
|
||||||
if (!email || !password || !name) {
|
return res.status(401).json({ error: 'Nicht authentifiziert' });
|
||||||
res.status(400).json({ error: 'Email, password and name are required' });
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user already exists
|
const user = await db.get<User>(
|
||||||
const existingUser = await db.get<any>(
|
'SELECT id, email, name, role, phone, department FROM users WHERE id = ?',
|
||||||
|
[jwtUser.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return res.status(404).json({ error: 'Benutzer nicht gefunden' });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ user });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get current user error:', error);
|
||||||
|
res.status(500).json({ error: 'Ein Fehler ist beim Abrufen des Benutzers aufgetreten' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validateToken = async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const token = req.headers.authorization?.split(' ')[1];
|
||||||
|
if (!token) {
|
||||||
|
return res.status(401).json({ error: 'Kein Token vorhanden' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your-secret-key') as JWTPayload;
|
||||||
|
|
||||||
|
// Verify that the decoded token has the required fields
|
||||||
|
if (!decoded.id || !decoded.email || !decoded.role) {
|
||||||
|
throw new Error('Invalid token structure');
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ valid: true, user: decoded });
|
||||||
|
} catch (jwtError) {
|
||||||
|
return res.status(401).json({ valid: false, error: 'Ungültiger Token' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Token validation error:', error);
|
||||||
|
res.status(500).json({ valid: false, error: 'Fehler bei der Token-Validierung' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const register = async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const { email, password, name, phone, department, role = 'user' } = req.body as RegisterRequest;
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
if (!email || !password || !name) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: 'E-Mail, Passwort und Name sind erforderlich'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if email already exists
|
||||||
|
const existingUser = await db.get<User>(
|
||||||
'SELECT id FROM users WHERE email = ?',
|
'SELECT id FROM users WHERE email = ?',
|
||||||
[email]
|
[email]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
res.status(409).json({ error: 'User already exists' });
|
return res.status(400).json({
|
||||||
return;
|
error: 'Ein Benutzer mit dieser E-Mail existiert bereits'
|
||||||
}
|
});
|
||||||
|
|
||||||
// Validate role
|
|
||||||
const validRoles = ['admin', 'instandhalter', 'user'];
|
|
||||||
if (!validRoles.includes(role)) {
|
|
||||||
res.status(400).json({ error: 'Invalid role' });
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash password
|
// Hash password
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
const userId = uuidv4();
|
|
||||||
|
|
||||||
// Create user
|
// Insert user
|
||||||
await db.run(
|
const result = await db.run(
|
||||||
'INSERT INTO users (id, email, password, name, role) VALUES (?, ?, ?, ?, ?)',
|
`INSERT INTO users (email, password, name, role, phone, department)
|
||||||
[userId, email, hashedPassword, name, role]
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||||
|
[email, hashedPassword, name, role, phone, department]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generate token
|
if (!result.lastID) {
|
||||||
const token = jwt.sign(
|
throw new Error('Benutzer konnte nicht erstellt werden');
|
||||||
{
|
}
|
||||||
userId,
|
|
||||||
email,
|
// Get created user
|
||||||
role
|
const newUser = await db.get<User>(
|
||||||
},
|
'SELECT id, email, name, role, phone, department FROM users WHERE id = ?',
|
||||||
JWT_SECRET as jwt.Secret,
|
[result.lastID]
|
||||||
{ expiresIn: JWT_EXPIRES_IN as jwt.SignOptions['expiresIn'] }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Return user without password
|
res.status(201).json({ user: newUser });
|
||||||
const user = {
|
|
||||||
id: userId,
|
|
||||||
email,
|
|
||||||
name,
|
|
||||||
role,
|
|
||||||
createdAt: new Date().toISOString()
|
|
||||||
};
|
|
||||||
|
|
||||||
res.status(201).json({
|
|
||||||
user,
|
|
||||||
token,
|
|
||||||
expiresIn: JWT_EXPIRES_IN
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Registration error:', error);
|
console.error('Registration error:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({
|
||||||
|
error: 'Fehler bei der Registrierung'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logout = async (req: AuthRequest, res: Response): Promise<void> => {
|
export const logout = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
// Bei JWT gibt es keinen Server-side logout, aber wir können den Token client-seitig entfernen
|
// Note: Since we're using JWTs, we don't need to do anything server-side
|
||||||
res.json({ message: 'Logged out successfully' });
|
// The client should remove the token from storage
|
||||||
|
res.json({ message: 'Erfolgreich abgemeldet' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Logout error:', error);
|
console.error('Logout error:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({
|
||||||
}
|
error: 'Fehler beim Abmelden'
|
||||||
};
|
});
|
||||||
|
|
||||||
export const getCurrentUser = async (req: AuthRequest, res: Response): Promise<void> => {
|
|
||||||
try {
|
|
||||||
const userId = req.user?.userId;
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
res.status(401).json({ error: 'Not authenticated' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await db.get<any>(
|
|
||||||
'SELECT id, email, name, role, created_at FROM users WHERE id = ?',
|
|
||||||
[userId]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
res.status(404).json({ error: 'User not found' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json(user);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get current user error:', error);
|
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,35 +1,23 @@
|
|||||||
// backend/src/controllers/setupController.ts
|
// backend/src/controllers/setupController.ts
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcrypt';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { randomUUID } from 'crypto';
|
||||||
import { db } from '../services/databaseService.js';
|
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 {
|
||||||
// First, ensure database is properly initialized
|
const adminExists = await db.get<{ 'COUNT(*)': number }>(
|
||||||
try {
|
'SELECT COUNT(*) FROM users WHERE role = ?',
|
||||||
const adminExists = await db.get<{ count: number }>(
|
['admin']
|
||||||
'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({
|
res.status(500).json({
|
||||||
error: 'Internal server error',
|
error: 'Internal server error during setup check'
|
||||||
needsSetup: true
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -37,66 +25,58 @@ export const checkSetupStatus = async (req: Request, res: Response): Promise<voi
|
|||||||
export const setupAdmin = async (req: Request, res: Response): Promise<void> => {
|
export const setupAdmin = async (req: Request, res: Response): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
// Check if admin already exists
|
// Check if admin already exists
|
||||||
const adminExists = await db.get<{ count: number }>(
|
const adminExists = await db.get<{ 'COUNT(*)': number }>(
|
||||||
'SELECT COUNT(*) as count FROM users WHERE role = ?',
|
'SELECT COUNT(*) FROM users WHERE role = ?',
|
||||||
['admin']
|
['admin']
|
||||||
);
|
);
|
||||||
|
|
||||||
if (adminExists && adminExists.count > 0) {
|
if (adminExists && adminExists['COUNT(*)'] > 0) {
|
||||||
res.status(400).json({ error: 'Admin user already exists' });
|
res.status(400).json({ error: 'Admin existiert bereits' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { email, password, name, phone, department } = req.body;
|
const { password, name, phone, department } = req.body;
|
||||||
|
const email = 'admin@instandhaltung.de'; // Fixed admin email
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
if (!email || !password || !name) {
|
if (!password || !name) {
|
||||||
res.status(400).json({ error: 'Email, password, and name are required' });
|
res.status(400).json({ error: 'Passwort und Name sind erforderlich' });
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email format validation
|
|
||||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
||||||
if (!emailRegex.test(email)) {
|
|
||||||
res.status(400).json({ error: 'Invalid email format' });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Password length validation
|
// Password length validation
|
||||||
if (password.length < 6) {
|
if (password.length < 6) {
|
||||||
res.status(400).json({ error: 'Password must be at least 6 characters long' });
|
res.status(400).json({ error: 'Das Passwort muss mindestens 6 Zeichen lang sein' });
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if email already exists
|
|
||||||
const existingUser = await db.get<{ id: string }>(
|
|
||||||
'SELECT id FROM users WHERE email = ?',
|
|
||||||
[email]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingUser) {
|
|
||||||
res.status(409).json({ error: 'Email already exists' });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash password
|
// Hash password
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
const adminId = uuidv4();
|
const adminId = randomUUID();
|
||||||
|
|
||||||
// Create admin user
|
try {
|
||||||
await db.run(
|
// Create admin user
|
||||||
`INSERT INTO users (id, email, password, name, role, phone, department, is_active)
|
await db.run(
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
`INSERT INTO users (id, email, password, name, role, phone, department, is_active)
|
||||||
[adminId, email, hashedPassword, name, 'admin', phone || null, department || null, true]
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
);
|
[adminId, email, hashedPassword, name, 'admin', phone || null, department || null, true]
|
||||||
|
);
|
||||||
|
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
message: 'Admin user created successfully',
|
success: true,
|
||||||
userId: adminId,
|
message: 'Admin erfolgreich erstellt',
|
||||||
email: email
|
email: email
|
||||||
});
|
});
|
||||||
|
} catch (dbError) {
|
||||||
|
console.error('Database error during admin creation:', dbError);
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Fehler beim Erstellen des Admin-Accounts'
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in setup:', error);
|
console.error('Error in setup:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({
|
||||||
|
error: 'Ein unerwarteter Fehler ist aufgetreten'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,12 +1,22 @@
|
|||||||
// backend/src/routes/auth.ts
|
// backend/src/routes/auth.ts
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { login, register, logout, getCurrentUser } from '../controllers/authController.js';
|
import {
|
||||||
|
login,
|
||||||
|
register,
|
||||||
|
logout,
|
||||||
|
getCurrentUser,
|
||||||
|
validateToken
|
||||||
|
} from '../controllers/authController.js';
|
||||||
import { authMiddleware } from '../middleware/auth.js';
|
import { authMiddleware } from '../middleware/auth.js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
// Public routes
|
||||||
router.post('/login', login);
|
router.post('/login', login);
|
||||||
router.post('/register', register);
|
router.post('/register', register);
|
||||||
|
router.get('/validate', validateToken);
|
||||||
|
|
||||||
|
// Protected routes (require authentication)
|
||||||
router.post('/logout', authMiddleware, logout);
|
router.post('/logout', authMiddleware, logout);
|
||||||
router.get('/me', authMiddleware, getCurrentUser);
|
router.get('/me', authMiddleware, getCurrentUser);
|
||||||
|
|
||||||
|
|||||||
@@ -42,18 +42,13 @@ app.get('/api/initial-setup', async (req: any, res: any) => {
|
|||||||
try {
|
try {
|
||||||
const { db } = await import('./services/databaseService.js');
|
const { db } = await import('./services/databaseService.js');
|
||||||
|
|
||||||
// Define proper interface for the result
|
const adminExists = await db.get<{ 'COUNT(*)': number }>(
|
||||||
interface AdminCountResult {
|
'SELECT COUNT(*) FROM users WHERE role = ?',
|
||||||
count: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminExists = await db.get<AdminCountResult>(
|
|
||||||
'SELECT COUNT(*) as count FROM users WHERE role = ?',
|
|
||||||
['admin']
|
['admin']
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
needsInitialSetup: !adminExists || adminExists.count === 0
|
needsInitialSetup: !adminExists || adminExists['COUNT(*)'] === 0
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error checking initial setup:', error);
|
console.error('Error checking initial setup:', error);
|
||||||
@@ -61,23 +56,29 @@ app.get('/api/initial-setup', async (req: any, res: any) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start server
|
// Initialize the application
|
||||||
app.listen(PORT, async () => {
|
const initializeApp = async () => {
|
||||||
console.log('🎉 BACKEND STARTED SUCCESSFULLY!');
|
|
||||||
console.log(`📍 Port: ${PORT}`);
|
|
||||||
console.log(`📍 Health: http://localhost:${PORT}/api/health`);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await initializeDatabase();
|
await initializeDatabase();
|
||||||
console.log('✅ Database initialized successfully');
|
console.log('✅ Database initialized successfully');
|
||||||
|
|
||||||
await setupDefaultTemplate();
|
await setupDefaultTemplate();
|
||||||
console.log('✅ Default template checked/created');
|
console.log('✅ Default template checked/created');
|
||||||
|
|
||||||
|
// Start server only after successful initialization
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log('🎉 BACKEND STARTED SUCCESSFULLY!');
|
||||||
|
console.log(`📍 Port: ${PORT}`);
|
||||||
|
console.log(`📍 Health: http://localhost:${PORT}/api/health`);
|
||||||
|
console.log('');
|
||||||
|
console.log(`🔧 Setup ready at: http://localhost:${PORT}/api/setup/status`);
|
||||||
|
console.log('📝 Create your admin account on first launch');
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error during initialization:', error);
|
console.error('❌ Error during initialization:', error);
|
||||||
|
process.exit(1); // Exit if initialization fails
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
console.log('');
|
// Start the application
|
||||||
console.log(`🔧 Setup ready at: http://localhost:${PORT}/api/setup/status`);
|
initializeApp();
|
||||||
console.log('📝 Create your admin account on first launch');
|
|
||||||
});
|
|
||||||
@@ -32,11 +32,11 @@ class Database {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(sql: string, params: any[] = []): Promise<void> {
|
async run(sql: string, params: any[] = []): Promise<{ lastID?: number }> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.db.run(sql, params, (err) => {
|
this.db.run(sql, params, function(err) {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
else resolve();
|
else resolve({ lastID: this.lastID });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user