From 5c3f69e0058d4ee84a1f9885e08484e9710fcebf Mon Sep 17 00:00:00 2001 From: aoezyetimoglu Date: Tue, 4 May 2021 11:53:13 +0200 Subject: [PATCH] RED-1186: updates --- .../v1/server/client/ProjectClient.java | 9 + .../service/ReportGenerationService.java | 13 +- .../service/WordReportGenerationService.java | 208 ++++++------------ ...anitisation justification Appendix A1.docx | Bin 78520 -> 78566 bytes .../RedactionReportIntegrationTest.java | 30 ++- 5 files changed, 116 insertions(+), 144 deletions(-) create mode 100644 redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/ProjectClient.java diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/ProjectClient.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/ProjectClient.java new file mode 100644 index 0000000..81c19c8 --- /dev/null +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/ProjectClient.java @@ -0,0 +1,9 @@ +package com.iqser.red.service.redaction.report.v1.server.client; + +import com.iqser.red.service.file.management.v1.api.resources.ProjectResource; +import org.springframework.cloud.openfeign.FeignClient; + +@FeignClient(name = "ProjectResource", url = "${file-management-service.url}") +public interface ProjectClient extends ProjectResource { + +} diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java index a254cf6..3fa73e4 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java @@ -2,11 +2,13 @@ package com.iqser.red.service.redaction.report.v1.server.service; import com.iqser.red.service.configuration.v1.api.model.LegalBasisMapping; import com.iqser.red.service.file.management.v1.api.model.FileStatus; +import com.iqser.red.service.file.management.v1.api.model.Project; import com.iqser.red.service.redaction.report.v1.api.model.ReportRequestMessage; import com.iqser.red.service.redaction.report.v1.api.model.ReportType; import com.iqser.red.service.redaction.report.v1.api.model.StoredFileInformation; import com.iqser.red.service.redaction.report.v1.server.client.FileStatusClient; import com.iqser.red.service.redaction.report.v1.server.client.LegalBasisMappingClient; +import com.iqser.red.service.redaction.report.v1.server.client.ProjectClient; import com.iqser.red.service.redaction.report.v1.server.model.ReportRedactionEntry; import com.iqser.red.service.redaction.report.v1.server.storage.ReportStorageService; import com.iqser.red.service.redaction.v1.model.RedactionLog; @@ -31,6 +33,7 @@ public class ReportGenerationService { private final LegalBasisMappingClient legalBasisMappingClient; private final RedactionLogConverterService redactionLogConverterService; private final FileStatusClient fileStatusClient; + private final ProjectClient projectClient; public List generateReport(ReportRequestMessage reportMessage) { @@ -47,6 +50,8 @@ public class ReportGenerationService { List storedFileInformation = new ArrayList<>(); + Project project = projectClient.getProjectById(reportMessage.getProjectId()); + int i = 1; for (String fileId : reportMessage.getFileIds()) { @@ -71,15 +76,15 @@ public class ReportGenerationService { } if (reportMessage.getReportTypes().contains(ReportType.WORD_SINGLE_FILE_APPENDIX_A1_TEMPLATE)) { - byte[] wordEFSATemplate = wordReportGenerationService.generateReport(ReportType.WORD_SINGLE_FILE_APPENDIX_A1_TEMPLATE, reportEntries, fileStatus - .getFilename()); + byte[] wordEFSATemplate = wordReportGenerationService.generateReport(ReportType.WORD_SINGLE_FILE_APPENDIX_A1_TEMPLATE, + reportEntries, redactionLog.getRuleSetId(), fileStatus, project); String storageId = reportStorageService.storeObject(reportMessage.getDownloadId(), wordEFSATemplate); storedFileInformation.add(new StoredFileInformation(fileId, storageId, ReportType.WORD_SINGLE_FILE_APPENDIX_A1_TEMPLATE)); } if (reportMessage.getReportTypes().contains(ReportType.WORD_SINGLE_FILE_APPENDIX_A2_TEMPLATE)) { - byte[] wordSyngentaTemplate = wordReportGenerationService.generateReport(ReportType.WORD_SINGLE_FILE_APPENDIX_A2_TEMPLATE, reportEntries, fileStatus - .getFilename()); + byte[] wordSyngentaTemplate = wordReportGenerationService.generateReport(ReportType.WORD_SINGLE_FILE_APPENDIX_A2_TEMPLATE, + reportEntries, redactionLog.getRuleSetId(), fileStatus, project); String storageId = reportStorageService.storeObject(reportMessage.getDownloadId(), wordSyngentaTemplate); storedFileInformation.add(new StoredFileInformation(fileId, storageId, ReportType.WORD_SINGLE_FILE_APPENDIX_A2_TEMPLATE)); } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java index 83be349..642ed1b 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java @@ -1,29 +1,24 @@ package com.iqser.red.service.redaction.report.v1.server.service; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.time.LocalDate; -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.regex.Pattern; - -import javax.annotation.PostConstruct; - import com.iqser.red.service.configuration.v1.api.model.FileAttributesConfig; -import com.iqser.red.service.redaction.report.v1.server.client.*; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.util.Units; +import com.iqser.red.service.file.management.v1.api.model.FileStatus; +import com.iqser.red.service.file.management.v1.api.model.Project; +import com.iqser.red.service.redaction.report.v1.api.model.ReportType; +import com.iqser.red.service.redaction.report.v1.server.client.FileAttributesClient; +import com.iqser.red.service.redaction.report.v1.server.model.ReportRedactionEntry; +import com.iqser.red.service.redaction.report.v1.server.utils.ResourceLoader; +import lombok.RequiredArgsConstructor; import org.apache.poi.xwpf.usermodel.*; import org.springframework.stereotype.Service; -import com.iqser.red.service.redaction.report.v1.api.model.ReportType; -import com.iqser.red.service.redaction.report.v1.server.model.ReportRedactionEntry; -import com.iqser.red.service.redaction.report.v1.server.utils.ResourceLoader; - -import lombok.RequiredArgsConstructor; +import javax.annotation.PostConstruct; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.regex.Pattern; @Service @RequiredArgsConstructor @@ -31,7 +26,7 @@ public class WordReportGenerationService { private byte[] appendixA1Template; private byte[] appendixA2Template; - private FileAttributesClient fileAttributesClient; + private final FileAttributesClient fileAttributesClient; public static final String FILE_NAME_PLACEHOLDER = "{{file.name}}"; public static final String PAGE_PLACEHOLDER = "{{redaction.page}}"; @@ -50,25 +45,19 @@ public class WordReportGenerationService { public static final String DOSSIER_NAME_PLACEHOLDER = "{{dossier.name}}"; - List placeholders = List.of(FILE_NAME_PLACEHOLDER, FORMAT_DATE_ISO_PLACEHOLDER, FORMAT_DATE_GER_PLACEHOLDER, FORMAT_DATE_ENG_PLACEHOLDER, FORMAT_TIME_ISO_PLACEHOLDER, DOSSIER_NAME_PLACEHOLDER); - @PostConstruct public void init() { appendixA1Template = ResourceLoader.load("templates/Sanitisation justification Appendix A1.docx"); appendixA2Template = ResourceLoader.load("templates/Sanitisation justification Appendix A2.docx"); + } - public byte[] generateReport(ReportType reportType, List reportEntries, String filename, String ruleSetId) { - - Map placeholders = new HashMap<>(); - - FileAttributesConfig fileAttributesConfig = fileAttributesClient.getFileAttributes(ruleSetId); - fileAttributesConfig.getFileAttributeConfigs().forEach(fileAttributeConfig -> { - String placeholder = "{{file.attribute" + fileAttributeConfig.getLabel().replace(" ", "-").toLowerCase(Locale.ROOT) + "}}"; - placeholders.put(placeholder, fileAttributeConfig.getId()); - }); + public byte[] generateReport(ReportType reportType, List reportEntries, String ruleSetId, FileStatus fileStatus, Project project) { + List placeholders = getDefaultPlaceholders(); + Map fileAttributePlaceholders = getFileAttributePlaceholders(ruleSetId); + placeholders.addAll(fileAttributePlaceholders.keySet()); byte[] template; @@ -82,23 +71,10 @@ public class WordReportGenerationService { try (ByteArrayInputStream is = new ByteArrayInputStream(template)) { XWPFDocument doc = new XWPFDocument(is); + addTableRows(doc, reportEntries, fileStatus.getFilename()); for(String placeholder: placeholders) { - replaceTextPlaceholders(doc, placeholder, getPlaceholderValue(placeholder, , , placeholders)); - + replaceTextPlaceholders(doc, placeholder, getPlaceholderValue(placeholder, project, fileStatus, fileAttributePlaceholders)); } - for (ImagePlaceholder imagePlaceholder: placeholders.getImagePlaceholders()){ - replaceImagePlaceholders(doc, imagePlaceholder); - } - for (Placeholder placeholder : placeholders.getTextPlaceholders()) { - replaceTextPlaceholders(doc, placeholder.getPlaceholder(), placeholder.getValue()); - } - for (DatePlaceholder datePlaceholder: placeholders.getDatePlaceholders()) { - replaceDatePlaceholder(doc, datePlaceholder.getPlaceholder()); - } - for (TimePlaceholder timePlaceholder: placeholders.getTimePlaceholders()) { - replaceTimePlaceholder(doc, timePlaceholder.getPlaceholder()); - } - addTableRows(doc, reportEntries, filename); return toByteArray(doc); } catch (IOException e) { throw new RuntimeException(e); @@ -107,7 +83,24 @@ public class WordReportGenerationService { } } - private String getPlaceholderValue(String placeholder, String dossierName, String fileName, Map placeholders) { + private List getDefaultPlaceholders() { + List defPlaceholders = new ArrayList<>(); + defPlaceholders.addAll(Arrays.asList(FILE_NAME_PLACEHOLDER, FORMAT_DATE_ISO_PLACEHOLDER, FORMAT_DATE_GER_PLACEHOLDER, FORMAT_DATE_ENG_PLACEHOLDER, FORMAT_TIME_ISO_PLACEHOLDER, DOSSIER_NAME_PLACEHOLDER)); + return defPlaceholders; + } + + private Map getFileAttributePlaceholders(String ruleSetId) { + Map fileAttributePlaceholders = new HashMap<>(); + + FileAttributesConfig fileAttributesConfig = fileAttributesClient.getFileAttributes(ruleSetId); + fileAttributesConfig.getFileAttributeConfigs().forEach(fileAttributeConfig -> { + String fileAttributePlaceholderName = "{{file.attribute." + fileAttributeConfig.getLabel().replace(" ", "-").toLowerCase(Locale.ROOT) + "}}"; + fileAttributePlaceholders.put(fileAttributePlaceholderName, fileAttributeConfig.getId()); + }); + return fileAttributePlaceholders; + } + + private String getPlaceholderValue(String placeholder, Project project, FileStatus fileStatus, Map fileAttributePlaceholders) { if (placeholder.equals(FORMAT_DATE_ISO_PLACEHOLDER)) { return OffsetDateTime.now().format(FORMAT_DATE_ISO); } @@ -121,84 +114,19 @@ public class WordReportGenerationService { return OffsetDateTime.now().format(FORMAT_TIME_ISO); } if (placeholder.equals(DOSSIER_NAME_PLACEHOLDER)) { - return dossierName; + return project.getProjectName(); } if (placeholder.equals(FILE_NAME_PLACEHOLDER)) { - return fileName; + return fileStatus.getFilename(); } - return null; + if (fileAttributePlaceholders.containsKey(placeholder)) { + String id = fileAttributePlaceholders.get(placeholder); + return fileStatus.getFileAttributes().getAttributeIdToValue().get(id); + } + throw new RuntimeException("unknown placeholder"); } - private void replaceTimePlaceholder(XWPFDocument doc, String timePlaceholder) { - replaceParagraphForTimePlaceholder(doc.getParagraphs(), timePlaceholder); - for (XWPFTable tbl : doc.getTables()) { - for (XWPFTableRow row : tbl.getRows()) { - for (XWPFTableCell cell : row.getTableCells()) { - replaceParagraphForTimePlaceholder(cell.getParagraphs(), timePlaceholder); - } - } - } - } - - private void replaceParagraphForTimePlaceholder(List paragraphs, String timePlaceholder) { - for (XWPFParagraph p : paragraphs) { - String paragraphText = p.getText(); - if (paragraphText.contains(timePlaceholder)) { - String safeToUseInReplaceAllString = Pattern.quote(timePlaceholder); -// String replace = timePlaceholder.substring(timePlaceholder.length()-7, timePlaceholder.length()-2); - String replace = OffsetDateTime.now().truncatedTo(ChronoUnit.MINUTES).toLocalTime().toString(); - paragraphText = paragraphText.replaceAll(safeToUseInReplaceAllString, replace); - XWPFRun run = p.getRuns().get(0); - run.setText(paragraphText, 0); - int size = p.getRuns().size(); - for (int i = 1; i < size; i++) { - p.removeRun(1); - } - } - } - } - - private void replaceDatePlaceholder(XWPFDocument doc, String datePlaceholder) { - replaceParagraphForDatePlaceholder(doc.getParagraphs(), datePlaceholder); - for (XWPFTable tbl : doc.getTables()) { - for (XWPFTableRow row : tbl.getRows()) { - for (XWPFTableCell cell : row.getTableCells()) { - replaceParagraphForDatePlaceholder(cell.getParagraphs(), datePlaceholder); - } - } - } - } - - private void replaceParagraphForDatePlaceholder(List paragraphs, String datePlaceholder) { - for (XWPFParagraph p : paragraphs) { - String paragraphText = p.getText(); - if (paragraphText.contains(datePlaceholder)) { - String safeToUseInReplaceAllString = Pattern.quote(datePlaceholder); -// String replace = datePlaceholder.substring(datePlaceholder.length()-12, datePlaceholder.length()-2); - String replace = OffsetDateTime.now().toLocalDate().toString(); - paragraphText = paragraphText.replaceAll(safeToUseInReplaceAllString, replace); - XWPFRun run = p.getRuns().get(0); - run.setText(paragraphText, 0); - int size = p.getRuns().size(); - for (int i = 1; i < size; i++) { - p.removeRun(1); - } - } - } - } - - private void replaceImagePlaceholders(XWPFDocument doc, ImagePlaceholder imagePlaceholder) { - replaceParagraphForImagePlaceholder(doc.getParagraphs(), imagePlaceholder); - for (XWPFTable tbl: doc.getTables()) { - for (XWPFTableRow row: tbl.getRows()) { - for (XWPFTableCell cell : row.getTableCells()) { - replaceParagraphForImagePlaceholder(cell.getParagraphs(), imagePlaceholder); - } - } - } - } - - private void replaceParagraphForImagePlaceholder(List paragraphs, ImagePlaceholder imagePlaceholder) { + /*private void replaceParagraphForImagePlaceholder(List paragraphs, ImagePlaceholder imagePlaceholder) { for (XWPFParagraph p : paragraphs) { String paragraphText = p.getText(); if (paragraphText.contains(imagePlaceholder.getPlaceholder())) { @@ -212,20 +140,20 @@ public class WordReportGenerationService { } } } - } + }*/ public void replaceTextPlaceholders(XWPFDocument doc, String search, String replace) { - replaceParagraphForTextPlaceholder(doc.getParagraphs(), search, replace); + replacePlaceholderInParagraph(doc.getParagraphs(), search, replace); for (XWPFTable tbl : doc.getTables()) { for (XWPFTableRow row : tbl.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { - replaceParagraphForTextPlaceholder(cell.getParagraphs(), search, replace); + replacePlaceholderInParagraph(cell.getParagraphs(), search, replace); } } } } - private void replaceParagraphForTextPlaceholder(List paragraphs, String search, String replace) { + private void replacePlaceholderInParagraph(List paragraphs, String search, String replace) { for (XWPFParagraph p : paragraphs) { String paragraphText = p.getText(); if (paragraphText.contains(search)) { @@ -241,41 +169,45 @@ public class WordReportGenerationService { } } - private XWPFTable getTableWithTextPlaceholder(XWPFDocument doc) { + private XWPFTable getRedactionTable(XWPFDocument doc) { for (XWPFTable tbl : doc.getTables()) { String tblText = tbl.getText(); - if (containsTextPlaceholder(tblText)) { + if (tblText.contains(PAGE_PLACEHOLDER) + || tblText.contains(PARAGRAPH_PLACEHOLDER) + || tblText.contains(JUSTIFICATION_PLACEHOLDER)) { return tbl; } } return null; } - private boolean containsTextPlaceholder(String place) { - return place.contains(FILENAME_PLACEHOLDER) - || place.contains(PAGE_PLACEHOLDER) - || place.contains(PARAGRAPH_PLACEHOLDER) - || place.contains(JUSTIFICATION_PLACEHOLDER); + private boolean containsRedactionPlaceholder(String text) { + return text.contains(FILE_NAME_PLACEHOLDER) + || text.contains(PAGE_PLACEHOLDER) + || text.contains(PARAGRAPH_PLACEHOLDER) + || text.contains(JUSTIFICATION_PLACEHOLDER); } private void addTableRows(XWPFDocument doc, List reportEntries, String filename) { List finalPlaceholders = new ArrayList<>(); - finalPlaceholders.addAll(Arrays.asList(FILENAME_PLACEHOLDER, PAGE_PLACEHOLDER, PARAGRAPH_PLACEHOLDER, JUSTIFICATION_PLACEHOLDER)); + finalPlaceholders.addAll(Arrays.asList(FILE_NAME_PLACEHOLDER, PAGE_PLACEHOLDER, PARAGRAPH_PLACEHOLDER, JUSTIFICATION_PLACEHOLDER)); + + XWPFTable table = getRedactionTable(doc); + if (table == null) { + return; + } - XWPFTable table = getTableWithTextPlaceholder(doc); Map placeholderCellPos = new HashMap<>(); int placeholderRow = -1; for (int j=0; j replaceParagraphForTextPlaceholder(cell.getParagraphs(), ph, ph)); - if (containsTextPlaceholder(cell.getText())) { + if (containsRedactionPlaceholder(cell.getText())) { placeholderCellPos.put(i, cell.getText()); placeholderRow = j; } } - } table.removeRow(placeholderRow); @@ -288,7 +220,7 @@ public class WordReportGenerationService { } private String replaceTextPlaceholderWithEntries(ReportRedactionEntry entry, String filename, String placeholder) { - if(placeholder.equals(FILENAME_PLACEHOLDER)) { + if(placeholder.equals(FILE_NAME_PLACEHOLDER)) { return filename; } if(placeholder.equals(PAGE_PLACEHOLDER)) { diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/templates/Sanitisation justification Appendix A1.docx b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/templates/Sanitisation justification Appendix A1.docx index c04fdadb76ee3f34a2e6fad3b45664755113e440..b6e997ffe70a77559c48cf27a20a7f17d6c71292 100644 GIT binary patch delta 8720 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 delta 8707 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 x0xBf reportEntries = redactionLogConverterService.convertAndSort(redactionLog, legalBasisMapping); - byte[] report = wordReportGenerationService.generateReport(ReportType.WORD_SINGLE_FILE_APPENDIX_A2_TEMPLATE, reportEntries, redactionLog - .getFilename()); + List fileAttributeConfigs = new ArrayList<>(); + fileAttributeConfigs.add(new FileAttributeConfig("3e9b9569-5d2e-4619-848b-dd0a3e96527f", "", "Document Title", true, true)); + FileAttributesConfig fileAttributesConfig = new FileAttributesConfig("", "", fileAttributeConfigs); + when(fileAttributesClient.getFileAttributes(redactionLog.getRuleSetId())).thenReturn(fileAttributesConfig); + + Map attributeIdToValue = new HashMap(); + attributeIdToValue.put("3e9b9569-5d2e-4619-848b-dd0a3e96527f", "Test"); + + FileAttributes fileAttributes = new FileAttributes(attributeIdToValue); + FileStatus fileStatus = FileStatus.builder().filename("filename").fileAttributes(fileAttributes).build(); + + Project project = Project.builder().projectId("projectId").projectName("projectName").build(); + + byte[] report = wordReportGenerationService.generateReport(ReportType.WORD_SINGLE_FILE_APPENDIX_A1_TEMPLATE, reportEntries, redactionLog + .getRuleSetId(), fileStatus, project); try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/efsa_template.docx")) { fileOutputStream.write(report);