248 lines
8.3 KiB
JavaScript
248 lines
8.3 KiB
JavaScript
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;
|