AuditExportService.java
package com.edtech.service;
import com.edtech.model.AuditLog;
import com.edtech.model.Document;
import com.edtech.repository.AuditLogRepository;
import com.edtech.repository.DocumentRepository;
import com.edtech.repository.ProjectMemberRepository;
import java.io.ByteArrayOutputStream;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import org.openpdf.text.DocumentException;
import org.openpdf.text.Font;
import org.openpdf.text.FontFactory;
import org.openpdf.text.PageSize;
import org.openpdf.text.Paragraph;
import org.openpdf.text.Phrase;
import org.openpdf.text.pdf.PdfPCell;
import org.openpdf.text.pdf.PdfPTable;
import org.openpdf.text.pdf.PdfWriter;
import org.springframework.stereotype.Service;
/** Service responsavel por exportar trilhas de auditoria de documentos. */
@Service
public class AuditExportService {
private static final String CSV_FORMAT = "csv";
private static final String PDF_FORMAT = "pdf";
private static final String DOCUMENT_RESOURCE_TYPE = "Document";
private final AuditLogRepository auditLogRepository;
private final DocumentRepository documentRepository;
private final ProjectMemberRepository projectMemberRepository;
private final AuditTrailCsvExporter csvExporter;
/** Cria o servico com os repositorios e exportador necessarios. */
public AuditExportService(
AuditLogRepository auditLogRepository,
DocumentRepository documentRepository,
ProjectMemberRepository projectMemberRepository,
AuditTrailCsvExporter csvExporter) {
this.auditLogRepository = auditLogRepository;
this.documentRepository = documentRepository;
this.projectMemberRepository = projectMemberRepository;
this.csvExporter = csvExporter;
}
/**
* Exporta os logs de auditoria relacionados a um documento.
*
* @param documentId identificador do documento.
* @param userId identificador do usuario que solicitou a exportacao.
* @param format formato solicitado para exportacao.
* @return conteudo do arquivo exportado em bytes.
*/
public byte[] exportDocumentAuditTrail(UUID documentId, UUID userId, String format) {
String normalizedFormat = normalizeFormat(format);
if (!CSV_FORMAT.equals(normalizedFormat) && !PDF_FORMAT.equals(normalizedFormat)) {
throw new IllegalArgumentException("Formato invalido. Use: csv ou pdf");
}
Document document =
documentRepository
.findById(documentId)
.orElseThrow(() -> new RuntimeException("Document not found"));
projectMemberRepository
.findByProjectIdAndUserId(document.getProject().getId(), userId)
.orElseThrow(
() -> new RuntimeException("Access denied: You are not a member of this project"));
List<AuditLog> logs =
auditLogRepository.findByResourceTypeAndResourceIdOrderByCreatedAtAsc(
DOCUMENT_RESOURCE_TYPE, documentId);
if (PDF_FORMAT.equals(normalizedFormat)) {
return exportPdf(logs);
}
return csvExporter.export(logs);
}
private byte[] exportPdf(List<AuditLog> logs) {
org.openpdf.text.Document pdfDoc = new org.openpdf.text.Document(PageSize.A4.rotate());
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
PdfWriter.getInstance(pdfDoc, out);
pdfDoc.open();
Font fontTitle = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
fontTitle.setSize(18);
Paragraph title = new Paragraph("Trilha de Auditoria do Documento", fontTitle);
title.setAlignment(Paragraph.ALIGN_CENTER);
pdfDoc.add(title);
pdfDoc.add(new Paragraph(" "));
PdfPTable table = new PdfPTable(6);
table.setWidthPercentage(100f);
table.setWidths(new float[] {1.5f, 2.5f, 2.0f, 2.0f, 1.5f, 4.0f});
Font fontHeader = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
fontHeader.setSize(10);
String[] headers = {"ID", "Timestamp", "Ação", "Usuário ID", "IP", "Detalhes"};
for (String header : headers) {
PdfPCell cell = new PdfPCell();
cell.setPhrase(new Phrase(header, fontHeader));
table.addCell(cell);
}
Font fontData = FontFactory.getFont(FontFactory.HELVETICA);
fontData.setSize(8);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (AuditLog log : logs) {
table.addCell(new Phrase(log.getId() != null ? log.getId().toString() : "", fontData));
table.addCell(
new Phrase(
log.getCreatedAt() != null ? log.getCreatedAt().format(formatter) : "", fontData));
table.addCell(new Phrase(log.getAction() != null ? log.getAction().name() : "", fontData));
table.addCell(
new Phrase(log.getUserId() != null ? log.getUserId().toString() : "", fontData));
table.addCell(new Phrase(log.getIpAddress() != null ? log.getIpAddress() : "", fontData));
table.addCell(new Phrase(log.getDetails() != null ? log.getDetails() : "", fontData));
}
pdfDoc.add(table);
pdfDoc.close();
} catch (DocumentException e) {
throw new RuntimeException("Erro ao gerar PDF", e);
}
return out.toByteArray();
}
public String buildFilename(UUID documentId, String format) {
return "audit-trail-" + documentId + "." + normalizeFormat(format);
}
private String normalizeFormat(String format) {
if (format == null || format.isBlank()) {
return CSV_FORMAT;
}
return format.toLowerCase(Locale.ROOT);
}
}