import pg from 'pg'; import fs from 'fs'; import path from 'path'; const DATABASE_URL = process.env.DATABASE_URL || 'postgresql://edumanager:EduManager2026!Seguro@150.230.87.131:5432/edumanager'; const pool = new pg.Pool({ connectionString: DATABASE_URL }); async function recover() { const client = await pool.connect(); try { console.log('🔄 Iniciando processo de recuperação de Provas e Questões...'); // Tentar ler do backup original let backupPath = '/app/backup_supabase_2026-04-19.json'; if (!fs.existsSync(backupPath)) { backupPath = path.join(process.cwd(), 'backup_supabase_2026-04-19.json'); } if (!fs.existsSync(backupPath)) { throw new Error(`Arquivo de backup não encontrado em: ${backupPath}`); } console.log(`Lendo dados de backup em: ${backupPath}`); const rawData = fs.readFileSync(backupPath, 'utf8'); const data = JSON.parse(rawData); if (!data.exams || !Array.isArray(data.exams)) { throw new Error('Chave "exams" não encontrada ou não é um array no backup.'); } console.log(`Encontradas ${data.exams.length} provas no arquivo de backup.`); await client.query('BEGIN'); // Habilitar a gravação das provas no Postgres let countProvasInseridas = 0; let countQuestoesInseridas = 0; for (const e of data.exams) { if (!e.id || !e.title) continue; // Inserir Prova await client.query( `INSERT INTO provas (id, turma_id, disciplina_id, periodo_id, titulo, duracao_minutos, status, permitir_refacao, is_deleted, evaluation_type, max_score) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) ON CONFLICT (id) DO UPDATE SET turma_id = COALESCE(provas.turma_id, EXCLUDED.turma_id), disciplina_id = COALESCE(provas.disciplina_id, EXCLUDED.disciplina_id), periodo_id = COALESCE(provas.periodo_id, EXCLUDED.periodo_id), titulo = EXCLUDED.titulo, duracao_minutos = EXCLUDED.duracao_minutos, status = EXCLUDED.status, permitir_refacao = EXCLUDED.permitir_refacao, evaluation_type = EXCLUDED.evaluation_type, max_score = EXCLUDED.max_score`, [ e.id, e.classId || e.turma_id || null, e.subjectId || e.disciplina_id || null, e.periodId || e.periodo_id || null, e.title || e.titulo, e.durationMinutes || e.duracao_minutos || 60, e.status || 'draft', e.allowRetake || e.permitir_refacao || false, e.isDeleted || e.is_deleted || false, e.evaluationType || e.evaluation_type || 'exam', e.maxScore !== undefined ? Number(e.maxScore) : (e.max_score !== undefined ? Number(e.max_score) : 10.0) ] ); countProvasInseridas++; // Inserir Questões da Prova if (e.questions && Array.isArray(e.questions)) { let ordem = 0; for (const q of e.questions) { if (!q.id || !q.text) continue; await client.query( `INSERT INTO questoes_provas (id, prova_id, texto, opcoes, indice_correto, ordem, imagem_url) VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (id) DO UPDATE SET texto = EXCLUDED.texto, opcoes = EXCLUDED.opcoes, indice_correto = EXCLUDED.indice_correto, ordem = EXCLUDED.ordem, imagem_url = COALESCE(questoes_provas.imagem_url, EXCLUDED.imagem_url)`, [ q.id, e.id, q.text, JSON.stringify(q.options || []), q.correctOptionIndex !== undefined ? q.correctOptionIndex : (q.indice_correto ?? 0), q.order !== undefined ? q.order : (q.ordem ?? ordem++), q.imageUrl || q.imagem_url || null ] ); countQuestoesInseridas++; } } } console.log(`Restaurando chaves no school_data JSON da tabela school_data no Postgres...`); const { rows } = await client.query('SELECT data FROM school_data WHERE id = 1'); if (rows[0]?.data) { const currentJson = rows[0].data; // Atualizar a chave exams no JSON currentJson.exams = data.exams; await client.query('UPDATE school_data SET data = $1, updated_at = NOW() WHERE id = 1', [JSON.stringify(currentJson)]); console.log('Chave exams atualizada no JSON school_data da tabela.'); } await client.query('COMMIT'); console.log(`✅ Sucesso! Foram restauradas ${countProvasInseridas} provas e ${countQuestoesInseridas} questões no PostgreSQL.`); } catch (err) { await client.query('ROLLBACK'); console.error('❌ Erro na recuperação:', err); } finally { client.release(); await pool.end(); } } recover();