Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package fr.insee.genesis.controller.dto;

import fr.insee.genesis.controller.utils.ExportType;
import fr.insee.genesis.domain.model.context.schedule.DestinationType;
import fr.insee.genesis.domain.model.context.schedule.TrustParameters;
import fr.insee.genesis.domain.model.surveyunit.Mode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class KraftwerkExecutionScheduleInput {
private String collectionInstrumentId;
private String scheduleUuid;
private ExportType exportType;
private String frequency;
private LocalDateTime startDate;
private LocalDateTime endDate;
private Mode mode;
private DestinationType destinationType;
private boolean addStates;
private String destinationFolder;
private TrustParameters trustParameters;
private Integer batchSize;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package fr.insee.genesis.controller.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import fr.insee.genesis.controller.utils.ExportType;
import fr.insee.genesis.domain.model.context.schedule.DestinationType;
import fr.insee.genesis.domain.model.surveyunit.Mode;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "Request used to schedule a Kraftwerk export workflow")
public class ScheduleRequestDto {

@NotBlank
@Schema(description = "Collection instrument to call Kraftwerk on", example = "EAP2026A00", requiredMode = Schema.RequiredMode.REQUIRED)
private String collectionInstrumentId;

@NotNull
@Schema(description = "Export type", allowableValues = {"JSON", "CSV_PARQUET"}, requiredMode = Schema.RequiredMode.REQUIRED)
private ExportType exportType;

@NotBlank
@Schema(description = "Frequency in Spring cron format (6 inputs). Example: 0 0 6 * * *", example = "0 0 6 * * *", requiredMode = Schema.RequiredMode.REQUIRED)
private String frequency;

@NotNull
@Schema(description = "Schedule effective date and time", example = "2024-01-01T12:00:00", requiredMode = Schema.RequiredMode.REQUIRED)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime scheduleBeginDate;

@NotNull
@Schema(description = "Schedule end date and time", example = "2024-01-01T12:00:00", requiredMode = Schema.RequiredMode.REQUIRED)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime scheduleEndDate;

private Mode mode;

@Schema(defaultValue = "APPLISHARE")
private DestinationType destinationType = DestinationType.APPLISHARE;

@Schema(defaultValue = "false")
private boolean useEncryption = false;

@Schema(description = "Encryption vault path")
private String encryptionVaultPath = "";

@Schema(defaultValue = "false")
private boolean useSignature = false;

@Schema(description = "Add variable states to export", example = "false", defaultValue = "false")
private boolean addStates = false;

@NotBlank
@Schema(description = "Destination folder (Applishare or S3)", requiredMode = Schema.RequiredMode.REQUIRED)
private String destinationFolder;

@Schema(description = "Batch size", defaultValue = "100")
private Integer batchSize;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fr.insee.genesis.controller.dto.rawdata;

import com.fasterxml.jackson.annotation.JsonFormat;
import fr.insee.genesis.controller.utils.ExportType;
import fr.insee.genesis.domain.model.context.schedule.DestinationType;
import fr.insee.genesis.domain.model.surveyunit.Mode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ScheduleV2Dto {

private String scheduleUuid;
private String collectionInstrumentId;
private LocalDateTime lastExecution;

private String frequency;
private ExportType exportType;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime scheduleBeginDate;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime scheduleEndDate;

private Mode mode;
private DestinationType destinationType;
private boolean useEncryption;
private String encryptionVaultPath;
private boolean useSignature;
private boolean addStates;
private String destinationFolder;
private Integer batchSize;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package fr.insee.genesis.controller.rest;

import fr.insee.genesis.Constants;
import fr.insee.genesis.controller.dto.KraftwerkExecutionScheduleInput;
import fr.insee.genesis.controller.dto.ScheduleDto;
import fr.insee.genesis.controller.dto.ScheduleRequestDto;
import fr.insee.genesis.controller.dto.rawdata.ScheduleV2Dto;
import fr.insee.genesis.domain.model.context.schedule.ServiceToCall;
import fr.insee.genesis.domain.model.context.schedule.TrustParameters;
import fr.insee.genesis.domain.ports.api.DataProcessingContextApiPort;
import fr.insee.genesis.exceptions.GenesisException;
import fr.insee.genesis.infrastructure.utils.FileUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatusCode;
Expand Down Expand Up @@ -97,6 +101,46 @@ public ResponseEntity<Object> getReviewIndicator(
}
}

@Operation(summary = "Create a Kraftwerk execution schedule V2")
@PostMapping(path = "/contexts/schedules/v2")
@PreAuthorize("hasRole('USER_KRAFTWERK')")
public ResponseEntity<Object> createScheduleV2(
@Valid @RequestBody ScheduleRequestDto request
) {
try {
TrustParameters trustParameters = null;
if (request.isUseEncryption()) {
trustParameters = new TrustParameters(
fileUtils.getKraftwerkOutFolder(request.getCollectionInstrumentId()),
"",
request.getEncryptionVaultPath(),
request.isUseSignature()
);
}

KraftwerkExecutionScheduleInput scheduleInput = KraftwerkExecutionScheduleInput.builder()
.collectionInstrumentId(request.getCollectionInstrumentId())
.exportType(request.getExportType())
.frequency(request.getFrequency())
.startDate(request.getScheduleBeginDate())
.endDate(request.getScheduleEndDate())
.mode(request.getMode())
.destinationType(request.getDestinationType())
.addStates(request.isAddStates())
.destinationFolder(request.getDestinationFolder())
.trustParameters(trustParameters)
.batchSize(request.getBatchSize())
.build();

String scheduleUuid = dataProcessingContextApiPort.createKraftwerkExecutionSchedule(scheduleInput);

return ResponseEntity.ok(scheduleUuid);

} catch (GenesisException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatusCode.valueOf(e.getStatus()));
}
}

@Deprecated(forRemoval = true)
@Operation(summary = "Schedule a Kraftwerk execution")
@PutMapping(path = "/context/schedules")
Expand Down Expand Up @@ -189,6 +233,49 @@ public ResponseEntity<Object> saveScheduleWithCollectionInstrumentId(
return ResponseEntity.ok().build();
}

@Operation(summary = "Update a Kraftwerk execution schedule V2")
@PutMapping(path = "/contexts/{collectionInstrumentId}/schedules/v2/{scheduleUuid}")
@PreAuthorize("hasRole('USER_KRAFTWERK')")
public ResponseEntity<Object> updateScheduleV2(
@PathVariable("collectionInstrumentId") String collectionInstrumentId,
@PathVariable("scheduleUuid") String scheduleUuid,
@Valid @RequestBody ScheduleRequestDto request
) {
try {
TrustParameters trustParameters = null;
if (request.isUseEncryption()) {
trustParameters = new TrustParameters(
fileUtils.getKraftwerkOutFolder(collectionInstrumentId),
"",
request.getEncryptionVaultPath(),
request.isUseSignature()
);
}

KraftwerkExecutionScheduleInput scheduleInput = KraftwerkExecutionScheduleInput.builder()
.collectionInstrumentId(collectionInstrumentId)
.scheduleUuid(scheduleUuid)
.exportType(request.getExportType())
.frequency(request.getFrequency())
.startDate(request.getScheduleBeginDate())
.endDate(request.getScheduleEndDate())
.mode(request.getMode())
.destinationType(request.getDestinationType())
.addStates(request.isAddStates())
.destinationFolder(request.getDestinationFolder())
.trustParameters(trustParameters)
.batchSize(request.getBatchSize())
.build();

dataProcessingContextApiPort.updateKraftwerkExecutionSchedule(scheduleInput);

} catch (GenesisException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatusCode.valueOf(e.getStatus()));
}

return ResponseEntity.ok().build();
}

@Deprecated(forRemoval = true)
@Operation(summary = "Fetch all schedules")
@GetMapping(path = "/context/schedules")
Expand All @@ -215,6 +302,29 @@ public ResponseEntity<Object> getAllSchedulesV2() {
return ResponseEntity.ok(surveyScheduleDocumentModels);
}

@Operation(summary = "Fetch all schedules V2")
@GetMapping(path = "/contexts/schedules/v2")
@PreAuthorize("hasAnyRole('SCHEDULER','READER')")
public ResponseEntity<Object> getAllSchedulesV3() {
log.debug("Got GET all schedules V2 request");

List<ScheduleV2Dto> schedules = dataProcessingContextApiPort.getAllSchedulesV2();

log.info("Returning {} V2 schedule documents...", schedules.size());
return ResponseEntity.ok(schedules);
}

@Operation(summary = "Fetch V2 schedules by collection instrument id")
@GetMapping(path = "/contexts/{collectionInstrumentId}/schedules/v2")
@PreAuthorize("hasAnyRole('SCHEDULER','READER')")
public ResponseEntity<Object> getSchedulesV2ByCollectionInstrumentId(
@PathVariable("collectionInstrumentId") String collectionInstrumentId
) {
List<ScheduleV2Dto> schedules =
dataProcessingContextApiPort.getSchedulesV2ByCollectionInstrumentId(collectionInstrumentId);

return ResponseEntity.ok(schedules);
}

@Deprecated(forRemoval = true)
@Operation(summary = "Set last execution date of a partition with new date or nothing")
Expand Down Expand Up @@ -280,6 +390,37 @@ public ResponseEntity<Object> deleteSchedulesByCollectionInstrumentId(
return ResponseEntity.ok().build();
}

@Operation(summary = "Delete all V2 Kraftwerk execution schedules of a collection instrument id")
@DeleteMapping(path = "/contexts/{collectionInstrumentId}/schedules/v2")
@PreAuthorize("hasRole('USER_KRAFTWERK')")
public ResponseEntity<Object> deleteSchedulesV2ByCollectionInstrumentId(
@PathVariable("collectionInstrumentId") String collectionInstrumentId
){
try {
dataProcessingContextApiPort.deleteSchedulesV2ByCollectionInstrumentId(collectionInstrumentId);
} catch (GenesisException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatusCode.valueOf(e.getStatus()));
}
log.info("All V2 schedules deleted for collection instrument {}", collectionInstrumentId);
return ResponseEntity.ok().build();
}

@Operation(summary = "Delete a V2 Kraftwerk execution schedule")
@DeleteMapping(path = "/contexts/{collectionInstrumentId}/schedules/v2/{scheduleUuid}")
@PreAuthorize("hasRole('USER_KRAFTWERK')")
public ResponseEntity<Object> deleteScheduleV2(
@PathVariable(value = "collectionInstrumentId") String collectionInstrumentId,
@PathVariable(value = "scheduleUuid") String scheduleUuid
){
try {
dataProcessingContextApiPort.deleteScheduleV2(collectionInstrumentId, scheduleUuid);
} catch (GenesisException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatusCode.valueOf(e.getStatus()));
}
log.info("V2 schedule {} deleted for collection instrument {}", scheduleUuid, collectionInstrumentId);
return ResponseEntity.ok().build();
}

@Operation(summary = "Delete expired schedules")
@DeleteMapping(path = "/context/schedules/expired-schedules")
@PreAuthorize("hasRole('SCHEDULER')")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package fr.insee.genesis.controller.utils;

public enum ExportType {
JSON,
CSV_PARQUET
}
Loading
Loading