FEAT: Adiciona função de sanitização de comentários do GLPI para remover HTML e limpar metadados.
This commit is contained in:
parent
a656762989
commit
33e78e70c3
@ -5,7 +5,7 @@ const TicketSyncModel = require('../models/ticketSyncModel');
|
||||
const TicketUpdateModel = require('../models/ticketUpdateModel');
|
||||
const { logInfo, logError } = require('../utils/logger');
|
||||
const { existingCommentInServiceNow, syncCommentToServiceNow } = require('./servicenowService');
|
||||
|
||||
const { sanitizeGLPIComment } = require('../utils/commentSanitizer');
|
||||
|
||||
// Sincroniza comentários do GLPI para o Banco de Dados local
|
||||
const syncCommentsGlpi = async () => {
|
||||
@ -23,12 +23,21 @@ const syncCommentsGlpi = async () => {
|
||||
|
||||
for (const comment of comments) {
|
||||
|
||||
// DEBUG: Mostra antes e depois
|
||||
logInfo(`🔍 Processando comentário GLPI ID: ${comment.id}`);
|
||||
logInfo(`📝 CONTEÚDO ORIGINAL: ${comment.content.substring(0, 200)}...`);
|
||||
|
||||
// Sanitiza o comentário
|
||||
const sanitizedContent = sanitizeGLPIComment(comment);
|
||||
|
||||
logInfo(`✨ CONTEÚDO SANITIZADO: ${sanitizedContent.substring(0, 200)}...`);
|
||||
|
||||
const existingComment = await TicketUpdateModel.getCommentSync(ticket.glpi_ticket_id, comment.id);
|
||||
|
||||
const commentExistsInSN = await existingCommentInServiceNow(
|
||||
ticket.sn_ticket_id,
|
||||
comment.content
|
||||
)
|
||||
sanitizedContent // ✅ Usa o conteúdo sanitizado
|
||||
);
|
||||
|
||||
if (existingComment && commentExistsInSN) {
|
||||
logInfo(`Comentário ID ${comment.id} já sincronizado no banco de dados e no ServiceNow`, { step: 3 });
|
||||
@ -41,7 +50,7 @@ const syncCommentsGlpi = async () => {
|
||||
const commentData = {
|
||||
ticket_sync_id: sync_id,
|
||||
source_system: 'glpi',
|
||||
content: comment.content,
|
||||
content: sanitizedContent, // ✅ Usa o conteúdo sanitizado
|
||||
created_at: new Date(comment.date_creation),
|
||||
updated_at: new Date(comment.date_mod),
|
||||
source_id: comment.id,
|
||||
@ -59,10 +68,9 @@ const syncCommentsGlpi = async () => {
|
||||
if (existingComment && !commentExistsInSN) {
|
||||
logInfo(`Comentário ID ${comment.id} já existe no banco, mas não no ServiceNow. Sincronizando...`, { step: 3 });
|
||||
// Só sincroniza no ServiceNow
|
||||
const snCommentId = await syncCommentToServiceNow(ticket.sn_ticket_id, comment.content);
|
||||
// Se quiser, pode atualizar o registro no banco com o id do ServiceNow aqui
|
||||
const snCommentId = await syncCommentToServiceNow(ticket.sn_ticket_id, sanitizedContent); // ✅ Usa o conteúdo sanitizado
|
||||
logInfo(`✅ Comentário ID ${comment.id} sincronizado no ServiceNow!`, { step: 4 });
|
||||
const updateData = await TicketUpdateModel.updateDestinyId(comment.id, snCommentId);
|
||||
const updateData = await TicketUpdateModel.updateDestinyId(comment.id, snCommentId);
|
||||
if (updateData && updateData.success) {
|
||||
logInfo(`✅ ID do comentário de destino atualizado no banco: ${snCommentId}`, { step: 4 });
|
||||
}
|
||||
@ -70,12 +78,12 @@ const syncCommentsGlpi = async () => {
|
||||
}
|
||||
|
||||
// Se não existe em nenhum dos dois, sincroniza nos dois normalmente
|
||||
const snCommentId = await syncCommentToServiceNow(ticket.sn_ticket_id, comment);
|
||||
const snCommentId = await syncCommentToServiceNow(ticket.sn_ticket_id, sanitizedContent); // ✅ Usa o conteúdo sanitizado
|
||||
const sync_id = await TicketSyncModel.getIdSyncByGlpiId(ticket.glpi_ticket_id);
|
||||
const commentData = {
|
||||
ticket_sync_id: sync_id,
|
||||
source_system: 'glpi',
|
||||
content: comment.content,
|
||||
content: sanitizedContent, // ✅ Usa o conteúdo sanitizado
|
||||
created_at: new Date(comment.date_creation),
|
||||
updated_at: new Date(comment.date_mod),
|
||||
source_id: comment.id,
|
||||
@ -89,22 +97,20 @@ const syncCommentsGlpi = async () => {
|
||||
}
|
||||
|
||||
const hasError = !insertResult.success;
|
||||
const snStatus = 'pending';
|
||||
const glpiStatus = hasError ? 'Error' :'updated';
|
||||
const snStatus = 'pending';
|
||||
const glpiStatus = hasError ? 'Error' : 'updated';
|
||||
await TicketSyncModel.updateStatus(ticket.id, glpiStatus, snStatus);
|
||||
logInfo(`Status de sincronização para o ticket ID ${ticket.id} atualizado para GLPI: '${glpiStatus}', SN: '${snStatus}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
logInfo('✅ Sincronização de comentários do GLPI -> ServiceNow concluída!');
|
||||
}catch (error) {
|
||||
} catch (error) {
|
||||
logError(error, 'GLPI Tickets');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @module glpiCommentService
|
||||
* @description Este módulo fornece serviços para sincronizar comentários do GLPI para o banco de dados local.
|
||||
|
||||
132
src/utils/commentSanitizer.js
Normal file
132
src/utils/commentSanitizer.js
Normal file
@ -0,0 +1,132 @@
|
||||
// src/utils/commentSanitizer.js
|
||||
const { logInfo, logWarning } = require('./logger');
|
||||
|
||||
/**
|
||||
* Remove HTML tags e converte entidades HTML - CORRIGIDO
|
||||
*/
|
||||
const stripHTML = (html) => {
|
||||
if (!html) return '';
|
||||
|
||||
// PRIMEIRO: converte entidades HTML para caracteres normais
|
||||
let cleaned = html
|
||||
.replace(/</g, '<') // < para <
|
||||
.replace(/>/g, '>') // > para >
|
||||
.replace(/&/g, '&') // & para &
|
||||
.replace(/ /g, ' ') // para espaço
|
||||
.replace(/</g, '<') // < para <
|
||||
.replace(/>/g, '>') // > para >
|
||||
.replace(/&/g, '&') // & para &
|
||||
.replace(/"/g, '"'); // " para "
|
||||
|
||||
// DEPOIS: remove tags HTML
|
||||
cleaned = cleaned
|
||||
.replace(/<br\s*\/?>/gi, '\n') // <br> para quebra de linha
|
||||
.replace(/<p>/gi, '') // Remove <p>
|
||||
.replace(/<\/p>/gi, '\n\n') // </p> para duas quebras
|
||||
.replace(/<strong>/gi, '**') // <strong> para **
|
||||
.replace(/<\/strong>/gi, '**') // </strong> para **
|
||||
.replace(/<em>/gi, '*') // <em> para *
|
||||
.replace(/<\/em>/gi, '*') // </em> para *
|
||||
.replace(/<blockquote>/gi, '> ') // <blockquote> para citação
|
||||
.replace(/<\/blockquote>/gi, '') // </blockquote>
|
||||
.replace(/<div[^>]*>/gi, '') // Remove <div> com qualquer atributo
|
||||
.replace(/<\/div>/gi, '\n') // </div> para quebra
|
||||
.replace(/<[^>]*>/g, '') // Remove todas outras tags HTML
|
||||
.replace(/\n\s*\n\s*\n/g, '\n\n') // Remove múltiplas quebras
|
||||
.replace(/^\s+|\s+$/g, '') // Remove espaços no início/fim
|
||||
.trim();
|
||||
|
||||
return cleaned;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detecta e trata imagens do GLPI
|
||||
*/
|
||||
const handleImages = (content) => {
|
||||
const imgRegex = /<img[^>]+src="([^"]+)"[^>]*>/gi;
|
||||
const hasImages = imgRegex.test(content);
|
||||
|
||||
if (hasImages) {
|
||||
logWarning('📷 Imagem detectada no comentário GLPI');
|
||||
// Remove toda a tag de imagem mas mantém o texto around
|
||||
return content.replace(/<a[^>]*>.*?<img[^>]*>.*?<\/a>/gi, '[IMAGEM ANEXA NO GLPI]');
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
/**
|
||||
* Limpa metadados JSON do GLPI
|
||||
*/
|
||||
const cleanJSONMetadata = (content) => {
|
||||
if (typeof content === 'string' && content.includes('{id=') && content.includes('content=')) {
|
||||
try {
|
||||
// Extrai o conteúdo do campo content= do objeto
|
||||
const contentMatch = content.match(/content=([^,]+),/);
|
||||
if (contentMatch && contentMatch[1]) {
|
||||
let extracted = contentMatch[1].trim();
|
||||
// Remove aspas se existirem
|
||||
extracted = extracted.replace(/^['"]|['"]$/g, '');
|
||||
return extracted;
|
||||
}
|
||||
} catch (error) {
|
||||
logWarning('Não foi possível extrair conteúdo do metadado GLPI', { content });
|
||||
}
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
/**
|
||||
* Função principal de sanitização
|
||||
*/
|
||||
const sanitizeGLPIComment = (commentObj) => {
|
||||
if (!commentObj || typeof commentObj !== 'object') {
|
||||
logWarning('Comentário inválido recebido', { comment: commentObj });
|
||||
return '';
|
||||
}
|
||||
|
||||
// Pega o conteúdo do objeto comment
|
||||
let content = commentObj.content || '';
|
||||
|
||||
// Se for string vazia, retorna vazio
|
||||
if (!content) return '';
|
||||
|
||||
// Aplica as limpezas em sequência
|
||||
content = cleanJSONMetadata(content.toString());
|
||||
content = handleImages(content);
|
||||
content = stripHTML(content);
|
||||
|
||||
// Log para debugging
|
||||
if (content !== commentObj.content) {
|
||||
logInfo('🔧 Comentário sanitizado', {
|
||||
original: commentObj.content.substring(0, 100) + '...',
|
||||
cleaned: content.substring(0, 100) + '...'
|
||||
});
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
/**
|
||||
* Esse módulo fornece funções para sanitizar comentários importados do GLPI.
|
||||
* Ele remove tags HTML, trata imagens e limpa metadados JSON específicos do GLPI.
|
||||
* O objetivo é garantir que os comentários sejam legíveis e seguros para exibição.
|
||||
*
|
||||
* Funções principais:
|
||||
* - sanitizeGLPIComment: Função principal que aplica todas as sanitizações.
|
||||
* - stripHTML: Remove tags HTML e converte algumas entidades para texto simples.
|
||||
* - handleImages: Detecta imagens e substitui por um marcador de imagem.
|
||||
* - cleanJSONMetadata: Remove metadados JSON do GLPI, extraindo apenas o conteúdo relevante.
|
||||
*
|
||||
* Logs são gerados para ajudar no debugging e monitoramento do processo de sanitização.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
sanitizeGLPIComment,
|
||||
stripHTML,
|
||||
handleImages,
|
||||
cleanJSONMetadata
|
||||
};
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user