This commit is contained in:
Carsten Graf
2026-01-26 17:58:12 +01:00
parent dfbc7d8bbc
commit ca48cdf78f
9 changed files with 971 additions and 178 deletions

View File

@@ -2,28 +2,218 @@ const sqlite3 = require('sqlite3').verbose();
const bcrypt = require('bcryptjs');
const path = require('path');
const fs = require('fs');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
const dbPath = path.join(__dirname, 'stundenerfassung.db');
console.log('🔄 Setze Datenbank zurück...\n');
// Datenbank schließen falls offen
let db = null;
let savedLdapConfig = [];
try {
// Prüfe ob Datenbank existiert
if (fs.existsSync(dbPath)) {
console.log('📁 Datenbankdatei gefunden, lösche sie...');
fs.unlinkSync(dbPath);
console.log('✅ Datenbankdatei gelöscht\n');
} else {
console.log(' Datenbankdatei existiert nicht, erstelle neue...\n');
// Hilfsfunktion zum Warten
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Funktion zum Prüfen und Beenden von Prozessen auf bestimmten Ports
async function checkAndKillPorts(ports) {
const killedProcesses = [];
for (const port of ports) {
try {
// Prüfe, ob der Port belegt ist (Windows)
const { stdout } = await execAsync(`netstat -ano | findstr :${port}`);
if (stdout) {
// Extrahiere PID aus der Ausgabe
const lines = stdout.trim().split('\n');
const pids = new Set();
for (const line of lines) {
const parts = line.trim().split(/\s+/);
if (parts.length > 0) {
const pid = parts[parts.length - 1];
if (pid && !isNaN(pid)) {
pids.add(pid);
}
}
}
// Beende alle Prozesse, die den Port verwenden
for (const pid of pids) {
try {
console.log(`🛑 Beende Prozess ${pid} auf Port ${port}...`);
await execAsync(`taskkill /F /PID ${pid}`);
killedProcesses.push({ port, pid });
console.log(`✅ Prozess ${pid} beendet`);
} catch (err) {
// Prozess könnte bereits beendet sein oder keine Berechtigung
if (!err.message.includes('not found') && !err.message.includes('not running')) {
console.log(`⚠️ Konnte Prozess ${pid} nicht beenden: ${err.message}`);
}
}
}
}
} catch (err) {
// Port ist nicht belegt oder netstat hat nichts gefunden
if (!err.message.includes('findstr') && !err.message.includes('not found')) {
// Ignoriere Fehler, wenn der Port nicht belegt ist
}
}
}
if (killedProcesses.length > 0) {
console.log(`\n${killedProcesses.length} Prozess(e) beendet\n`);
// Warte kurz, damit die Ports freigegeben werden
await sleep(1000);
} else {
console.log(' Keine Prozesse auf Ports 3333 oder 3334 gefunden\n');
}
return killedProcesses.length > 0;
}
// Neue Datenbank erstellen
db = new sqlite3.Database(dbPath);
// Funktion zum Löschen der Datenbankdatei mit Retry-Logik (async)
async function deleteDatabaseFile(retries = 10, initialDelay = 500) {
if (!fs.existsSync(dbPath)) {
return true;
}
for (let i = 0; i < retries; i++) {
try {
fs.unlinkSync(dbPath);
console.log('✅ Datenbankdatei gelöscht\n');
return true;
} catch (err) {
if (err.code === 'EBUSY' && i < retries - 1) {
// Exponentielle Backoff-Strategie
const waitTime = initialDelay * Math.pow(2, i);
console.log(`⏳ Datenbankdatei noch gesperrt (Versuch ${i + 1}/${retries}), warte ${waitTime}ms...`);
await sleep(waitTime);
continue;
}
if (i === retries - 1) {
console.error(`❌ Konnte Datenbankdatei nach ${retries} Versuchen nicht löschen.`);
console.error(' Bitte stellen Sie sicher, dass alle Prozesse geschlossen sind, die die Datenbank verwenden.');
return false;
}
throw err;
}
}
return false;
}
db.serialize(() => {
// Promise-Wrapper für sqlite3 Database.all
function dbAll(db, query, params = []) {
return new Promise((resolve, reject) => {
db.all(query, params, (err, rows) => {
if (err) reject(err);
else resolve(rows);
});
});
}
// Promise-Wrapper für sqlite3 Database.close
function dbClose(db) {
return new Promise((resolve, reject) => {
db.close((err) => {
if (err) reject(err);
else resolve();
});
});
}
// Promise-Wrapper für sqlite3 Database-Konstruktor
function openDatabase(path, mode = sqlite3.OPEN_READONLY) {
return new Promise((resolve, reject) => {
const db = new sqlite3.Database(path, mode, (err) => {
if (err) reject(err);
else resolve(db);
});
});
}
// Hauptfunktion als async
async function resetDatabase() {
try {
// Prüfe und beende Prozesse auf Ports 3333 und 3334
console.log('🔍 Prüfe auf laufende Server auf Ports 3333 und 3334...\n');
await checkAndKillPorts([3333, 3334]);
// Prüfe ob Datenbank existiert und sichere ldap_config Daten
if (fs.existsSync(dbPath)) {
console.log('📁 Datenbankdatei gefunden...');
try {
// Temporäre Datenbankverbindung zum Lesen der ldap_config
const tempDb = await openDatabase(dbPath, sqlite3.OPEN_READONLY);
try {
// Lese ldap_config Daten
const rows = await dbAll(tempDb, 'SELECT * FROM ldap_config');
if (rows && rows.length > 0) {
savedLdapConfig = rows;
console.log(`💾 ${rows.length} LDAP-Konfiguration(en) gesichert\n`);
} else {
console.log(' Keine LDAP-Konfiguration vorhanden\n');
}
} catch (err) {
console.log(' ldap_config Tabelle existiert nicht oder konnte nicht gelesen werden\n');
}
// Schließe die temporäre Datenbank
await dbClose(tempDb);
// Warte etwas länger, damit die Datenbank wirklich geschlossen ist
await sleep(500);
// Datenbank löschen
const success = await deleteDatabaseFile();
if (success) {
createNewDatabase();
} else {
console.error('❌ Konnte Datenbankdatei nicht löschen');
process.exit(1);
}
} catch (err) {
console.log('⚠️ Konnte Datenbank nicht öffnen zum Lesen, fahre fort...\n');
// Datenbank löschen
const success = await deleteDatabaseFile();
if (success) {
createNewDatabase();
} else {
console.error('❌ Konnte Datenbankdatei nicht löschen');
process.exit(1);
}
}
} else {
console.log(' Datenbankdatei existiert nicht, erstelle neue...\n');
createNewDatabase();
}
} catch (error) {
console.error('❌ Fehler beim Zurücksetzen der Datenbank:', error);
if (db) {
db.close();
}
process.exit(1);
}
}
// Starte das Reset
resetDatabase().catch((error) => {
console.error('❌ Unerwarteter Fehler:', error);
process.exit(1);
});
function createNewDatabase() {
// Neue Datenbank erstellen
db = new sqlite3.Database(dbPath);
db.serialize(() => {
console.log('📊 Erstelle Tabellen...\n');
// Benutzer-Tabelle
@@ -126,7 +316,42 @@ try {
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`, (err) => {
if (err) console.error('Fehler bei ldap_config:', err);
else console.log('✅ Tabelle ldap_config erstellt');
else {
console.log('✅ Tabelle ldap_config erstellt');
// Stelle gesicherte LDAP-Konfiguration wieder her
if (savedLdapConfig.length > 0) {
console.log('🔄 Stelle LDAP-Konfiguration wieder her...');
savedLdapConfig.forEach((config) => {
db.run(`INSERT INTO ldap_config (
id, enabled, url, bind_dn, bind_password, base_dn,
user_search_filter, username_attribute, firstname_attribute,
lastname_attribute, sync_interval, last_sync, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
config.id,
config.enabled,
config.url,
config.bind_dn,
config.bind_password,
config.base_dn,
config.user_search_filter,
config.username_attribute,
config.firstname_attribute,
config.lastname_attribute,
config.sync_interval,
config.last_sync,
config.created_at,
config.updated_at
], (err) => {
if (err) {
console.error('Fehler beim Wiederherstellen der LDAP-Konfiguration:', err);
} else {
console.log(`✅ LDAP-Konfiguration (ID: ${config.id}) wiederhergestellt`);
}
});
});
}
}
});
// LDAP-Sync-Log-Tabelle
@@ -217,11 +442,4 @@ try {
}, 500);
});
});
} catch (error) {
console.error('❌ Fehler beim Zurücksetzen der Datenbank:', error);
if (db) {
db.close();
}
process.exit(1);
}