From cd26c425ff656ea217d701abeddb01268181b794 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Fri, 3 Jul 2026 14:42:54 +0200 Subject: [PATCH 1/9] feat: add contextual variables execution report endpoint --- .../dto/ContextualVariableFileReportDto.java | 6 ++ .../dto/SaveContextualVariablesReportDto.java | 9 +++ .../ContextualVariableController.java | 22 ++++++ .../ports/api/ContextualVariableApiPort.java | 6 ++ .../ContextualVariableJsonService.java | 75 +++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 src/main/java/fr/insee/genesis/controller/dto/ContextualVariableFileReportDto.java create mode 100644 src/main/java/fr/insee/genesis/controller/dto/SaveContextualVariablesReportDto.java diff --git a/src/main/java/fr/insee/genesis/controller/dto/ContextualVariableFileReportDto.java b/src/main/java/fr/insee/genesis/controller/dto/ContextualVariableFileReportDto.java new file mode 100644 index 000000000..b9c6f5ea2 --- /dev/null +++ b/src/main/java/fr/insee/genesis/controller/dto/ContextualVariableFileReportDto.java @@ -0,0 +1,6 @@ +package fr.insee.genesis.controller.dto; + +public record ContextualVariableFileReportDto( + String fileName, + String type +) {} diff --git a/src/main/java/fr/insee/genesis/controller/dto/SaveContextualVariablesReportDto.java b/src/main/java/fr/insee/genesis/controller/dto/SaveContextualVariablesReportDto.java new file mode 100644 index 000000000..3246288c1 --- /dev/null +++ b/src/main/java/fr/insee/genesis/controller/dto/SaveContextualVariablesReportDto.java @@ -0,0 +1,9 @@ +package fr.insee.genesis.controller.dto; + +import java.util.List; + +public record SaveContextualVariablesReportDto( + String questionnaireId, + int processedFiles, + List files +) {} diff --git a/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java b/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java index ff3a17101..b01862b78 100644 --- a/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java +++ b/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java @@ -2,6 +2,7 @@ import fr.insee.genesis.Constants; import fr.insee.genesis.configuration.Config; +import fr.insee.genesis.controller.dto.SaveContextualVariablesReportDto; import fr.insee.genesis.domain.model.surveyunit.Mode; import fr.insee.genesis.domain.ports.api.ContextualExternalVariableApiPort; import fr.insee.genesis.domain.ports.api.ContextualPreviousVariableApiPort; @@ -62,6 +63,27 @@ public ResponseEntity saveContextualVariables( } + @Operation(summary = "Save all contextual variables json files and return processed file details") + @PostMapping(path = "/json/report") + @PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER')") + public ResponseEntity saveContextualVariablesWithReport( + @RequestParam("questionnaireId") String questionnaireId + ) throws GenesisException { + FileUtils fileUtils = new FileUtils(config); + + String contextualFolderPath = + fileUtils.getDataFolder(questionnaireId, "WEB", null) + Constants.CONTEXTUAL_FOLDER; + + SaveContextualVariablesReportDto report = + contextualVariableApiPort.saveContextualVariableFilesWithReport( + questionnaireId, + fileUtils, + contextualFolderPath + ); + + return ResponseEntity.ok(report); + } + @Operation(summary = "Add contextual previous json file") @PostMapping(path = "previous/json") @PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER','USER_BACK_OFFICE')") diff --git a/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java b/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java index 152321ee5..c88495dab 100644 --- a/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java +++ b/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java @@ -1,5 +1,6 @@ package fr.insee.genesis.domain.ports.api; +import fr.insee.genesis.controller.dto.SaveContextualVariablesReportDto; import fr.insee.genesis.domain.model.contextualvariable.ContextualVariableModel; import fr.insee.genesis.exceptions.GenesisException; import fr.insee.genesis.infrastructure.utils.FileUtils; @@ -7,4 +8,9 @@ public interface ContextualVariableApiPort { ContextualVariableModel getContextualVariable(String collectionInstrumentId, String interrogationId); int saveContextualVariableFiles(String collectionInstrumentId, FileUtils fileUtils, String contextualFolderPath) throws GenesisException; + SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( + String collectionInstrumentId, + FileUtils fileUtils, + String contextualFolderPath + ) throws GenesisException; } \ No newline at end of file diff --git a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java index 50e17cef4..9bed404aa 100644 --- a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java +++ b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java @@ -1,5 +1,7 @@ package fr.insee.genesis.domain.service.contextualvariable; +import fr.insee.genesis.controller.dto.ContextualVariableFileReportDto; +import fr.insee.genesis.controller.dto.SaveContextualVariablesReportDto; import fr.insee.genesis.controller.dto.VariableQualityToolDto; import fr.insee.genesis.controller.dto.VariableStateDto; import fr.insee.genesis.domain.model.contextualvariable.ContextualExternalVariableModel; @@ -26,6 +28,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Stream; @Service @@ -101,6 +104,78 @@ public int saveContextualVariableFiles(String collectionInstrumentId, FileUtils return fileCount; } + @Override + public SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( + String collectionInstrumentId, + FileUtils fileUtils, + String contextualFolderPath + ) throws GenesisException { + List files = new ArrayList<>(); + + for (Mode mode : Mode.values()) { + try (Stream filePaths = Files.list(Path.of(contextualFolderPath))) { + Iterator it = filePaths + .filter(path -> path.toString().endsWith(".json")) + .iterator(); + + while (it.hasNext()) { + Path jsonFilePath = it.next(); + + Optional type = processContextualVariableFileAndGetType( + collectionInstrumentId, + jsonFilePath + ); + + if (type.isPresent()) { + moveFile(collectionInstrumentId, mode, fileUtils, jsonFilePath.toString()); + + files.add(new ContextualVariableFileReportDto( + jsonFilePath.getFileName().toString(), + type.get() + )); + } + } + } catch (NoSuchFileException nsfe) { + log.debug(nsfe.toString()); + } catch (IOException ioe) { + log.warn(ioe.toString()); + } + } + + return new SaveContextualVariablesReportDto( + collectionInstrumentId, + files.size(), + files + ); + } + + private Optional processContextualVariableFileAndGetType( + String collectionInstrumentId, + Path jsonFilePath + ) throws GenesisException { + boolean isPrevious = contextualPreviousVariableApiPort.readContextualPreviousFile( + collectionInstrumentId.toUpperCase(), + null, + jsonFilePath.toString() + ); + + if (isPrevious) { + return Optional.of("PREVIOUS"); + } + + boolean isExternal = contextualExternalVariableApiPort.readContextualExternalFile( + collectionInstrumentId.toUpperCase(), + jsonFilePath.toString() + ); + + if (isExternal) { + return Optional.of("EXTERNAL"); + } + + return Optional.empty(); + } + + private static void moveFile(String collectionInstrumentId, Mode mode, FileUtils fileUtils, String filePath) throws GenesisException { try { fileUtils.moveFiles(Path.of(filePath), fileUtils.getDoneFolder(collectionInstrumentId, mode.getFolder())); From 925940d399915cb6d118fd5868f1c9ea4bd03ba5 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Fri, 3 Jul 2026 15:58:41 +0200 Subject: [PATCH 2/9] add exception message --- .../ContextualVariableJsonService.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java index 9bed404aa..0655571dd 100644 --- a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java +++ b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java @@ -121,18 +121,29 @@ public SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( while (it.hasNext()) { Path jsonFilePath = it.next(); - Optional type = processContextualVariableFileAndGetType( - collectionInstrumentId, - jsonFilePath - ); - - if (type.isPresent()) { - moveFile(collectionInstrumentId, mode, fileUtils, jsonFilePath.toString()); + try { + Optional type = processContextualVariableFileAndGetType( + collectionInstrumentId, + jsonFilePath + ); - files.add(new ContextualVariableFileReportDto( - jsonFilePath.getFileName().toString(), - type.get() - )); + if (type.isPresent()) { + moveFile(collectionInstrumentId, mode, fileUtils, jsonFilePath.toString()); + + files.add(new ContextualVariableFileReportDto( + jsonFilePath.getFileName().toString(), + type.get() + )); + } + } catch (GenesisException e) { + throw new GenesisException( + e.getStatus(), + "Error while processing file '%s' : %s" + .formatted( + jsonFilePath.getFileName(), + e.getMessage() + ) + ); } } } catch (NoSuchFileException nsfe) { From 874786417affe979292d060335727f7487420977 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Fri, 3 Jul 2026 15:59:59 +0200 Subject: [PATCH 3/9] add exception message --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fd64d2163..d43661fc7 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 3.20.0 - 1.2.1 + 1.2.2 3.0.3 1.6.3 1.25.5 From e943baf88ce11f00f872c75d8de030e67b345bf7 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Fri, 3 Jul 2026 16:07:17 +0200 Subject: [PATCH 4/9] refactor the method --- .../ContextualVariableJsonService.java | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java index 0655571dd..1bab7c8cb 100644 --- a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java +++ b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java @@ -121,29 +121,12 @@ public SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( while (it.hasNext()) { Path jsonFilePath = it.next(); - try { - Optional type = processContextualVariableFileAndGetType( - collectionInstrumentId, - jsonFilePath - ); + Optional report = + processContextualVariableFileForReport(collectionInstrumentId, jsonFilePath); - if (type.isPresent()) { - moveFile(collectionInstrumentId, mode, fileUtils, jsonFilePath.toString()); - - files.add(new ContextualVariableFileReportDto( - jsonFilePath.getFileName().toString(), - type.get() - )); - } - } catch (GenesisException e) { - throw new GenesisException( - e.getStatus(), - "Error while processing file '%s' : %s" - .formatted( - jsonFilePath.getFileName(), - e.getMessage() - ) - ); + if (report.isPresent()) { + moveFile(collectionInstrumentId, mode, fileUtils, jsonFilePath.toString()); + files.add(report.get()); } } } catch (NoSuchFileException nsfe) { @@ -160,6 +143,29 @@ public SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( ); } + private Optional processContextualVariableFileForReport( + String collectionInstrumentId, + Path jsonFilePath + ) throws GenesisException { + try { + Optional type = processContextualVariableFileAndGetType( + collectionInstrumentId, + jsonFilePath + ); + + return type.map(value -> new ContextualVariableFileReportDto( + jsonFilePath.getFileName().toString(), + value + )); + } catch (GenesisException e) { + throw new GenesisException( + e.getStatus(), + "Error while processing file '%s' : %s" + .formatted(jsonFilePath.getFileName().toString(), e.getMessage()) + ); + } + } + private Optional processContextualVariableFileAndGetType( String collectionInstrumentId, Path jsonFilePath From ec545ef6e184ec8a0acef1f307c75e0f291d5240 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Mon, 6 Jul 2026 11:31:00 +0200 Subject: [PATCH 5/9] add tests --- src/main/java/fr/insee/genesis/Constants.java | 2 + .../ContextualVariableJsonService.java | 12 ++++- .../ContextualVariableControllerTest.java | 38 ++++++++++++++++ .../ContextualVariableJsonServiceTest.java | 44 +++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/insee/genesis/Constants.java b/src/main/java/fr/insee/genesis/Constants.java index 5a23c2167..bb311271b 100644 --- a/src/main/java/fr/insee/genesis/Constants.java +++ b/src/main/java/fr/insee/genesis/Constants.java @@ -21,6 +21,8 @@ public class Constants { public static final String MONGODB_CONTEXT_COLLECTION_NAME = "dataProcessingContexts"; public static final String MONGODB_CONTEXTUAL_PREVIOUS_COLLECTION_NAME = "editedPrevious"; public static final String MONGODB_CONTEXTUAL_EXTERNAL_COLLECTION_NAME = "editedExternal"; + public static final String TYPE_PREVIOUS = "PREVIOUS"; + public static final String TYPE_EXTERNAL = "EXTERNAL"; public static final String LOOP_NAME_PREFIX = "BOUCLE"; public static final String MONGODB_RESPONSE_COLLECTION_NAME = "responses"; public static final String MONGODB_RAW_RESPONSES_COLLECTION_NAME = "rawResponses"; diff --git a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java index 1bab7c8cb..cd54e9d0b 100644 --- a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java +++ b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java @@ -31,6 +31,9 @@ import java.util.Optional; import java.util.stream.Stream; +import static fr.insee.genesis.Constants.TYPE_EXTERNAL; +import static fr.insee.genesis.Constants.TYPE_PREVIOUS; + @Service @Slf4j public class ContextualVariableJsonService implements ContextualVariableApiPort { @@ -104,6 +107,11 @@ public int saveContextualVariableFiles(String collectionInstrumentId, FileUtils return fileCount; } + /** + * Generates a detailed report of processed contextual variable files. + * Added to preserve the existing behavior of {@link #saveContextualVariableFiles(String, FileUtils, String)}, + * which only returns the number of processed files. + */ @Override public SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( String collectionInstrumentId, @@ -177,7 +185,7 @@ private Optional processContextualVariableFileAndGetType( ); if (isPrevious) { - return Optional.of("PREVIOUS"); + return Optional.of(TYPE_PREVIOUS); } boolean isExternal = contextualExternalVariableApiPort.readContextualExternalFile( @@ -186,7 +194,7 @@ private Optional processContextualVariableFileAndGetType( ); if (isExternal) { - return Optional.of("EXTERNAL"); + return Optional.of(TYPE_EXTERNAL); } return Optional.empty(); diff --git a/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java b/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java index 34ca174c1..77f11fbb2 100644 --- a/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java +++ b/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java @@ -2,6 +2,8 @@ import fr.insee.genesis.Constants; import fr.insee.genesis.TestConstants; +import fr.insee.genesis.controller.dto.ContextualVariableFileReportDto; +import fr.insee.genesis.controller.dto.SaveContextualVariablesReportDto; import fr.insee.genesis.domain.model.contextualvariable.ContextualVariableModel; import fr.insee.genesis.domain.model.surveyunit.Mode; import fr.insee.genesis.domain.ports.api.ContextualExternalVariableApiPort; @@ -18,10 +20,13 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; @@ -92,6 +97,39 @@ void saveContextualVariables() { ); } + @Test + @SneakyThrows + void saveContextualVariablesWithReport() { + // GIVEN + SaveContextualVariablesReportDto report = new SaveContextualVariablesReportDto( + TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID, + 1, + List.of(new ContextualVariableFileReportDto("ok.json", "PREVIOUS")) + ); + + doReturn(report).when(contextualVariableApiPort).saveContextualVariableFilesWithReport( + eq(TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID), + any(), + any() + ); + + // WHEN + ResponseEntity response = + contextualVariableController.saveContextualVariablesWithReport( + TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID + ); + + // THEN + verify(contextualVariableApiPort, times(1)).saveContextualVariableFilesWithReport( + eq(TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID), + any(), + any() + ); + + Assertions.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + Assertions.assertThat(response.getBody()).isEqualTo(report); + } + @Test @SneakyThrows void readContextualPreviousJson() { diff --git a/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java b/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java index 3196b6a75..08a6c4495 100644 --- a/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java +++ b/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java @@ -1,6 +1,8 @@ package fr.insee.genesis.domain.service.contextualvariable; import fr.insee.genesis.TestConstants; +import fr.insee.genesis.controller.dto.ContextualVariableFileReportDto; +import fr.insee.genesis.controller.dto.SaveContextualVariablesReportDto; import fr.insee.genesis.controller.dto.VariableQualityToolDto; import fr.insee.genesis.controller.dto.VariableStateDto; import fr.insee.genesis.domain.model.contextualvariable.ContextualExternalVariableModel; @@ -338,6 +340,48 @@ void saveContextualVariableFiles() { ); } + @Test + @SneakyThrows + void saveContextualVariableFilesWithReport() { + // GIVEN + String collectionInstrumentId = "test"; + FileUtils fileUtils = mock(FileUtils.class); + String doneFolder = "testDone"; + + doReturn(doneFolder).when(fileUtils).getDoneFolder(anyString(), anyString()); + + doReturn(true).when(contextualPreviousVariableApiPort) + .readContextualPreviousFile(any(), any(), any()); + + doAnswer(invocation -> + Files.deleteIfExists(invocation.getArgument(0)) + ).when(fileUtils).moveFiles(any(Path.class), any()); + + // WHEN + SaveContextualVariablesReportDto report = + contextualVariableJsonService.saveContextualVariableFilesWithReport( + collectionInstrumentId, + fileUtils, + TEST_FOLDER_PATH.toString() + ); + + // THEN + Assertions.assertThat(report).isNotNull(); + Assertions.assertThat(report.questionnaireId()).isEqualTo(collectionInstrumentId); + Assertions.assertThat(report.processedFiles()).isEqualTo(2); + + Assertions.assertThat(report.files()) + .hasSize(2) + .extracting(ContextualVariableFileReportDto::fileName) + .containsExactlyInAnyOrder("ok.json", "ok2.json"); + + Assertions.assertThat(report.files()) + .extracting(ContextualVariableFileReportDto::type) + .containsOnly("PREVIOUS"); + + verify(fileUtils, times(2)).moveFiles(any(Path.class), eq(doneFolder)); + } + @AfterEach void clean() throws IOException { if (Files.exists(TEST_FOLDER_PATH)){ From 37ad2fea98b9e25674f9dac21e2c495f2178ace5 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Tue, 7 Jul 2026 17:12:38 +0200 Subject: [PATCH 6/9] refactor saveContextualVariableFiles after CR --- .../ContextualVariableJsonService.java | 47 ++++--------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java index cd54e9d0b..381e790ce 100644 --- a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java +++ b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java @@ -82,29 +82,16 @@ public ContextualVariableModel getContextualVariable(String collectionInstrument } @Override - public int saveContextualVariableFiles(String collectionInstrumentId, FileUtils fileUtils, String contextualFolderPath) throws GenesisException { - int fileCount = 0; - - for (Mode mode : Mode.values()) { - try (Stream filePaths = Files.list(Path.of(contextualFolderPath))) { - Iterator it = filePaths - .filter(path -> path.toString().endsWith(".json")) - .iterator(); - while (it.hasNext()) { - Path jsonFilePath = it.next(); - if (processContextualVariableFile(collectionInstrumentId, jsonFilePath)) { - //If the file is indeed a contextual variables file and had been processed - moveFile(collectionInstrumentId, mode, fileUtils, jsonFilePath.toString()); - fileCount++; - } - } - } catch (NoSuchFileException nsfe) { - log.debug(nsfe.toString()); - } catch (IOException ioe) { - log.warn(ioe.toString()); - } - } - return fileCount; + public int saveContextualVariableFiles( + String collectionInstrumentId, + FileUtils fileUtils, + String contextualFolderPath + ) throws GenesisException { + return saveContextualVariableFilesWithReport( + collectionInstrumentId, + fileUtils, + contextualFolderPath + ).processedFiles(); } /** @@ -242,18 +229,4 @@ private VariableQualityToolDto extractValue(Object variable, String variableName ); return variableQualityToolDto; } - - /** - * @return true if any contextual variable part found in file, false otherwise - */ - private boolean processContextualVariableFile(String collectionInstrumentId, Path jsonFilePath) throws GenesisException { - return contextualPreviousVariableApiPort.readContextualPreviousFile( - collectionInstrumentId.toUpperCase(), - null, - jsonFilePath.toString() - ) || contextualExternalVariableApiPort.readContextualExternalFile( - collectionInstrumentId.toUpperCase(), - jsonFilePath.toString() - ); - } } From be63b0f63bfc68b923e3ba38595c78efc0a67347 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Tue, 7 Jul 2026 17:22:41 +0200 Subject: [PATCH 7/9] correct after sonar --- .../contextualvariable/ContextualVariableJsonService.java | 3 ++- .../rest/responses/ContextualVariableControllerTest.java | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java index 381e790ce..7977faf39 100644 --- a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java +++ b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java @@ -108,7 +108,8 @@ public SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( List files = new ArrayList<>(); for (Mode mode : Mode.values()) { - try (Stream filePaths = Files.list(Path.of(contextualFolderPath))) { + Path contextualFolder = Path.of(contextualFolderPath); + try (Stream filePaths = Files.list(contextualFolder)) { Iterator it = filePaths .filter(path -> path.toString().endsWith(".json")) .iterator(); diff --git a/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java b/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java index 77f11fbb2..2ce27d1ce 100644 --- a/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java +++ b/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java @@ -172,7 +172,7 @@ void readContextualPreviousJson() { } @Test - void readContextualPreviousJson_notJson() throws GenesisException { + void readContextualPreviousJson_notJson() { Assertions.assertThatThrownBy(() -> contextualVariableController.readContextualPreviousJson( TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID, Mode.WEB, @@ -218,13 +218,13 @@ void readContextualExternalJson() { //THEN verify(contextualExternalVariableApiPort).readContextualExternalFile( - eq(TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID.toUpperCase()), - eq(expectedFilePath) + TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID.toUpperCase(), + expectedFilePath ); } @Test - void readContextualExternalJson_notJson() throws GenesisException { + void readContextualExternalJson_notJson() { Assertions.assertThatThrownBy(() -> contextualVariableController.readContextualExternalJson( TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID, From d556c9edcd8cca9612ecba5c64e9b71555756d2f Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Wed, 8 Jul 2026 10:18:41 +0200 Subject: [PATCH 8/9] correct after sonar --- .../ContextualVariableController.java | 10 ++------- .../ports/api/ContextualVariableApiPort.java | 5 ++--- .../ContextualVariableJsonService.java | 15 +++++++------ .../ContextualVariableControllerTest.java | 3 --- .../ContextualVariableJsonServiceTest.java | 22 ++++++++++++------- 5 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java b/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java index b01862b78..491f691fc 100644 --- a/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java +++ b/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java @@ -55,9 +55,7 @@ public ResponseEntity saveContextualVariables( ) throws GenesisException{ FileUtils fileUtils = new FileUtils(config); - String contextualFolderPath = fileUtils.getDataFolder(questionnaireId, "WEB", null) + Constants.CONTEXTUAL_FOLDER; - - int fileCount = contextualVariableApiPort.saveContextualVariableFiles(questionnaireId, fileUtils,contextualFolderPath); + int fileCount = contextualVariableApiPort.saveContextualVariableFiles(questionnaireId, fileUtils); return ResponseEntity.ok("%d file(s) processed for questionnaire %s !".formatted(fileCount, questionnaireId)); @@ -71,14 +69,10 @@ public ResponseEntity saveContextualVariablesW ) throws GenesisException { FileUtils fileUtils = new FileUtils(config); - String contextualFolderPath = - fileUtils.getDataFolder(questionnaireId, "WEB", null) + Constants.CONTEXTUAL_FOLDER; - SaveContextualVariablesReportDto report = contextualVariableApiPort.saveContextualVariableFilesWithReport( questionnaireId, - fileUtils, - contextualFolderPath + fileUtils ); return ResponseEntity.ok(report); diff --git a/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java b/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java index c88495dab..f27bb29ce 100644 --- a/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java +++ b/src/main/java/fr/insee/genesis/domain/ports/api/ContextualVariableApiPort.java @@ -7,10 +7,9 @@ public interface ContextualVariableApiPort { ContextualVariableModel getContextualVariable(String collectionInstrumentId, String interrogationId); - int saveContextualVariableFiles(String collectionInstrumentId, FileUtils fileUtils, String contextualFolderPath) throws GenesisException; + int saveContextualVariableFiles(String collectionInstrumentId, FileUtils fileUtils) throws GenesisException; SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( String collectionInstrumentId, - FileUtils fileUtils, - String contextualFolderPath + FileUtils fileUtils ) throws GenesisException; } \ No newline at end of file diff --git a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java index 7977faf39..8af5bde8a 100644 --- a/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java +++ b/src/main/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonService.java @@ -31,6 +31,7 @@ import java.util.Optional; import java.util.stream.Stream; +import static fr.insee.genesis.Constants.CONTEXTUAL_FOLDER; import static fr.insee.genesis.Constants.TYPE_EXTERNAL; import static fr.insee.genesis.Constants.TYPE_PREVIOUS; @@ -84,28 +85,28 @@ public ContextualVariableModel getContextualVariable(String collectionInstrument @Override public int saveContextualVariableFiles( String collectionInstrumentId, - FileUtils fileUtils, - String contextualFolderPath + FileUtils fileUtils ) throws GenesisException { return saveContextualVariableFilesWithReport( collectionInstrumentId, - fileUtils, - contextualFolderPath + fileUtils ).processedFiles(); } /** * Generates a detailed report of processed contextual variable files. - * Added to preserve the existing behavior of {@link #saveContextualVariableFiles(String, FileUtils, String)}, + * Added to preserve the existing behavior of {@link #saveContextualVariableFiles(String, FileUtils)}, * which only returns the number of processed files. */ @Override public SaveContextualVariablesReportDto saveContextualVariableFilesWithReport( String collectionInstrumentId, - FileUtils fileUtils, - String contextualFolderPath + FileUtils fileUtils ) throws GenesisException { List files = new ArrayList<>(); + String contextualFolderPath = + fileUtils.getDataFolder(collectionInstrumentId, "WEB", null) + + CONTEXTUAL_FOLDER; for (Mode mode : Mode.values()) { Path contextualFolder = Path.of(contextualFolderPath); diff --git a/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java b/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java index 2ce27d1ce..fbc12251b 100644 --- a/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java +++ b/src/test/java/fr/insee/genesis/controller/rest/responses/ContextualVariableControllerTest.java @@ -92,7 +92,6 @@ void saveContextualVariables() { //THEN verify(contextualVariableApiPort, times(1)).saveContextualVariableFiles( eq(TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID), - any(), any() ); } @@ -109,7 +108,6 @@ void saveContextualVariablesWithReport() { doReturn(report).when(contextualVariableApiPort).saveContextualVariableFilesWithReport( eq(TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID), - any(), any() ); @@ -122,7 +120,6 @@ void saveContextualVariablesWithReport() { // THEN verify(contextualVariableApiPort, times(1)).saveContextualVariableFilesWithReport( eq(TestConstants.DEFAULT_COLLECTION_INSTRUMENT_ID), - any(), any() ); diff --git a/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java b/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java index 08a6c4495..122e94854 100644 --- a/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java +++ b/src/test/java/fr/insee/genesis/domain/service/contextualvariable/ContextualVariableJsonServiceTest.java @@ -1,5 +1,6 @@ package fr.insee.genesis.domain.service.contextualvariable; +import fr.insee.genesis.Constants; import fr.insee.genesis.TestConstants; import fr.insee.genesis.controller.dto.ContextualVariableFileReportDto; import fr.insee.genesis.controller.dto.SaveContextualVariablesReportDto; @@ -37,6 +38,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -65,8 +67,12 @@ void setUp() throws IOException { FileSystemUtils.deleteRecursively(TEST_FOLDER_PATH); } Files.createDirectories(TEST_FOLDER_PATH); - Files.createFile(TEST_FOLDER_PATH.resolve("ok.json")); - Files.createFile(TEST_FOLDER_PATH.resolve("ok2.json")); + + Path contextualFolderPath = TEST_FOLDER_PATH.resolve("contextual"); + Files.createDirectories(contextualFolderPath); + + Files.createFile(contextualFolderPath.resolve("ok.json")); + Files.createFile(contextualFolderPath.resolve("ok2.json")); } @Test @@ -315,6 +321,8 @@ void saveContextualVariableFiles() { Path.of("ok2.json") ); String doneFolder = "testDone"; + doReturn(TEST_FOLDER_PATH.toString()).when(fileUtils) + .getDataFolder(eq(collectionInstrumentId), eq("WEB"), isNull()); doReturn(doneFolder).when(fileUtils).getDoneFolder(anyString(),anyString()); doReturn(pathList).when(fileUtils).listFiles(anyString()); doReturn(true).when(contextualPreviousVariableApiPort) @@ -328,9 +336,7 @@ void saveContextualVariableFiles() { //WHEN int fileCount = contextualVariableJsonService.saveContextualVariableFiles( collectionInstrumentId, - fileUtils, - TEST_FOLDER_PATH.toString() - ); + fileUtils); //THEN Assertions.assertThat(fileCount).isEqualTo(pathList.size()); @@ -347,7 +353,8 @@ void saveContextualVariableFilesWithReport() { String collectionInstrumentId = "test"; FileUtils fileUtils = mock(FileUtils.class); String doneFolder = "testDone"; - + doReturn(TEST_FOLDER_PATH.toString()).when(fileUtils) + .getDataFolder(eq(collectionInstrumentId), eq("WEB"), isNull()); doReturn(doneFolder).when(fileUtils).getDoneFolder(anyString(), anyString()); doReturn(true).when(contextualPreviousVariableApiPort) @@ -361,8 +368,7 @@ void saveContextualVariableFilesWithReport() { SaveContextualVariablesReportDto report = contextualVariableJsonService.saveContextualVariableFilesWithReport( collectionInstrumentId, - fileUtils, - TEST_FOLDER_PATH.toString() + fileUtils ); // THEN From 1097cd7685f942ad1d58a5637c55054d9a43b3df Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Wed, 8 Jul 2026 10:38:58 +0200 Subject: [PATCH 9/9] correct after sonar --- src/main/java/fr/insee/genesis/Constants.java | 4 ++++ .../responses/ContextualVariableController.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/fr/insee/genesis/Constants.java b/src/main/java/fr/insee/genesis/Constants.java index bb311271b..eb06a6197 100644 --- a/src/main/java/fr/insee/genesis/Constants.java +++ b/src/main/java/fr/insee/genesis/Constants.java @@ -2,6 +2,8 @@ import lombok.experimental.UtilityClass; +import java.util.regex.Pattern; + @UtilityClass public class Constants { @@ -11,6 +13,8 @@ public class Constants { public static final String METADATA_SEPARATOR = "."; public static final String DATE_REGEX = "(^([0-9]{4})[\\-\\/]([0-9]|1[0-2]|0[1-9])[\\-\\/]([0-9]|[0-2][0-9]|3[0-1])$)|" + "(^([0-9]|[0-2][0-9]|3[0-1])[\\-\\/]([0-9]|1[0-2]|0[1-9])[\\-\\/]([0-9]{4})$)"; + public static final Pattern QUESTIONNAIRE_ID_PATTERN = + Pattern.compile("^[A-Za-z0-9_-]+$"); public static final String FILTER_RESULT_PREFIX = "FILTER_RESULT_"; public static final String MISSING_SUFFIX = "_MISSING"; public static final String MONGODB_LUNATIC_RAWDATA_COLLECTION_NAME = "lunaticjsondata"; diff --git a/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java b/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java index 491f691fc..b2a8b0757 100644 --- a/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java +++ b/src/main/java/fr/insee/genesis/controller/rest/responses/ContextualVariableController.java @@ -23,6 +23,9 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.regex.Pattern; + +import static fr.insee.genesis.Constants.QUESTIONNAIRE_ID_PATTERN; @RequestMapping(path = "/contextual-variables") @Controller @@ -35,6 +38,7 @@ public class ContextualVariableController { private final ContextualVariableApiPort contextualVariableApiPort; private final Config config; + @Operation(summary = "Get contextual variables (external and previous)") @GetMapping(path = "/") @PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER')") @@ -53,6 +57,8 @@ public ResponseEntity getContextualVariables( public ResponseEntity saveContextualVariables( @RequestParam("questionnaireId") String questionnaireId ) throws GenesisException{ + validateQuestionnaireId(questionnaireId); + FileUtils fileUtils = new FileUtils(config); int fileCount = contextualVariableApiPort.saveContextualVariableFiles(questionnaireId, fileUtils); @@ -67,6 +73,8 @@ public ResponseEntity saveContextualVariables( public ResponseEntity saveContextualVariablesWithReport( @RequestParam("questionnaireId") String questionnaireId ) throws GenesisException { + validateQuestionnaireId(questionnaireId); + FileUtils fileUtils = new FileUtils(config); SaveContextualVariablesReportDto report = @@ -137,4 +145,10 @@ private static void moveFile(String questionnaireId, Mode mode, FileUtils fileUt throw new GenesisException(HttpStatus.INTERNAL_SERVER_ERROR, "Error while moving file to done"); } } + + private void validateQuestionnaireId(String questionnaireId) throws GenesisException { + if (!QUESTIONNAIRE_ID_PATTERN.matcher(questionnaireId).matches()) { + throw new GenesisException(HttpStatus.BAD_REQUEST, "Invalid questionnaireId"); + } + } }