| const { Pool } = require('pg'); |
| const fs = require('fs'); |
| const path = require('path'); |
|
|
| |
| |
| |
| |
|
|
| class DatabaseManager { |
| constructor(logPath) { |
| this.logPath = logPath; |
| this.useDB = !!process.env.DATABASE_URL; |
| this.pool = null; |
|
|
| if (this.useDB) { |
| console.log('[Z374-DB] 🗄️ Database URL detected. Initializing PostgreSQL pool...'); |
| this.pool = new Pool({ |
| connectionString: process.env.DATABASE_URL, |
| ssl: { rejectUnauthorized: false } |
| }); |
| this.initDB(); |
| } else { |
| console.log('[Z374-DB] 📁 No database detected. Falling back to local file logging.'); |
| } |
| } |
|
|
| async initDB() { |
| try { |
| const client = await this.pool.connect(); |
| await client.query(` |
| CREATE TABLE IF NOT EXISTS audit_logs ( |
| id SERIAL PRIMARY KEY, |
| timestamp TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, |
| action TEXT, |
| details JSONB |
| ); |
| `); |
| client.release(); |
| console.log('[Z374-DB] ✅ Database schema verified.'); |
| } catch (e) { |
| console.error('[Z374-DB] ❌ Database initialization failed:', e.message); |
| this.useDB = false; |
| } |
| } |
|
|
| async log(action, details) { |
| const timestamp = new Date().toISOString(); |
| const entry = `[${timestamp}] ACTION: ${action} | DETAILS: ${JSON.stringify(details)}\n`; |
|
|
| |
| console.log(`[AUDIT] ${action}:`, details); |
|
|
| |
| if (this.useDB) { |
| try { |
| await this.pool.query( |
| 'INSERT INTO audit_logs (action, details) VALUES ($1, $2)', |
| [action, details] |
| ); |
| } catch (e) { |
| console.error('[Z374-DB] ⚠️ DB log failed, falling back to file:', e.message); |
| } |
| } |
|
|
| |
| try { |
| fs.appendFileSync(this.logPath, entry); |
| } catch (e) { |
| console.error('[Z374-DB] ⚠️ File log failed:', e.message); |
| } |
| } |
|
|
| async getLogs(limit = 50) { |
| if (this.useDB) { |
| try { |
| const res = await this.pool.query( |
| 'SELECT timestamp, action, details FROM audit_logs ORDER BY timestamp DESC LIMIT $1', |
| [limit] |
| ); |
| return res.rows.map(row => |
| `[${row.timestamp.toISOString()}] ACTION: ${row.action} | DETAILS: ${JSON.stringify(row.details)}` |
| ); |
| } catch (e) { |
| console.error('[Z374-DB] ⚠️ DB fetch failed:', e.message); |
| } |
| } |
|
|
| |
| if (!fs.existsSync(this.logPath)) return []; |
| return fs.readFileSync(this.logPath, 'utf8') |
| .split('\n') |
| .filter(l => l) |
| .reverse() |
| .slice(0, limit); |
| } |
|
|
| async purge() { |
| if (this.useDB) { |
| try { |
| await this.pool.query('DELETE FROM audit_logs'); |
| } catch (e) { |
| console.error('[Z374-DB] ⚠️ DB purge failed:', e.message); |
| } |
| } |
| fs.writeFileSync(this.logPath, `[${new Date().toISOString()}] AUDIT_PURGE: Log cleared by operator.\n`); |
| } |
| } |
|
|
| module.exports = DatabaseManager; |
|
|