Merge branch 'RED-9142' into 'master'
RED-9142 - Basic component management Closes RED-9142 See merge request redactmanager/persistence-service!515
This commit is contained in:
commit
fb133a4770
@ -13,8 +13,10 @@ import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@ -33,14 +35,16 @@ import com.iqser.red.persistence.service.v1.external.api.impl.controller.Dossier
|
||||
import com.iqser.red.persistence.service.v1.external.api.impl.controller.FileAttributesController;
|
||||
import com.iqser.red.persistence.service.v2.external.api.impl.mapper.ComponentMappingMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMappingDownloadModel;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentDefinitionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentMappingService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.RulesValidationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierAttributeConfigPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.RulesValidationMapper;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
|
||||
@ -48,6 +52,9 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCatego
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinition;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionUpdateRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
|
||||
@ -88,6 +95,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
DossierTemplatePersistenceService dossierTemplatePersistenceService;
|
||||
DossierStatusPersistenceService dossierStatusPersistenceService;
|
||||
DossierAttributeConfigPersistenceService dossierAttributeConfigPersistenceService;
|
||||
ComponentDefinitionService componentDefinitionService;
|
||||
|
||||
|
||||
public List<DossierTemplateModel> getAllDossierTemplates() {
|
||||
@ -181,100 +189,6 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER_STATUS + "')")
|
||||
public DossierStatusDefinitionList getDossierStatusDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
|
||||
return new DossierStatusDefinitionList(dossierStatusPersistenceService.getAllDossierStatusForTemplate(dossierTemplateId)
|
||||
.stream()
|
||||
.map(dossierStatusInfo -> DossierStatusDefinition.builder()
|
||||
.id(dossierStatusInfo.getId())
|
||||
.name(dossierStatusInfo.getName())
|
||||
.description(dossierStatusInfo.getDescription())
|
||||
.rank(dossierStatusInfo.getRank())
|
||||
.color(dossierStatusInfo.getColor())
|
||||
.dossierCount(dossierStatusInfo.getDossierCount() != null ? dossierStatusInfo.getDossierCount() : 0)
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER_ATTRIBUTES_CONFIG + "')")
|
||||
public DossierAttributeDefinitionList getDossierAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
|
||||
return new DossierAttributeDefinitionList(dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId)
|
||||
.stream()
|
||||
.map(config -> DossierAttributeDefinition.builder()
|
||||
|
||||
.id(config.getId())
|
||||
.name(config.getLabel())
|
||||
.type(config.getType())
|
||||
.reportingPlaceholder(config.getPlaceholder())
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private ResponseEntity<DroolsValidationResponse> uploadRules(String dossierTemplateId, RuleFileType ruleFileType, MultipartFile file, boolean dryRun) {
|
||||
|
||||
var rulesUploadRequest = RulesUploadRequest.builder()
|
||||
.rules(new String(file.getBytes(), StandardCharsets.UTF_8))
|
||||
.dossierTemplateId(dossierTemplateId)
|
||||
.ruleFileType(ruleFileType)
|
||||
.build();
|
||||
|
||||
DroolsValidationResponse rulesValidationResponse = new DroolsValidationResponse();
|
||||
|
||||
try {
|
||||
var droolsValidation = rulesValidationService.validateRules(rulesUploadRequest.getRuleFileType(), rulesUploadRequest.getRules());
|
||||
rulesValidationResponse = RulesValidationMapper.createFromDroolsValidation(droolsValidation);
|
||||
if (!droolsValidation.isCompiled()) {
|
||||
|
||||
return new ResponseEntity<>(rulesValidationResponse, !dryRun ? HttpStatus.UNPROCESSABLE_ENTITY : HttpStatus.OK);
|
||||
}
|
||||
} catch (FeignException e) {
|
||||
if (e.status() == HttpStatus.BAD_REQUEST.value()) {
|
||||
throw new BadRequestException("The provided rule string is not a valid drools rule file!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!dryRun) {
|
||||
rulesPersistenceService.setRules(rulesUploadRequest.getRules(), rulesUploadRequest.getDossierTemplateId(), rulesUploadRequest.getRuleFileType());
|
||||
}
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(rulesUploadRequest.getDossierTemplateId())
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message(String.format("%s rules have been %s", rulesUploadRequest.getRuleFileType(), dryRun ? "validated" : "updated"))
|
||||
.build());
|
||||
|
||||
return new ResponseEntity<>(rulesValidationResponse, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
private ResponseEntity<?> downloadRules(String dossierTemplateId, RuleFileType ruleFileType) {
|
||||
|
||||
RuleSetEntity ruleEntity = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
|
||||
|
||||
var data = ruleEntity.getValue().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
httpHeaders.add("Content-Disposition",
|
||||
"attachment" + "; filename*=utf-8''" + StringEncodingUtils.urlEncode(ruleFileType.name().toLowerCase(Locale.ROOT) + RULES_DOWNLOAD_FILE_NAME_SUFFIX));
|
||||
|
||||
InputStream is = new ByteArrayInputStream(data);
|
||||
|
||||
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
|
||||
public ComponentMappingSummary getComponentMappingSummaries(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
@ -371,6 +285,145 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER_STATUS + "')")
|
||||
public DossierStatusDefinitionList getDossierStatusDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
|
||||
return new DossierStatusDefinitionList(dossierStatusPersistenceService.getAllDossierStatusForTemplate(dossierTemplateId)
|
||||
.stream()
|
||||
.map(dossierStatusInfo -> DossierStatusDefinition.builder()
|
||||
.id(dossierStatusInfo.getId())
|
||||
.name(dossierStatusInfo.getName())
|
||||
.description(dossierStatusInfo.getDescription())
|
||||
.rank(dossierStatusInfo.getRank())
|
||||
.color(dossierStatusInfo.getColor())
|
||||
.dossierCount(dossierStatusInfo.getDossierCount() != null ? dossierStatusInfo.getDossierCount() : 0)
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DOSSIER_ATTRIBUTES_CONFIG + "')")
|
||||
public DossierAttributeDefinitionList getDossierAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
|
||||
|
||||
getDossierTemplate(dossierTemplateId);
|
||||
|
||||
return new DossierAttributeDefinitionList(dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId)
|
||||
.stream()
|
||||
.map(config -> DossierAttributeDefinition.builder()
|
||||
|
||||
.id(config.getId())
|
||||
.name(config.getLabel())
|
||||
.type(config.getType())
|
||||
.reportingPlaceholder(config.getPlaceholder())
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> createComponents(String dossierTemplateId, List<ComponentDefinitionAddRequest> componentDefinitionAddRequests) {
|
||||
|
||||
if (componentDefinitionAddRequests.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ComponentDefinition> componentDefinitions = componentDefinitionService.createComponents(componentDefinitionAddRequests);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components added.")
|
||||
.details(Map.of("Number of added components", componentDefinitions.size()))
|
||||
.build());
|
||||
return componentDefinitions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> getComponents(String dossierTemplateId, boolean includeSoftDeleted) {
|
||||
|
||||
return componentDefinitionService.getComponentsByDossierTemplateId(dossierTemplateId, includeSoftDeleted);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ComponentDefinition getComponent(String dossierTemplateId, String componentId) {
|
||||
|
||||
return componentDefinitionService.getComponentByDossierTemplateIdAndComponentId(dossierTemplateId, componentId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> updateComponents(String dossierTemplateId, List<ComponentDefinitionUpdateRequest> componentDefinitionUpdateRequests) {
|
||||
|
||||
if (componentDefinitionUpdateRequests.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ComponentDefinition> componentDefinitions = componentDefinitionService.updateComponents(dossierTemplateId, componentDefinitionUpdateRequests);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components updated.")
|
||||
.details(Map.of("Number of updated components", componentDefinitions.size()))
|
||||
.build());
|
||||
return componentDefinitions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void deleteComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
List<ComponentDefinitionEntity> components = componentDefinitionService.deleteComponents(dossierTemplateId, componentIds);
|
||||
if (!components.isEmpty()) {
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components deleted.")
|
||||
.details(Map.of("Number of deleted components", components.size()))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> restoreComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
List<ComponentDefinition> components = componentDefinitionService.restoreComponents(dossierTemplateId, componentIds);
|
||||
if (!components.isEmpty()) {
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components restored.")
|
||||
.details(Map.of("Number of restored components", components.size()))
|
||||
.build());
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ComponentDefinition> reorderComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
List<ComponentDefinition> orderedComponents = componentDefinitionService.reorderComponents(dossierTemplateId, componentIds);
|
||||
if (!orderedComponents.isEmpty()) {
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(dossierTemplateId)
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message("Components reordered.")
|
||||
.details(Map.of("Number of reordered components", orderedComponents.size()))
|
||||
.build());
|
||||
}
|
||||
return orderedComponents;
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private static Path saveToFile(MultipartFile file) {
|
||||
|
||||
@ -382,4 +435,61 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
return mappingFile;
|
||||
}
|
||||
|
||||
|
||||
private ResponseEntity<?> downloadRules(String dossierTemplateId, RuleFileType ruleFileType) {
|
||||
|
||||
RuleSetEntity ruleEntity = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
|
||||
|
||||
var data = ruleEntity.getValue().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
httpHeaders.add("Content-Disposition",
|
||||
"attachment" + "; filename*=utf-8''" + StringEncodingUtils.urlEncode(ruleFileType.name().toLowerCase(Locale.ROOT) + RULES_DOWNLOAD_FILE_NAME_SUFFIX));
|
||||
|
||||
InputStream is = new ByteArrayInputStream(data);
|
||||
|
||||
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private ResponseEntity<DroolsValidationResponse> uploadRules(String dossierTemplateId, RuleFileType ruleFileType, MultipartFile file, boolean dryRun) {
|
||||
|
||||
var rulesUploadRequest = RulesUploadRequest.builder()
|
||||
.rules(new String(file.getBytes(), StandardCharsets.UTF_8))
|
||||
.dossierTemplateId(dossierTemplateId)
|
||||
.ruleFileType(ruleFileType)
|
||||
.build();
|
||||
|
||||
DroolsValidationResponse rulesValidationResponse = new DroolsValidationResponse();
|
||||
|
||||
try {
|
||||
var droolsValidation = rulesValidationService.validateRules(rulesUploadRequest.getRuleFileType(), rulesUploadRequest.getRules());
|
||||
rulesValidationResponse = RulesValidationMapper.createFromDroolsValidation(droolsValidation);
|
||||
if (!droolsValidation.isCompiled()) {
|
||||
|
||||
return new ResponseEntity<>(rulesValidationResponse, !dryRun ? HttpStatus.UNPROCESSABLE_ENTITY : HttpStatus.OK);
|
||||
}
|
||||
} catch (FeignException e) {
|
||||
if (e.status() == HttpStatus.BAD_REQUEST.value()) {
|
||||
throw new BadRequestException("The provided rule string is not a valid drools rule file!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!dryRun) {
|
||||
rulesPersistenceService.setRules(rulesUploadRequest.getRules(), rulesUploadRequest.getDossierTemplateId(), rulesUploadRequest.getRuleFileType());
|
||||
}
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(rulesUploadRequest.getDossierTemplateId())
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message(String.format("%s rules have been %s", rulesUploadRequest.getRuleFileType(), dryRun ? "validated" : "updated"))
|
||||
.build());
|
||||
|
||||
return new ResponseEntity<>(rulesValidationResponse, HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package com.iqser.red.persistence.service.v2.external.api.impl.controller;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.quartz.JobDataMap;
|
||||
@ -10,6 +11,7 @@ import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
@ -167,6 +169,23 @@ public class ExternalControllerAdviceV2 {
|
||||
}
|
||||
|
||||
|
||||
@Hidden
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(value = DataIntegrityViolationException.class)
|
||||
public ErrorMessage handleDataIntegrityViolationException(DataIntegrityViolationException exception) {
|
||||
|
||||
String message = Objects.requireNonNull(exception.getRootCause()).getMessage();
|
||||
if (message.contains("uq_component_definition_technical_name_template")) {
|
||||
message = "A component with the same technical name already exists in the given dossier template.";
|
||||
} else {
|
||||
message = "Database error occurred.";
|
||||
}
|
||||
|
||||
return new ErrorMessage(OffsetDateTime.now(), message);
|
||||
}
|
||||
|
||||
|
||||
@Order(10000)
|
||||
public static class BinderControllerAdvice {
|
||||
|
||||
|
||||
@ -1,18 +1,6 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.resource;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierStatusDefinitionList;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -22,13 +10,30 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinition;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionUpdateRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierStatusDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.FileAttributeDefinitionList;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "429", description = "Too many requests.")})
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@ -47,7 +52,6 @@ public interface DossierTemplateResource {
|
||||
String DOSSIER_TEMPLATE_ID_PARAM = "dossierTemplateId";
|
||||
String DOSSIER_TEMPLATE_ID_PATH_VARIABLE = "/{" + DOSSIER_TEMPLATE_ID_PARAM + "}";
|
||||
|
||||
|
||||
String COMPONENT_MAPPING_ID_PARAM = "componentMappingId";
|
||||
String COMPONENT_MAPPING_ID_PATH_VARIABLE = "/{" + COMPONENT_MAPPING_ID_PARAM + "}";
|
||||
|
||||
@ -56,6 +60,15 @@ public interface DossierTemplateResource {
|
||||
String DELIMITER_PARAM = "delimiter";
|
||||
String MAPPING_NAME_PARAM = "name";
|
||||
|
||||
String INCLUDE_SOFT_DELETED = "includeSoftDeleted";
|
||||
String COMPONENT_ID_PARAM = "componentId";
|
||||
String COMPONENT_ID_PATH = "/{" + COMPONENT_ID_PARAM + "}";
|
||||
String COMPONENT_IDS = "componentIds";
|
||||
String COMPONENT_PATH = "/component-definitions";
|
||||
String REORDER_PATH = "/reorder";
|
||||
String RESTORE_PATH = "/restore";
|
||||
|
||||
|
||||
@GetMapping(value = PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Lists all existing DossierTemplates.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "List of all existing DossierTemplates.")})
|
||||
@ -156,6 +169,7 @@ public interface DossierTemplateResource {
|
||||
@DeleteMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH + COMPONENT_MAPPING_ID_PATH_VARIABLE)
|
||||
ResponseEntity<?> deleteMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId);
|
||||
|
||||
|
||||
@Operation(summary = "Returns the list of all existing dossier status definitions.", description = "None")
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_STATUS_DEFINITIONS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully returned the dossier status definitions for the specified dossier template."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
@ -167,4 +181,63 @@ public interface DossierTemplateResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully returned the dossier attribute definitions for the specified dossier template."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
|
||||
DossierAttributeDefinitionList getDossierAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@Operation(summary = "Create new components", description = "Create new components for a given dossier template.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Created")})
|
||||
@PostMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> createComponents(@Valid @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@RequestBody List<ComponentDefinitionAddRequest> componentDefinitionUpdateRequests);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Get all components", description = "Get all components for a given dossier template.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> getComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Parameter(name = INCLUDE_SOFT_DELETED, description = "Include files which are soft deleted. Default is false.") @RequestParam(value = INCLUDE_SOFT_DELETED, defaultValue = "false") boolean includeSoftDeleted);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Get a component by ID", description = "Get specific details for a component by ID.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified component is not found.")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH + COMPONENT_ID_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
ComponentDefinition getComponent(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_ID_PARAM) String componentId);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Update components", description = "Update existing components.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@PutMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> updateComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
|
||||
@Valid @RequestBody List<ComponentDefinitionUpdateRequest> componentDefinitionUpdateRequests);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Delete components", description = "Delete existing components by their IDs.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "No Content")})
|
||||
@DeleteMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH)
|
||||
void deleteComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @RequestParam(name = COMPONENT_IDS) List<String> componentIds);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Restore components", description = "Restore previously soft deleted components based on their IDs.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@PutMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH + RESTORE_PATH)
|
||||
List<ComponentDefinition> restoreComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @RequestParam(name = COMPONENT_IDS) List<String> componentIds);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@Operation(summary = "Reorder components", description = "Reorder components based on their rank.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_PATH + REORDER_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<ComponentDefinition> reorderComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @RequestParam(name = COMPONENT_IDS) List<String> componentIds);
|
||||
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@ paths:
|
||||
tags:
|
||||
- 1. Dossier Templates
|
||||
description: |
|
||||
Use this endpoint to retrieves a collection of file attribute definitions associated with a specific dossier template. Each file
|
||||
Use this endpoint to retrieve a collection of file attribute definitions associated with a specific dossier template. Each file
|
||||
attribute definition includes details such as attribute type, name, and other relevant metadata. This endpoint
|
||||
is useful for clients needing to understand what attributes are expected or allowed for files associated with
|
||||
a specific dossier template.
|
||||
@ -587,6 +587,269 @@ paths:
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
/dossier-templates/{dossierTemplateId}/component-definitions:
|
||||
post:
|
||||
operationId: createComponents
|
||||
tags:
|
||||
- Component Definitions
|
||||
summary: Create new component definitions
|
||||
description: |
|
||||
Create new component definitions for a given dossier template. The component will have a technical name which is automatically converted to snake case
|
||||
that can't be updated after the creation. The rank is used to determine the order in which the components are displayed. The component's rank will
|
||||
automatically be appended at the end based on the current number of components of this dossier template.
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinitionAddRequest'
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinition'
|
||||
"400":
|
||||
$ref: '#/components/responses/400'
|
||||
"401":
|
||||
$ref: '#/components/responses/401'
|
||||
"403":
|
||||
$ref: '#/components/responses/403'
|
||||
"404":
|
||||
$ref: '#/components/responses/404-dossier-template'
|
||||
"429":
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
get:
|
||||
operationId: getComponents
|
||||
tags:
|
||||
- Component Definitions
|
||||
summary: Get all component definitions
|
||||
description: |
|
||||
Get all the component definitions in a given dossier template. `includeSoftDeleted` is false by default and will not return soft deleted components. If set to true,
|
||||
this endpoint will also return components that have been soft deleted.
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
- name: includeSoftDeleted
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
default: false
|
||||
type: boolean
|
||||
description: |
|
||||
A toggle to include or exclude soft-deleted components: If `false` (default), soft-deleted components
|
||||
are not included. If `true`, they are included.
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinition'
|
||||
"400":
|
||||
$ref: '#/components/responses/400'
|
||||
"401":
|
||||
$ref: '#/components/responses/401'
|
||||
"403":
|
||||
$ref: '#/components/responses/403'
|
||||
"404":
|
||||
$ref: '#/components/responses/404-component-definition'
|
||||
"429":
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
put:
|
||||
operationId: updateComponents
|
||||
tags:
|
||||
- Component Definitions
|
||||
summary: Update existing component definitions
|
||||
description: |
|
||||
Update specific existing component definitions. The rank and technical name cannot be updated via this endpoint. The technical name cannot be updated
|
||||
at all after creation. To update the rank, use the [reorder endpoint](#/paths/~1dossier-templates~1{dossierTemplateId}~1component-definitions~1reorder/post).
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinitionUpdateRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinition'
|
||||
"400":
|
||||
$ref: '#/components/responses/400'
|
||||
"401":
|
||||
$ref: '#/components/responses/401'
|
||||
"403":
|
||||
$ref: '#/components/responses/403'
|
||||
"404":
|
||||
$ref: '#/components/responses/404-component-definition'
|
||||
"429":
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
delete:
|
||||
operationId: deleteComponents
|
||||
tags:
|
||||
- Component Definitions
|
||||
summary: Soft delete component definitions
|
||||
description: |
|
||||
Soft delete existing component definitions by their IDs. Soft deletion is done by setting the `softDeletedTime` value to the current time of the request. If a component
|
||||
does not have `softDeletedTime` set, it means the component is not soft deleted.
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
- name: componentIds
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: The IDs of the component definitions to soft delete
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"400":
|
||||
$ref: '#/components/responses/400'
|
||||
"401":
|
||||
$ref: '#/components/responses/401'
|
||||
"403":
|
||||
$ref: '#/components/responses/403'
|
||||
"404":
|
||||
$ref: '#/components/responses/404-component-definition'
|
||||
"429":
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
/dossier-templates/{dossierTemplateId}/component-definitions/reorder:
|
||||
post:
|
||||
operationId: reorderComponents
|
||||
tags:
|
||||
- Component Definitions
|
||||
summary: Reorder component definitions
|
||||
description: Reorder the component definitions based on the provided list. Their ranks will be updated based on the order provided in the request, starting from rank 1.
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
- name: componentIds
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: The IDs of the component definitions in the order in which they will be reordered.
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinition'
|
||||
"400":
|
||||
$ref: '#/components/responses/400'
|
||||
"401":
|
||||
$ref: '#/components/responses/401'
|
||||
"403":
|
||||
$ref: '#/components/responses/403'
|
||||
"404":
|
||||
$ref: '#/components/responses/404-component-definition'
|
||||
"429":
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
/api/dossier-templates/{dossierTemplateId}/component-definitions/{componentId}:
|
||||
get:
|
||||
operationId: getComponent
|
||||
tags:
|
||||
- Component Definitions
|
||||
summary: Get specific component by ID
|
||||
description: Get details about a specific component based on its ID for a given dossier template.
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
- $ref: '#/components/parameters/componentId'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinition'
|
||||
"400":
|
||||
$ref: '#/components/responses/400'
|
||||
"401":
|
||||
$ref: '#/components/responses/401'
|
||||
"403":
|
||||
$ref: '#/components/responses/403'
|
||||
"404":
|
||||
$ref: '#/components/responses/404-component-definition'
|
||||
"429":
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
/api/dossier-templates/{dossierTemplateId}/component-definitions/restore:
|
||||
post:
|
||||
operationId: restoreComponents
|
||||
tags:
|
||||
- Component Definitions
|
||||
summary: Restore soft deleted components by ID
|
||||
description: |
|
||||
Restore a previously soft-deleted component. The restored component will be placed at the end of the rank order.
|
||||
For example, if there are 5 components ranked 1, 2, 3, 4, and 5, and the third component is soft-deleted, the ranks will be updated to 1, 2, 4, and 5.
|
||||
If the soft-deleted component is then restored, it will be appended to the end, resulting in ranks 1, 2, 4, 5, and 6.
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
- name: componentIds
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: The IDs of the component definitions to restore.
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ComponentDefinition'
|
||||
"400":
|
||||
$ref: '#/components/responses/400'
|
||||
"401":
|
||||
$ref: '#/components/responses/401'
|
||||
"403":
|
||||
$ref: '#/components/responses/403'
|
||||
"404":
|
||||
$ref: '#/components/responses/404-component-definition'
|
||||
"429":
|
||||
$ref: '#/components/responses/429'
|
||||
"500":
|
||||
$ref: '#/components/responses/500'
|
||||
/api/dossier-templates/{dossierTemplateId}/dossiers:
|
||||
get:
|
||||
operationId: getDossiers
|
||||
@ -1602,6 +1865,13 @@ components:
|
||||
$ref: '#/components/schemas/ErrorMessage'
|
||||
description: |
|
||||
Dossier template or component mapping not found. This happens if the requested dossier template or component mapping does not exist.
|
||||
"404-component-definition":
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorMessage'
|
||||
description: |
|
||||
Dossier template or component definition not found. This happens if the requested dossier template or component definition does not exist.
|
||||
"404-dossier":
|
||||
content:
|
||||
'application/json':
|
||||
@ -1682,6 +1952,15 @@ components:
|
||||
style: simple
|
||||
explode: false
|
||||
description: The identifier of a component mapping
|
||||
componentId:
|
||||
name: componentId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
style: simple
|
||||
explode: false
|
||||
description: The identifier of a component definition.
|
||||
dryRun:
|
||||
name: dryRun
|
||||
in: query
|
||||
@ -3062,6 +3341,98 @@ components:
|
||||
required:
|
||||
- dossierTemplateId
|
||||
- componentMappingList
|
||||
ComponentDefinition:
|
||||
description: The ComponentDefinition object represents a component definition within a dossier template.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
description: A unique identifier for the component definition.
|
||||
type: string
|
||||
format: uuid
|
||||
dossierTemplateId:
|
||||
description: The ID of the dossier template to which this component belongs.
|
||||
type: string
|
||||
technicalName:
|
||||
description: The technical name of the component.
|
||||
type: string
|
||||
displayName:
|
||||
description: The display name of the component.
|
||||
type: string
|
||||
description:
|
||||
description: A brief description of the component.
|
||||
type: string
|
||||
rank:
|
||||
description: The rank of the component within the template, used for ordering.
|
||||
type: integer
|
||||
softDeleteTime:
|
||||
description: The timestamp indicating when the component was soft deleted. If null, the component is not soft deleted.
|
||||
type: string
|
||||
format: date-time
|
||||
required:
|
||||
- id
|
||||
- dossierTemplateId
|
||||
- technicalName
|
||||
- displayName
|
||||
- rank
|
||||
example:
|
||||
id: 300b9406-59c0-4473-9c8a-1f5f0b4a88c3
|
||||
dossierTemplateId: 8cd4b482-fb49-4315-9b51-789b4ae46c57
|
||||
technicalName: study_conclusion
|
||||
displayName: Study Conclusion
|
||||
description: The drawn conclusion from the performed study
|
||||
rank: 1
|
||||
softDeleteTime: null
|
||||
ComponentDefinitionAddRequest:
|
||||
description: |
|
||||
The ComponentDefinitionAddRequest object represents a request to create a component definition within a dossier template.
|
||||
The rank will be automatically generated and does not need to be provided at creation.
|
||||
example:
|
||||
dossierTemplateId: 8cd4b482-fb49-4315-9b51-789b4ae46c57
|
||||
technicalName: study_conclusion
|
||||
displayName: Study conclusion
|
||||
description: The conclusion of the study
|
||||
type: object
|
||||
properties:
|
||||
dossierTemplateId:
|
||||
description: The ID of the dossier template to which this component belongs.
|
||||
type: string
|
||||
technicalName:
|
||||
description: The technical name of the component.
|
||||
type: string
|
||||
displayName:
|
||||
description: The display name of the component.
|
||||
type: string
|
||||
description:
|
||||
description: A brief description of the component.
|
||||
type: string
|
||||
required:
|
||||
- dossierTemplateId
|
||||
- technicalName
|
||||
- displayName
|
||||
ComponentDefinitionUpdateRequest:
|
||||
description: |
|
||||
The ComponentDefinitionUpdateRequest object represents a request to update a component definition within a dossier template.
|
||||
Only the display name and description can be updated.
|
||||
example:
|
||||
id: aa7107f7-cc5b-490f-b91c-35c9d86749f7
|
||||
displayName: Study conclusion
|
||||
description: The conclusion of the study
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
description: The unique identifier for the component to be updated.
|
||||
type: string
|
||||
format: uuid
|
||||
displayName:
|
||||
description: The new display name of the component.
|
||||
type: string
|
||||
description:
|
||||
description: The new description of the component.
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- displayName
|
||||
- description
|
||||
DossierTemplate:
|
||||
description: |
|
||||
The `DossierTemplate` object represents the blueprint for creating and
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.entity.dossier;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Table(name = "component_definition", uniqueConstraints = {@UniqueConstraint(columnNames = {"technical_name", "dossier_template_id"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
public class ComponentDefinitionEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, updatable = false)
|
||||
private String id;
|
||||
|
||||
@Column(name = "dossier_template_id", nullable = false)
|
||||
private String dossierTemplateId;
|
||||
|
||||
@Column(name = "technical_name", nullable = false)
|
||||
private String technicalName;
|
||||
|
||||
@Column(name = "display_name", nullable = false)
|
||||
private String displayName;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Column(name = "rank")
|
||||
private Integer rank;
|
||||
|
||||
@Column(name = "soft_delete_time")
|
||||
private OffsetDateTime softDeleteTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.ADD_UPDATE_DICTIONARY_TYPE;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.DELETE_DICTIONARY_TYPE;
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_DICTIONARY_TYPES;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ComponentDefinitionPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinition;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionUpdateRequest;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class ComponentDefinitionService {
|
||||
|
||||
ComponentDefinitionPersistenceService componentDefinitionPersistenceService;
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + ADD_UPDATE_DICTIONARY_TYPE + "')")
|
||||
@Transactional
|
||||
public List<ComponentDefinition> createComponents(List<ComponentDefinitionAddRequest> componentDefinitionAddRequests) {
|
||||
|
||||
validateComponentRequest(componentDefinitionAddRequests);
|
||||
List<ComponentDefinitionEntity> componentEntities = new ArrayList<>();
|
||||
componentDefinitionAddRequests.forEach(componentDefinitionAddRequest -> componentEntities.add(componentDefinitionPersistenceService.insert(componentDefinitionAddRequest)));
|
||||
return componentEntities.stream()
|
||||
.map(componentDefinitionEntity -> MagicConverter.convert(componentDefinitionEntity, ComponentDefinition.class))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
private void validateComponentRequest(List<ComponentDefinitionAddRequest> componentDefinitionAddRequests) {
|
||||
|
||||
String firstDossierTemplateId = componentDefinitionAddRequests.get(0).getDossierTemplateId();
|
||||
boolean allMatch = componentDefinitionAddRequests.stream()
|
||||
.allMatch(request -> request.getDossierTemplateId().equals(firstDossierTemplateId));
|
||||
if (!allMatch) {
|
||||
throw new BadRequestException("All components must have the same dossierTemplateId.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DICTIONARY_TYPES + "')")
|
||||
public ComponentDefinition getComponentByDossierTemplateIdAndComponentId(String dossierTemplateId, String componentId) {
|
||||
|
||||
return MagicConverter.convert(componentDefinitionPersistenceService.findComponentByDossierTemplateIdAndComponentId(dossierTemplateId, componentId),
|
||||
ComponentDefinition.class);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + READ_DICTIONARY_TYPES + "')")
|
||||
public List<ComponentDefinition> getComponentsByDossierTemplateId(String dossierTemplateId, boolean includeSoftDeleted) {
|
||||
|
||||
List<ComponentDefinitionEntity> entities;
|
||||
|
||||
if (includeSoftDeleted) {
|
||||
entities = componentDefinitionPersistenceService.findComponentsByDossierTemplateId(dossierTemplateId);
|
||||
} else {
|
||||
entities = componentDefinitionPersistenceService.findComponentsByDossierTemplateIdExcludeSoftDeleted(dossierTemplateId);
|
||||
}
|
||||
|
||||
return entities.stream()
|
||||
.map(entity -> MagicConverter.convert(entity, ComponentDefinition.class))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + ADD_UPDATE_DICTIONARY_TYPE + "')")
|
||||
@Transactional
|
||||
public List<ComponentDefinition> updateComponents(String dossierTemplateId, List<ComponentDefinitionUpdateRequest> componentDefinitionUpdateRequests) {
|
||||
|
||||
List<ComponentDefinitionEntity> componentEntities = new ArrayList<>();
|
||||
componentDefinitionUpdateRequests.forEach(componentDefinitionUpdateRequest -> {
|
||||
ComponentDefinitionEntity componentDefinitionEntity = componentDefinitionPersistenceService.findComponent(dossierTemplateId, componentDefinitionUpdateRequest.getId());
|
||||
componentDefinitionEntity.setDescription(componentDefinitionUpdateRequest.getDescription());
|
||||
componentDefinitionEntity.setDisplayName(componentDefinitionUpdateRequest.getDisplayName());
|
||||
componentEntities.add(componentDefinitionPersistenceService.update(componentDefinitionEntity));
|
||||
});
|
||||
return componentEntities.stream()
|
||||
.map(componentDefinitionEntity -> MagicConverter.convert(componentDefinitionEntity, ComponentDefinition.class))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DELETE_DICTIONARY_TYPE + "')")
|
||||
@Transactional
|
||||
public List<ComponentDefinitionEntity> deleteComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
OffsetDateTime now = OffsetDateTime.now();
|
||||
return componentDefinitionPersistenceService.softDeleteComponents(dossierTemplateId, componentIds, now);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + ADD_UPDATE_DICTIONARY_TYPE + "')")
|
||||
@Transactional
|
||||
public List<ComponentDefinition> restoreComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
|
||||
List<ComponentDefinitionEntity> componentDefinitionEntities = componentDefinitionPersistenceService.restoreComponents(dossierTemplateId, componentIds);
|
||||
int rank = componentDefinitionPersistenceService.countByDossierTemplateId(dossierTemplateId);
|
||||
for (ComponentDefinitionEntity componentDefinitionEntity : componentDefinitionEntities) {
|
||||
componentDefinitionEntity.setRank(++rank);
|
||||
componentDefinitionPersistenceService.update(componentDefinitionEntity);
|
||||
}
|
||||
return componentDefinitionEntities.stream()
|
||||
.map(componentDefinitionEntity -> MagicConverter.convert(componentDefinitionEntity, ComponentDefinition.class))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + ADD_UPDATE_DICTIONARY_TYPE + "')")
|
||||
@Transactional
|
||||
public List<ComponentDefinition> reorderComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
List<ComponentDefinition> orderedComponents = new ArrayList<>();
|
||||
List<ComponentDefinitionEntity> existingComponents = componentDefinitionPersistenceService.findComponentsByDossierTemplateIdExcludeSoftDeleted(dossierTemplateId);
|
||||
|
||||
Map<String, ComponentDefinitionEntity> componentMap = existingComponents.stream()
|
||||
.collect(Collectors.toMap(ComponentDefinitionEntity::getId, component -> component));
|
||||
|
||||
int rank = 1;
|
||||
for (String componentId : componentIds) {
|
||||
ComponentDefinitionEntity component = componentMap.get(componentId);
|
||||
if (component != null) {
|
||||
component.setRank(rank++);
|
||||
componentDefinitionPersistenceService.update(component);
|
||||
orderedComponents.add(MagicConverter.convert(component, ComponentDefinition.class));
|
||||
}
|
||||
}
|
||||
|
||||
return orderedComponents;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,13 +1,17 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ComponentDefinitionPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry;
|
||||
@ -27,55 +31,20 @@ public class ComponentLogService {
|
||||
private final FileManagementStorageService fileManagementStorageService;
|
||||
private final ComponentLogMongoService componentLogMongoService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
|
||||
// TODO: make this DB changeable!
|
||||
private static final List<String> ORDER = List.of("Study_Title",
|
||||
"Performing_Laboratory",
|
||||
"Report_Number",
|
||||
"GLP_Study",
|
||||
"Test_Guidelines_1",
|
||||
"Test_Guidelines_2",
|
||||
"Experimental_Starting_Date",
|
||||
"Experimental_Completion_Date",
|
||||
"Certificate_of_Analysis_Batch_Identification",
|
||||
"Species",
|
||||
"Strain",
|
||||
"Was_the_definitive_study_conducted_with_positive_control",
|
||||
"Study_Design_Main_Study",
|
||||
"Results_Main_Study",
|
||||
"Preliminary_Test_Results",
|
||||
"What_was_the_approach_used",
|
||||
"Sex",
|
||||
"Number_of_Animals",
|
||||
"Study_Design",
|
||||
"Test_Results",
|
||||
"Results_and_Conclusions",
|
||||
"Conducted_with_4_Hours_of_Exposure",
|
||||
"Dosages",
|
||||
"Doses_mg_per_kg_bw",
|
||||
"Mortality",
|
||||
"Dose_Mortality",
|
||||
"Mortality_Statement",
|
||||
"Weight_Behavior_Changes",
|
||||
"Clinical_Observations",
|
||||
"Clinical_Signs",
|
||||
"Body_Weight_Changes",
|
||||
"Necropsy_Findings",
|
||||
"Detailing_of_Reported_Changes",
|
||||
"Deviation_from_the_Guideline",
|
||||
"Conclusion_LD50_Greater_than",
|
||||
"Conclusion_LD50_mg_per_kg",
|
||||
"Conclusion_Minimum_Confidence",
|
||||
"Conclusion_Maximum_Confidence",
|
||||
"Study_Conclusion");
|
||||
private final ComponentDefinitionPersistenceService componentDefinitionPersistenceService;
|
||||
|
||||
|
||||
public ComponentLog getComponentLog(String dossierId, String fileId, boolean includeOverrides) {
|
||||
|
||||
List<ComponentDefinitionEntity> orderedEntities = componentDefinitionPersistenceService.findByDossierTemplateIdAndNotSoftDeleted(dossierId);
|
||||
List<String> orderedNames = orderedEntities.stream()
|
||||
.map(ComponentDefinitionEntity::getTechnicalName)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ComponentLog componentLog = fileManagementStorageService.getComponentLog(dossierId, fileId);
|
||||
|
||||
if (!includeOverrides) {
|
||||
componentLog = sortComponentLogEntriesByOrderList(componentLog, ORDER);
|
||||
componentLog = sortComponentLogEntries(componentLog, orderedNames);
|
||||
return componentLog;
|
||||
}
|
||||
|
||||
@ -83,12 +52,34 @@ public class ComponentLogService {
|
||||
|
||||
replaceOverriddenComponentLogEntries(componentLog, componentOverrides);
|
||||
|
||||
componentLog = sortComponentLogEntriesByOrderList(componentLog, ORDER);
|
||||
componentLog = sortComponentLogEntries(componentLog, orderedNames);
|
||||
return componentLog;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private ComponentLog sortComponentLogEntries(ComponentLog componentLog, List<String> orderedNames) {
|
||||
|
||||
List<ComponentLogEntry> componentLogEntries = componentLog.getComponentLogEntries();
|
||||
|
||||
List<ComponentLogEntry> sortedLogEntries = new ArrayList<>();
|
||||
List<ComponentLogEntry> nonOrderedLogEntries = new ArrayList<>();
|
||||
|
||||
for (ComponentLogEntry entry : componentLogEntries) {
|
||||
if (orderedNames.contains(entry.getName())) {
|
||||
sortedLogEntries.add(entry);
|
||||
} else {
|
||||
nonOrderedLogEntries.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
nonOrderedLogEntries.sort(new ComponentOrderComparator(orderedNames));
|
||||
sortedLogEntries.addAll(nonOrderedLogEntries);
|
||||
|
||||
return new ComponentLog(componentLog.getAnalysisNumber(), componentLog.getComponentRulesVersion(), sortedLogEntries);
|
||||
}
|
||||
|
||||
|
||||
private void replaceOverriddenComponentLogEntries(ComponentLog componentLog, List<ComponentLogEntry> componentOverrides) {
|
||||
|
||||
componentLog.getComponentLogEntries()
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.persistence;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ComponentDefinitionRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.SnakeCaseUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ComponentDefinitionPersistenceService {
|
||||
|
||||
private final ComponentDefinitionRepository componentDefinitionRepository;
|
||||
|
||||
|
||||
public ComponentDefinitionEntity insert(ComponentDefinitionAddRequest component) {
|
||||
|
||||
ComponentDefinitionEntity componentDefinitionEntity = new ComponentDefinitionEntity();
|
||||
componentDefinitionEntity.setId(UUID.randomUUID().toString());
|
||||
componentDefinitionEntity.setDossierTemplateId(component.getDossierTemplateId());
|
||||
componentDefinitionEntity.setTechnicalName(SnakeCaseUtils.toSnakeCase(component.getTechnicalName()));
|
||||
componentDefinitionEntity.setDisplayName(component.getDisplayName());
|
||||
componentDefinitionEntity.setDescription(component.getDescription());
|
||||
componentDefinitionEntity.setRank(countByDossierTemplateId(component.getDossierTemplateId()) + 1);
|
||||
return componentDefinitionRepository.saveAndFlush(componentDefinitionEntity);
|
||||
}
|
||||
|
||||
|
||||
public int countByDossierTemplateId(String dossierTemplateId) {
|
||||
|
||||
return componentDefinitionRepository.countByDossierTemplateId(dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
public ComponentDefinitionEntity update(ComponentDefinitionEntity componentDefinitionEntity) {
|
||||
|
||||
return componentDefinitionRepository.saveAndFlush(componentDefinitionEntity);
|
||||
}
|
||||
|
||||
|
||||
public ComponentDefinitionEntity findComponent(String dossierTemplateId, String componentId) {
|
||||
|
||||
return componentDefinitionRepository.findByIdAndDossierTemplateId(componentId, dossierTemplateId)
|
||||
.orElseThrow(() -> new NotFoundException("Component with id: " + componentId + " not found"));
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ComponentDefinitionEntity> softDeleteComponents(String dossierTemplateId, List<String> componentIds, OffsetDateTime softDeleteTime) {
|
||||
|
||||
componentDefinitionRepository.updateSoftDeleteForIds(componentIds, dossierTemplateId, softDeleteTime);
|
||||
return componentDefinitionRepository.findByIdsAndDossierTemplateId(componentIds, dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ComponentDefinitionEntity> restoreComponents(String dossierTemplateId, List<String> componentIds) {
|
||||
|
||||
componentDefinitionRepository.updateSoftDeleteForIds(componentIds, dossierTemplateId, null);
|
||||
return componentDefinitionRepository.findByIdsAndDossierTemplateId(componentIds, dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
public ComponentDefinitionEntity findComponentByDossierTemplateIdAndComponentId(String dossierTemplateId, String componentId) {
|
||||
|
||||
return componentDefinitionRepository.findByIdAndDossierTemplateId(componentId, dossierTemplateId)
|
||||
.orElseThrow(() -> new NotFoundException(String.format("Component with id %s not found in dossier template %s", componentId, dossierTemplateId)));
|
||||
}
|
||||
|
||||
|
||||
public List<ComponentDefinitionEntity> findComponentsByDossierTemplateId(String dossierTemplateId) {
|
||||
|
||||
return componentDefinitionRepository.findByDossierTemplateId(dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
public List<ComponentDefinitionEntity> findComponentsByDossierTemplateIdExcludeSoftDeleted(String dossierTemplateId) {
|
||||
|
||||
return componentDefinitionRepository.findByDossierTemplateIdAndSoftDeletedTimeIsNull(dossierTemplateId);
|
||||
}
|
||||
|
||||
|
||||
public List<ComponentDefinitionEntity> findByDossierTemplateIdAndNotSoftDeleted(String dossierTemplateId) {
|
||||
|
||||
return componentDefinitionRepository.findByDossierTemplateIdAndSoftDeletedTimeIsNull(dossierTemplateId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity;
|
||||
|
||||
@Repository
|
||||
public interface ComponentDefinitionRepository extends JpaRepository<ComponentDefinitionEntity, Long> {
|
||||
|
||||
List<ComponentDefinitionEntity> findByDossierTemplateId(String dossierTemplateId);
|
||||
|
||||
|
||||
Optional<ComponentDefinitionEntity> findByIdAndDossierTemplateId(String componentId, String dossierTemplateId);
|
||||
|
||||
|
||||
@Query("SELECT c FROM ComponentDefinitionEntity c WHERE c.dossierTemplateId = :dossierTemplateId AND c.softDeleteTime IS NULL")
|
||||
List<ComponentDefinitionEntity> findByDossierTemplateIdAndSoftDeletedTimeIsNull(@Param("dossierTemplateId") String dossierTemplateId);
|
||||
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE ComponentDefinitionEntity c SET c.softDeleteTime = :softDeleteTime WHERE c.id IN :ids AND c.dossierTemplateId = :dossierTemplateId")
|
||||
void updateSoftDeleteForIds(@Param("ids") List<String> ids, @Param("dossierTemplateId") String dossierTemplateId, @Param("softDeleteTime") OffsetDateTime softDeleteTime);
|
||||
|
||||
|
||||
@Query("SELECT c FROM ComponentDefinitionEntity c WHERE c.id in :ids AND c.dossierTemplateId = :dossierTemplateId")
|
||||
List<ComponentDefinitionEntity> findByIdsAndDossierTemplateId(@Param("ids") List<String> ids, @Param("dossierTemplateId") String dossierTemplateId);
|
||||
|
||||
|
||||
@Query("SELECT COUNT(c) from ComponentDefinitionEntity c WHERE c.dossierTemplateId = :dossierTemplateId AND c.softDeleteTime IS NULL")
|
||||
int countByDossierTemplateId(@Param("dossierTemplateId") String dossierTemplateId);
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.utils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class SnakeCaseUtils {
|
||||
|
||||
public static String toSnakeCase(String input) {
|
||||
|
||||
return input.replaceAll("([a-z])([A-Z])", "$1_$2").replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2").replaceAll("[\\s-]+", "_").toLowerCase(Locale.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
@ -209,3 +209,5 @@ databaseChangeLog:
|
||||
file: db/changelog/tenant/128-add-component-mapping-versions-to-file.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/126-add-uuid-to-download-status.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/129-add-component-table.yaml
|
||||
@ -0,0 +1,51 @@
|
||||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: 129-add-component-table
|
||||
author: aisvoran
|
||||
changes:
|
||||
- createTable:
|
||||
tableName: component_definition
|
||||
columns:
|
||||
- column:
|
||||
name: id
|
||||
type: VARCHAR(255)
|
||||
constraints:
|
||||
primaryKey: true
|
||||
primaryKeyName: component_definition_pkey
|
||||
nullable: false
|
||||
- column:
|
||||
name: dossier_template_id
|
||||
type: VARCHAR(255)
|
||||
constraints:
|
||||
nullable: false
|
||||
- column:
|
||||
name: technical_name
|
||||
type: VARCHAR(255)
|
||||
constraints:
|
||||
nullable: false
|
||||
- column:
|
||||
name: display_name
|
||||
type: VARCHAR(255)
|
||||
constraints:
|
||||
nullable: false
|
||||
- column:
|
||||
name: description
|
||||
type: TEXT
|
||||
- column:
|
||||
name: rank
|
||||
type: INTEGER
|
||||
- column:
|
||||
name: soft_delete_time
|
||||
type: TIMESTAMP
|
||||
- addUniqueConstraint:
|
||||
columnNames: technical_name, dossier_template_id
|
||||
tableName: component_definition
|
||||
constraintName: uq_component_definition_technical_name_template
|
||||
- addForeignKeyConstraint:
|
||||
baseTableName: component_definition
|
||||
baseColumnNames: dossier_template_id
|
||||
constraintName: fk_component_definition_dossier_template
|
||||
referencedTableName: dossier_template
|
||||
referencedColumnNames: id
|
||||
onDelete: CASCADE
|
||||
onUpdate: CASCADE
|
||||
@ -0,0 +1,10 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource;
|
||||
|
||||
@FeignClient(name = "DossierTemplateExternalClient", url = "http://localhost:${server.port}", configuration = FeignSupportConfig.class)
|
||||
public interface DossierTemplateExternalClient extends DossierTemplateResource {
|
||||
|
||||
}
|
||||
@ -0,0 +1,289 @@
|
||||
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.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
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.utils.AbstractPersistenceServerServiceTest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionAddRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentDefinitionUpdateRequest;
|
||||
|
||||
import feign.FeignException;
|
||||
|
||||
public class ComponentDefinitionTests extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
@Autowired
|
||||
private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;
|
||||
|
||||
@Autowired
|
||||
private DossierTemplateExternalClient dossierTemplateExternalClient;
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateComponentDefinition() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
|
||||
var componentDefinitionAddRequest = buildComponentDefinitionAddRequest(dossierTemplate);
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(), List.of(componentDefinitionAddRequest));
|
||||
|
||||
assertEquals(response.size(), 1);
|
||||
assertEquals(response.get(0).getRank(), 1);
|
||||
assertEquals(response.get(0).getDescription(), componentDefinitionAddRequest.getDescription());
|
||||
assertEquals(response.get(0).getDisplayName(), componentDefinitionAddRequest.getDisplayName());
|
||||
assertEquals(response.get(0).getTechnicalName(), componentDefinitionAddRequest.getTechnicalName());
|
||||
assertNull(response.get(0).getSoftDeleteTime());
|
||||
}
|
||||
|
||||
|
||||
private ComponentDefinitionAddRequest buildComponentDefinitionAddRequest(DossierTemplateModel dossierTemplate) {
|
||||
|
||||
return ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("component_1")
|
||||
.displayName("Component 1")
|
||||
.description("Description")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetComponentDefinition() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
|
||||
var componentDefinitionAddRequest = buildComponentDefinitionAddRequest(dossierTemplate);
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(), List.of(componentDefinitionAddRequest));
|
||||
assertEquals(response.size(), 1);
|
||||
|
||||
var component = dossierTemplateExternalClient.getComponent(dossierTemplate.getId(), response.get(0).getId());
|
||||
assertEquals(component.getRank(), 1);
|
||||
assertEquals(component.getDescription(), componentDefinitionAddRequest.getDescription());
|
||||
assertEquals(component.getDisplayName(), componentDefinitionAddRequest.getDisplayName());
|
||||
assertEquals(component.getTechnicalName(), componentDefinitionAddRequest.getTechnicalName());
|
||||
assertNull(component.getSoftDeleteTime());
|
||||
|
||||
var componentDefinitionAddRequest2 = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("component_2")
|
||||
.displayName("Component 2")
|
||||
.description("Description")
|
||||
.build();
|
||||
|
||||
response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(), List.of(componentDefinitionAddRequest2));
|
||||
assertEquals(response.size(), 1);
|
||||
|
||||
var components = dossierTemplateExternalClient.getComponents(dossierTemplate.getId(), false);
|
||||
assertEquals(components.size(), 2);
|
||||
|
||||
dossierTemplateExternalClient.deleteComponents(dossierTemplate.getId(), List.of(response.get(0).getId()));
|
||||
component = dossierTemplateExternalClient.getComponent(dossierTemplate.getId(), response.get(0).getId());
|
||||
assertEquals(component.getRank(), 2);
|
||||
assertNotNull(component.getSoftDeleteTime());
|
||||
|
||||
components = dossierTemplateExternalClient.getComponents(dossierTemplate.getId(), false);
|
||||
assertEquals(components.size(), 1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpdateComponentDefinition() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
|
||||
var componentDefinitionAddRequest = buildComponentDefinitionAddRequest(dossierTemplate);
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(), List.of(componentDefinitionAddRequest));
|
||||
assertEquals(response.size(), 1);
|
||||
|
||||
var componentDefinitionUpdateRequest = ComponentDefinitionUpdateRequest.builder()
|
||||
.id(response.get(0).getId())
|
||||
.description("updated description")
|
||||
.displayName("updated display name")
|
||||
.build();
|
||||
var updatedComponents = dossierTemplateExternalClient.updateComponents(dossierTemplate.getId(), List.of(componentDefinitionUpdateRequest));
|
||||
assertEquals(updatedComponents.size(), 1);
|
||||
assertEquals(updatedComponents.get(0).getRank(), 1);
|
||||
assertEquals(updatedComponents.get(0).getDescription(), componentDefinitionUpdateRequest.getDescription());
|
||||
assertEquals(updatedComponents.get(0).getDisplayName(), componentDefinitionUpdateRequest.getDisplayName());
|
||||
assertEquals(updatedComponents.get(0).getTechnicalName(), componentDefinitionAddRequest.getTechnicalName());
|
||||
assertNull(updatedComponents.get(0).getSoftDeleteTime());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSoftDeleteComponentDefinition() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
|
||||
var componentDefinitionAddRequest = buildComponentDefinitionAddRequest(dossierTemplate);
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(), List.of(componentDefinitionAddRequest));
|
||||
assertEquals(response.size(), 1);
|
||||
|
||||
dossierTemplateExternalClient.deleteComponents(dossierTemplate.getId(), List.of(response.get(0).getId()));
|
||||
|
||||
var softDeletedComponent = dossierTemplateExternalClient.getComponent(dossierTemplate.getId(), response.get(0).getId());
|
||||
assertNotNull(softDeletedComponent.getSoftDeleteTime());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRestoreDeletedComponentDefinitions() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
|
||||
var componentDefinitionAddRequest = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 1")
|
||||
.displayName("Component 1")
|
||||
.description("Description")
|
||||
.build();
|
||||
var componentDefinitionAddRequest2 = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 2")
|
||||
.displayName("Component 2")
|
||||
.description("Description")
|
||||
.build();
|
||||
var componentDefinitionAddRequest3 = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 3")
|
||||
.displayName("Component 3")
|
||||
.description("Description")
|
||||
.build();
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(),
|
||||
List.of(componentDefinitionAddRequest, componentDefinitionAddRequest2, componentDefinitionAddRequest3));
|
||||
assertEquals(response.size(), 3);
|
||||
|
||||
dossierTemplateExternalClient.deleteComponents(dossierTemplate.getId(), List.of(response.get(0).getId()));
|
||||
|
||||
var softDeletedComponent = dossierTemplateExternalClient.getComponent(dossierTemplate.getId(), response.get(0).getId());
|
||||
assertNotNull(softDeletedComponent.getSoftDeleteTime());
|
||||
|
||||
var restoredComponents = dossierTemplateExternalClient.restoreComponents(dossierTemplate.getId(), List.of(response.get(0).getId()));
|
||||
assertEquals(restoredComponents.size(), 1);
|
||||
assertEquals(restoredComponents.get(0).getId(), response.get(0).getId());
|
||||
assertEquals(restoredComponents.get(0).getRank(), 4);
|
||||
assertNull(restoredComponents.get(0).getSoftDeleteTime());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void createComponentDefinitionsWithDifferentDossierTemplateIds() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate("dossier1");
|
||||
var dossierTemplate2 = dossierTemplateTesterAndProvider.provideTestTemplate("dossier2");
|
||||
var componentDefinitionAddRequest = buildComponentDefinitionAddRequest(dossierTemplate);
|
||||
var componentDefinitionAddRequest2 = buildComponentDefinitionAddRequest(dossierTemplate2);
|
||||
|
||||
var error = assertThrows(FeignException.class,
|
||||
() -> dossierTemplateExternalClient.createComponents(dossierTemplate.getId(),
|
||||
List.of(componentDefinitionAddRequest, componentDefinitionAddRequest2)));
|
||||
assertTrue(error.getMessage().contains("All components must have the same dossierTemplateId."));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSnakeCaseTechnicalName() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate("dossier1");
|
||||
var componentDefinitionAddRequest = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 1")
|
||||
.displayName("Component 1")
|
||||
.description("Description")
|
||||
.build();
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(), List.of(componentDefinitionAddRequest));
|
||||
assertEquals(response.size(), 1);
|
||||
assertEquals(response.get(0).getTechnicalName(), "component_1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetAllComponentsForADossierTemplate() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate("dossier1");
|
||||
var componentDefinitionAddRequest = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 1")
|
||||
.displayName("Component 1")
|
||||
.description("Description")
|
||||
.build();
|
||||
var componentDefinitionAddRequest2 = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 2")
|
||||
.displayName("Component 2")
|
||||
.description("Description")
|
||||
.build();
|
||||
var componentDefinitionAddRequest3 = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 3")
|
||||
.displayName("Component 3")
|
||||
.description("Description")
|
||||
.build();
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(),
|
||||
List.of(componentDefinitionAddRequest, componentDefinitionAddRequest2, componentDefinitionAddRequest3));
|
||||
assertEquals(response.size(), 3);
|
||||
|
||||
var components = dossierTemplateExternalClient.getComponents(dossierTemplate.getId(), false);
|
||||
assertEquals(components.size(), 3);
|
||||
assertEquals(components.get(0).getId(), response.get(0).getId());
|
||||
assertEquals(components.get(0).getRank(), response.get(0).getRank());
|
||||
assertEquals(components.get(1).getId(), response.get(1).getId());
|
||||
assertEquals(components.get(1).getRank(), response.get(1).getRank());
|
||||
assertEquals(components.get(2).getId(), response.get(2).getId());
|
||||
assertEquals(components.get(2).getRank(), response.get(2).getRank());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReorderComponentDefinitions() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate("dossier1");
|
||||
var componentDefinitionAddRequest = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 1")
|
||||
.displayName("Component 1")
|
||||
.description("Description")
|
||||
.build();
|
||||
var componentDefinitionAddRequest2 = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 2")
|
||||
.displayName("Component 2")
|
||||
.description("Description")
|
||||
.build();
|
||||
var componentDefinitionAddRequest3 = ComponentDefinitionAddRequest.builder()
|
||||
.dossierTemplateId(dossierTemplate.getId())
|
||||
.technicalName("Component 3")
|
||||
.displayName("Component 3")
|
||||
.description("Description")
|
||||
.build();
|
||||
|
||||
var response = dossierTemplateExternalClient.createComponents(dossierTemplate.getId(),
|
||||
List.of(componentDefinitionAddRequest, componentDefinitionAddRequest2, componentDefinitionAddRequest3));
|
||||
assertEquals(response.size(), 3);
|
||||
String firstComponentId = response.get(0).getId();
|
||||
String secondComponentId = response.get(1).getId();
|
||||
String thirdComponentId = response.get(2).getId();
|
||||
|
||||
var newOrder = dossierTemplateExternalClient.reorderComponents(dossierTemplate.getId(), List.of(secondComponentId, thirdComponentId, firstComponentId));
|
||||
assertEquals(newOrder.size(), 3);
|
||||
assertEquals(newOrder.get(0).getId(), secondComponentId);
|
||||
assertEquals(newOrder.get(0).getRank(), 1);
|
||||
assertEquals(newOrder.get(1).getId(), thirdComponentId);
|
||||
assertEquals(newOrder.get(1).getRank(), 2);
|
||||
assertEquals(newOrder.get(2).getId(), firstComponentId);
|
||||
assertEquals(newOrder.get(2).getRank(), 3);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.component;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class ComponentDefinition {
|
||||
|
||||
private String id;
|
||||
private String dossierTemplateId;
|
||||
private String technicalName;
|
||||
private String displayName;
|
||||
private String description;
|
||||
private Integer rank;
|
||||
private OffsetDateTime softDeleteTime;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.component;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Object containing information about a component.")
|
||||
public class ComponentDefinitionAddRequest {
|
||||
|
||||
@NonNull
|
||||
@Schema(description = "The dossierTemplateId for this component.")
|
||||
private String dossierTemplateId;
|
||||
|
||||
@NonNull
|
||||
@Schema(description = "The technical name of the component in snake case. Must be unique within the same dossier template.")
|
||||
private String technicalName;
|
||||
|
||||
@NonNull
|
||||
@Schema(description = "The display name of the component.")
|
||||
private String displayName;
|
||||
|
||||
@Schema(description = "The component's description (optional).")
|
||||
private String description;
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.component;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Object containing information about a component.")
|
||||
public class ComponentDefinitionUpdateRequest {
|
||||
|
||||
@Schema(description = "The id of the component.")
|
||||
private String id;
|
||||
|
||||
@NonNull
|
||||
@Schema(description = "The display name of the component.")
|
||||
private String displayName;
|
||||
|
||||
@Schema(description = "The component's description.")
|
||||
private String description;
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user