neue db verbindung

This commit is contained in:
cay 2026-03-27 16:39:28 +00:00
parent 6f5c9a28a1
commit 16fb18f9e6
3 changed files with 224 additions and 107 deletions

View File

@ -1 +1 @@
4PsgCvoOJLNXPpxOHOvm+KbVYz3pNxg8oOXO7zoH3MPffEhZLI7i5qf3o6oqZDI04us8xSSz9j3KIN+Atno/VFlYzSoq3ki1F+WSTz37LfcE3goPqhm6UaH8c9lHdulemH9tqgGq/DxgbKaup5t/ZJnLseaHHpdyTZok1jWULN0nlDuL/HvVVtqw5sboPqU=
MgmDGURt7NfYtetWb79ghkifQA6ztKwK/7Hl1BNBG2QA+kIbDtHM+1R8XPRiTtDtBHPo+T8UmzvmOuztdphLvMnMW7/Jlqo+VAg4mbYDRLz8WQja5KBmIQJf1eF5riHPu0zQDjY7VU1AX2mzR8xfWrB+CngkagEHXv7OsigsRmxlrB3oGTd6GY6PeAYq3jTblo4kjDDg6GWeDJoF

View File

@ -3,45 +3,76 @@ const router = express.Router();
const mysql = require("mysql2/promise");
// ✅ nutzt deinen bestehenden config-manager (NICHT utils/config!)
const { configExists, saveConfig } = require("../config-manager");
const { configExists, loadConfig, saveConfig } = require("../config-manager");
// ✅ DB + Session Reset (wie in deiner app.js)
const db = require("../db");
const { resetSessionStore } = require("../config/session");
/**
* Setup darf nur laufen, wenn config.enc NICHT existiert
* (sonst könnte jeder die DB später überschreiben)
* Setup ist immer erreichbar auch wenn config.enc schon existiert.
* So kann die DB-Verbindung jederzeit korrigiert werden.
* Schutz: Nur wenn DB bereits erreichbar ist UND User eingeloggt ist blockieren.
*/
function blockIfInstalled(req, res, next) {
if (configExists()) {
return res.redirect("/");
}
// Immer durchlassen Setup muss auch zur Korrektur nutzbar sein
next();
}
/**
* Setup Form anzeigen
* Setup Form anzeigen vorhandene Werte aus config.enc als Defaults laden
*/
router.get("/", blockIfInstalled, (req, res) => {
// Bestehende Config als Vorausfüllung laden (Passwort bleibt leer)
let existing = {};
try {
if (configExists()) {
const cfg = loadConfig();
existing = cfg?.db || {};
}
} catch (e) {
existing = {};
}
return res.render("setup/index", {
title: "Erstinstallation",
title: configExists() ? "DB-Verbindung ändern" : "Erstinstallation",
isUpdate: configExists(),
defaults: {
host: "127.0.0.1",
port: 3306,
user: "",
password: "",
name: "",
host: existing.host || "85.215.63.122",
port: existing.port || 3306,
user: existing.user || "",
password: "", // Passwort aus Sicherheitsgründen nie vorausfüllen
name: existing.name || "",
},
});
});
/**
* Passwort auflösen: wenn leer altes Passwort aus config.enc nehmen
*/
function resolvePassword(inputPassword) {
if (inputPassword && inputPassword.trim() !== "") {
return inputPassword;
}
// Passwort-Feld leer → altes Passwort aus bestehender Config beibehalten
try {
if (configExists()) {
const old = loadConfig();
return old?.db?.password || "";
}
} catch (e) {
/* ignore */
}
return "";
}
/**
* Verbindung testen (AJAX)
*/
router.post("/test", blockIfInstalled, async (req, res) => {
try {
const { host, port, user, password, name } = req.body;
const { host, port, user, name } = req.body;
const password = resolvePassword(req.body.password);
if (!host || !user || !name) {
return res.status(400).json({
@ -51,12 +82,12 @@ router.post("/test", blockIfInstalled, async (req, res) => {
}
const connection = await mysql.createConnection({
host,
host: host.trim(),
port: Number(port || 3306),
user,
user: user.trim(),
password,
database: name,
connectTimeout: 5000,
database: name.trim(),
connectTimeout: 6000,
});
await connection.query("SELECT 1");
@ -76,7 +107,9 @@ router.post("/test", blockIfInstalled, async (req, res) => {
*/
router.post("/", blockIfInstalled, async (req, res) => {
try {
const { host, port, user, password, name } = req.body;
const { host, port, user, name } = req.body;
// Passwort: leer = altes Passwort beibehalten
const password = resolvePassword(req.body.password);
if (!host || !user || !name) {
req.session.flash = req.session.flash || [];
@ -88,41 +121,50 @@ router.post("/", blockIfInstalled, async (req, res) => {
}
// ✅ Verbindung testen bevor speichern
const connection = await mysql.createConnection({
host,
port: Number(port || 3306),
user,
password,
database: name,
connectTimeout: 5000,
});
let connection;
try {
connection = await mysql.createConnection({
host: host.trim(),
port: Number(port || 3306),
user: user.trim(),
password,
database: name.trim(),
connectTimeout: 6000,
});
await connection.query("SELECT 1");
await connection.end();
} catch (connErr) {
req.session.flash = req.session.flash || [];
req.session.flash.push({
type: "danger",
message: "❌ DB-Verbindung fehlgeschlagen: " + connErr.message,
});
return res.redirect("/setup");
}
await connection.query("SELECT 1");
await connection.end();
// ✅ speichern
// ✅ In config.enc speichern
saveConfig({
db: {
host,
host: host.trim(),
port: Number(port || 3306),
user,
user: user.trim(),
password,
name,
name: name.trim(),
},
});
// ✅ DB Pool neu starten (damit neue config sofort aktiv ist)
// ✅ DB Pool neu initialisieren (neue Config sofort aktiv)
if (typeof db.resetPool === "function") {
db.resetPool();
}
// ✅ Session Store neu starten
// ✅ Session Store neu initialisieren
resetSessionStore();
req.session.flash = req.session.flash || [];
req.session.flash.push({
type: "success",
message: "✅ Setup abgeschlossen. Du kannst dich jetzt einloggen.",
message: "✅ DB-Verbindung gespeichert. Du kannst dich jetzt einloggen.",
});
return res.redirect("/login");

View File

@ -6,105 +6,177 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
font-family: Arial, sans-serif;
background: #f5f5f5;
padding: 20px;
background: #f0f2f5;
padding: 40px 20px;
min-height: 100vh;
display: flex;
align-items: flex-start;
justify-content: center;
}
.card {
max-width: 560px;
margin: 0 auto;
width: 100%;
max-width: 580px;
background: white;
padding: 20px;
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
padding: 32px;
border-radius: 14px;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.10);
}
.card h2 {
margin: 0 0 6px 0;
font-size: 22px;
color: #111827;
}
.card p {
margin: 0 0 24px 0;
color: #6b7280;
font-size: 14px;
}
.badge-update {
display: inline-block;
background: #fef3c7;
color: #92400e;
font-size: 12px;
font-weight: 600;
padding: 3px 10px;
border-radius: 20px;
margin-bottom: 16px;
border: 1px solid #fcd34d;
}
label {
display: block;
margin-top: 12px;
margin-top: 16px;
margin-bottom: 5px;
font-weight: 600;
font-size: 13px;
color: #374151;
}
input {
width: 100%;
padding: 10px;
margin-top: 6px;
padding: 10px 12px;
border-radius: 8px;
border: 1px solid #ddd;
border: 1px solid #d1d5db;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}
input:focus {
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37,99,235,0.12);
}
.row {
display: flex;
gap: 12px;
}
.row > div {
flex: 1;
.row > div { flex: 1; }
.btn-row {
display: flex;
gap: 10px;
margin-top: 24px;
flex-wrap: wrap;
}
button {
margin-top: 16px;
padding: 10px 14px;
padding: 10px 18px;
border: 0;
border-radius: 10px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
transition: opacity 0.2s;
}
.btn-primary {
background: #2563eb;
color: white;
}
.btn-secondary {
background: #111827;
color: white;
}
button:hover { opacity: 0.88; }
.btn-primary { background: #2563eb; color: white; flex: 1; }
.btn-secondary { background: #111827; color: white; }
.msg {
margin-top: 10px;
padding: 10px;
margin-top: 14px;
padding: 12px 14px;
border-radius: 10px;
font-size: 14px;
display: none;
}
.msg.ok {
background: #dcfce7;
color: #166534;
}
.msg.bad {
background: #fee2e2;
color: #991b1b;
.msg.ok { background: #dcfce7; color: #166534; border: 1px solid #86efac; }
.msg.bad { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; }
.msg.pending { background: #eff6ff; color: #1d4ed8; border: 1px solid #93c5fd; }
.divider {
border: none;
border-top: 1px solid #e5e7eb;
margin: 24px 0;
}
</style>
</head>
<body>
<div class="card">
<h2>🛠️ Erstinstallation</h2>
<p>
Bitte DB Daten eingeben. Danach wird
<code>config.enc</code> gespeichert.
</p>
<h2>🛠️ <%= title %></h2>
<form method="POST" action="/setup">
<label>DB Host</label>
<input name="host" placeholder="85.215.63.122" required />
<% if (typeof isUpdate !== 'undefined' && isUpdate) { %>
<span class="badge-update">⚠️ Bestehende Konfiguration wird überschrieben</span>
<% } %>
<label>DB Port</label>
<input name="port" placeholder="3306" value="3306" required />
<p>DB-Verbindungsdaten eingeben. Die Verbindung wird vor dem Speichern geprüft.</p>
<label>DB Benutzer</label>
<input name="user" placeholder="praxisuser" required />
<form method="POST" action="/setup" id="setupForm">
<label>DB Passwort</label>
<input name="password" type="password" required />
<div class="row">
<div>
<label for="host">DB Host</label>
<input
id="host"
name="host"
placeholder="85.215.63.122"
value="<%= defaults.host %>"
required
/>
</div>
<div style="max-width:110px">
<label for="port">Port</label>
<input
id="port"
name="port"
placeholder="3306"
value="<%= defaults.port %>"
required
/>
</div>
</div>
<label>DB Name</label>
<input name="name" placeholder="praxissoftware" required />
<label>Passwort</label>
<label for="user">DB Benutzer</label>
<input
name="password"
type="password"
value="<%= defaults.password %>"
id="user"
name="user"
placeholder="praxisuser"
value="<%= defaults.user %>"
required
/>
<button type="button" class="btn-secondary" onclick="testConnection()">
🔍 Verbindung testen
</button>
<button type="submit" class="btn-primary">
✅ Speichern & Setup abschließen
</button>
<label for="password">DB Passwort</label>
<input
id="password"
name="password"
type="password"
placeholder="<%= typeof isUpdate !== 'undefined' && isUpdate ? '(unverändert lassen = leer lassen)' : '' %>"
/>
<label for="name">DB Name</label>
<input
id="name"
name="name"
placeholder="praxissoftware"
value="<%= defaults.name %>"
required
/>
<hr class="divider" />
<div class="btn-row">
<button type="button" class="btn-secondary" onclick="testConnection()">
🔍 Verbindung testen
</button>
<button type="submit" class="btn-primary">
✅ Speichern & abschließen
</button>
</div>
<div id="msg" class="msg"></div>
</form>
@ -112,14 +184,19 @@
<script>
async function testConnection() {
const form = document.querySelector("form");
const data = new FormData(form);
const body = Object.fromEntries(data.entries());
const msg = document.getElementById("msg");
msg.className = "msg pending";
msg.style.display = "block";
msg.className = "msg";
msg.textContent = "Teste Verbindung...";
msg.textContent = "⏳ Teste Verbindung...";
// Felder einzeln auslesen (sicherer als FormData bei doppelten Namen)
const body = {
host: document.getElementById("host").value.trim(),
port: document.getElementById("port").value.trim(),
user: document.getElementById("user").value.trim(),
password: document.getElementById("password").value,
name: document.getElementById("name").value.trim(),
};
try {
const res = await fetch("/setup/test", {
@ -129,13 +206,11 @@
});
const json = await res.json();
msg.className = "msg " + (json.ok ? "ok" : "bad");
msg.textContent = json.message;
if (json.ok) msg.classList.add("ok");
else msg.classList.add("bad");
} catch (e) {
msg.textContent = "❌ Fehler: " + e.message;
msg.classList.add("bad");
msg.className = "msg bad";
msg.textContent = "❌ Netzwerkfehler: " + e.message;
}
}
</script>