const express = require('express'); const router = express.Router(); const db = require('../database'); const { verifyPassword } = require('../auth'); const fs = require('fs').promises; const path = require('path'); const storage = require('../storage'); // ================================================================ // DELETE /api/system/factory-reset - Limpar sistema inteiro // ================================================================ router.delete('/factory-reset', async (req, res) => { try { const { password } = req.body; const userId = req.user.id; if (!password) { return res.status(400).json({ error: 'A senha é obrigatória para confirmar a limpeza.' }); } // 1. Validar usuário e senha const user = await db.get('SELECT * FROM users WHERE id = $1', [userId]); if (!user) { return res.status(404).json({ error: 'Usuário não encontrado' }); } const validPassword = await verifyPassword(password, user.password_hash); if (!validPassword) { return res.status(401).json({ error: 'A senha atual está incorreta. Acesso negado.' }); } // 2. Limpar banco de dados (tabelas de imagens e GTOs) await db.run('DELETE FROM gto_images'); await db.run('DELETE FROM gtos'); await db.run('DELETE FROM images'); // 3. Limpar arquivos físicos (uploads e processed) const dirsToClean = [ path.join(__dirname, '..', 'uploads'), path.join(__dirname, '..', 'processed') ]; let deletedFiles = 0; for (const dirPath of dirsToClean) { try { const files = await fs.readdir(dirPath); for (const file of files) { // Ignora arquivos como .gitkeep se existirem if (file === '.gitkeep') continue; await fs.unlink(path.join(dirPath, file)); deletedFiles++; } } catch (err) { console.error(`Erro ao limpar a pasta ${dirPath}:`, err); } } res.json({ success: true, message: 'Sistema resetado com sucesso.', filesDeleted: deletedFiles }); } catch (error) { console.error('Erro no Factory Reset:', error); res.status(500).json({ error: 'Erro interno ao processar a limpeza' }); } }); // ================================================================ // GET /api/system/storage-config - Ler configurações de armazenamento // ================================================================ router.get('/storage-config', async (req, res) => { try { const row = await db.get( "SELECT value FROM system_config WHERE key = 'wasabi_config'" ); if (!row || !row.value) { // Retorna estrutura vazia — Wasabi não configurado return res.json({ enabled: false, wasabiAccessKey: '', wasabiSecretKey: '', wasabiBucket: '', wasabiRegion: '', wasabiEndpoint: '' }); } const config = JSON.parse(row.value); // Mascara a secret key parcialmente por segurança const maskedSecret = config.wasabiSecretKey ? config.wasabiSecretKey.substring(0, 4) + '****' : ''; return res.json({ enabled: !!(config.wasabiAccessKey && config.wasabiBucket), wasabiAccessKey: config.wasabiAccessKey || '', wasabiSecretKey: maskedSecret, wasabiBucket: config.wasabiBucket || '', wasabiRegion: config.wasabiRegion || '', wasabiEndpoint: config.wasabiEndpoint || '' }); } catch (error) { console.error('Erro ao ler storage-config:', error); res.status(500).json({ error: 'Erro interno ao ler configurações.' }); } }); // ================================================================ // GET /api/system/wasabi-status - Retorna status em tempo real // ================================================================ router.get('/wasabi-status', (req, res) => { try { const status = storage.getWasabiStatus(); res.json(status); } catch (error) { res.status(500).json({ error: 'Erro ao verificar status do Wasabi.' }); } }); // ================================================================ // POST /api/system/storage-config - Salvar configurações de armazenamento // ================================================================ router.post('/storage-config', async (req, res) => { try { const { wasabiAccessKey, wasabiSecretKey, wasabiBucket, wasabiRegion, wasabiEndpoint } = req.body; if (!wasabiAccessKey || !wasabiBucket) { return res.status(400).json({ error: 'Access Key e Bucket são obrigatórios.' }); } // Se a secret key vier mascarada (****), preserva a anterior let finalSecret = wasabiSecretKey; if (wasabiSecretKey && wasabiSecretKey.includes('****')) { const existing = await db.get( "SELECT value FROM system_config WHERE key = 'wasabi_config'" ); if (existing && existing.value) { const prev = JSON.parse(existing.value); finalSecret = prev.wasabiSecretKey || wasabiSecretKey; } } const finalAccessKey = wasabiAccessKey.trim(); const finalBucket = wasabiBucket.trim(); const finalRegion = (wasabiRegion || 'us-east-1').trim(); const finalEndpoint = (wasabiEndpoint || 's3.wasabisys.com').trim(); // 1. Validar as credenciais contra os servidores do Wasabi ANTES de salvar const validation = await storage.validateCredentials( finalAccessKey, finalSecret, finalBucket, finalRegion, finalEndpoint ); if (!validation.valid) { return res.status(400).json({ error: validation.message }); } // 2. Se for válido, salvar no banco const configJson = JSON.stringify({ wasabiAccessKey: finalAccessKey, wasabiSecretKey: finalSecret, wasabiBucket: finalBucket, wasabiRegion: finalRegion, wasabiEndpoint: finalEndpoint }); await db.run(` INSERT INTO system_config (key, value, updated_at) VALUES ('wasabi_config', $1, NOW()) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW() `, [configJson]); // 3. CRÍTICO: recarregar a config no processo em execução, senão o cliente S3 // em memória continua usando as credenciais antigas (uploads falham com 403). await storage.loadConfigFromDb(); return res.json({ success: true, message: 'Configurações salvas com sucesso.' }); } catch (error) { console.error('Erro ao salvar storage-config:', error); res.status(500).json({ error: 'Erro interno ao salvar configurações.' }); } }); // ================================================================ // GET /api/system/settings — Preferências do usuário logado // Usado pela tela "Configurações" do mobile // ================================================================ router.get('/settings', async (req, res) => { try { const userId = req.user.id; const row = await db.get( "SELECT value FROM system_config WHERE key = $1", [`user_settings_${userId}`] ); const defaults = { theme: 'light', notifications: true, galleryView: 'grid', autoSync: true, imageQuality: 'high', }; const settings = row && row.value ? { ...defaults, ...JSON.parse(row.value) } : defaults; res.json({ success: true, settings }); } catch (error) { console.error('Erro ao ler settings:', error); res.status(500).json({ error: 'Erro ao ler configurações.' }); } }); // ================================================================ // PUT /api/system/settings — Salvar preferências do usuário // ================================================================ router.put('/settings', async (req, res) => { try { const userId = req.user.id; const settings = req.body; if (!settings || typeof settings !== 'object') { return res.status(400).json({ error: 'Corpo da requisição deve ser um objeto JSON.' }); } const configJson = JSON.stringify(settings); await db.run(` INSERT INTO system_config (key, value, updated_at) VALUES ($1, $2, NOW()) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW() `, [`user_settings_${userId}`, configJson]); res.json({ success: true, message: 'Configurações salvas.' }); } catch (error) { console.error('Erro ao salvar settings:', error); res.status(500).json({ error: 'Erro ao salvar configurações.' }); } }); module.exports = router;