feat: reestruturacao de menus na sidebar, niveis de acesso e migracao para postgresql/dragonflydb
continuous-integration/webhook Deploy concluido (rx.scoreodonto.com)
continuous-integration/webhook Deploy concluido (rx.scoreodonto.com)
This commit is contained in:
@@ -41,7 +41,7 @@ router.post('/', requireAdmin, async (req, res) => {
|
||||
|
||||
try {
|
||||
// Verificar se email já existe
|
||||
const existing = await db.get(`SELECT id FROM clinics_devices WHERE email = ?`, [email]);
|
||||
const existing = await db.get(`SELECT id FROM clinics_devices WHERE email = $1`, [email]);
|
||||
if (existing) {
|
||||
return res.status(400).json({ success: false, message: 'Email já cadastrado para outra clínica' });
|
||||
}
|
||||
@@ -52,7 +52,7 @@ router.post('/', requireAdmin, async (req, res) => {
|
||||
|
||||
await db.run(`
|
||||
INSERT INTO clinics_devices (clinic_name, email, password_hash, pc_name, machine_token)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
VALUES ($1, $2, $3, $4, $5) RETURNING id
|
||||
`, [clinic_name, email, password_hash, pc_name, machine_token]);
|
||||
|
||||
res.json({
|
||||
@@ -74,7 +74,7 @@ router.put('/:id/status', requireAdmin, async (req, res) => {
|
||||
const { is_active } = req.body;
|
||||
|
||||
try {
|
||||
await db.run(`UPDATE clinics_devices SET is_active = ? WHERE id = ?`, [is_active ? 1 : 0, id]);
|
||||
await db.run(`UPDATE clinics_devices SET is_active = $1 WHERE id = $2`, [is_active ? 1 : 0, id]);
|
||||
res.json({ success: true, message: 'Status atualizado com sucesso' });
|
||||
} catch (error) {
|
||||
res.status(500).json({ success: false, message: 'Erro interno' });
|
||||
@@ -88,7 +88,7 @@ router.delete('/:id', requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await db.run(`DELETE FROM clinics_devices WHERE id = ?`, [id]);
|
||||
await db.run(`DELETE FROM clinics_devices WHERE id = $1`, [id]);
|
||||
res.json({ success: true, message: 'Clínica excluída com sucesso' });
|
||||
} catch (error) {
|
||||
res.status(500).json({ success: false, message: 'Erro interno' });
|
||||
|
||||
@@ -19,7 +19,7 @@ router.post('/login', async (req, res) => {
|
||||
|
||||
// Buscar usuário
|
||||
const user = await db.get(
|
||||
'SELECT * FROM users WHERE username = ? OR email = ?',
|
||||
'SELECT * FROM users WHERE username = $1 OR email = $2',
|
||||
[username, username]
|
||||
);
|
||||
|
||||
@@ -77,7 +77,7 @@ router.get('/verify', async (req, res) => {
|
||||
const jwt = require('jsonwebtoken');
|
||||
const decoded = jwt.verify(token, require('../auth').JWT_SECRET);
|
||||
|
||||
const user = await db.get('SELECT * FROM users WHERE id = ?', [decoded.id]);
|
||||
const user = await db.get('SELECT * FROM users WHERE id = $1', [decoded.id]);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Usuário não encontrado' });
|
||||
@@ -131,7 +131,7 @@ router.post('/create-user', authenticateToken, async (req, res) => {
|
||||
|
||||
// Verificar se usuário já existe
|
||||
const existing = await db.get(
|
||||
'SELECT * FROM users WHERE username = ? OR email = ?',
|
||||
'SELECT * FROM users WHERE username = $1 OR email = $2',
|
||||
[username, email]
|
||||
);
|
||||
|
||||
@@ -147,7 +147,7 @@ router.post('/create-user', authenticateToken, async (req, res) => {
|
||||
// Criar usuário
|
||||
const result = await db.run(
|
||||
`INSERT INTO users (username, email, password_hash, clinic_name, pc_name, is_admin, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, NOW())`,
|
||||
VALUES ($1, $2, $3, $4, $5, $6, CURRENT_TIMESTAMP) RETURNING id`,
|
||||
[username, email, passwordHash, clinic_name || null, pc_name || null, !!is_admin]
|
||||
);
|
||||
|
||||
@@ -188,7 +188,7 @@ router.delete('/users/:id', authenticateToken, async (req, res) => {
|
||||
if (parseInt(userId) === req.user.id) {
|
||||
return res.status(400).json({ error: 'Não é possível excluir o próprio usuário admin' });
|
||||
}
|
||||
await db.run('DELETE FROM users WHERE id = ?', [userId]);
|
||||
await db.run('DELETE FROM users WHERE id = $1', [userId]);
|
||||
res.json({ success: true, message: 'Usuário excluído com sucesso' });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Erro ao excluir usuário' });
|
||||
@@ -200,7 +200,7 @@ router.post('/users/:id/token', authenticateToken, async (req, res) => {
|
||||
if (!req.user.is_admin) {
|
||||
return res.status(403).json({ error: 'Acesso negado' });
|
||||
}
|
||||
const user = await db.get('SELECT * FROM users WHERE id = ?', [req.params.id]);
|
||||
const user = await db.get('SELECT * FROM users WHERE id = $1', [req.params.id]);
|
||||
if (!user) return res.status(404).json({ error: 'Usuário não encontrado' });
|
||||
|
||||
// Gera um token com duração longa para uso no desktop (ex: 3650 dias = ~10 anos)
|
||||
@@ -229,7 +229,7 @@ router.put('/update-credentials', authenticateToken, async (req, res) => {
|
||||
}
|
||||
|
||||
// Buscar usuário atual para verificar a senha
|
||||
const user = await db.get('SELECT * FROM users WHERE id = ?', [userId]);
|
||||
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' });
|
||||
}
|
||||
@@ -246,7 +246,7 @@ router.put('/update-credentials', authenticateToken, async (req, res) => {
|
||||
|
||||
// Verificar e aplicar novo username se fornecido
|
||||
if (newUsername && newUsername !== user.username) {
|
||||
const existing = await db.get('SELECT * FROM users WHERE username = ? AND id != ?', [newUsername, userId]);
|
||||
const existing = await db.get('SELECT * FROM users WHERE username = $1 AND id != $2', [newUsername, userId]);
|
||||
if (existing) {
|
||||
return res.status(409).json({ error: 'Este nome de usuário já está em uso' });
|
||||
}
|
||||
@@ -255,7 +255,7 @@ router.put('/update-credentials', authenticateToken, async (req, res) => {
|
||||
|
||||
// Verificar e aplicar novo e-mail se fornecido
|
||||
if (newEmail && newEmail !== user.email) {
|
||||
const existing = await db.get('SELECT * FROM users WHERE email = ? AND id != ?', [newEmail, userId]);
|
||||
const existing = await db.get('SELECT * FROM users WHERE email = $1 AND id != $2', [newEmail, userId]);
|
||||
if (existing) {
|
||||
return res.status(409).json({ error: 'Este e-mail já está em uso' });
|
||||
}
|
||||
@@ -272,7 +272,7 @@ router.put('/update-credentials', authenticateToken, async (req, res) => {
|
||||
|
||||
// Atualizar no banco de dados
|
||||
await db.run(
|
||||
'UPDATE users SET username = ?, email = ?, password_hash = ? WHERE id = ?',
|
||||
'UPDATE users SET username = $1, email = $2, password_hash = $3 WHERE id = $4',
|
||||
[finalUsername, finalEmail, finalPasswordHash, userId]
|
||||
);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ router.post('/login', async (req, res) => {
|
||||
|
||||
try {
|
||||
// 1. Buscar o dispositivo pelo Token
|
||||
const device = await db.get(`SELECT * FROM clinics_devices WHERE machine_token = ?`, [machine_token]);
|
||||
const device = await db.get(`SELECT * FROM clinics_devices WHERE machine_token = $1`, [machine_token]);
|
||||
|
||||
if (!device) {
|
||||
return res.status(401).json({ success: false, message: 'Token da máquina inválido ou inexistente' });
|
||||
@@ -46,7 +46,7 @@ router.post('/login', async (req, res) => {
|
||||
|
||||
// Atualizar último IP conectado
|
||||
const clientIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
|
||||
await db.run(`UPDATE clinics_devices SET last_ip = ? WHERE id = ?`, [clientIp, device.id]);
|
||||
await db.run(`UPDATE clinics_devices SET last_ip = $1 WHERE id = $2`, [clientIp, device.id]);
|
||||
|
||||
// 5. Gerar Token JWT de Sessão
|
||||
// O Token vale por 2 horas, obrigando o cliente a re-logar ou pedir refresh
|
||||
|
||||
@@ -15,7 +15,7 @@ router.get('/', async (req, res) => {
|
||||
`SELECT g.*, COUNT(gi.id) as image_count
|
||||
FROM gtos g
|
||||
LEFT JOIN gto_images gi ON gi.gto_id = g.id
|
||||
WHERE g.patient_name = ?
|
||||
WHERE g.patient_name = $1
|
||||
GROUP BY g.id
|
||||
ORDER BY g.created_at DESC`,
|
||||
[patient]
|
||||
@@ -42,14 +42,14 @@ router.get('/', async (req, res) => {
|
||||
// ================================================================
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const gto = await db.get('SELECT * FROM gtos WHERE id = ?', [req.params.id]);
|
||||
const gto = await db.get('SELECT * FROM gtos WHERE id = $1', [req.params.id]);
|
||||
if (!gto) return res.status(404).json({ error: 'GTO não encontrada' });
|
||||
|
||||
const images = await db.all(
|
||||
`SELECT i.*, gi.id as link_id
|
||||
FROM gto_images gi
|
||||
JOIN images i ON i.id = gi.image_id
|
||||
WHERE gi.gto_id = ?
|
||||
WHERE gi.gto_id = $1
|
||||
ORDER BY gi.created_at DESC`,
|
||||
[req.params.id]
|
||||
);
|
||||
@@ -71,10 +71,10 @@ router.post('/', async (req, res) => {
|
||||
return res.status(400).json({ error: 'gto_number e patient_name são obrigatórios' });
|
||||
}
|
||||
const result = await db.run(
|
||||
`INSERT INTO gtos (gto_number, patient_name, description) VALUES (?, ?, ?)`,
|
||||
`INSERT INTO gtos (gto_number, patient_name, description) VALUES ($1, $2, $3) RETURNING id`,
|
||||
[gto_number.trim(), patient_name.trim(), description || '']
|
||||
);
|
||||
const gto = await db.get('SELECT * FROM gtos WHERE id = ?', [result.lastID]);
|
||||
const gto = await db.get('SELECT * FROM gtos WHERE id = $1', [result.lastID]);
|
||||
res.status(201).json(gto);
|
||||
} catch (err) {
|
||||
console.error('Erro ao criar GTO:', err);
|
||||
@@ -89,10 +89,10 @@ router.put('/:id', async (req, res) => {
|
||||
try {
|
||||
const { gto_number, description } = req.body;
|
||||
await db.run(
|
||||
`UPDATE gtos SET gto_number = ?, description = ? WHERE id = ?`,
|
||||
`UPDATE gtos SET gto_number = $1, description = $2 WHERE id = $3`,
|
||||
[gto_number, description || '', req.params.id]
|
||||
);
|
||||
const gto = await db.get('SELECT * FROM gtos WHERE id = ?', [req.params.id]);
|
||||
const gto = await db.get('SELECT * FROM gtos WHERE id = $1', [req.params.id]);
|
||||
res.json(gto);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
@@ -104,8 +104,8 @@ router.put('/:id', async (req, res) => {
|
||||
// ================================================================
|
||||
router.delete('/:id', async (req, res) => {
|
||||
try {
|
||||
await db.run('DELETE FROM gto_images WHERE gto_id = ?', [req.params.id]);
|
||||
await db.run('DELETE FROM gtos WHERE id = ?', [req.params.id]);
|
||||
await db.run('DELETE FROM gto_images WHERE gto_id = $1', [req.params.id]);
|
||||
await db.run('DELETE FROM gtos WHERE id = $1', [req.params.id]);
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
@@ -123,13 +123,13 @@ router.post('/:id/images', async (req, res) => {
|
||||
|
||||
// Verificar se já está vinculada
|
||||
const existing = await db.get(
|
||||
'SELECT id FROM gto_images WHERE gto_id = ? AND image_id = ?',
|
||||
'SELECT id FROM gto_images WHERE gto_id = $1 AND image_id = $2',
|
||||
[req.params.id, image_id]
|
||||
);
|
||||
if (existing) return res.status(409).json({ error: 'Imagem já vinculada a esta GTO' });
|
||||
|
||||
await db.run(
|
||||
'INSERT INTO gto_images (gto_id, image_id) VALUES (?, ?)',
|
||||
'INSERT INTO gto_images (gto_id, image_id) VALUES ($1, $2) RETURNING id',
|
||||
[req.params.id, image_id]
|
||||
);
|
||||
res.status(201).json({ success: true, message: 'Imagem vinculada à GTO' });
|
||||
@@ -145,7 +145,7 @@ router.post('/:id/images', async (req, res) => {
|
||||
router.delete('/:id/images/:imageId', async (req, res) => {
|
||||
try {
|
||||
await db.run(
|
||||
'DELETE FROM gto_images WHERE gto_id = ? AND image_id = ?',
|
||||
'DELETE FROM gto_images WHERE gto_id = $1 AND image_id = $2',
|
||||
[req.params.id, req.params.imageId]
|
||||
);
|
||||
res.json({ success: true });
|
||||
|
||||
@@ -14,17 +14,19 @@ router.get('/', async (req, res) => {
|
||||
const search = req.query.search || '';
|
||||
const clientName = req.query.client || '';
|
||||
|
||||
let query = `SELECT * FROM images WHERE enabled = ?`;
|
||||
let query = `SELECT * FROM images WHERE enabled = $1`;
|
||||
let params = [showDisabled ? 0 : 1];
|
||||
let paramIndex = 2;
|
||||
|
||||
if (clientName) {
|
||||
query += ` AND client_name = ?`;
|
||||
query += ` AND client_name = $${paramIndex++}`;
|
||||
params.push(clientName);
|
||||
}
|
||||
|
||||
if (search) {
|
||||
query += ` AND (patient_name LIKE ? OR image_guid LIKE ? OR filename LIKE ?)`;
|
||||
query += ` AND (patient_name LIKE $${paramIndex} OR image_guid LIKE $${paramIndex + 1} OR filename LIKE $${paramIndex + 2})`;
|
||||
params.push(`%${search}%`, `%${search}%`, `%${search}%`);
|
||||
paramIndex += 3;
|
||||
}
|
||||
|
||||
query += ` ORDER BY created_at DESC LIMIT 100`;
|
||||
@@ -47,17 +49,19 @@ router.get('/patients', async (req, res) => {
|
||||
const clientName = req.query.client || '';
|
||||
const enabledVal = showDisabled ? 0 : 1;
|
||||
|
||||
let where = `WHERE enabled = ${enabledVal}`;
|
||||
let params = [];
|
||||
|
||||
let paramIndex = 1;
|
||||
let where = `WHERE enabled = $${paramIndex++}`;
|
||||
let params = [enabledVal];
|
||||
|
||||
if (clientName) {
|
||||
where += ` AND client_name = ?`;
|
||||
where += ` AND client_name = $${paramIndex++}`;
|
||||
params.push(clientName);
|
||||
}
|
||||
|
||||
|
||||
if (search) {
|
||||
where += ` AND (patient_name LIKE ? OR image_guid LIKE ?)`;
|
||||
where += ` AND (patient_name LIKE $${paramIndex} OR image_guid LIKE $${paramIndex + 1})`;
|
||||
params.push(`%${search}%`, `%${search}%`);
|
||||
paramIndex += 2;
|
||||
}
|
||||
|
||||
// Group by patient_name — pick thumbnail from most recent image
|
||||
@@ -102,7 +106,7 @@ router.get('/by-patient', async (req, res) => {
|
||||
|
||||
const images = await db.all(
|
||||
`SELECT * FROM images
|
||||
WHERE patient_name = ? AND enabled = ?
|
||||
WHERE patient_name = $1 AND enabled = $2
|
||||
ORDER BY created_at DESC`,
|
||||
[patientName, showDisabled ? 0 : 1]
|
||||
);
|
||||
@@ -119,7 +123,7 @@ router.get('/by-patient', async (req, res) => {
|
||||
// ================================================================
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const image = await db.get('SELECT * FROM images WHERE id = ?', [req.params.id]);
|
||||
const image = await db.get('SELECT * FROM images WHERE id = $1', [req.params.id]);
|
||||
if (!image) {
|
||||
return res.status(404).json({ error: 'Imagem não encontrada' });
|
||||
}
|
||||
@@ -155,14 +159,14 @@ router.get('/stats', async (req, res) => {
|
||||
// ================================================================
|
||||
router.get('/:id/transformations', async (req, res) => {
|
||||
try {
|
||||
const image = await db.get('SELECT * FROM images WHERE id = ?', [req.params.id]);
|
||||
const image = await db.get('SELECT * FROM images WHERE id = $1', [req.params.id]);
|
||||
if (!image) {
|
||||
return res.status(404).json({ error: 'Imagem não encontrada' });
|
||||
}
|
||||
|
||||
// Buscar a imagem original se esta é uma transformação
|
||||
const originalId = image.original_image_id || image.id;
|
||||
const originalImage = await db.get('SELECT * FROM images WHERE id = ?', [originalId]);
|
||||
const originalImage = await db.get('SELECT * FROM images WHERE id = $1', [originalId]);
|
||||
|
||||
const originalPath = path.join(__dirname, '../uploads', originalImage.filename);
|
||||
let originalBuffer;
|
||||
@@ -217,7 +221,7 @@ router.get('/:id/transformations', async (req, res) => {
|
||||
router.post('/:id/transform', async (req, res) => {
|
||||
try {
|
||||
const { rotation, flipH, flipV, remark } = req.body;
|
||||
const originalImage = await db.get('SELECT * FROM images WHERE id = ?', [req.params.id]);
|
||||
const originalImage = await db.get('SELECT * FROM images WHERE id = $1', [req.params.id]);
|
||||
|
||||
if (!originalImage) {
|
||||
return res.status(404).json({ error: 'Imagem não encontrada' });
|
||||
@@ -225,7 +229,7 @@ router.post('/:id/transform', async (req, res) => {
|
||||
|
||||
// Buscar a imagem original real se esta é uma transformação
|
||||
const realOriginalId = originalImage.original_image_id || originalImage.id;
|
||||
const realOriginal = await db.get('SELECT * FROM images WHERE id = ?', [realOriginalId]);
|
||||
const realOriginal = await db.get('SELECT * FROM images WHERE id = $1', [realOriginalId]);
|
||||
|
||||
// Processar a imagem
|
||||
const originalPath = path.join(__dirname, '../uploads', realOriginal.filename);
|
||||
@@ -250,9 +254,9 @@ router.post('/:id/transform', async (req, res) => {
|
||||
const processedPath = path.join(__dirname, '../processed', processedFilename);
|
||||
await fs.writeFile(processedPath, processed);
|
||||
|
||||
// Desabilitar a imagem atual para que não fique duplicada na interface
|
||||
await db.run('UPDATE images SET enabled = 0 WHERE id = ?', [req.params.id]);
|
||||
|
||||
// Desabilitar a imagem active atual para que não fique duplicada na interface
|
||||
await db.run('UPDATE images SET enabled = 0 WHERE id = $1', [req.params.id]);
|
||||
|
||||
const newRemark = remark !== undefined ? remark : originalImage.remark;
|
||||
|
||||
// Inserir a nova imagem como a versão ativa
|
||||
@@ -260,7 +264,7 @@ router.post('/:id/transform', async (req, res) => {
|
||||
`INSERT INTO images (
|
||||
image_guid, patient_name, client_name, original_filename, filename,
|
||||
enabled, rotation, flip_horizontal, flip_vertical, original_image_id, created_at, remark, doctor
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`,
|
||||
[
|
||||
`${realOriginal.image_guid}_${timestamp}`,
|
||||
realOriginal.patient_name,
|
||||
@@ -298,11 +302,11 @@ router.put('/:id/patient-info', async (req, res) => {
|
||||
|
||||
await db.run(
|
||||
`UPDATE images SET
|
||||
patient_name_resumed = ?,
|
||||
tooth_number = ?,
|
||||
tooth_side = ?,
|
||||
patient_name_resumed = $1,
|
||||
tooth_number = $2,
|
||||
tooth_side = $3,
|
||||
enabled = 1
|
||||
WHERE id = ?`,
|
||||
WHERE id = $4`,
|
||||
[patientNameResumed, toothNumber, toothSide, req.params.id]
|
||||
);
|
||||
|
||||
@@ -317,7 +321,7 @@ router.put('/:id/patient-info', async (req, res) => {
|
||||
// ================================================================
|
||||
router.get('/:id/download', async (req, res) => {
|
||||
try {
|
||||
const image = await db.get('SELECT * FROM images WHERE id = ?', [req.params.id]);
|
||||
const image = await db.get('SELECT * FROM images WHERE id = $1', [req.params.id]);
|
||||
if (!image) {
|
||||
return res.status(404).json({ error: 'Imagem não encontrada' });
|
||||
}
|
||||
@@ -344,7 +348,7 @@ router.get('/:id/download', async (req, res) => {
|
||||
// ================================================================
|
||||
router.delete('/:id', async (req, res) => {
|
||||
try {
|
||||
const image = await db.get('SELECT * FROM images WHERE id = ?', [req.params.id]);
|
||||
const image = await db.get('SELECT * FROM images WHERE id = $1', [req.params.id]);
|
||||
if (!image) {
|
||||
return res.status(404).json({ error: 'Imagem não encontrada' });
|
||||
}
|
||||
@@ -366,7 +370,7 @@ router.delete('/:id', async (req, res) => {
|
||||
}
|
||||
|
||||
// Apagar do banco
|
||||
await db.run('DELETE FROM images WHERE id = ?', [req.params.id]);
|
||||
await db.run('DELETE FROM images WHERE id = $1', [req.params.id]);
|
||||
|
||||
res.json({ success: true, message: 'Imagem apagada com sucesso' });
|
||||
} catch (error) {
|
||||
@@ -380,13 +384,13 @@ router.delete('/:id', async (req, res) => {
|
||||
// ================================================================
|
||||
router.put('/:id/toggle-enabled', async (req, res) => {
|
||||
try {
|
||||
const image = await db.get('SELECT * FROM images WHERE id = ?', [req.params.id]);
|
||||
const image = await db.get('SELECT * FROM images WHERE id = $1', [req.params.id]);
|
||||
if (!image) {
|
||||
return res.status(404).json({ error: 'Imagem não encontrada' });
|
||||
}
|
||||
|
||||
const newEnabled = image.enabled ? 0 : 1;
|
||||
await db.run('UPDATE images SET enabled = ? WHERE id = ?', [newEnabled, req.params.id]);
|
||||
await db.run('UPDATE images SET enabled = $1 WHERE id = $2', [newEnabled, req.params.id]);
|
||||
|
||||
res.json({ success: true, enabled: newEnabled === 1 });
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
// Caminho do banco de dados oficial do Dental Sensor
|
||||
const DENTAL_DB_PATH = 'C:/ProgramData/RF/Dental Sensor/data';
|
||||
|
||||
// ================================================================
|
||||
// Conexão LAZY — abre o banco só quando necessário e fecha logo
|
||||
// após, evitando conflitos de lock com o banco principal do servidor
|
||||
// ================================================================
|
||||
function openDentalDb() {
|
||||
const { DatabaseSync } = require('node:sqlite');
|
||||
return new DatabaseSync(DENTAL_DB_PATH);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// POST /api/patients - Criar novo paciente no Dental Sensor
|
||||
// ================================================================
|
||||
router.post('/', (req, res) => {
|
||||
let db;
|
||||
try {
|
||||
db = openDentalDb();
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao conectar ao banco do Dental Sensor:', error.message);
|
||||
return res.status(500).json({
|
||||
error: 'Não foi possível conectar ao banco do Dental Sensor. Verifique se o software está instalado.',
|
||||
detail: error.message
|
||||
});
|
||||
}
|
||||
|
||||
const { firstName, lastName, doctor, birthday, gender, phone, email, address, zipCode, remark } = req.body;
|
||||
|
||||
if (!firstName || !lastName) {
|
||||
if (db) try { db.close(); } catch (_) {}
|
||||
return res.status(400).json({ error: 'Nome e Sobrenome são obrigatórios.' });
|
||||
}
|
||||
|
||||
const formattedBirthday = birthday ? `${birthday} 00:00:00` : null;
|
||||
|
||||
try {
|
||||
const insertStmt = db.prepare(`
|
||||
INSERT INTO Patients (
|
||||
FirstName, LastName, Doctor, Birthday, Gender, Phone, Email, Address, ZipCode, Remark, LastActTime, VFlag
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), 1)
|
||||
`);
|
||||
|
||||
const result = insertStmt.run(
|
||||
firstName,
|
||||
lastName,
|
||||
doctor || '',
|
||||
formattedBirthday,
|
||||
gender !== undefined ? parseInt(gender, 10) : 0,
|
||||
phone || '',
|
||||
email || '',
|
||||
address || '',
|
||||
zipCode || '',
|
||||
remark || ''
|
||||
);
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
patientId: result.lastInsertRowid,
|
||||
message: 'Paciente cadastrado com sucesso no Dental Sensor'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Erro ao inserir paciente:', error);
|
||||
res.status(500).json({ error: 'Erro ao cadastrar paciente: ' + error.message });
|
||||
} finally {
|
||||
// SEMPRE fechar o banco após o uso para liberar o lock
|
||||
if (db) {
|
||||
try { db.close(); } catch (_) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ================================================================
|
||||
// GET /api/patients - Listar pacientes do Dental Sensor (opcional)
|
||||
// ================================================================
|
||||
router.get('/', (req, res) => {
|
||||
let db;
|
||||
try {
|
||||
db = openDentalDb();
|
||||
const search = req.query.search || '';
|
||||
let stmt;
|
||||
let rows;
|
||||
|
||||
if (search) {
|
||||
stmt = db.prepare(`
|
||||
SELECT ID, FirstName, LastName, Doctor, Birthday, Gender, Phone, Remark
|
||||
FROM Patients
|
||||
WHERE (FirstName LIKE ? OR LastName LIKE ?)
|
||||
AND VFlag = 1
|
||||
ORDER BY LastActTime DESC
|
||||
LIMIT 100
|
||||
`);
|
||||
rows = stmt.all(`%${search}%`, `%${search}%`);
|
||||
} else {
|
||||
stmt = db.prepare(`
|
||||
SELECT ID, FirstName, LastName, Doctor, Birthday, Gender, Phone, Remark
|
||||
FROM Patients
|
||||
WHERE VFlag = 1
|
||||
ORDER BY LastActTime DESC
|
||||
LIMIT 100
|
||||
`);
|
||||
rows = stmt.all();
|
||||
}
|
||||
|
||||
res.json(rows);
|
||||
} catch (error) {
|
||||
console.error('Erro ao listar pacientes do Dental Sensor:', error.message);
|
||||
res.status(500).json({ error: 'Erro ao consultar banco do Dental Sensor: ' + error.message });
|
||||
} finally {
|
||||
if (db) {
|
||||
try { db.close(); } catch (_) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -18,7 +18,7 @@ router.delete('/factory-reset', async (req, res) => {
|
||||
}
|
||||
|
||||
// 1. Validar usuário e senha
|
||||
const user = await db.get('SELECT * FROM users WHERE id = ?', [userId]);
|
||||
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' });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user