Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions backend/src/modules/records/records.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' });
}
Comment on lines +721 to +723

// 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 });
}
Comment on lines +744 to +747
});
}
7 changes: 6 additions & 1 deletion backend/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -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".
Comment on lines +255 to +259
reply.status(statusCode).send({
error: true,
error: message,
message,
statusCode
});
Expand Down
31 changes: 21 additions & 10 deletions frontend/src/pages/kb/KBView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ const isProbablyHtml = (value) => {
return /<\/?[a-z][\s\S]*>/i.test(String(value));
};

// A API sempre manda { error: '<mensagem>' } 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.
Comment on lines +22 to +26
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();
Expand Down Expand Up @@ -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);
}
Expand All @@ -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.');
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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));
}
};

Expand All @@ -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));
}
};

Expand All @@ -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));
}
};

Expand All @@ -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));
}
};

Expand All @@ -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));
}
};

Expand All @@ -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));
}
};

Expand Down