Update db.js

This commit is contained in:
2026-01-09 23:12:12 +01:00
committed by GitHub
parent a6dc1d789e
commit 6aaca6adc4

View File

@@ -47,8 +47,6 @@ const dbInterface = {
return { return {
query: executeQuery, query: executeQuery,
release: () => {}, release: () => {},
// Mock transaction methods for Postgres simple wrapper
// In a real prod app, you would get a specific client from the pool here
beginTransaction: async () => {}, beginTransaction: async () => {},
commit: async () => {}, commit: async () => {},
rollback: async () => {} rollback: async () => {}
@@ -66,44 +64,47 @@ const initDb = async () => {
const TIMESTAMP_TYPE = 'TIMESTAMP'; const TIMESTAMP_TYPE = 'TIMESTAMP';
const LONG_TEXT_TYPE = DB_CLIENT === 'postgres' ? 'TEXT' : 'LONGTEXT'; // For base64 files const LONG_TEXT_TYPE = DB_CLIENT === 'postgres' ? 'TEXT' : 'LONGTEXT'; // For base64 files
const JSON_TYPE = 'JSON';
// 0. Settings Table (Global App Settings) // --- 0. SETTINGS TABLE ---
// Definizione completa per nuova installazione
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS settings ( CREATE TABLE IF NOT EXISTS settings (
id INT PRIMARY KEY, id INT PRIMARY KEY,
current_year INT, current_year INT,
smtp_config JSON ${DB_CLIENT === 'postgres' ? 'NULL' : 'NULL'}, smtp_config ${JSON_TYPE},
features JSON ${DB_CLIENT === 'postgres' ? 'NULL' : 'NULL'}, features ${JSON_TYPE},
storage_config JSON ${DB_CLIENT === 'postgres' ? 'NULL' : 'NULL'} storage_config ${JSON_TYPE},
branding ${JSON_TYPE}
) )
`); `);
// Migration: Add features column if not exists // MIGRATION: Controllo e aggiunta colonne mancanti per installazioni esistenti
try { try {
let hasFeatures = false; let cols = [];
let hasStorage = false;
if (DB_CLIENT === 'postgres') { if (DB_CLIENT === 'postgres') {
const [cols] = await connection.query("SELECT column_name FROM information_schema.columns WHERE table_name='settings'"); const [res] = await connection.query("SELECT column_name FROM information_schema.columns WHERE table_name='settings'");
hasFeatures = cols.some(c => c.column_name === 'features'); cols = res.map(c => c.column_name);
hasStorage = cols.some(c => c.column_name === 'storage_config');
} else { } else {
const [cols] = await connection.query("SHOW COLUMNS FROM settings"); const [res] = await connection.query("SHOW COLUMNS FROM settings");
hasFeatures = cols.some(c => c.Field === 'features'); cols = res.map(c => c.Field);
hasStorage = cols.some(c => c.Field === 'storage_config');
} }
if (!hasFeatures) { if (!cols.includes('features')) {
console.log('Migrating: Adding features to settings...'); console.log('Migrating: Adding features to settings...');
await connection.query("ALTER TABLE settings ADD COLUMN features JSON"); await connection.query("ALTER TABLE settings ADD COLUMN features JSON");
} }
if (!hasStorage) { if (!cols.includes('storage_config')) {
console.log('Migrating: Adding storage_config to settings...'); console.log('Migrating: Adding storage_config to settings...');
await connection.query("ALTER TABLE settings ADD COLUMN storage_config JSON"); await connection.query("ALTER TABLE settings ADD COLUMN storage_config JSON");
} }
if (!cols.includes('branding')) {
console.log('Migrating: Adding branding to settings...');
await connection.query("ALTER TABLE settings ADD COLUMN branding JSON");
}
} catch(e) { console.warn("Settings migration warning:", e.message); } } catch(e) { console.warn("Settings migration warning:", e.message); }
// 1. Condos Table // --- 1. CONDOS TABLE ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS condos ( CREATE TABLE IF NOT EXISTS condos (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -123,24 +124,24 @@ const initDb = async () => {
) )
`); `);
// Migration for condos due_day // Migration condos
try { try {
let hasDueDay = false; let cols = [];
if (DB_CLIENT === 'postgres') { if (DB_CLIENT === 'postgres') {
const [cols] = await connection.query("SELECT column_name FROM information_schema.columns WHERE table_name='condos'"); const [res] = await connection.query("SELECT column_name FROM information_schema.columns WHERE table_name='condos'");
hasDueDay = cols.some(c => c.column_name === 'due_day'); cols = res.map(c => c.column_name);
} else { } else {
const [cols] = await connection.query("SHOW COLUMNS FROM condos"); const [res] = await connection.query("SHOW COLUMNS FROM condos");
hasDueDay = cols.some(c => c.Field === 'due_day'); cols = res.map(c => c.Field);
} }
if (!hasDueDay) { if (!cols.includes('due_day')) {
console.log('Migrating: Adding due_day to condos...'); console.log('Migrating: Adding due_day to condos...');
await connection.query("ALTER TABLE condos ADD COLUMN due_day INT DEFAULT 10"); await connection.query("ALTER TABLE condos ADD COLUMN due_day INT DEFAULT 10");
} }
} catch(e) { console.warn("Condo migration warning:", e.message); } } catch(e) { console.warn("Condo migration warning:", e.message); }
// 2. Families Table // --- 2. FAMILIES TABLE ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS families ( CREATE TABLE IF NOT EXISTS families (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -157,7 +158,24 @@ const initDb = async () => {
) )
`); `);
// 3. Payments Table // Migration families
try {
let cols = [];
if (DB_CLIENT === 'postgres') {
const [res] = await connection.query("SELECT column_name FROM information_schema.columns WHERE table_name='families'");
cols = res.map(c => c.column_name);
} else {
const [res] = await connection.query("SHOW COLUMNS FROM families");
cols = res.map(c => c.Field);
}
if (!cols.includes('custom_monthly_quota')) {
console.log('Migrating: Adding custom_monthly_quota to families...');
await connection.query("ALTER TABLE families ADD COLUMN custom_monthly_quota DECIMAL(10, 2) NULL");
}
} catch(e) { console.warn("Family migration warning:", e.message); }
// --- 3. PAYMENTS TABLE ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS payments ( CREATE TABLE IF NOT EXISTS payments (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -173,7 +191,7 @@ const initDb = async () => {
) )
`); `);
// 4. Users Table // --- 4. USERS TABLE ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -189,7 +207,7 @@ const initDb = async () => {
) )
`); `);
// 5. Alerts Table // --- 5. ALERTS TABLE ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS alerts ( CREATE TABLE IF NOT EXISTS alerts (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -206,7 +224,7 @@ const initDb = async () => {
) )
`); `);
// 6. Notices Table // --- 6. NOTICES TABLE ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS notices ( CREATE TABLE IF NOT EXISTS notices (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -217,13 +235,30 @@ const initDb = async () => {
link VARCHAR(255), link VARCHAR(255),
date ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP, date ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP,
active BOOLEAN DEFAULT TRUE, active BOOLEAN DEFAULT TRUE,
target_families JSON ${DB_CLIENT === 'postgres' ? 'NULL' : 'NULL'}, target_families ${JSON_TYPE},
created_at ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP, created_at ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (condo_id) REFERENCES condos(id) ON DELETE CASCADE FOREIGN KEY (condo_id) REFERENCES condos(id) ON DELETE CASCADE
) )
`); `);
// 7. Notice Reads // Migration notices
try {
let cols = [];
if (DB_CLIENT === 'postgres') {
const [res] = await connection.query("SELECT column_name FROM information_schema.columns WHERE table_name='notices'");
cols = res.map(c => c.column_name);
} else {
const [res] = await connection.query("SHOW COLUMNS FROM notices");
cols = res.map(c => c.Field);
}
if (!cols.includes('target_families')) {
console.log('Migrating: Adding target_families to notices...');
await connection.query("ALTER TABLE notices ADD COLUMN target_families JSON");
}
} catch(e) { console.warn("Notices migration warning:", e.message); }
// --- 7. NOTICE READS ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS notice_reads ( CREATE TABLE IF NOT EXISTS notice_reads (
user_id VARCHAR(36), user_id VARCHAR(36),
@@ -234,7 +269,7 @@ const initDb = async () => {
) )
`); `);
// 8. Tickets Table // --- 8. TICKETS TABLE ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS tickets ( CREATE TABLE IF NOT EXISTS tickets (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -252,7 +287,7 @@ const initDb = async () => {
) )
`); `);
// 9. Ticket Attachments // --- 9. TICKET ATTACHMENTS ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS ticket_attachments ( CREATE TABLE IF NOT EXISTS ticket_attachments (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -265,7 +300,7 @@ const initDb = async () => {
) )
`); `);
// 10. Ticket Comments // --- 10. TICKET COMMENTS ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS ticket_comments ( CREATE TABLE IF NOT EXISTS ticket_comments (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -278,7 +313,7 @@ const initDb = async () => {
) )
`); `);
// 11. Extraordinary Expenses // --- 11. EXTRAORDINARY EXPENSES ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS extraordinary_expenses ( CREATE TABLE IF NOT EXISTS extraordinary_expenses (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -330,7 +365,7 @@ const initDb = async () => {
) )
`); `);
// 12. CONDO ORDINARY EXPENSES (USCITE) // --- 12. CONDO ORDINARY EXPENSES (USCITE) ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS condo_expenses ( CREATE TABLE IF NOT EXISTS condo_expenses (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -360,7 +395,7 @@ const initDb = async () => {
) )
`); `);
// 13. DOCUMENTS (Cloud/Local) // --- 13. DOCUMENTS (Cloud/Local) ---
await connection.query(` await connection.query(`
CREATE TABLE IF NOT EXISTS documents ( CREATE TABLE IF NOT EXISTS documents (
id VARCHAR(36) PRIMARY KEY, id VARCHAR(36) PRIMARY KEY,
@@ -370,7 +405,7 @@ const initDb = async () => {
file_name VARCHAR(255) NOT NULL, file_name VARCHAR(255) NOT NULL,
file_type VARCHAR(100), file_type VARCHAR(100),
file_size INT, file_size INT,
tags JSON ${DB_CLIENT === 'postgres' ? 'NULL' : 'NULL'}, tags ${JSON_TYPE},
storage_provider VARCHAR(50) DEFAULT 'local_db', storage_provider VARCHAR(50) DEFAULT 'local_db',
file_data ${LONG_TEXT_TYPE}, file_data ${LONG_TEXT_TYPE},
upload_date ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP, upload_date ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP,
@@ -388,48 +423,45 @@ const initDb = async () => {
reports: true, reports: true,
extraordinaryExpenses: true, extraordinaryExpenses: true,
condoFinancialsView: false, condoFinancialsView: false,
documents: true // Enabled by default for demo documents: true
}; };
const defaultStorage = { const defaultStorage = {
provider: 'local_db' provider: 'local_db',
apiKey: '',
apiSecret: '',
bucket: '',
region: ''
};
const defaultBranding = {
appName: 'CondoPay',
primaryColor: 'blue',
logoUrl: '',
loginBackgroundUrl: ''
}; };
if (rows.length === 0) { if (rows.length === 0) {
const currentYear = new Date().getFullYear(); const currentYear = new Date().getFullYear();
await connection.query( await connection.query(
'INSERT INTO settings (id, current_year, features, storage_config) VALUES (1, ?, ?, ?)', 'INSERT INTO settings (id, current_year, features, storage_config, branding) VALUES (1, ?, ?, ?, ?)',
[currentYear, JSON.stringify(defaultFeatures), JSON.stringify(defaultStorage)] [currentYear, JSON.stringify(defaultFeatures), JSON.stringify(defaultStorage), JSON.stringify(defaultBranding)]
); );
} else {
// Ensure features column has defaults if null const hash = await bcrypt.hash('admin', 10);
if (!rows[0].features) {
await connection.query('UPDATE settings SET features = ? WHERE id = 1', [JSON.stringify(defaultFeatures)]);
}
if (!rows[0].storage_config) {
await connection.query('UPDATE settings SET storage_config = ? WHERE id = 1', [JSON.stringify(defaultStorage)]);
}
}
// ENSURE ADMIN EXISTS
const [admins] = await connection.query('SELECT * FROM users WHERE email = ?', ['fcarra79@gmail.com']);
if (admins.length === 0) {
const hashedPassword = await bcrypt.hash('Mr10921.', 10);
const { v4: uuidv4 } = require('uuid');
await connection.query( await connection.query(
'INSERT INTO users (id, email, password_hash, name, role) VALUES (?, ?, ?, ?, ?)', 'INSERT INTO users (id, email, password_hash, name, role, receive_alerts) VALUES (?, ?, ?, ?, ?, ?)',
[uuidv4(), 'fcarra79@gmail.com', hashedPassword, 'Amministratore', 'admin'] ['admin-id', 'admin@condo.it', hash, 'Amministratore', 'admin', true]
); );
} else { console.log("Database initialized with seed data.");
await connection.query('UPDATE users SET role = ? WHERE email = ?', ['admin', 'fcarra79@gmail.com']);
} }
console.log('Database tables initialized.'); if (DB_CLIENT !== 'postgres') {
if (connection.release) connection.release(); connection.release();
} catch (error) { }
console.error('Database initialization failed:', error); } catch (e) {
process.exit(1); console.error("Database init error:", e);
} }
}; };
module.exports = { pool: dbInterface, initDb }; module.exports = { pool: DB_CLIENT === 'postgres' ? pgPool : mysqlPool, initDb };