From 0f15e686236e2b071eb2a0ecf994ab4ef15e87ae Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Wed, 31 Jul 2024 10:32:36 +0200 Subject: [PATCH] RED-9771 - Fixes for updating component mappings --- .../DossierTemplateControllerV2.java | 57 ++++++----- .../service/ComponentMappingService.java | 13 ++- .../tests/ComponentMappingTest.java | 98 +++++++++++++++++++ .../files/componentmapping/empty.csv | 0 .../resources/files/componentmapping/file.csv | 10 ++ .../files/componentmapping/update_file.csv | 5 + 6 files changed, 153 insertions(+), 30 deletions(-) create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentMappingTest.java create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/empty.csv create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/file.csv create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/update_file.csv diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java index 3a5519650..4523ee997 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java @@ -249,6 +249,36 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource { dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId); + String nameToUse = validateFileName(file, name); + + if (Strings.isNullOrEmpty(delimiter)) { + throw new BadRequestException("The provided delimiter is not valid! Can't be null or empty."); + } else if (delimiter.length() != 1) { + throw new BadRequestException(format("The provided delimiter %s is not valid! Only a single character is allowed.", delimiter)); + } + char cleanDelimiter = delimiter.charAt(0); + + + Path mappingFile = saveToFile(file); + + try { + ComponentMappingMetadata resultMetaData = componentMappingService.update(dossierTemplateId, + componentMappingId, + nameToUse, + encoding, + cleanDelimiter, + mappingFile.toFile(), + file.getOriginalFilename()); + + return componentMappingMapper.toModel(resultMetaData); + } finally { + Files.deleteIfExists(mappingFile); + } + } + + + private static String validateFileName(MultipartFile file, String name) { + if (Strings.isNullOrEmpty(file.getOriginalFilename()) || !file.getOriginalFilename().endsWith(".csv")) { throw new BadRequestException(format("File name \"%s\" does not end with .csv", file.getOriginalFilename())); } @@ -260,32 +290,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource { if (Strings.isNullOrEmpty(nameToUse)) { throw new BadRequestException(format("The provided file name \"%s\" is not valid!", nameToUse)); } - - if (Strings.isNullOrEmpty(delimiter)) { - throw new BadRequestException("The provided delimiter is not valid! Can't be null or empty."); - } else if (delimiter.length() != 1) { - throw new BadRequestException(format("The provided delimiter %s is not valid! Only a single character is allowed.", delimiter)); - } - char cleanDelimiter = delimiter.charAt(0); - - if (Strings.isNullOrEmpty(delimiter) || delimiter.length() != 1) { - throw new BadRequestException("The provided delimiter is not valid! Only a single character is allowed."); - } - - Path mappingFile = saveToFile(file); - - try { - ComponentMappingMetadata resultMetaData = componentMappingService.update(dossierTemplateId, - componentMappingId, - nameToUse, - encoding, - cleanDelimiter, - mappingFile.toFile()); - - return componentMappingMapper.toModel(resultMetaData); - } finally { - Files.deleteIfExists(mappingFile); - } + return nameToUse; } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentMappingService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentMappingService.java index c9c775b4b..647c740cd 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentMappingService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentMappingService.java @@ -62,11 +62,11 @@ public class ComponentMappingService { @SneakyThrows - public ComponentMappingMetadata update(String dossierTemplateId, String mappingId, String name, String encoding, char delimiter, File mappingFile) { + public ComponentMappingMetadata update(String dossierTemplateId, String mappingId, String name, String encoding, char delimiter, File mappingFile, String fileName) { ComponentMappingEntity entity = componentMappingPersistenceService.getEntityById(dossierTemplateId, mappingId); - return updateOrCreate(entity, name, encoding, delimiter, mappingFile); + return updateOrCreate(entity, name, encoding, delimiter, mappingFile, fileName); } @@ -86,13 +86,13 @@ public class ComponentMappingService { .fileName(fileName) .build(); - return updateOrCreate(entity, name, encoding, delimiter, mappingFile); + return updateOrCreate(entity, name, encoding, delimiter, mappingFile, fileName); } @SneakyThrows - private ComponentMappingMetadata updateOrCreate(ComponentMappingEntity entity, String name, String encoding, char delimiter, File mappingFile) { + private ComponentMappingMetadata updateOrCreate(ComponentMappingEntity entity, String name, String encoding, char delimiter, File mappingFile, String fileName) { Charset charset = resolveCharset(encoding); @@ -104,6 +104,7 @@ public class ComponentMappingService { entity.setNumberOfLines(stats.numberOfLines()); entity.setColumnLabels(stats.columnLabels()); entity.setVersion(entity.getVersion() + 1); + entity.setFileName(fileName); componentMappingPersistenceService.updateOrCreate(entity.getStorageId(), mappingFile, entity); @@ -139,6 +140,10 @@ public class ComponentMappingService { List rows = reader.readAll(); + if (rows.isEmpty()) { + throw new BadRequestException("CSV file can not be empty!"); + } + columnLabels = rows.remove(0); // remove header row if (Arrays.stream(columnLabels) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentMappingTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentMappingTest.java new file mode 100644 index 000000000..cb57fd08e --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentMappingTest.java @@ -0,0 +1,98 @@ +package com.iqser.red.service.peristence.v1.server.integration.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.mock.web.MockMultipartFile; + +import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateExternalClient; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.persistence.management.v1.processor.entity.ComponentMappingEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierTemplateEntity; +import com.iqser.red.service.persistence.management.v1.processor.service.ComponentMappingPersistenceService; +import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel; + +import feign.FeignException; +import lombok.SneakyThrows; + +@EnableJpaAuditing +public class ComponentMappingTest extends AbstractPersistenceServerServiceTest { + + @Autowired + private DossierTesterAndProvider dossierTesterAndProvider; + + @Autowired + private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider; + + @Autowired + private DossierTemplateExternalClient dossierTemplateExternalClient; + + @MockBean + private ComponentMappingPersistenceService componentMappingPersistenceService; + + + @Test + @SneakyThrows + public void testComponentMappingUpdate() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + + var mockMultipartFile = new MockMultipartFile("file.csv", + "file.csv", + "application/csv", + IOUtils.toByteArray(new ClassPathResource("files/componentmapping/file.csv").getInputStream())); + + ComponentMappingMetadataModel componentMappingMetadataModel = dossierTemplateExternalClient.uploadMapping(dossierTemplate.getId(), mockMultipartFile, "file", "UTF-8", ","); + + assertEquals(componentMappingMetadataModel.getFileName(), mockMultipartFile.getOriginalFilename()); + + var updateMockMultipartFile = new MockMultipartFile("update_file.csv", + "update_file.csv", + "application/csv", + IOUtils.toByteArray(new ClassPathResource("files/componentmapping/update_file.csv").getInputStream())); + + when(componentMappingPersistenceService.getEntityById(anyString(), anyString())).thenReturn(ComponentMappingEntity.builder() + .id(componentMappingMetadataModel.getId()) + .dossierTemplate(new DossierTemplateEntity()) + .storageId(buildStorageId(dossierTemplate.getId(), componentMappingMetadataModel.getId(), "file", "update_file.csv")) + .fileName("update_file.csv") + .build()); + + componentMappingMetadataModel = dossierTemplateExternalClient.updateMapping(dossierTemplate.getId(), componentMappingMetadataModel.getId(), updateMockMultipartFile, "file", "UTF-8", ","); + + assertEquals(componentMappingMetadataModel.getFileName(), updateMockMultipartFile.getOriginalFilename()); + } + + + @Test + @SneakyThrows + public void testCreateComponentMappingWithEmptyCsv() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + + var mockMultipartFile = new MockMultipartFile("file.csv", + "empty.csv", + "application/csv", + IOUtils.toByteArray(new ClassPathResource("files/componentmapping/empty.csv").getInputStream())); + + var result = assertThrows(FeignException.class, () -> dossierTemplateExternalClient.uploadMapping(dossierTemplate.getId(), mockMultipartFile, "file", "UTF-8", ",")); + assertTrue(result.getMessage().contains("CSV file can not be empty!")); + } + + + public static String buildStorageId(String dossierTemplateId, String id, String name, String fileName) { + + return dossierTemplateId + "/" + id + "_" + name + "_" + fileName; + } +} \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/empty.csv b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/empty.csv new file mode 100644 index 000000000..e69de29bb diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/file.csv b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/file.csv new file mode 100644 index 000000000..1f9cec709 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/file.csv @@ -0,0 +1,10 @@ +1,"Eldon Base for stackable storage shelf, platinum",Muhammed MacIntyre,3,-213.25,38.94,35,Nunavut,Storage & Organization,0.8 +2,"1.7 Cubic Foot Compact ""Cube"" Office Refrigerators",Barry French,293,457.81,208.16,68.02,Nunavut,Appliances,0.58 +3,"Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl",Barry French,293,46.71,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +4,R380,Clay Rozendal,483,1198.97,195.99,3.99,Nunavut,Telephones and Communication,0.58 +5,Holmes HEPA Air Purifier,Carlos Soltero,515,30.94,21.78,5.94,Nunavut,Appliances,0.5 +6,G.E. Longer-Life Indoor Recessed Floodlight Bulbs,Carlos Soltero,515,4.43,6.64,4.95,Nunavut,Office Furnishings,0.37 +7,"Angle-D Binders with Locking Rings, Label Holders",Carl Jackson,613,-54.04,7.3,7.72,Nunavut,Binders and Binder Accessories,0.38 +8,"SAFCO Mobile Desk Side File, Wire Frame",Carl Jackson,613,127.70,42.76,6.22,Nunavut,Storage & Organization, +9,"SAFCO Commercial Wire Shelving, Black",Monica Federle,643,-695.26,138.14,35,Nunavut,Storage & Organization, +10,Xerox 198,Dorothy Badders,678,-226.36,4.98,8.33,Nunavut,Paper,0.38 \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/update_file.csv b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/update_file.csv new file mode 100644 index 000000000..0f702adf1 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentmapping/update_file.csv @@ -0,0 +1,5 @@ +1,"Eldon Base for stackable storage shelf, platinum",Muhammed MacIntyre,3,-213.25,38.94,35,Nunavut,Storage & Organization,0.8 +2,"1.7 Cubic Foot Compact ""Cube"" Office Refrigerators",Barry French,293,457.81,208.16,68.02,Nunavut,Appliances,0.58 +3,"Cardinal Slant-D� Ring Binder, Heavy Gauge Vinyl",Barry French,293,46.71,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +4,R380,Clay Rozendal,483,1198.97,195.99,3.99,Nunavut,Telephones and Communication,0.58 +5,Holmes HEPA Air Purifier,Carlos Soltero,515,30.94,21.78,5.94,Nunavut,Appliances,0.5 \ No newline at end of file