const sqlite3 = require('sqlite3').verbose(); const path = require('path'); const bcrypt = require('bcryptjs'); const dbPath = process.env.DB_PATH || path.join(__dirname, '../data/database.sqlite'); const db = new sqlite3.Database(dbPath); console.log('Using database at', dbPath); function bootstrapInitialAdmin() { const username = process.env.INITIAL_ADMIN_USERNAME; const password = process.env.INITIAL_ADMIN_PASSWORD; const passwordHash = process.env.INITIAL_ADMIN_PASSWORD_HASH || (password ? bcrypt.hashSync(password, 10) : null); if (!username && !passwordHash) { return; } if (!username || !passwordHash) { console.warn('Set INITIAL_ADMIN_USERNAME together with INITIAL_ADMIN_PASSWORD_HASH to bootstrap an admin.'); return; } db.get('SELECT id FROM users WHERE username = ?', [username], (err, row) => { if (err || row) return; db.run( 'INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)', [username, passwordHash, 'admin'], (insertErr) => { if (insertErr) { console.error('Failed to create initial admin:', insertErr.message); return; } console.log(`Initial admin created: ${username}`); } ); }); db.get('SELECT id, role FROM users WHERE username = ?', [username], (err, row) => { if (err || !row || row.role === 'admin') return; db.run('UPDATE users SET role = ? WHERE id = ?', ['admin', row.id], (updateErr) => { if (updateErr) { console.error('Failed to promote initial admin:', updateErr.message); return; } console.log(`Initial admin promoted: ${username}`); }); }); } function runMigrations(migrations, index = 0) { if (index >= migrations.length) { bootstrapInitialAdmin(); return; } migrations[index](() => runMigrations(migrations, index + 1)); } db.serialize(() => { // Users: mit created_at fuer Client-Ablauf (30 Tage) db.run(`CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'client', created_at DATETIME DEFAULT CURRENT_TIMESTAMP )`); // Migration: Spalten hinzufuegen falls Tabelle schon existiert (alte DB ohne role/created_at). // SQLite erlaubt CURRENT_TIMESTAMP nicht als DEFAULT bei ALTER TABLE, deshalb wird created_at // ohne Default angelegt und danach fuer bestehende Nutzer befuellt. db.all(`PRAGMA table_info(users)`, (err, columns) => { if (err) { console.error('User-Migration fehlgeschlagen:', err.message); return; } const columnNames = new Set(columns.map((column) => column.name)); const migrations = []; if (!columnNames.has('role')) { migrations.push((done) => db.run(`ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'client'`, (alterErr) => { if (alterErr) { console.error('Migration role fehlgeschlagen:', alterErr.message); done(); return; } // Alte Admins (die einzigen User vor dem Update) als admin markieren. db.run(`UPDATE users SET role = 'admin' WHERE id = 1`, () => { console.log('Migration: role-Spalte hinzugefuegt, User ID 1 als admin gesetzt'); done(); }); })); } if (!columnNames.has('created_at')) { migrations.push((done) => db.run(`ALTER TABLE users ADD COLUMN created_at DATETIME`, (alterErr) => { if (alterErr) { console.error('Migration created_at fehlgeschlagen:', alterErr.message); done(); return; } db.run(`UPDATE users SET created_at = datetime('now') WHERE created_at IS NULL`, () => { console.log('Migration: created_at-Spalte hinzugefuegt'); done(); }); })); } else { migrations.push((done) => db.run(`UPDATE users SET created_at = datetime('now') WHERE created_at IS NULL`, done)); } runMigrations(migrations); }); // Ordner-Zuweisung (neu) db.run(`CREATE TABLE IF NOT EXISTS user_folders ( user_id INTEGER, folder_name TEXT, FOREIGN KEY(user_id) REFERENCES users(id), UNIQUE(user_id, folder_name) )`); // Alte Tabelle behalten fuer Kompatibilitaet, aber nicht mehr nutzen db.run(`CREATE TABLE IF NOT EXISTS user_images ( user_id INTEGER, image_name TEXT, FOREIGN KEY(user_id) REFERENCES users(id), UNIQUE(user_id, image_name) )`); }); module.exports = db;