Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ça serait bien de définir des private static final String ... (constante ou fonction) pour faire plaisir à Sonar sur les string dupliquées

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
Expand Down Expand Up @@ -150,6 +151,54 @@ public ResponseEntity<String> processRawResponsesByCollectionInstrumentId(
}
}

@Operation(summary = "Reprocess raw data for processed data of a collection instrument")
@PostMapping(path = "/raw-responses/{collectionInstrumentId}/reprocess")
@PreAuthorize("hasRole('SCHEDULER')")
public ResponseEntity<String> reProcessRawResponsesByCollectionInstrumentId(
@Parameter(
description = "Id of the collection instrument (old questionnaireId)",
example = "ENQTEST2025X00"
)
@PathVariable("collectionInstrumentId") String collectionInstrumentId,
@RequestParam(value = "sinceDate", required = false)
@Parameter(description = "Extract since",
schema = @Schema(type = "string", format = "date-time", example = "2026-01-01T00:00:00")
)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime sinceDate,
@RequestParam(value = "endDate", required = false)
@Parameter(description = "Extract until",
schema = @Schema(type = "string", format = "date-time", example = "2026-02-02T00:00:00")
)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate
) {
log.info(
"Try to reprocess raw responses for collectionInstrumentId {}, sinceDate={}, endDate={}",
collectionInstrumentId,
sinceDate,
endDate
);

try {
DataProcessResult result = rawResponseApiPort.reprocessRawResponses(
collectionInstrumentId,
sinceDate,
endDate
);

return result.formattedDataCount() == 0
? ResponseEntity.ok(NB_DOCS.formatted(result.dataCount(), collectionInstrumentId))
: ResponseEntity.ok(
NB_DOCS_WITH_FORMATTED.formatted(
result.dataCount(),
result.formattedDataCount(),
collectionInstrumentId
)
);
} catch (GenesisException e) {
return ResponseEntity.status(e.getStatus()).body(e.getMessage());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Est-ce qu'on gèrerait pas plutôt via un ExceptionHandler ?

}
}

@Operation(summary = "Get the list of collection instruments containing unprocessed interrogations")
@GetMapping(path = "/raw-responses/unprocessed/collection-instrument-ids")
@PreAuthorize("hasRole('SCHEDULER')")
Expand Down Expand Up @@ -229,6 +278,54 @@ public ResponseEntity<String> processJsonRawData(
}
}

@Operation(summary = "Reprocess raw data of a questionnaire (old raw model)")
@PostMapping(path = "/responses/raw/lunatic-json/{questionnaireId}/reprocess")
@PreAuthorize("hasRole('SCHEDULER')")
public ResponseEntity<String> reProcessJsonRawDataByQuestionnaireId(
@Parameter(
description = "Id of the questionnaireId",
example = "ENQTEST2025X00"
)
@PathVariable("questionnaireId") String questionnaireId,
@RequestParam(value = "sinceDate", required = false)
@Parameter(description = "Extract since",
schema = @Schema(type = "string", format = "date-time", example = "2026-01-01T00:00:00")
)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime sinceDate,
@RequestParam(value = "endDate", required = false)
@Parameter(description = "Extract until",
schema = @Schema(type = "string", format = "date-time", example = "2026-02-02T00:00:00")
)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate
) {
log.info(
"Try to reprocess raw responses for questionnaireId {}, sinceDate={}, endDate={}",
questionnaireId,
sinceDate,
endDate
);

try {
DataProcessResult result = lunaticJsonRawDataApiPort.reprocessRawData(
questionnaireId,
sinceDate,
endDate
);

return result.formattedDataCount() == 0
? ResponseEntity.ok(NB_DOCS.formatted(result.dataCount(), questionnaireId))
: ResponseEntity.ok(
NB_DOCS_WITH_FORMATTED.formatted(
result.dataCount(),
result.formattedDataCount(),
questionnaireId
)
);
} catch (GenesisException e) {
return ResponseEntity.status(e.getStatus()).body(e.getMessage());
}
}

@Operation(summary = "Get processed data ids from last n hours (default 24h)")
@GetMapping(path = "/responses/raw/lunatic-json/processed/ids")
@PreAuthorize("hasRole('ADMIN')")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ public ControllerUtils(FileUtils fileUtils) {

/**
* If a mode is specified, we treat only this mode.
* If no mode is specified, we treat all modes in the campaign.
* If no mode is specified, we treat all modes in the questionnaireId.
* If no mode is specified and no specs are found, we return an error
* @param campaign campaign id to get modes
* @param questionnaireId questionnaireId id to get modes
* @param modeSpecified a Mode to use, null if we want all modes available
* @return a list with the mode in modeSpecified or all modes if null
* @throws GenesisException if error in specs structure
*/
public List<Mode> getModesList(String campaign, Mode modeSpecified) throws GenesisException {
public List<Mode> getModesList(String questionnaireId, Mode modeSpecified) throws GenesisException {
if (modeSpecified != null){
return Collections.singletonList(modeSpecified);
}
List<Mode> modes = new ArrayList<>();
String specFolder = fileUtils.getSpecFolder(campaign);
String specFolder = fileUtils.getSpecFolder(questionnaireId);
List<String> modeSpecFolders = fileUtils.listFolders(specFolder);
if (modeSpecFolders.isEmpty()) {
throw new GenesisException(404, "No specification folder found " + specFolder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ public interface LunaticJsonRawDataApiPort {
void save(LunaticJsonRawDataModel rawData);
List<LunaticJsonRawDataModel> getRawData(String campaignName, Mode mode, List<String> interrogationIdList);
List<LunaticJsonRawDataModel> getRawDataByQuestionnaireId(String questionnaireId, Mode mode, List<String> interrogationIdList);

DataProcessResult reprocessRawData(
String questionnaireId,
LocalDateTime sinceDate,
LocalDateTime endDate
) throws GenesisException;

List<SurveyUnitModel> convertRawData(List<LunaticJsonRawDataModel> rawData, VariablesMap variablesMap);

List<LunaticJsonRawDataUnprocessedDto> getUnprocessedDataIds();
Set<String> getUnprocessedDataQuestionnaireIds();
void updateProcessDates(List<SurveyUnitModel> surveyUnitModels);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.data.domain.Pageable;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

Expand All @@ -20,6 +21,13 @@ public interface RawResponseApiPort {
List<RawResponseModel> getRawResponsesByInterrogationID(String interrogationId);
DataProcessResult processRawResponses(String collectionInstrumentId, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException;
DataProcessResult processRawResponses(String collectionInstrumentId) throws GenesisException;

DataProcessResult reprocessRawResponses(
String collectionInstrumentId,
LocalDateTime sinceDate,
LocalDateTime endDate
) throws GenesisException;

List<SurveyUnitModel> convertRawResponse(List<RawResponseModel> rawResponses, VariablesMap variablesMap);
List<String> getUnprocessedCollectionInstrumentIds();
void updateProcessDates(List<SurveyUnitModel> surveyUnitModels);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ List<InterrogationId> findDistinctPageableInterrogationIdsByQuestionnaireId(Stri

Long deleteByCollectionInstrumentId(String collectionInstrumentId);

Long deleteByCollectionInstrumentIdAndInterrogationIds(
String collectionInstrumentId,
Set<String> interrogationIds
);

Long deleteByQuestionnaireIdAndInterrogationIds(
String questionnaireId,
Set<String> interrogationIds
);

long countResponses();

Set<String> findQuestionnaireIdsByCampaignId(String campaignId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
public interface LunaticJsonRawDataPersistencePort {

void save(LunaticJsonRawDataModel rawData);
List<LunaticJsonRawDataModel> findRawData(String campaignName, Mode mode, List<String> interrogationIdList);
List<LunaticJsonRawDataModel> findRawData(String questionnaireId, Mode mode, List<String> interrogationIdList);
List<LunaticJsonRawDataModel> findRawDataByQuestionnaireId(String questionnaireId, Mode mode, List<String> interrogationIdList);
Page<LunaticJsonRawDataModel> findRawDataByQuestionnaireId(String questionnaireId, Pageable pageable);
List<LunaticJsonRawDataModel> findRawDataByInterrogationID(String interrogationId);
List<LunaticJsonRawDataModel> getAllUnprocessedData();
void updateProcessDates(String campaignId, Set<String> interrogationIds);

void resetProcessDates(String questionnaireId, Set<String> interrogationIds);

Set<String> findDistinctQuestionnaireIds();
Set<String> findDistinctQuestionnaireIdsByNullProcessDate();
Set<Mode> findModesByQuestionnaire(String questionnaireId);
Expand All @@ -31,4 +34,12 @@ public interface LunaticJsonRawDataPersistencePort {

boolean existsByInterrogationId(String interrogationId);
long countDistinctInterrogationIdsByQuestionnaireId(String questionnaireId);

Set<String> findProcessedInterrogationIdsByQuestionnaireId(String questionnaireId);

Set<String> findProcessedInterrogationIdsByQuestionnaireIdAndRecordDateBetween(
String questionnaireId,
LocalDateTime sinceDate,
LocalDateTime endDate
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.data.domain.Pageable;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

Expand All @@ -23,6 +24,13 @@ public interface RawResponsePersistencePort {
Set<String> findDistinctCollectionInstrumentIds();
long countDistinctInterrogationIdsByCollectionInstrumentId(String collectionInstrumentId);
Page<RawResponseModel> findByCollectionInstrumentId(String collectionInstrumentId, Pageable pageable);
Set<String> findProcessedInterrogationIdsByCollectionInstrumentId(String collectionInstrumentId);
Set<String> findProcessedInterrogationIdsByCollectionInstrumentIdAndRecordDateBetween(
String collectionInstrumentId,
LocalDateTime sinceDate,
LocalDateTime endDate
);

void resetProcessDates(String collectionInstrumentId, Set<String> interrogationIds);
boolean existsByInterrogationId(String interrogationId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ List<SurveyUnitModel> findInterrogationIdsByCollectionInstrumentIdAndRecordDateB

Long deleteByCollectionInstrumentId(String collectionInstrumentId);

Long deleteByCollectionInstrumentIdAndInterrogationIds(
String collectionInstrumentId,
Set<String> interrogationIds
);

Long deleteByQuestionnaireIdAndInterrogationIds(
String questionnaireId,
Set<String> interrogationIds
);

long count();

Set<String> findQuestionnaireIdsByCampaignId(String campaignId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public MetadataModel find(String collectionInstrumentId, Mode mode) throws Genes
}

@Override
public MetadataModel loadAndSaveIfNotExists(String campaignName, String collectionInstrumentId, Mode mode, FileUtils fileUtils,
public MetadataModel loadAndSaveIfNotExists(String questionnaireId, String collectionInstrumentId, Mode mode, FileUtils fileUtils,
List<GenesisError> errors) throws GenesisException {
List<QuestionnaireMetadataModel> questionnaireMetadataModels =
questionnaireMetadataPersistencePort.find(collectionInstrumentId.toUpperCase(), mode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -97,8 +98,8 @@
}

@Override
public List<LunaticJsonRawDataModel> getRawData(String campaignName, Mode mode, List<String> interrogationIdList) {
return lunaticJsonRawDataPersistencePort.findRawData(campaignName, mode, interrogationIdList);
public List<LunaticJsonRawDataModel> getRawData(String questionnaireId, Mode mode, List<String> interrogationIdList) {
return lunaticJsonRawDataPersistencePort.findRawData(questionnaireId, mode, interrogationIdList);
}

@Override
Expand All @@ -113,15 +114,15 @@

@Override
@Deprecated(since = "1.13.0")
public DataProcessResult processRawData(String campaignName, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException {
public DataProcessResult processRawData(String questionnaireId, List<String> interrogationIdList, List<GenesisError> errors) throws GenesisException {

Check warning on line 117 in src/main/java/fr/insee/genesis/domain/service/rawdata/LunaticJsonRawDataService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add the missing @deprecated Javadoc tag.

See more on https://sonarcloud.io/project/issues?id=InseeFr_genesis-api&issues=AZzdUKPPosbqXbX6EOYx&open=AZzdUKPPosbqXbX6EOYx&pullRequest=425

Check warning on line 117 in src/main/java/fr/insee/genesis/domain/service/rawdata/LunaticJsonRawDataService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=InseeFr_genesis-api&issues=AZzdUKPPosbqXbX6EOYw&open=AZzdUKPPosbqXbX6EOYw&pullRequest=425
int dataCount=0;
int formattedDataCount=0;
DataProcessingContextModel dataProcessingContext =
dataProcessingContextService.getContextByCollectionInstrumentId(campaignName);
List<Mode> modesList = controllerUtils.getModesList(campaignName, null);
dataProcessingContextService.getContextByCollectionInstrumentId(questionnaireId);
List<Mode> modesList = controllerUtils.getModesList(questionnaireId, null);
for (Mode mode : modesList) {
//Load and save metadata into database, throw exception if none
VariablesMap variablesMap = getVariablesMap(campaignName, mode, errors);
VariablesMap variablesMap = getVariablesMap(questionnaireId, mode, errors);
int totalBatchs = Math.ceilDiv(interrogationIdList.size() , config.getRawDataProcessingBatchSize());
int batchNumber = 1;
List<String> interrogationIdListForMode = new ArrayList<>(interrogationIdList);
Expand All @@ -130,7 +131,7 @@
int maxIndex = Math.min(interrogationIdListForMode.size(), config.getRawDataProcessingBatchSize());
List<String> interrogationIdToProcess = interrogationIdListForMode.subList(0, maxIndex);

List<LunaticJsonRawDataModel> rawData = getRawData(campaignName, mode, interrogationIdToProcess);
List<LunaticJsonRawDataModel> rawData = getRawData(questionnaireId, mode, interrogationIdToProcess);

List<SurveyUnitModel> surveyUnitModels = convertRawData(
rawData,
Expand Down Expand Up @@ -222,6 +223,7 @@
return new DataProcessResult(dataCount, formattedDataCount, errors);
}


private VariablesMap getVariablesMap(String questionnaireId, Mode mode, List<GenesisError> errors) throws GenesisException {
VariablesMap variablesMap = metadataService.loadAndSaveIfNotExists(questionnaireId, questionnaireId, mode, fileUtils,
errors).getVariables();
Expand Down Expand Up @@ -269,6 +271,57 @@
return processedInterrogationIdsPerQuestionnaire;
}


@Override
public DataProcessResult reprocessRawData(
String questionnaireId,
LocalDateTime sinceDate,
LocalDateTime endDate
) throws GenesisException {

log.info(
"Reprocessing raw responses for questionnaireId={}, sinceDate={}, endDate={}",
questionnaireId,
sinceDate,
endDate
);

if (sinceDate == null && endDate != null) {
throw new GenesisException(400, "endDate cannot be provided without sinceDate");
}

if (sinceDate != null && endDate != null && endDate.isBefore(sinceDate)) {
throw new GenesisException(400, "endDate must be after or equal to sinceDate");
}

Set<String> interrogationIds;

if (sinceDate == null) {
interrogationIds =
lunaticJsonRawDataPersistencePort.findProcessedInterrogationIdsByQuestionnaireId(questionnaireId);
} else {
LocalDateTime effectiveEndDate = endDate != null ? endDate : LocalDateTime.now();

interrogationIds =
lunaticJsonRawDataPersistencePort.findProcessedInterrogationIdsByQuestionnaireIdAndRecordDateBetween(
questionnaireId,
sinceDate,
effectiveEndDate
);
}

if (interrogationIds.isEmpty()) {
return new DataProcessResult(0, 0, new ArrayList<>());
}

surveyUnitService.deleteByQuestionnaireIdAndInterrogationIds(questionnaireId, interrogationIds);
lunaticJsonRawDataPersistencePort.resetProcessDates(questionnaireId, interrogationIds);

return processRawData(questionnaireId, new ArrayList<>(interrogationIds),
new ArrayList<>());
}


@Override
public List<SurveyUnitModel> convertRawData(List<LunaticJsonRawDataModel> rawDataList, VariablesMap variablesMap) {
//Convert to genesis model
Expand Down Expand Up @@ -334,7 +387,7 @@
private static LocalDateTime getValidationDate(LunaticJsonRawDataModel rawData) {
try{
return rawData.data().get("validationDate") == null ? null :
LocalDateTime.parse(rawData.data().get("validationDate").toString());
LocalDateTime.parse(rawData.data().get("validationDate").toString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}catch(Exception e){
log.warn("Exception when parsing validation date : {}}",e.toString());
return null;
Expand Down
Loading
Loading