136 lines
5.5 KiB
JavaScript
136 lines
5.5 KiB
JavaScript
import mysql from 'mysql2/promise';
|
||
import dotenv from 'dotenv';
|
||
import fs from 'fs';
|
||
import path from 'path';
|
||
import { fileURLToPath } from 'url';
|
||
|
||
dotenv.config();
|
||
|
||
// Fix per __dirname in ES Modules
|
||
const __filename = fileURLToPath(import.meta.url);
|
||
const __dirname = path.dirname(__filename);
|
||
|
||
// Configurazione DB con gestione esplicita della porta e casting a numero
|
||
const dbConfig = {
|
||
host: process.env.DB_HOST || 'db',
|
||
port: Number(process.env.DB_PORT) || 3306,
|
||
user: process.env.DB_USER || 'omni_user',
|
||
password: process.env.DB_PASSWORD || 'omni_pass',
|
||
database: process.env.DB_NAME || 'omnisupport',
|
||
waitForConnections: true,
|
||
connectionLimit: 10,
|
||
queueLimit: 0,
|
||
multipleStatements: true // Necessario per eseguire schema.sql che contiene più query
|
||
};
|
||
|
||
const pool = mysql.createPool(dbConfig);
|
||
|
||
export const query = async (sql, params) => {
|
||
try {
|
||
const [results] = await pool.execute(sql, params);
|
||
return results;
|
||
} catch (error) {
|
||
console.error('Database query error:', error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
export const checkConnection = async () => {
|
||
try {
|
||
const connection = await pool.getConnection();
|
||
await connection.ping();
|
||
connection.release();
|
||
console.log(`✅ Connected to MySQL Database at ${dbConfig.host}:${dbConfig.port}`);
|
||
return true;
|
||
} catch (error) {
|
||
console.error(`❌ Database connection failed (${dbConfig.host}:${dbConfig.port}):`, error.message);
|
||
return false;
|
||
}
|
||
};
|
||
|
||
export const initDb = async () => {
|
||
try {
|
||
console.log(`🔌 Attempting connection to database at ${dbConfig.host}:${dbConfig.port}...`);
|
||
|
||
const isConnected = await checkConnection();
|
||
if (!isConnected) {
|
||
console.error("❌ Skipping initialization due to connection failure.");
|
||
return;
|
||
}
|
||
|
||
// Check if main tables exist
|
||
const [agentsExist] = await pool.query("SHOW TABLES LIKE 'agents'");
|
||
const [settingsExist] = await pool.query("SHOW TABLES LIKE 'settings'");
|
||
|
||
// Scenario 1: DB completely initialized
|
||
if (agentsExist.length > 0 && settingsExist.length > 0) {
|
||
console.log('ℹ️ Database tables already exist. Checking for migrations...');
|
||
|
||
// MIGRATION: Add 'visibility' to kb_articles if not exists
|
||
try {
|
||
await pool.query("ALTER TABLE kb_articles ADD COLUMN visibility ENUM('public', 'internal') DEFAULT 'public'");
|
||
console.log("✅ Added visibility column to kb_articles");
|
||
} catch (e) { /* Column likely exists */ }
|
||
|
||
// MIGRATION: Add 'has_been_analyzed' to tickets if not exists
|
||
try {
|
||
await pool.query("ALTER TABLE tickets ADD COLUMN has_been_analyzed BOOLEAN DEFAULT FALSE");
|
||
console.log("✅ Added has_been_analyzed column to tickets");
|
||
} catch (e) { /* Column likely exists */ }
|
||
|
||
// MIGRATION: Add 'attachments' to tickets if not exists
|
||
try {
|
||
await pool.query("ALTER TABLE tickets ADD COLUMN attachments JSON DEFAULT NULL");
|
||
console.log("✅ Added attachments column to tickets");
|
||
} catch (e) { /* Column likely exists */ }
|
||
|
||
// MIGRATION: Add 'attachments' to ticket_messages if not exists
|
||
try {
|
||
await pool.query("ALTER TABLE ticket_messages ADD COLUMN attachments JSON DEFAULT NULL");
|
||
console.log("✅ Added attachments column to ticket_messages");
|
||
} catch (e) { /* Column likely exists */ }
|
||
|
||
return;
|
||
}
|
||
|
||
// Scenario 2: Partial migration (Agents exist but Settings missing)
|
||
if (agentsExist.length > 0 && settingsExist.length === 0) {
|
||
console.log('⚠️ Settings table missing (Partial Migration). Creating...');
|
||
const createSettingsSql = `
|
||
CREATE TABLE IF NOT EXISTS settings (
|
||
id INT PRIMARY KEY DEFAULT 1,
|
||
branding JSON,
|
||
smtp JSON,
|
||
email_templates JSON,
|
||
features JSON,
|
||
ai_config JSON
|
||
);
|
||
INSERT INTO settings (id, branding, smtp, email_templates, features, ai_config) VALUES (
|
||
1,
|
||
'{"appName": "OmniSupport AI", "primaryColor": "#0284c7", "logoUrl": "https://via.placeholder.com/150"}',
|
||
'{"host": "smtp.example.com", "port": 587, "user": "notifications@omnisupport.ai", "pass": "password", "secure": true, "fromEmail": "noreply@omnisupport.ai"}',
|
||
'[{"id": "t1", "name": "Conferma Apertura Ticket", "trigger": "ticket_created", "audience": "client", "subject": "Ticket #{ticket_id} Creato", "body": "Grazie per averci contattato.", "isActive": true}]',
|
||
'{"kbEnabled": true, "maxKbArticles": 50, "maxSupervisors": 2, "aiKnowledgeAgentEnabled": true, "maxAiGeneratedArticles": 10, "maxAgents": 10, "attachmentsEnabled": true, "maxFileSizeMb": 5, "allowedFileTypes": "jpg,png,pdf"}',
|
||
'{"provider": "gemini", "apiKey": "", "model": "gemini-3-flash-preview", "isActive": true, "agentName": "OmniSupport AI", "customPrompt": ""}'
|
||
);
|
||
`;
|
||
await pool.query(createSettingsSql);
|
||
console.log('✅ Settings table created successfully.');
|
||
return;
|
||
}
|
||
|
||
// Scenario 3: Fresh Install
|
||
console.log('⚠️ Database empty. Running full schema.sql...');
|
||
const schemaPath = path.join(__dirname, 'schema.sql');
|
||
const schemaSql = fs.readFileSync(schemaPath, 'utf8');
|
||
|
||
await pool.query(schemaSql);
|
||
|
||
console.log('✅ Database initialized successfully with schema and seed data.');
|
||
console.log('👤 Superadmin created: fcarra79@gmail.com');
|
||
|
||
} catch (error) {
|
||
console.error('❌ Failed to initialize database:', error);
|
||
}
|
||
};
|