Skip to content
Snippets Groups Projects
Commit 645ad164 authored by Jan Zickermann's avatar Jan Zickermann
Browse files

OZG-8070 Extract zip files into attachments

parent dcc5eaf9
No related branches found
No related tags found
1 merge request!2Ozg 8070 map primary fom datar representation
Pipeline #2396 failed
...@@ -23,43 +23,72 @@ ...@@ -23,43 +23,72 @@
*/ */
package de.ozgcloud.eingang.formsolutions; package de.ozgcloud.eingang.formsolutions;
import static java.util.Collections.*;
import java.io.File; import java.io.File;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import jakarta.annotation.Nullable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFile;
import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
import de.ozgcloud.eingang.semantik.common.ZipAttachmentReader;
import lombok.extern.log4j.Log4j2;
@Log4j2
@Component @Component
class FormSolutionsAttachmentsMapper { class FormSolutionsAttachmentsMapper {
public static final String ZIP = "zip"; public static final String ZIP = "zip";
public static final String FILE_NAME_ZIP_ATTACHMENT = "attachments.zip"; public static final String FILE_NAME_ZIP_ATTACHMENT = "attachments.zip";
public static final String ZIP_CONTENT_TYPE = "application/zip"; public static final String ZIP_CONTENT_TYPE = "application/zip";
public static final String FILE_GROUP_ZIP_NAME = "gezippte Anhänge";
public List<IncomingFileGroup> mapAttachments(File zipFile) { public List<IncomingFileGroup> mapAttachments(@Nullable File zipFile) {
if (Objects.nonNull(zipFile) && zipFile.length() > 0) { if (Objects.nonNull(zipFile) && zipFile.length() > 0) {
return Collections.singletonList(buildFileGroup(buildZipFile(zipFile))); return extractAttachmentGroups(zipFile);
} }
return Collections.emptyList(); return emptyList();
} }
private IncomingFileGroup buildFileGroup(IncomingFile zipFile) { List<IncomingFileGroup> extractAttachmentGroups(File zipFile) {
return IncomingFileGroup.builder() var attachmentIncomingFiles = extractAttachments(zipFile);
.name(FILE_GROUP_ZIP_NAME) return attachmentIncomingFiles.isEmpty()
.files(List.of(zipFile)) ? emptyList()
.build(); : List.of(IncomingFileGroup.builder()
.name("Anhänge")
.files(attachmentIncomingFiles)
.build());
}
List<IncomingFile> extractAttachments(File zipFile) {
try {
return readFromZip(zipFile);
} catch (RuntimeException e) {
LOG.error("Cannot read source ZIP. Attach it as is.", e);
return List.of(buildZipFile(zipFile));
}
} }
private IncomingFile buildZipFile(File zipFile) { IncomingFile buildZipFile(File zipFile) {
return IncomingFile.builder() return IncomingFile.builder()
.file(zipFile) .file(zipFile)
.contentType(ZIP_CONTENT_TYPE) .contentType(ZIP_CONTENT_TYPE)
.name(FILE_NAME_ZIP_ATTACHMENT) .name(FILE_NAME_ZIP_ATTACHMENT)
.build(); .build();
} }
List<IncomingFile> readFromZip(File zipFile) {
var reader = buildReader(zipFile);
var readContent = reader.readContent();
reader.deleteSourceFile();
return readContent;
}
ZipAttachmentReader buildReader(File zipFile) {
return ZipAttachmentReader.from(zipFile, null);
}
} }
\ No newline at end of file
...@@ -26,6 +26,7 @@ package de.ozgcloud.eingang.formsolutions; ...@@ -26,6 +26,7 @@ package de.ozgcloud.eingang.formsolutions;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
...@@ -40,6 +41,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; ...@@ -40,6 +41,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.common.errorhandling.TechnicalException;
import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormData;
import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFile;
import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@Component @Component
...@@ -67,22 +69,25 @@ class FormSolutionsRequestMapper { ...@@ -67,22 +69,25 @@ class FormSolutionsRequestMapper {
} }
FormData buildFormData(File jsonFile, FormSolutionsEingang eingang) { FormData buildFormData(File jsonFile, FormSolutionsEingang eingang) {
var builder = FormData.builder() var attachments = attachmentMapper.mapAttachments(eingang.getZip());
.attachments(attachmentMapper.mapAttachments(eingang.getZip())) var representations = getRepresentations(jsonFile, eingang);
.representation(buildJsonFile(jsonFile));
var numberOfRepresentations = 1;
if (Objects.nonNull(eingang.getPdf())) {
builder.representation(buildPdfFile(eingang.getPdf()));
numberOfRepresentations++;
}
return builder return FormData.builder()
.attachments(attachments)
.representations(representations)
.control(buildFormDataControl()) .control(buildFormDataControl())
.numberOfRepresentations(numberOfRepresentations) .numberOfRepresentations(representations.size())
.numberOfAttachments(FilesMapperHelper.countAttachedFiles(attachments))
.build(); .build();
} }
List<IncomingFile> getRepresentations(File jsonFile, FormSolutionsEingang eingang) {
var jsonRepresentation = buildJsonFile(jsonFile);
return Objects.nonNull(eingang.getPdf())
? List.of(jsonRepresentation, buildPdfFile(eingang.getPdf()))
: List.of(jsonRepresentation);
}
FormData.FormDataControl buildFormDataControl() { FormData.FormDataControl buildFormDataControl() {
return FormData.FormDataControl.builder() return FormData.FormDataControl.builder()
.representations(Optional.of(buildControlRepresentations())) .representations(Optional.of(buildControlRepresentations()))
......
...@@ -24,74 +24,273 @@ ...@@ -24,74 +24,273 @@
package de.ozgcloud.eingang.formsolutions; package de.ozgcloud.eingang.formsolutions;
import static de.ozgcloud.eingang.formsolutions.FormSolutionsAttachmentsMapper.*; import static de.ozgcloud.eingang.formsolutions.FormSolutionsAttachmentsMapper.*;
import static de.ozgcloud.eingang.formsolutions.FormSolutionsFilesTestFactory.*;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import de.ozgcloud.common.binaryfile.TempFileUtils;
import de.ozgcloud.common.test.TestUtils;
import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFile;
import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
import lombok.SneakyThrows; import de.ozgcloud.eingang.semantik.common.ZipAttachmentReader;
class FormSolutionsAttachmentsMapperTest { class FormSolutionsAttachmentsMapperTest {
@Spy
@InjectMocks @InjectMocks
private FormSolutionsAttachmentsMapper mapper; private FormSolutionsAttachmentsMapper mapper;
@Mock
private File zipFile; private File zipFile;
@DisplayName("map attachments")
@Nested
class TestMapAttachments {
@Mock
private IncomingFileGroup incomingFileGroup;
@DisplayName("with valid file")
@Nested
class TestWithValidFile {
@BeforeEach
void mock() {
when(zipFile.length()).thenReturn(1L);
doReturn(List.of(incomingFileGroup)).when(mapper).extractAttachmentGroups(any());
}
@DisplayName("should call extractAttachmentGroups")
@Test
void shouldCallExtractAttachmentGroups() {
mapper.mapAttachments(zipFile);
verify(mapper).extractAttachmentGroups(zipFile);
}
@DisplayName("should return")
@Test
void shouldReturn() {
var result = mapper.mapAttachments(zipFile);
assertThat(result).containsExactly(incomingFileGroup);
}
}
@DisplayName("should return empty if file null")
@Test
void shouldReturnEmptyIfFileNull() {
var result = mapper.mapAttachments(null);
assertThat(result).isEmpty();
}
@DisplayName("should return empty if file empty")
@Test
void shouldReturnEmptyIfFileEmpty() {
when(zipFile.length()).thenReturn(0L);
var result = mapper.mapAttachments(zipFile);
assertThat(result).isEmpty();
}
}
@DisplayName("extract attachment groups")
@Nested
class TestExtractAttachmentGroups {
@Mock
private IncomingFile incomingFile;
@DisplayName("with files")
@Nested
class TestWithFiles {
@BeforeEach
void mock() {
doReturn(List.of(incomingFile)).when(mapper).extractAttachments(any());
}
@DisplayName("should call extractAttachments")
@Test
void shouldCallExtractAttachments() {
mapper.extractAttachmentGroups(zipFile);
verify(mapper).extractAttachments(zipFile);
}
@DisplayName("should return")
@Test
void shouldReturn() {
var result = mapper.extractAttachmentGroups(zipFile);
assertThat(result)
.flatExtracting(IncomingFileGroup::getFiles)
.containsExactly(incomingFile);
}
@DisplayName("should return name")
@Test
void shouldReturnName() {
var result = mapper.extractAttachmentGroups(zipFile);
assertThat(result)
.flatExtracting(IncomingFileGroup::getName)
.containsExactly("Anhänge");
}
}
@DisplayName("should return empty with no files")
@Test
void shouldReturnEmptyWithNoFiles() {
doReturn(List.of()).when(mapper).extractAttachments(any());
var result = mapper.extractAttachmentGroups(zipFile);
assertThat(result).isEmpty();
}
}
@DisplayName("extract attachments")
@Nested
class TestExtractAttachments {
@Mock
private IncomingFile incomingFile;
@DisplayName("without exception")
@Nested
class TestWithoutException {
@BeforeEach @BeforeEach
void writeZipFile() { void mock() {
zipFile = TempFileUtils.writeTmpFile(ZIP_DECODED); doReturn(List.of(incomingFile)).when(mapper).readFromZip(any());
}
@DisplayName("should call readFromZip")
@Test
void shouldCallReadFromZip() {
mapper.extractAttachments(zipFile);
verify(mapper).readFromZip(zipFile);
} }
@AfterEach @DisplayName("should return")
void delZipFile() { @Test
zipFile.delete(); void shouldReturn() {
var result = mapper.extractAttachments(zipFile);
assertThat(result).containsExactly(incomingFile);
}
} }
@DisplayName("with exception")
@Nested @Nested
class TestAttachmentsMapping { class TestWithException {
@BeforeEach
void mock() {
doThrow(new RuntimeException()).when(mapper).readFromZip(any());
doReturn(incomingFile).when(mapper).buildZipFile(any());
}
@DisplayName("should call buildZipFile")
@Test @Test
@SneakyThrows void shouldCallBuildZipFile() {
void shouldParseZip() { mapper.extractAttachments(zipFile);
var map = mapper.mapAttachments(zipFile);
assertThat(TestUtils.contentStreamToByteArray(getAttachment(map).getContentStream())).isEqualTo(ZIP_DECODED); verify(mapper).buildZipFile(zipFile);
} }
@DisplayName("should return zip")
@Test @Test
void shouldSetContentType() { void shouldReturnZip() {
var map = mapper.mapAttachments(zipFile); var result = mapper.extractAttachments(zipFile);
assertThat(getAttachment(map).getContentType()).isEqualTo(ZIP_CONTENT_TYPE); assertThat(result).containsExactly(incomingFile);
}
}
} }
@DisplayName("build zip file")
@Nested
class TestBuildZipFile {
@DisplayName("should map file")
@Test @Test
void shouldSetFileName() { void shouldMapFile() {
var map = mapper.mapAttachments(zipFile); var result = mapper.buildZipFile(zipFile);
assertThat(getAttachment(map).getName()).isEqualTo(FILE_NAME_ZIP_ATTACHMENT); assertThat(result.getFile()).isEqualTo(zipFile);
} }
@DisplayName("should map content type")
@Test @Test
void shouldSetGroupName() { void shouldMapContentType() {
var map = mapper.mapAttachments(zipFile); var result = mapper.buildZipFile(zipFile);
assertThat(map.get(0).getName()).isEqualTo(FILE_GROUP_ZIP_NAME); assertThat(result.getContentType()).isEqualTo(ZIP_CONTENT_TYPE);
} }
@DisplayName("should map name")
@Test
void shouldMapName() {
var result = mapper.buildZipFile(zipFile);
assertThat(result.getName()).isEqualTo(FILE_NAME_ZIP_ATTACHMENT);
}
}
@DisplayName("read from zip")
@Nested
class TestReadFromZip {
@Mock
private IncomingFile incomingFile;
@Mock
private ZipAttachmentReader reader;
@BeforeEach
void mock() {
doReturn(reader).when(mapper).buildReader(any());
when(reader.readContent()).thenReturn(List.of(incomingFile));
}
@DisplayName("should call buildReader")
@Test
void shouldCallBuildReader() {
mapper.readFromZip(zipFile);
verify(mapper).buildReader(zipFile);
} }
private IncomingFile getAttachment(List<IncomingFileGroup> attachments) { @DisplayName("should call readContent")
return attachments.get(0).getFiles().get(0); @Test
void shouldCallReadContent() {
mapper.readFromZip(zipFile);
verify(reader).readContent();
}
@DisplayName("should call deleteSourceFile")
@Test
void shouldCallDeleteSourceFile() {
mapper.readFromZip(zipFile);
verify(reader).deleteSourceFile();
}
@DisplayName("should return")
@Test
void shouldReturn() {
var result = mapper.readFromZip(zipFile);
assertThat(result).containsExactly(incomingFile);
}
} }
} }
...@@ -138,8 +138,7 @@ class FormSolutionsRequestMapperTest { ...@@ -138,8 +138,7 @@ class FormSolutionsRequestMapperTest {
@Mock @Mock
private File zipFile; private File zipFile;
@Mock private final IncomingFileGroup attachmentGroup = IncomingFileGroupTestFactory.create();
private IncomingFileGroup attachmentGroup;
@Mock @Mock
private IncomingFile jsonIncomingFile; private IncomingFile jsonIncomingFile;
...@@ -153,9 +152,9 @@ class FormSolutionsRequestMapperTest { ...@@ -153,9 +152,9 @@ class FormSolutionsRequestMapperTest {
@BeforeEach @BeforeEach
void mock() { void mock() {
when(eingang.getZip()).thenReturn(zipFile); when(eingang.getZip()).thenReturn(zipFile);
when(attachmentMapper.mapAttachments(any())).thenReturn(List.of(attachmentGroup)); when(attachmentMapper.mapAttachments(any())).thenReturn(List.of(attachmentGroup));
doReturn(jsonIncomingFile).when(mapper).buildJsonFile(any());
doReturn(List.of(jsonIncomingFile)).when(mapper).getRepresentations(any(), any());
doReturn(formDataControl).when(mapper).buildFormDataControl(); doReturn(formDataControl).when(mapper).buildFormDataControl();
} }
...@@ -175,12 +174,12 @@ class FormSolutionsRequestMapperTest { ...@@ -175,12 +174,12 @@ class FormSolutionsRequestMapperTest {
assertThat(result.getAttachments()).containsExactly(attachmentGroup); assertThat(result.getAttachments()).containsExactly(attachmentGroup);
} }
@DisplayName("should call buildJsonFile") @DisplayName("should call getRepresentations")
@Test @Test
void shouldCallBuildJsonFile() { void shouldCallGetRepresentations() {
buildFormData(); buildFormData();
verify(mapper).buildJsonFile(simpleJsonFile); verify(mapper).getRepresentations(simpleJsonFile, eingang);
} }
@DisplayName("should return representations") @DisplayName("should return representations")
...@@ -199,10 +198,60 @@ class FormSolutionsRequestMapperTest { ...@@ -199,10 +198,60 @@ class FormSolutionsRequestMapperTest {
assertThat(result.getControl()).isEqualTo(formDataControl); assertThat(result.getControl()).isEqualTo(formDataControl);
} }
@DisplayName("should return numberOfRepresentations")
@Test
void shouldReturnNumberOfRepresentations() {
var result = buildFormData();
assertThat(result.getNumberOfRepresentations()).isEqualTo(1);
}
@DisplayName("should return numberOfAttachments")
@Test
void shouldReturnNumberOfAttachments() {
var result = buildFormData();
assertThat(result.getNumberOfAttachments()).isEqualTo(1);
}
private FormData buildFormData() {
return mapper.buildFormData(simpleJsonFile, eingang);
}
}
@DisplayName("get representations")
@Nested
class TestGetRepresentations {
@Mock
private FormSolutionsEingang eingang;
@Mock
private IncomingFile jsonIncomingFile;
@BeforeEach
void mock() {
doReturn(jsonIncomingFile).when(mapper).buildJsonFile(any());
}
@DisplayName("should call buildJsonFile")
@Test
void shouldCallBuildJsonFile() {
getRepresentations();
verify(mapper).buildJsonFile(simpleJsonFile);
}
@DisplayName("with pdf") @DisplayName("with pdf")
@Nested @Nested
class TestWithPdf { class TestWithPdf {
@Mock
private File pdfFile;
@Mock
private IncomingFile pdfIncomingFile;
@BeforeEach @BeforeEach
void mock() { void mock() {
when(eingang.getPdf()).thenReturn(pdfFile); when(eingang.getPdf()).thenReturn(pdfFile);
...@@ -212,7 +261,7 @@ class FormSolutionsRequestMapperTest { ...@@ -212,7 +261,7 @@ class FormSolutionsRequestMapperTest {
@DisplayName("should call buildPdfFile") @DisplayName("should call buildPdfFile")
@Test @Test
void shouldCallBuildPdfFile() { void shouldCallBuildPdfFile() {
buildFormData(); getRepresentations();
verify(mapper).buildPdfFile(eingang.getPdf()); verify(mapper).buildPdfFile(eingang.getPdf());
} }
...@@ -220,14 +269,24 @@ class FormSolutionsRequestMapperTest { ...@@ -220,14 +269,24 @@ class FormSolutionsRequestMapperTest {
@DisplayName("should return representations") @DisplayName("should return representations")
@Test @Test
void shouldReturnRepresentations() { void shouldReturnRepresentations() {
var result = buildFormData(); var result = getRepresentations();
assertThat(result.getRepresentations()).containsExactly(jsonIncomingFile, pdfIncomingFile); assertThat(result).containsExactly(jsonIncomingFile, pdfIncomingFile);
} }
} }
private FormData buildFormData() { @DisplayName("should return without pdf")
return mapper.buildFormData(simpleJsonFile, eingang); @Test
void shouldReturnWithoutPdf() {
when(eingang.getPdf()).thenReturn(null);
var result = getRepresentations();
assertThat(result).containsExactly(jsonIncomingFile);
}
private List<IncomingFile> getRepresentations() {
return mapper.getRepresentations(simpleJsonFile, eingang);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment