From 5be0827d3ab38f5e0465524da5a9d2f5a9e626f1 Mon Sep 17 00:00:00 2001 From: aoezyetimoglu Date: Wed, 9 Jun 2021 10:06:12 +0200 Subject: [PATCH] RED-455: replace dossier attributes in report --- .../client/DossierAttributesClient.java | 9 +++++ .../client/DossierAttributesConfigClient.java | 9 +++++ .../service/WordReportGenerationService.java | 35 +++++++++++++++--- .../RedactionReportIntegrationTest.java | 30 +++++++++------ .../resources/templates/TEST_TEMPLATE.docx | Bin 78566 -> 78610 bytes 5 files changed, 66 insertions(+), 17 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/DossierAttributesClient.java create mode 100644 redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/DossierAttributesConfigClient.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/DossierAttributesClient.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/DossierAttributesClient.java new file mode 100644 index 0000000..7958a35 --- /dev/null +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/DossierAttributesClient.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.DossierAttributesResource; +import org.springframework.cloud.openfeign.FeignClient; + +@FeignClient(name = "DossierAttributesResource", url = "${file-management-service.url}") +public interface DossierAttributesClient extends DossierAttributesResource { +} diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/DossierAttributesConfigClient.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/DossierAttributesConfigClient.java new file mode 100644 index 0000000..16ae302 --- /dev/null +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/client/DossierAttributesConfigClient.java @@ -0,0 +1,9 @@ +package com.iqser.red.service.redaction.report.v1.server.client; + +import com.iqser.red.service.configuration.v1.api.resource.DossierAttributesResource; +import org.springframework.cloud.openfeign.FeignClient; + + +@FeignClient(name = "DossierAttributesConfigResource", url = "${configuration-service.url}") +public interface DossierAttributesConfigClient extends DossierAttributesResource { +} \ No newline at end of file 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 c7791d7..fd3fbfb 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,10 +1,12 @@ package com.iqser.red.service.redaction.report.v1.server.service; +import com.iqser.red.service.configuration.v1.api.model.DossierAttributeConfig; +import com.iqser.red.service.configuration.v1.api.model.DossierAttributesConfig; import com.iqser.red.service.configuration.v1.api.model.FileAttributesConfig; -import com.iqser.red.service.file.management.v1.api.model.FileStatus; -import com.iqser.red.service.file.management.v1.api.model.Dossier; -import com.iqser.red.service.file.management.v1.api.model.ReportTemplate; +import com.iqser.red.service.file.management.v1.api.model.*; import com.iqser.red.service.redaction.report.v1.api.model.ReportType; +import com.iqser.red.service.redaction.report.v1.server.client.DossierAttributesClient; +import com.iqser.red.service.redaction.report.v1.server.client.DossierAttributesConfigClient; import com.iqser.red.service.redaction.report.v1.server.client.FileAttributesClient; import com.iqser.red.service.redaction.report.v1.server.client.ReportTemplateClient; import com.iqser.red.service.redaction.report.v1.server.model.ReportRedactionEntry; @@ -32,6 +34,8 @@ public class WordReportGenerationService { private final FileAttributesClient fileAttributesClient; private final ReportTemplateClient reportTemplateClient; private final ReportStorageService reportStorageService; + private final DossierAttributesClient dossierAttributesClient; + private final DossierAttributesConfigClient dossierAttributesConfigClient; public static final String FILE_NAME_PLACEHOLDER = "{{file.name}}"; public static final String PAGE_PLACEHOLDER = "{{redaction.page}}"; @@ -59,10 +63,26 @@ public class WordReportGenerationService { } - public byte[] generateReport(ReportType reportType, List reportEntries, String dossierTemplateId, String templateId, FileStatus fileStatus, Dossier project) { + public byte[] generateReport(ReportType reportType, List reportEntries, String dossierTemplateId, String templateId, FileStatus fileStatus, Dossier dossier) { List placeholders = getDefaultPlaceholders(); + + DossierAttributes dossierAttributes = dossierAttributesClient.getDossierAttributes(dossier.getDossierId()); + DossierAttributesConfig dossierAttributesConfig = dossierAttributesConfigClient.getDossierAttributes(dossierTemplateId); + + Map dossierAttributesPlaceholder = new HashMap<>(); //KEY:placeholder, VALUE:value + + for(DossierAttribute dossierAttribute: dossierAttributes.getDossierAttributeList()) { + for(DossierAttributeConfig attribute: dossierAttributesConfig.getDossierAttributeConfigs()) { + if(dossierAttribute.getDossierAttributeId().equals(attribute.getId())) { + dossierAttributesPlaceholder.put(attribute.getPlaceholder(), dossierAttribute.getValue()); + } + + } + } + Map fileAttributePlaceholders = getFileAttributePlaceholders(dossierTemplateId); placeholders.addAll(fileAttributePlaceholders.keySet()); + placeholders.addAll(dossierAttributesPlaceholder.keySet()); byte[] template; @@ -80,7 +100,7 @@ public class WordReportGenerationService { XWPFDocument doc = new XWPFDocument(is); addTableRows(doc, reportEntries, fileStatus.getFilename()); for (String placeholder : placeholders) { - String placeholderValue = getPlaceholderValue(placeholder, project, fileStatus, fileAttributePlaceholders); + String placeholderValue = getPlaceholderValue(placeholder, dossier, fileStatus, fileAttributePlaceholders, dossierAttributesPlaceholder); if(placeholderValue != null) { replaceTextPlaceholders(doc, placeholder, placeholderValue); } @@ -109,7 +129,7 @@ public class WordReportGenerationService { return fileAttributePlaceholders; } - private String getPlaceholderValue(String placeholder, Dossier project, FileStatus fileStatus, Map fileAttributePlaceholders) { + private String getPlaceholderValue(String placeholder, Dossier project, FileStatus fileStatus, Map fileAttributePlaceholders, Map dossierAttributesPlaceholders) { if (placeholder.equals(FORMAT_DATE_ISO_PLACEHOLDER)) { return OffsetDateTime.now().format(FORMAT_DATE_ISO); } @@ -136,6 +156,9 @@ public class WordReportGenerationService { return null; } } + if(dossierAttributesPlaceholders.containsKey(placeholder)) { + return dossierAttributesPlaceholders.get(placeholder); + } throw new RuntimeException("unknown placeholder"); } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java index 0077a13..6a460c6 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java @@ -3,14 +3,11 @@ package com.iqser.red.service.redaction.report.v1.server; import com.amazonaws.services.s3.AmazonS3; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.iqser.red.service.configuration.v1.api.model.FileAttributeConfig; -import com.iqser.red.service.configuration.v1.api.model.FileAttributesConfig; -import com.iqser.red.service.configuration.v1.api.model.LegalBasisMapping; -import com.iqser.red.service.file.management.v1.api.model.Dossier; -import com.iqser.red.service.file.management.v1.api.model.FileAttributes; -import com.iqser.red.service.file.management.v1.api.model.FileStatus; -import com.iqser.red.service.file.management.v1.api.model.ReportTemplate; +import com.iqser.red.service.configuration.v1.api.model.*; +import com.iqser.red.service.file.management.v1.api.model.*; import com.iqser.red.service.redaction.report.v1.api.model.ReportType; +import com.iqser.red.service.redaction.report.v1.server.client.DossierAttributesClient; +import com.iqser.red.service.redaction.report.v1.server.client.DossierAttributesConfigClient; import com.iqser.red.service.redaction.report.v1.server.client.FileAttributesClient; import com.iqser.red.service.redaction.report.v1.server.client.ReportTemplateClient; import com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration; @@ -32,10 +29,7 @@ import org.springframework.test.context.junit4.SpringRunner; import java.io.FileOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.mockito.Mockito.when; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -74,6 +68,13 @@ public class RedactionReportIntegrationTest { @Autowired private RedactionLogConverterService redactionLogConverterService; + @MockBean + private DossierAttributesConfigClient dossierAttributesConfigClient; + + @MockBean + private DossierAttributesClient dossierAttributesClient; + + @Test public void testWordReportGeneration() throws IOException { @@ -92,11 +93,18 @@ public class RedactionReportIntegrationTest { List reportEntries = redactionLogConverterService.convertAndSort(redactionLog, legalBasisMapping); + DossierAttributesConfig dossierAttributesConfig = new DossierAttributesConfig(Arrays.asList(new DossierAttributeConfig("id", "label", true, DossierAttributeConfig.DossierAttributeType.TEXT, "{{dossier.attribute.name}}"))); + when(dossierAttributesConfigClient.getDossierAttributes(dossierTemplateId)).thenReturn(dossierAttributesConfig); + + DossierAttributes dossierAttributes = new DossierAttributes(Arrays.asList(new DossierAttribute("id", "Michael"))); + when(dossierAttributesClient.getDossierAttributes("dossierId")).thenReturn(dossierAttributes); + List fileAttributeConfigs = new ArrayList<>(); fileAttributeConfigs.add(new FileAttributeConfig("3e9b9569-5d2e-4619-848b-dd0a3e96527f", "", "Document Title", true, true, FileAttributeConfig.FileAttributeType.TEXT, "{{file.attribute.placeholder}}")); FileAttributesConfig fileAttributesConfig = new FileAttributesConfig("", "", fileAttributeConfigs); when(fileAttributesClient.getFileAttributes(dossierTemplateId)).thenReturn(fileAttributesConfig); + Map attributeIdToValue = new HashMap(); attributeIdToValue.put("3e9b9569-5d2e-4619-848b-dd0a3e96527f", "Test"); diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TEST_TEMPLATE.docx b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TEST_TEMPLATE.docx index b6e997ffe70a77559c48cf27a20a7f17d6c71292..5092582074f93c5762ed0348420e522ed966529d 100644 GIT binary patch delta 8911 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 delta 9120 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 Ax&QzG