AuditExportService.java

1
package com.edtech.service;
2
3
import com.edtech.model.AuditLog;
4
import com.edtech.model.Document;
5
import com.edtech.repository.AuditLogRepository;
6
import com.edtech.repository.DocumentRepository;
7
import com.edtech.repository.ProjectMemberRepository;
8
import java.io.ByteArrayOutputStream;
9
import java.time.format.DateTimeFormatter;
10
import java.util.List;
11
import java.util.Locale;
12
import java.util.UUID;
13
import org.openpdf.text.DocumentException;
14
import org.openpdf.text.Font;
15
import org.openpdf.text.FontFactory;
16
import org.openpdf.text.PageSize;
17
import org.openpdf.text.Paragraph;
18
import org.openpdf.text.Phrase;
19
import org.openpdf.text.pdf.PdfPCell;
20
import org.openpdf.text.pdf.PdfPTable;
21
import org.openpdf.text.pdf.PdfWriter;
22
import org.springframework.stereotype.Service;
23
24
/** Service responsavel por exportar trilhas de auditoria de documentos. */
25
@Service
26
public class AuditExportService {
27
28
  private static final String CSV_FORMAT = "csv";
29
  private static final String PDF_FORMAT = "pdf";
30
  private static final String DOCUMENT_RESOURCE_TYPE = "Document";
31
32
  private final AuditLogRepository auditLogRepository;
33
  private final DocumentRepository documentRepository;
34
  private final ProjectMemberRepository projectMemberRepository;
35
  private final AuditTrailCsvExporter csvExporter;
36
37
  /** Cria o servico com os repositorios e exportador necessarios. */
38
  public AuditExportService(
39
      AuditLogRepository auditLogRepository,
40
      DocumentRepository documentRepository,
41
      ProjectMemberRepository projectMemberRepository,
42
      AuditTrailCsvExporter csvExporter) {
43
    this.auditLogRepository = auditLogRepository;
44
    this.documentRepository = documentRepository;
45
    this.projectMemberRepository = projectMemberRepository;
46
    this.csvExporter = csvExporter;
47
  }
48
49
  /**
50
   * Exporta os logs de auditoria relacionados a um documento.
51
   *
52
   * @param documentId identificador do documento.
53
   * @param userId identificador do usuario que solicitou a exportacao.
54
   * @param format formato solicitado para exportacao.
55
   * @return conteudo do arquivo exportado em bytes.
56
   */
57
  public byte[] exportDocumentAuditTrail(UUID documentId, UUID userId, String format) {
58
    String normalizedFormat = normalizeFormat(format);
59 2 1. exportDocumentAuditTrail : negated conditional → KILLED
2. exportDocumentAuditTrail : negated conditional → KILLED
    if (!CSV_FORMAT.equals(normalizedFormat) && !PDF_FORMAT.equals(normalizedFormat)) {
60
      throw new IllegalArgumentException("Formato invalido. Use: csv ou pdf");
61
    }
62
63
    Document document =
64
        documentRepository
65
            .findById(documentId)
66 1 1. lambda$exportDocumentAuditTrail$0 : replaced return value with null for com/edtech/service/AuditExportService::lambda$exportDocumentAuditTrail$0 → KILLED
            .orElseThrow(() -> new RuntimeException("Document not found"));
67
68
    projectMemberRepository
69
        .findByProjectIdAndUserId(document.getProject().getId(), userId)
70
        .orElseThrow(
71 1 1. lambda$exportDocumentAuditTrail$1 : replaced return value with null for com/edtech/service/AuditExportService::lambda$exportDocumentAuditTrail$1 → KILLED
            () -> new RuntimeException("Access denied: You are not a member of this project"));
72
73
    List<AuditLog> logs =
74
        auditLogRepository.findByResourceTypeAndResourceIdOrderByCreatedAtAsc(
75
            DOCUMENT_RESOURCE_TYPE, documentId);
76
77 1 1. exportDocumentAuditTrail : negated conditional → KILLED
    if (PDF_FORMAT.equals(normalizedFormat)) {
78 1 1. exportDocumentAuditTrail : replaced return value with null for com/edtech/service/AuditExportService::exportDocumentAuditTrail → NO_COVERAGE
      return exportPdf(logs);
79
    }
80
81 1 1. exportDocumentAuditTrail : replaced return value with null for com/edtech/service/AuditExportService::exportDocumentAuditTrail → KILLED
    return csvExporter.export(logs);
82
  }
83
84
  private byte[] exportPdf(List<AuditLog> logs) {
85
    org.openpdf.text.Document pdfDoc = new org.openpdf.text.Document(PageSize.A4.rotate());
86
    ByteArrayOutputStream out = new ByteArrayOutputStream();
87
88
    try {
89
      PdfWriter.getInstance(pdfDoc, out);
90 1 1. exportPdf : removed call to org/openpdf/text/Document::open → NO_COVERAGE
      pdfDoc.open();
91
92
      Font fontTitle = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
93 1 1. exportPdf : removed call to org/openpdf/text/Font::setSize → NO_COVERAGE
      fontTitle.setSize(18);
94
      Paragraph title = new Paragraph("Trilha de Auditoria do Documento", fontTitle);
95 1 1. exportPdf : removed call to org/openpdf/text/Paragraph::setAlignment → NO_COVERAGE
      title.setAlignment(Paragraph.ALIGN_CENTER);
96
      pdfDoc.add(title);
97
      pdfDoc.add(new Paragraph(" "));
98
99
      PdfPTable table = new PdfPTable(6);
100 1 1. exportPdf : removed call to org/openpdf/text/pdf/PdfPTable::setWidthPercentage → NO_COVERAGE
      table.setWidthPercentage(100f);
101 1 1. exportPdf : removed call to org/openpdf/text/pdf/PdfPTable::setWidths → NO_COVERAGE
      table.setWidths(new float[] {1.5f, 2.5f, 2.0f, 2.0f, 1.5f, 4.0f});
102
103
      Font fontHeader = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
104 1 1. exportPdf : removed call to org/openpdf/text/Font::setSize → NO_COVERAGE
      fontHeader.setSize(10);
105
      String[] headers = {"ID", "Timestamp", "Ação", "Usuário ID", "IP", "Detalhes"};
106
      for (String header : headers) {
107
        PdfPCell cell = new PdfPCell();
108 1 1. exportPdf : removed call to org/openpdf/text/pdf/PdfPCell::setPhrase → NO_COVERAGE
        cell.setPhrase(new Phrase(header, fontHeader));
109
        table.addCell(cell);
110
      }
111
112
      Font fontData = FontFactory.getFont(FontFactory.HELVETICA);
113 1 1. exportPdf : removed call to org/openpdf/text/Font::setSize → NO_COVERAGE
      fontData.setSize(8);
114
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
115
116
      for (AuditLog log : logs) {
117 1 1. exportPdf : negated conditional → NO_COVERAGE
        table.addCell(new Phrase(log.getId() != null ? log.getId().toString() : "", fontData));
118
        table.addCell(
119
            new Phrase(
120 1 1. exportPdf : negated conditional → NO_COVERAGE
                log.getCreatedAt() != null ? log.getCreatedAt().format(formatter) : "", fontData));
121 1 1. exportPdf : negated conditional → NO_COVERAGE
        table.addCell(new Phrase(log.getAction() != null ? log.getAction().name() : "", fontData));
122
        table.addCell(
123 1 1. exportPdf : negated conditional → NO_COVERAGE
            new Phrase(log.getUserId() != null ? log.getUserId().toString() : "", fontData));
124 1 1. exportPdf : negated conditional → NO_COVERAGE
        table.addCell(new Phrase(log.getIpAddress() != null ? log.getIpAddress() : "", fontData));
125 1 1. exportPdf : negated conditional → NO_COVERAGE
        table.addCell(new Phrase(log.getDetails() != null ? log.getDetails() : "", fontData));
126
      }
127
128
      pdfDoc.add(table);
129 1 1. exportPdf : removed call to org/openpdf/text/Document::close → NO_COVERAGE
      pdfDoc.close();
130
131
    } catch (DocumentException e) {
132
      throw new RuntimeException("Erro ao gerar PDF", e);
133
    }
134
135 1 1. exportPdf : replaced return value with null for com/edtech/service/AuditExportService::exportPdf → NO_COVERAGE
    return out.toByteArray();
136
  }
137
138
  public String buildFilename(UUID documentId, String format) {
139 1 1. buildFilename : replaced return value with "" for com/edtech/service/AuditExportService::buildFilename → KILLED
    return "audit-trail-" + documentId + "." + normalizeFormat(format);
140
  }
141
142
  private String normalizeFormat(String format) {
143 2 1. normalizeFormat : negated conditional → KILLED
2. normalizeFormat : negated conditional → KILLED
    if (format == null || format.isBlank()) {
144 1 1. normalizeFormat : replaced return value with "" for com/edtech/service/AuditExportService::normalizeFormat → KILLED
      return CSV_FORMAT;
145
    }
146 1 1. normalizeFormat : replaced return value with "" for com/edtech/service/AuditExportService::normalizeFormat → KILLED
    return format.toLowerCase(Locale.ROOT);
147
  }
148
}

Mutations

59

1.1
Location : exportDocumentAuditTrail
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:exportDocumentAuditTrail_WithInvalidFormat_ThrowsBeforeRepositoryAccess()]
negated conditional → KILLED

2.2
Location : exportDocumentAuditTrail
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:exportDocumentAuditTrail_WithInvalidFormat_ThrowsBeforeRepositoryAccess()]
negated conditional → KILLED

66

1.1
Location : lambda$exportDocumentAuditTrail$0
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:exportDocumentAuditTrail_WhenDocumentDoesNotExist_Throws()]
replaced return value with null for com/edtech/service/AuditExportService::lambda$exportDocumentAuditTrail$0 → KILLED

71

1.1
Location : lambda$exportDocumentAuditTrail$1
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:exportDocumentAuditTrail_WhenUserIsNotProjectMember_Throws()]
replaced return value with null for com/edtech/service/AuditExportService::lambda$exportDocumentAuditTrail$1 → KILLED

77

1.1
Location : exportDocumentAuditTrail
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:exportDocumentAuditTrail_WithNullFormat_UsesCsvFormat()]
negated conditional → KILLED

78

1.1
Location : exportDocumentAuditTrail
Killed by : none
replaced return value with null for com/edtech/service/AuditExportService::exportDocumentAuditTrail → NO_COVERAGE

81

1.1
Location : exportDocumentAuditTrail
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:exportDocumentAuditTrail_WithNullFormat_UsesCsvFormat()]
replaced return value with null for com/edtech/service/AuditExportService::exportDocumentAuditTrail → KILLED

90

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/Document::open → NO_COVERAGE

93

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/Font::setSize → NO_COVERAGE

95

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/Paragraph::setAlignment → NO_COVERAGE

100

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/pdf/PdfPTable::setWidthPercentage → NO_COVERAGE

101

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/pdf/PdfPTable::setWidths → NO_COVERAGE

104

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/Font::setSize → NO_COVERAGE

108

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/pdf/PdfPCell::setPhrase → NO_COVERAGE

113

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/Font::setSize → NO_COVERAGE

117

1.1
Location : exportPdf
Killed by : none
negated conditional → NO_COVERAGE

120

1.1
Location : exportPdf
Killed by : none
negated conditional → NO_COVERAGE

121

1.1
Location : exportPdf
Killed by : none
negated conditional → NO_COVERAGE

123

1.1
Location : exportPdf
Killed by : none
negated conditional → NO_COVERAGE

124

1.1
Location : exportPdf
Killed by : none
negated conditional → NO_COVERAGE

125

1.1
Location : exportPdf
Killed by : none
negated conditional → NO_COVERAGE

129

1.1
Location : exportPdf
Killed by : none
removed call to org/openpdf/text/Document::close → NO_COVERAGE

135

1.1
Location : exportPdf
Killed by : none
replaced return value with null for com/edtech/service/AuditExportService::exportPdf → NO_COVERAGE

139

1.1
Location : buildFilename
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:buildFilename_NormalizesBlankAndUppercaseFormats()]
replaced return value with "" for com/edtech/service/AuditExportService::buildFilename → KILLED

143

1.1
Location : normalizeFormat
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:exportDocumentAuditTrail_WithInvalidFormat_ThrowsBeforeRepositoryAccess()]
negated conditional → KILLED

2.2
Location : normalizeFormat
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:buildFilename_NormalizesBlankAndUppercaseFormats()]
negated conditional → KILLED

144

1.1
Location : normalizeFormat
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:buildFilename_NormalizesBlankAndUppercaseFormats()]
replaced return value with "" for com/edtech/service/AuditExportService::normalizeFormat → KILLED

146

1.1
Location : normalizeFormat
Killed by : com.edtech.service.AuditExportServiceTest.[engine:junit-jupiter]/[class:com.edtech.service.AuditExportServiceTest]/[method:buildFilename_NormalizesBlankAndUppercaseFormats()]
replaced return value with "" for com/edtech/service/AuditExportService::normalizeFormat → KILLED

Active mutators

Tests examined


Report generated by PIT 1.25.9 support