diff --git a/backend/src/modules/records/records.routes.js b/backend/src/modules/records/records.routes.js index e138b19..bf19423 100644 --- a/backend/src/modules/records/records.routes.js +++ b/backend/src/modules/records/records.routes.js @@ -712,20 +712,38 @@ export default async function recordRoutes(fastify, options) { return reply.status(400).send({ error: 'Invalid record ID' }); } - await db.collection('records').deleteOne({ - _id: objectId, - tenant_id: request.tenantId - }); + try { + const deleteResult = await db.collection('records').deleteOne({ + _id: objectId, + tenant_id: request.tenantId + }); - // Delete versions - await db.collection('record_versions').deleteMany({ - record_id: objectId, - tenant_id: request.tenantId - }); + if (deleteResult.deletedCount === 0) { + return reply.status(404).send({ error: 'KB não encontrado' }); + } - // Update subscription usage - await db.collection('subscriptions').updateOne({ tenant_id: request.tenantId }, { $inc: { 'usage.records': -1 } }); + // Delete versions + await db.collection('record_versions').deleteMany({ + record_id: objectId, + tenant_id: request.tenantId + }); - return { success: true }; + // Update subscription usage + await db.collection('subscriptions').updateOne({ tenant_id: request.tenantId }, { $inc: { 'usage.records': -1 } }); + + await db.collection('audit_logs').insertOne({ + tenant_id: request.tenantId, + user_id: request.currentUser._id, + action: 'kb.deleted', + resource: 'record', + resource_id: objectId, + timestamp: new Date() + }); + + return { success: true }; + } catch (error) { + fastify.log.error({ err: error }, 'Falha ao excluir KB'); + return reply.status(500).send({ error: 'Falha ao excluir KB', details: error.message }); + } }); } \ No newline at end of file diff --git a/backend/src/server.js b/backend/src/server.js index 06e8e49..ed117f5 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -252,8 +252,13 @@ fastify.setErrorHandler((error, request, reply) => { const statusCode = error.statusCode || 500; const message = error.message || 'Internal Server Error'; + // `error` precisa ser a mensagem (string): todo o frontend le + // `error.response?.data?.error` esperando texto. Mandar `error: true` + // (booleano) fazia qualquer excecao nao tratada, em qualquer rota, + // aparecer como "...: true" para quem usa esse campo - ou, quando o + // fallback e usado, mascarava a causa real como "Erro desconhecido". reply.status(statusCode).send({ - error: true, + error: message, message, statusCode }); diff --git a/frontend/src/pages/kb/KBView.jsx b/frontend/src/pages/kb/KBView.jsx index c99e4c4..4f63982 100644 --- a/frontend/src/pages/kb/KBView.jsx +++ b/frontend/src/pages/kb/KBView.jsx @@ -19,6 +19,17 @@ const isProbablyHtml = (value) => { return /<\/?[a-z][\s\S]*>/i.test(String(value)); }; +// A API sempre manda { error: '' } em erros tratados, mas uma +// excecao nao tratada no servidor, ou uma falha de rede (sem response +// nenhum, ex.: CORS, timeout, servidor fora do ar) nao tem esse campo. Sem +// esses fallbacks, tudo isso virava um "Erro desconhecido" que escondia a +// causa real - inclusive de quem for depurar o problema depois. +const getErrorMessage = (error) => + error.response?.data?.error || + error.response?.data?.message || + (error.response ? `Erro ${error.response.status}` : error.message) || + 'Erro desconhecido'; + export default function KBView() { const { id } = useParams(); const navigate = useNavigate(); @@ -68,7 +79,7 @@ export default function KBView() { await recordAPI.submitForReview(id); fetchRecord(); } catch (error) { - alert('Falha ao enviar para revisão: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao enviar para revisão: ' + getErrorMessage(error)); } finally { setActionLoading(false); } @@ -80,7 +91,7 @@ export default function KBView() { await recordAPI.approve(id); fetchRecord(); } catch (error) { - const errorMsg = error.response?.data?.error || 'Erro desconhecido'; + const errorMsg = getErrorMessage(error); if (error.response?.status === 403) { if (errorMsg.includes('own KB')) { alert('Você não pode aprovar seu próprio KB.'); @@ -103,7 +114,7 @@ export default function KBView() { setRejectReason(''); fetchRecord(); } catch (error) { - alert('Falha ao rejeitar: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao rejeitar: ' + getErrorMessage(error)); } finally { setActionLoading(false); } @@ -115,7 +126,7 @@ export default function KBView() { await recordAPI.publish(id); fetchRecord(); } catch (error) { - alert('Falha ao publicar: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao publicar: ' + getErrorMessage(error)); } finally { setActionLoading(false); } @@ -126,7 +137,7 @@ export default function KBView() { await recordAPI.delete(id); navigate('/kb'); } catch (error) { - alert('Falha ao excluir: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao excluir: ' + getErrorMessage(error)); } }; @@ -137,7 +148,7 @@ export default function KBView() { const blob = new Blob([response.data], { type: 'text/markdown' }); downloadBlob(blob, `${record.title.replace(/[^a-zA-Z0-9]/g, '-')}.md`); } catch (error) { - alert('Falha ao exportar: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao exportar: ' + getErrorMessage(error)); } }; @@ -155,7 +166,7 @@ export default function KBView() { printWindow.print(); }; } catch (error) { - alert('Falha ao exportar PDF: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao exportar PDF: ' + getErrorMessage(error)); } }; @@ -165,7 +176,7 @@ export default function KBView() { const blob = new Blob([response.data], { type: 'application/json' }); downloadBlob(blob, `${record.title.replace(/[^a-zA-Z0-9]/g, '-')}.json`); } catch (error) { - alert('Falha ao exportar JSON: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao exportar JSON: ' + getErrorMessage(error)); } }; @@ -175,7 +186,7 @@ export default function KBView() { const blob = new Blob([response.data], { type: 'application/vnd.ms-word' }); downloadBlob(blob, `${record.title.replace(/[^a-zA-Z0-9]/g, '-')}.doc`); } catch (error) { - alert('Falha ao exportar Word: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao exportar Word: ' + getErrorMessage(error)); } }; @@ -185,7 +196,7 @@ export default function KBView() { const blob = new Blob([response.data], { type: 'text/plain' }); downloadBlob(blob, `${record.title.replace(/[^a-zA-Z0-9]/g, '-')}.txt`); } catch (error) { - alert('Falha ao exportar texto: ' + (error.response?.data?.error || 'Erro desconhecido')); + alert('Falha ao exportar texto: ' + getErrorMessage(error)); } };