diff --git a/redaction-report-service-v1/redaction-report-service-api-v1/pom.xml b/redaction-report-service-v1/redaction-report-service-api-v1/pom.xml
index 6add97d..2d525be 100644
--- a/redaction-report-service-v1/redaction-report-service-api-v1/pom.xml
+++ b/redaction-report-service-v1/redaction-report-service-api-v1/pom.xml
@@ -14,6 +14,11 @@
1.0-SNAPSHOT
+
+ com.iqser.red.service
+ redaction-service-api-v1
+ 1.1.1
+
diff --git a/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/FileRedactionLog.java b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/FileRedactionLog.java
new file mode 100644
index 0000000..adcffd8
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/FileRedactionLog.java
@@ -0,0 +1,17 @@
+package com.iqser.red.service.redaction.report.v1.api.model;
+
+import com.iqser.red.service.redaction.v1.model.RedactionLog;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class FileRedactionLog {
+
+ private String filename;
+ private RedactionLog redactionLog;
+
+}
diff --git a/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/MultiFileRedactionLog.java b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/MultiFileRedactionLog.java
new file mode 100644
index 0000000..23e0cc1
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/MultiFileRedactionLog.java
@@ -0,0 +1,17 @@
+package com.iqser.red.service.redaction.report.v1.api.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MultiFileRedactionLog {
+
+ private List FileRedactionLogs = new ArrayList<>();
+
+}
diff --git a/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/ReportResult.java b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/ReportResult.java
new file mode 100644
index 0000000..d10d383
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/model/ReportResult.java
@@ -0,0 +1,13 @@
+package com.iqser.red.service.redaction.report.v1.api.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ReportResult {
+
+ private byte[] document;
+}
diff --git a/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/resource/RedactionReportResource.java b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/resource/RedactionReportResource.java
new file mode 100644
index 0000000..89d20f3
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-api-v1/src/main/java/com/iqser/red/service/redaction/report/v1/api/resource/RedactionReportResource.java
@@ -0,0 +1,17 @@
+package com.iqser.red.service.redaction.report.v1.api.resource;
+
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import com.iqser.red.service.redaction.report.v1.api.model.MultiFileRedactionLog;
+import com.iqser.red.service.redaction.report.v1.api.model.ReportResult;
+
+public interface RedactionReportResource {
+
+ String SERVICE_NAME = "redaction-report-service-v1";
+
+ @PostMapping(value = "/generate", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
+ ReportResult generateReport(@RequestBody MultiFileRedactionLog multiFileRedactionLog);
+
+}
diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml b/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml
index a168bda..ca9d1ef 100644
--- a/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml
+++ b/redaction-report-service-v1/redaction-report-service-server-v1/pom.xml
@@ -19,6 +19,21 @@
redaction-report-service-api-v1
${project.version}
+
+ org.apache.poi
+ poi
+ 4.1.2
+
+
+ org.apache.poi
+ poi-ooxml
+ 4.1.2
+
+
+ org.apache.poi
+ poi-scratchpad
+ 4.1.2
+
com.iqser.gin4.commons
spring-commons
diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/RedactionReportController.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/RedactionReportController.java
new file mode 100644
index 0000000..7a0a1cc
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/controller/RedactionReportController.java
@@ -0,0 +1,23 @@
+package com.iqser.red.service.redaction.report.v1.server.controller;
+
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.iqser.red.service.redaction.report.v1.api.model.MultiFileRedactionLog;
+import com.iqser.red.service.redaction.report.v1.api.model.ReportResult;
+import com.iqser.red.service.redaction.report.v1.api.resource.RedactionReportResource;
+import com.iqser.red.service.redaction.report.v1.server.service.ReportGenerationService;
+
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequiredArgsConstructor
+public class RedactionReportController implements RedactionReportResource {
+
+ private final ReportGenerationService reportGenerationService;
+
+ public ReportResult generateReport(@RequestBody MultiFileRedactionLog multiFileRedactionLog){
+ return new ReportResult(reportGenerationService.generateReport(multiFileRedactionLog));
+ }
+
+}
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
new file mode 100644
index 0000000..cc1a4e7
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ReportGenerationService.java
@@ -0,0 +1,79 @@
+package com.iqser.red.service.redaction.report.v1.server.service;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.springframework.stereotype.Service;
+
+import com.iqser.red.service.redaction.report.v1.api.model.MultiFileRedactionLog;
+import com.iqser.red.service.redaction.report.v1.server.utils.ResourceLoader;
+
+@Service
+public class ReportGenerationService {
+
+ private byte[] template;
+
+
+ @PostConstruct
+ public void init() {
+
+ template = ResourceLoader.load("templates/Appendix A2.docx");
+ }
+
+
+ public byte[] generateReport(MultiFileRedactionLog multiFileRedactionLog) {
+
+ try (ByteArrayInputStream is = new ByteArrayInputStream(template)) {
+ XWPFDocument doc = new XWPFDocument(is);
+ doc = addTableRows(doc, multiFileRedactionLog);
+ return toByteArray(doc);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ private XWPFDocument addTableRows(XWPFDocument doc, MultiFileRedactionLog multiFileRedactionLog) {
+
+ XWPFTable table = doc.getTables().get(1);
+
+ multiFileRedactionLog.getFileRedactionLogs().forEach(fileRedactionLog -> {
+ fileRedactionLog.getRedactionLog().getRedactionLogEntry().forEach(redactionLogEntry -> {
+ Set pages = new HashSet<>();
+ redactionLogEntry.getPositions().forEach(position -> {
+ pages.add(position.getPage());
+ });
+ pages.forEach(page -> {
+ XWPFTableRow row = table.createRow();
+ row.getCell(0).setText(fileRedactionLog.getFilename());
+ row.getCell(1).setText(String.valueOf(page));
+ row.getCell(2).setText(String.valueOf(redactionLogEntry.getSectionNumber()));
+ row.getCell(3).setText(redactionLogEntry.getReason());
+ });
+
+ });
+ });
+
+ return doc;
+ }
+
+
+ private byte[] toByteArray(XWPFDocument doc) throws FileNotFoundException, IOException {
+
+ try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
+ doc.write(byteArrayOutputStream);
+ doc.close();
+ return byteArrayOutputStream.toByteArray();
+ }
+ }
+
+}
\ 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/utils/ResourceLoader.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/utils/ResourceLoader.java
new file mode 100644
index 0000000..23f1b96
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/utils/ResourceLoader.java
@@ -0,0 +1,24 @@
+package com.iqser.red.service.redaction.report.v1.server.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class ResourceLoader {
+
+ public byte[] load(String classpathPath) {
+
+ URL resource = ResourceLoader.class.getClassLoader().getResource(classpathPath);
+ if (resource == null) {
+ throw new IllegalArgumentException("could not load classpath resource: " + classpathPath);
+ }
+ try (InputStream is = resource.openStream()){
+ return is.readAllBytes();
+ } catch (IOException e){
+ throw new IllegalArgumentException("could not load classpath resource: " + classpathPath, e);
+ }
+ }
+}
diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/templates/Appendix A2.docx b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/templates/Appendix A2.docx
new file mode 100644
index 0000000..5e485b3
Binary files /dev/null and b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/resources/templates/Appendix A2.docx differ
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 b02a17c..44b1b19 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
@@ -1,16 +1,53 @@
package com.iqser.red.service.redaction.report.v1.server;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.junit4.SpringRunner;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.iqser.red.service.redaction.report.v1.api.model.FileRedactionLog;
+import com.iqser.red.service.redaction.report.v1.api.model.MultiFileRedactionLog;
+import com.iqser.red.service.redaction.report.v1.api.model.ReportResult;
+import com.iqser.red.service.redaction.report.v1.server.controller.RedactionReportController;
+import com.iqser.red.service.redaction.v1.model.RedactionLog;
+
@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = DEFINED_PORT)
public class RedactionReportIntegrationTest {
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private RedactionReportController redactionReportController;
+
+
@Test
- public void testServiceTemplate() {
+ public void testReportGeneration() throws IOException {
+
+ ClassPathResource redactionLogResource = new ClassPathResource("files/RedactionLog.txt");
+
+ RedactionLog redactionLog = objectMapper.readValue(redactionLogResource.getInputStream(), RedactionLog.class);
+
+ FileRedactionLog fileRedactionLog = new FileRedactionLog("Metholachlor 1", redactionLog);
+ MultiFileRedactionLog multiFileRedactionLog = new MultiFileRedactionLog(List.of(fileRedactionLog));
+
+ ReportResult reportResult = redactionReportController.generateReport(multiFileRedactionLog);
+
+ try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/document.docx")) {
+ fileOutputStream.write(reportResult.getDocument());
+ }
+
assertThat(true).isTrue();
}
diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/RedactionLog.txt b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/RedactionLog.txt
new file mode 100644
index 0000000..38abcc4
--- /dev/null
+++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/RedactionLog.txt
@@ -0,0 +1 @@
+{"redactionLogEntry":[{"id":"3080535605f06a5a397c4a9a5e501e9e","type":"address","value":"Regina Dorn","reason":"Applicant information was found","redacted":true,"section":"1.2.1 Name and address of applicant(s) for approval of the active substance","color":[0.0,1.0,1.0],"positions":[{"topLeft":{"x":147.86,"y":226.28998},"width":32.17697,"height":11.017679,"page":1},{"topLeft":{"x":181.79697,"y":226.28998},"width":23.68721,"height":11.017679,"page":1}],"sectionNumber":3,"manual":false,"hint":false},{"id":"b54d906a78a3988c54c67f188acab849","type":"address","value":"Schwarzwaldallee 215 P.O. Box CH-4002 Basel Switzerland","reason":"Applicant information was found","redacted":true,"section":"1.2.1 Name and address of applicant(s) for approval of the active substance","color":[0.0,1.0,1.0],"positions":[{"topLeft":{"x":147.86,"y":289.52997},"width":81.095245,"height":11.017679,"page":1},{"topLeft":{"x":230.73732,"y":289.52997},"width":17.438568,"height":11.017679,"page":1},{"topLeft":{"x":147.86,"y":276.93},"width":20.562881,"height":11.017679,"page":1},{"topLeft":{"x":170.18288,"y":276.93},"width":19.359528,"height":11.017679,"page":1},{"topLeft":{"x":147.86,"y":264.21002},"width":41.950012,"height":11.017679,"page":1},{"topLeft":{"x":191.57,"y":264.21002},"width":25.519852,"height":11.017679,"page":1},{"topLeft":{"x":147.86,"y":251.60999},"width":53.649796,"height":11.017679,"page":1}],"sectionNumber":3,"manual":false,"hint":false},{"id":"7b4ff6e32a8bdaa7de5dcdeb13ff8edd","type":"address","value":"regina.dorn@syngenta.com","reason":"Applicant information was found","redacted":true,"section":"1.2.1 Name and address of applicant(s) for approval of the active substance","color":[0.0,1.0,1.0],"positions":[{"topLeft":{"x":147.86,"y":188.34003},"width":122.451065,"height":11.017679,"page":1}],"sectionNumber":3,"manual":false,"hint":false},{"id":"c357d6781fb4bb7e7020a67dbc63763c","type":"address","value":"Syngenta Crop Protection AG","reason":"Applicant information was found","redacted":true,"section":"1.2.1 Name and address of applicant(s) for approval of the active substance","color":[0.0,1.0,1.0],"positions":[{"topLeft":{"x":147.86,"y":302.25},"width":41.88115,"height":11.017679,"page":1},{"topLeft":{"x":191.50114,"y":302.25},"width":23.080002,"height":11.017679,"page":1},{"topLeft":{"x":216.34114,"y":302.25},"width":46.23088,"height":11.017679,"page":1},{"topLeft":{"x":264.2106,"y":302.25},"width":16.886566,"height":11.017679,"page":1}],"sectionNumber":3,"manual":false,"hint":false},{"id":"946a2cc404d6568d34b1ca9a4c688ec9","type":"address","value":"+41 (61) 323 6358","reason":"Applicant information was found","redacted":true,"section":"1.2.1 Name and address of applicant(s) for approval of the active substance","color":[0.0,1.0,1.0],"positions":[{"topLeft":{"x":147.86,"y":213.65997},"width":18.266571,"height":11.017679,"page":1},{"topLeft":{"x":167.88657,"y":213.65997},"width":19.315353,"height":11.017679,"page":1},{"topLeft":{"x":188.99504,"y":213.65997},"width":17.438568,"height":11.017679,"page":1},{"topLeft":{"x":208.1936,"y":213.65997},"width":23.080017,"height":11.017679,"page":1}],"sectionNumber":3,"manual":false,"hint":false},{"id":"687171974a4fc3aa0f43ec2118256590","type":"address","value":"+41 (61) 323 6155","reason":"Applicant information was found","redacted":true,"section":"1.2.1 Name and address of applicant(s) for approval of the active substance","color":[0.0,1.0,1.0],"positions":[{"topLeft":{"x":147.86,"y":200.94},"width":18.266571,"height":11.017679,"page":1},{"topLeft":{"x":167.88657,"y":200.94},"width":19.315353,"height":11.017679,"page":1},{"topLeft":{"x":188.99504,"y":200.94},"width":17.438568,"height":11.017679,"page":1},{"topLeft":{"x":208.1936,"y":200.94},"width":23.080017,"height":11.017679,"page":1}],"sectionNumber":3,"manual":false,"hint":false}]}
\ No newline at end of file