feat: Version 1.10.0 — DB-Zugriff auf PHP-Bridge (DB4js_all.php) umgestellt
- lib/db.ts entfernt, mysql2-Abhängigkeit gestrichen - lib/phpdb.ts: HTTP-Client für alle DB-Operationen via DB4js_all.php - Alle API-Routen und Server Actions auf phpdb.ts umgestellt - compose.yml / docker-compose.prod.yml: MySQL/phpMyAdmin-Container entfernt - app/api/DB4js_all.php/route.ts: Proxy für Statistik-AJAX-Calls - Statistik-Grafik liest ab 2026 live aus logbuch statt StatistikJahre - PHP 7.3-Kompatibilität: str_contains → strpos Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+6
-19
@@ -2,15 +2,14 @@ import { createWriteStream, mkdirSync, unlinkSync } from 'fs';
|
||||
import { createGzip } from 'zlib';
|
||||
import { join } from 'path';
|
||||
import { spawn } from 'child_process';
|
||||
import { getPool } from './db';
|
||||
import { getBackupData } from './phpdb';
|
||||
|
||||
export function triggerBackup(): void {
|
||||
setImmediate(() => runBackup().catch((e) => console.error('[backup] Fehler:', e)));
|
||||
}
|
||||
|
||||
async function dumpToFile(filePath: string): Promise<void> {
|
||||
const dbName = process.env.DB_NAME || 'sternwarte';
|
||||
const pool = getPool();
|
||||
const { tables } = await getBackupData();
|
||||
|
||||
const gzip = createGzip();
|
||||
const file = createWriteStream(filePath);
|
||||
@@ -21,21 +20,12 @@ async function dumpToFile(filePath: string): Promise<void> {
|
||||
);
|
||||
|
||||
const now = new Date().toISOString();
|
||||
await write(`-- Führungsbuch Backup ${now}\n-- Datenbank: ${dbName} (ohne Tabelle beos)\n\nSET FOREIGN_KEY_CHECKS=0;\n\n`);
|
||||
await write(`-- Führungsbuch Backup ${now}\n-- Logbuch-Tabellen\n\nSET FOREIGN_KEY_CHECKS=0;\n\n`);
|
||||
|
||||
const [tableRows] = await pool.query('SHOW TABLES') as [Record<string, string>[], unknown];
|
||||
const tables = tableRows
|
||||
.map((r) => Object.values(r)[0])
|
||||
.filter((t) => t !== 'beos');
|
||||
|
||||
for (const table of tables) {
|
||||
const [[createRow]] = await pool.query(`SHOW CREATE TABLE \`${table}\``) as [Record<string, string>[], unknown];
|
||||
const createSql = Object.values(createRow)[1];
|
||||
|
||||
await write(`DROP TABLE IF EXISTS \`${table}\`;\n`);
|
||||
for (const { name, createSql, rows } of tables) {
|
||||
await write(`DROP TABLE IF EXISTS \`${name}\`;\n`);
|
||||
await write(`${createSql};\n\n`);
|
||||
|
||||
const [rows] = await pool.query(`SELECT * FROM \`${table}\``) as [Record<string, unknown>[], unknown];
|
||||
if (rows.length > 0) {
|
||||
const cols = Object.keys(rows[0]).map((c) => `\`${c}\``).join(', ');
|
||||
const batchSize = 200;
|
||||
@@ -45,11 +35,10 @@ async function dumpToFile(filePath: string): Promise<void> {
|
||||
'(' + Object.values(row).map((v) => {
|
||||
if (v === null) return 'NULL';
|
||||
if (typeof v === 'number') return String(v);
|
||||
if (v instanceof Date) return `'${v.toISOString().slice(0, 19).replace('T', ' ')}'`;
|
||||
return `'${String(v).replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
||||
}).join(', ') + ')'
|
||||
).join(',\n ');
|
||||
await write(`INSERT INTO \`${table}\` (${cols}) VALUES\n ${values};\n`);
|
||||
await write(`INSERT INTO \`${name}\` (${cols}) VALUES\n ${values};\n`);
|
||||
}
|
||||
await write('\n');
|
||||
}
|
||||
@@ -99,7 +88,6 @@ async function runBackup(): Promise<void> {
|
||||
'-o', 'ConnectTimeout=15',
|
||||
];
|
||||
|
||||
// Zielverzeichnis auf Remote anlegen falls nicht vorhanden
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const ssh = spawn('ssh', [...sshOpts, sshHost, `mkdir -p ${remotePath}`]);
|
||||
ssh.on('error', reject);
|
||||
@@ -118,7 +106,6 @@ async function runBackup(): Promise<void> {
|
||||
|
||||
console.log(`[backup] ${filename} → ${sshHost}:${remotePath}`);
|
||||
|
||||
// Backups älter als 30 Tage auf Remote löschen
|
||||
await new Promise<void>((resolve) => {
|
||||
const ssh = spawn('ssh', [
|
||||
...sshOpts, sshHost,
|
||||
|
||||
Reference in New Issue
Block a user