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