diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ComponentLogController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ComponentLogController.java index 56e093a9b..94f69420b 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ComponentLogController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ComponentLogController.java @@ -3,30 +3,21 @@ package com.iqser.red.persistence.service.v1.external.api.impl.controller; import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS; import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_REDACTION_LOG; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - +import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; +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.RequestBody; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.view.RedirectView; -import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService; import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService; -import com.iqser.red.service.persistence.management.v1.processor.service.ComponentOverrideService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.service.v1.api.external.resource.ComponentLogResource; -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; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue; -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.ComponentsOverrides; import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest; -import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -35,15 +26,15 @@ import lombok.experimental.FieldDefaults; @RestController @RequiredArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@Deprecated(forRemoval = true) public class ComponentLogController implements ComponentLogResource { ComponentLogService componentLogService; - ComponentOverrideService componentOverrideService; - AuditPersistenceService auditPersistenceService; AccessControlService accessControlService; @Override + @Deprecated(forRemoval = true) @PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')") public ComponentLog getComponentLog(String dossierId, String fileId, boolean includeOverrides) { @@ -54,134 +45,42 @@ public class ComponentLogController implements ComponentLogResource { } + @PostMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides) { + public RedirectView addOverride(String dossierTemplateId, + @PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestBody ComponentLogEntry override) { accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId); accessControlService.validateFileResourceExistence(fileId); - if (componentsOverrides.getComponentOverrides() == null || componentsOverrides.getComponentOverrides().isEmpty()) { - throw new BadRequestException("Request body cannot be empty!"); - } - var componentLog = componentLogService.getComponentLog(dossierId, fileId); - var allComponents = componentLog.getComponentLogEntries(); - - componentOverrideService.addOverrides(dossierId, fileId, componentsOverrides); - - componentsOverrides.getComponentOverrides() - .forEach((componentName, overrideValue) -> auditOverride(dossierId, fileId, componentName, overrideValue, allComponents)); + return new RedirectView(String.format("/api/dossier-templates/{%s}/dossiers/{%s}/files/{%s}/overrides", dossierTemplateId, dossierId, fileId), true); } + @GetMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { + public RedirectView getOverrides(String dossierTemplateId, @PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { accessControlService.checkDossierExistenceAndViewPermissionsToDossier(dossierId); accessControlService.validateFileResourceExistence(fileId); - return componentOverrideService.getOverrides(dossierId, fileId); + + return new RedirectView(String.format("/api/dossier-templates/{%s}/dossiers/{%s}/files/{%s}/overrides", dossierTemplateId, dossierId, fileId), true); } + @PostMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + "/revert" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest) { + public RedirectView revertOverrides(String dossierTemplateId, + @PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestBody RevertOverrideRequest revertOverrideRequest) { accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId); accessControlService.validateFileResourceExistence(fileId); - if (revertOverrideRequest.getComponents() == null || revertOverrideRequest.getComponents().isEmpty()) { - throw new BadRequestException("Request body cannot be empty!"); - } - var componentLog = componentLogService.getComponentLog(dossierId, fileId); - var allComponents = componentLog.getComponentLogEntries(); - - componentOverrideService.revertOverrides(dossierId, fileId, revertOverrideRequest); - - revertOverrideRequest.getComponents() - .forEach(componentNameToRevert -> auditOverrideRevert(dossierId, fileId, componentNameToRevert, allComponents)); - } - - - private void auditOverride(String dossierId, String fileId, String componentName, String overrideValue, List allComponentLogEntries) { - - Optional component = allComponentLogEntries.stream() - .filter(c -> c.getName().equals(componentName)) - .findFirst(); - String originalValue = getOriginalValue(component); - String value = getValue(component); - auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("The component is overwritten with value") - .details(Map.of(DOSSIER_ID, - dossierId, - FILE_ID, - fileId, - "ComponentName", - componentName, - "Action", - "MODIFY", - "OriginalValue", - originalValue, - "OldValue", - value, - "NewValue", - overrideValue)) - .build()); - } - - - private void auditOverrideRevert(String dossierId, String fileId, String componentNameToRevert, List allComponentLogEntries) { - - Optional component = allComponentLogEntries.stream() - .filter(c -> c.getName().equals(componentNameToRevert)) - .findFirst(); - String originalValue = getOriginalValue(component); - String value = getValue(component); - auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("The component override for was reverted") - .details(Map.of(DOSSIER_ID, - dossierId, - FILE_ID, - fileId, - "ComponentName", - componentNameToRevert, - "Action", - "REVERT", - "OriginalValue", - originalValue, - "OldValue", - value, - "NewValue", - originalValue)) - .build()); - } - - - private String getValue(Optional component) { - - return component.map(ComponentLogEntry::getComponentValues) - .stream() - .map(a -> a.stream() - .map(ComponentLogEntryValue::getValue) - .collect(Collectors.joining(", "))) - .findFirst() - .orElse(""); - } - - - private static String getOriginalValue(Optional component) { - - return component.map(ComponentLogEntry::getComponentValues) - .stream() - .map(a -> a.stream() - .map(ComponentLogEntryValue::getOriginalValue) - .collect(Collectors.joining(", "))) - .findFirst() - .orElse(""); + return new RedirectView(String.format("/api/dossier-templates/{%s}/dossiers/{%s}/files/{%s}/overrides/revert", dossierTemplateId, dossierId, fileId), true); } } diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RSSComponentLogController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RSSComponentLogController.java deleted file mode 100644 index 7a75cb402..000000000 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RSSComponentLogController.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.iqser.red.persistence.service.v1.external.api.impl.controller; - -import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService; -import com.iqser.red.service.persistence.management.v1.processor.service.ComponentOverrideService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; -import com.iqser.red.service.persistence.service.v1.api.external.resource.RSSResource; -import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; -import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntityReference; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue; -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.ComponentsOverrides; -import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSFileResponse; -import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSResponse; -import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSFileResponse; -import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSResponse; -import com.iqser.red.service.redaction.report.v1.api.model.rss.SCMComponent; -import com.iqser.red.service.redaction.report.v1.api.model.rss.ScmAnnotation; -import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; - -import lombok.RequiredArgsConstructor; - -@Deprecated(forRemoval = true) -@RestController -@RequiredArgsConstructor -@ConditionalOnProperty(name = "application.rss.component-log.enabled", havingValue = "true") -public class RSSComponentLogController implements RSSResource { - - private final ComponentOverrideService componentOverrideService; - private final AuditPersistenceService auditPersistenceService; - private final ComponentLogService componentLogService; - private final StatusController statusController; - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public RSSResponse getRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) { - - List dossierFiles; - if (StringUtils.isBlank(fileId)) { - dossierFiles = statusController.getDossierStatus(dossierId); - } else { - dossierFiles = List.of(statusController.getFileStatus(dossierId, fileId)); - } - - List fileResponses = dossierFiles.stream() - .map(this::getRssResponse) - .toList(); - - return new RSSResponse(fileResponses); - - } - - - private RSSFileResponse getRssResponse(FileStatus file) { - - var componentLog = componentLogService.getComponentLog(file.getDossierId(), file.getId(), true); - - Map results = new LinkedHashMap<>(); - - componentLog.getComponentLogEntries() - .forEach(entry -> { - if (entry.getComponentValues().size() <= 1) { - results.put(entry.getName(), - entry.getComponentValues() - .get(0).getValue()); - return; - } - - List componentValues = entry.getComponentValues(); - for (int i = 0, componentValuesSize = componentValues.size(); i < componentValuesSize; i++) { - ComponentLogEntryValue v = componentValues.get(i); - results.put(entry.getName() + "_" + (i + 1), v.getValue()); - } - }); - - return RSSFileResponse.builder().filename(file.getFilename()).result(results).build(); - - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) { - - List dossierFiles; - if (StringUtils.isBlank(fileId)) { - dossierFiles = statusController.getDossierStatus(dossierId); - } else { - dossierFiles = List.of(statusController.getFileStatus(dossierId, fileId)); - } - - List fileResponses = dossierFiles.stream() - .map(this::getDetailedRssResponse) - .toList(); - - return new DetailedRSSResponse(fileResponses); - } - - - private DetailedRSSFileResponse getDetailedRssResponse(FileStatus file) { - - var componentLog = componentLogService.getComponentLog(file.getDossierId(), file.getId(), true); - - Map results = new LinkedHashMap<>(); - - componentLog.getComponentLogEntries() - .forEach(entry -> { - if (entry.getComponentValues().size() <= 1) { - results.put(entry.getName(), - toSCMComponent(entry.getComponentValues() - .get(0))); - return; - } - - List componentValues = entry.getComponentValues(); - for (int i = 0, componentValuesSize = componentValues.size(); i < componentValuesSize; i++) { - ComponentLogEntryValue v = componentValues.get(i); - results.put(entry.getName() + "_" + (i + 1), toSCMComponent(v)); - } - }); - - return DetailedRSSFileResponse.builder().filename(file.getFilename()).result(results).build(); - } - - - private SCMComponent toSCMComponent(ComponentLogEntryValue v) { - - return SCMComponent.builder() - .value(v.getValue().equals(v.getOriginalValue()) ? null : v.getValue()) - .originalValue(v.getOriginalValue()) - .transformation(v.getValueDescription()) - .scmAnnotations(v.getComponentLogEntityReferences() - .stream() - .map(this::toScmAnnotation) - .toList()) - .build(); - } - - - private ScmAnnotation toScmAnnotation(ComponentLogEntityReference er) { - - return ScmAnnotation.builder().type(er.getType()).pages(Set.of(er.getPage())).ruleIdentifier(er.getEntityRuleId()).reason(formatType(er.getType())).build(); - } - - - private static String formatType(String type) { - - return type.substring(0, 1).toUpperCase(Locale.ENGLISH) + type.substring(1).toLowerCase(Locale.ENGLISH).replaceAll("_", " "); - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides) { - - var componentLog = componentLogService.getComponentLog(dossierId, fileId); - var allComponents = componentLog.getComponentLogEntries(); - - componentOverrideService.addOverrides(dossierId, fileId, componentsOverrides); - - componentsOverrides.getComponentOverrides() - .forEach((componentName, overrideValue) -> auditOverride(dossierId, fileId, componentName, overrideValue, allComponents)); - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { - - return componentOverrideService.getOverrides(dossierId, fileId); - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest) { - - var componentLog = componentLogService.getComponentLog(dossierId, fileId); - var allComponents = componentLog.getComponentLogEntries(); - - componentOverrideService.revertOverrides(dossierId, fileId, revertOverrideRequest); - - revertOverrideRequest.getComponents() - .forEach(componentNameToRevert -> auditOverrideRevert(dossierId, fileId, componentNameToRevert, allComponents)); - } - - - private void auditOverride(String dossierId, String fileId, String componentName, String overrideValue, List allComponentLogEntries) { - - Optional component = allComponentLogEntries.stream() - .filter(c -> c.getName().equals(componentName)) - .findFirst(); - String originalValue = getOriginalValue(component); - String value = getValue(component); - auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("The component is overwritten with value") - .details(Map.of(DOSSIER_ID, - dossierId, - FILE_ID, - fileId, - "ComponentName", - componentName, - "Action", - "MODIFY", - "OriginalValue", - originalValue, - "OldValue", - value, - "NewValue", - overrideValue)) - .build()); - } - - - private void auditOverrideRevert(String dossierId, String fileId, String componentNameToRevert, List allComponentLogEntries) { - - Optional component = allComponentLogEntries.stream() - .filter(c -> c.getName().equals(componentNameToRevert)) - .findFirst(); - String originalValue = getOriginalValue(component); - String value = getValue(component); - auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("The component override for was reverted") - .details(Map.of(DOSSIER_ID, - dossierId, - FILE_ID, - fileId, - "ComponentName", - componentNameToRevert, - "Action", - "REVERT", - "OriginalValue", - originalValue, - "OldValue", - value, - "NewValue", - originalValue)) - .build()); - } - - - private String getValue(Optional component) { - - return component.map(ComponentLogEntry::getComponentValues) - .stream() - .map(a -> a.stream() - .map(ComponentLogEntryValue::getValue) - .collect(Collectors.joining(", "))) - .findFirst() - .orElse(""); - } - - - private static String getOriginalValue(Optional component) { - - return component.map(ComponentLogEntry::getComponentValues) - .stream() - .map(a -> a.stream() - .map(ComponentLogEntryValue::getOriginalValue) - .collect(Collectors.joining(", "))) - .findFirst() - .orElse(""); - } - -} diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RSSController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RSSController.java deleted file mode 100644 index 87a8dc4fd..000000000 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RSSController.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.iqser.red.persistence.service.v1.external.api.impl.controller; - -import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS; - -import java.util.Map; -import java.util.stream.Collectors; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.iqser.red.service.persistence.management.v1.processor.client.redactionreportservice.RssReportClient; -import com.iqser.red.service.persistence.management.v1.processor.service.ComponentOverrideService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; -import com.iqser.red.service.persistence.service.v1.api.external.resource.RSSResource; -import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; -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.ComponentsOverrides; -import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSFileResponse; -import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSResponse; -import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSResponse; -import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; - -import lombok.RequiredArgsConstructor; - -@Deprecated(forRemoval = true) -@RestController -@RequiredArgsConstructor -@ConditionalOnProperty(name = "application.rss.component-log.enabled", havingValue = "false") -public class RSSController implements RSSResource { - - private final RssReportClient rssReportClient; - private final ComponentOverrideService componentOverrideService; - private final AuditPersistenceService auditPersistenceService; - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public RSSResponse getRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) { - - return convert(rssReportClient.getRSS(dossierId, fileId)); - - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - private RSSResponse convert(com.iqser.red.service.redaction.report.v1.api.model.rss.RSSResponse rssResponse) { - - return new RSSResponse(rssResponse.getFiles() - .stream() - .map(this::convert) - .collect(Collectors.toList())); - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - private RSSFileResponse convert(com.iqser.red.service.redaction.report.v1.api.model.rss.RSSFileResponse rssFileResponse) { - - return new RSSFileResponse(rssFileResponse.getFilename(), rssFileResponse.getResult()); - - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId) { - - return rssReportClient.getDetailedRSS(dossierId, fileId); - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides) { - - var rssReport = rssReportClient.getDetailedRSS(dossierId, fileId); - var components = rssReport.getFiles() - .get(0).getResult(); - - componentOverrideService.addOverrides(dossierId, fileId, componentsOverrides); - - componentsOverrides.getComponentOverrides() - .forEach((key, value) -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("The component is overwritten with value") - .details(Map.of(DOSSIER_ID, - dossierId, - FILE_ID, - fileId, - "ComponentName", - key, - "Action", - "MODIFY", - "OriginalValue", - components.get(key).getOriginalValue(), - "OldValue", - components.get(key).getValue() != null ? components.get(key) - .getValue() : components.get(key).getOriginalValue(), - "NewValue", - value)) - .build())); - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { - - return componentOverrideService.getOverrides(dossierId, fileId); - } - - - @PreAuthorize("hasAuthority('" + GET_RSS + "')") - public void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest) { - - var rssReport = rssReportClient.getDetailedRSS(dossierId, fileId); - var components = rssReport.getFiles() - .get(0).getResult(); - - componentOverrideService.revertOverrides(dossierId, fileId, revertOverrideRequest); - - revertOverrideRequest.getComponents() - .forEach(component -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("The component override for was reverted") - .details(Map.of(DOSSIER_ID, - dossierId, - FILE_ID, - fileId, - "ComponentName", - component, - "Action", - "REVERT", - "OriginalValue", - components.get(component).getOriginalValue(), - "OldValue", - components.get(component).getValue() != null ? components.get(component) - .getValue() : components.get(component).getOriginalValue(), - "NewValue", - components.get(component).getOriginalValue())) - .build())); - } - -} diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java index 943fba2d0..eeb47bc76 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java @@ -1,27 +1,25 @@ package com.iqser.red.persistence.service.v2.external.api.impl.controller; +import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.GET_RSS; import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.DOSSIER_ID_PARAM; import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM; import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PARAM; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController; import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController; +import com.iqser.red.persistence.service.v2.external.api.impl.mapper.ComponentMapper; import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntityReference; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue; +import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest; import com.iqser.red.service.persistence.service.v2.api.external.model.Component; -import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentValue; -import com.iqser.red.service.persistence.service.v2.api.external.model.EntityReference; +import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentOverrideModelList; import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents; import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponentsList; import com.iqser.red.service.persistence.service.v2.api.external.resource.ComponentResource; @@ -37,10 +35,12 @@ import lombok.experimental.FieldDefaults; @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ComponentControllerV2 implements ComponentResource { + DossierTemplateController dossierTemplateController; ComponentLogService componentLogService; StatusController statusController; FileStatusService fileStatusService; DossierTemplatePersistenceService dossierTemplatePersistenceService; + ComponentMapper componentMapper = ComponentMapper.INSTANCE; @Override @@ -52,65 +52,7 @@ public class ComponentControllerV2 implements ComponentResource { dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId); var componentLog = componentLogService.getComponentLog(dossierId, fileId, true); - Map> basicComponent = new LinkedHashMap<>(); - for (ComponentLogEntry componentLogEntry : componentLog.getComponentLogEntries()) { - basicComponent.put(componentLogEntry.getName(), - componentLogEntry.getComponentValues() - .stream() - .map(ComponentLogEntryValue::getValue) - .toList()); - } - - Map componentsDetails = new LinkedHashMap<>(); - if (includeDetails) { - for (ComponentLogEntry entry : componentLog.getComponentLogEntries()) { - componentsDetails.put(entry.getName(), Component.builder().name(entry.getName()).componentValues(toComponentList(entry)).build()); - } - } - - return FileComponents.builder() - .dossierTemplateId(dossierTemplateId) - .dossierId(dossierId) - .filename(fileStatusService.getFileName(fileId)) - .fileId(fileId) - .components(basicComponent) - .componentDetails(componentsDetails) - .build(); - } - - - private List toComponentList(ComponentLogEntry componentLogEntry) { - - return componentLogEntry.getComponentValues() - .stream() - .map(this::convert) - .toList(); - } - - - private ComponentValue convert(ComponentLogEntryValue componentValue) { - - return ComponentValue.builder() - .valueDescription(componentValue.getValueDescription()) - .componentRuleId(componentValue.getComponentRuleId()) - .entityReferences(componentValue.getComponentLogEntityReferences() - .stream() - .map(this::convertComponentEntityReference) - .toList()) - .originalValue(componentValue.getOriginalValue()) - .value(componentValue.getValue()) - .build(); - } - - - private EntityReference convertComponentEntityReference(ComponentLogEntityReference componentLogEntityReference) { - - return EntityReference.builder() - .id(componentLogEntityReference.getId()) - .entityRuleId(componentLogEntityReference.getEntityRuleId()) - .type(componentLogEntityReference.getType()) - .page(componentLogEntityReference.getPage()) - .build(); + return componentMapper.toFileComponents(componentLog, dossierTemplateId, dossierId, fileId, fileStatusService.getFileName(fileId), includeDetails); } @@ -127,4 +69,44 @@ public class ComponentControllerV2 implements ComponentResource { } + @Override + @PreAuthorize("hasAuthority('" + GET_RSS + "')") + public void addOverride(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @PathVariable(DOSSIER_ID_PARAM) String dossierId, + @PathVariable(FILE_ID_PARAM) String fileId, + @RequestBody Component override) { + + dossierTemplateController.getDossierTemplate(dossierTemplateId); + + componentLogService.addOverride(dossierId, fileId, componentMapper.toComponentLogEntry(override)); + } + + + @Override + @PreAuthorize("hasAuthority('" + GET_RSS + "')") + public ComponentOverrideModelList getOverrides(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @PathVariable(DOSSIER_ID_PARAM) String dossierId, + @PathVariable(FILE_ID_PARAM) String fileId) { + + dossierTemplateController.getDossierTemplate(dossierTemplateId); + + var overrides = componentLogService.getOverrides(dossierId, fileId); + var componentOverrides = componentMapper.toComponents(overrides); + + return ComponentOverrideModelList.builder().dossierTemplateId(dossierTemplateId).dossierId(dossierId).fileId(fileId).componentOverrideModels(componentOverrides).build(); + } + + + @Override + @PreAuthorize("hasAuthority('" + GET_RSS + "')") + public void revertOverrides(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @PathVariable(DOSSIER_ID_PARAM) String dossierId, + @PathVariable(FILE_ID_PARAM) String fileId, + @RequestBody RevertOverrideRequest revertOverrideRequest) { + + dossierTemplateController.getDossierTemplate(dossierTemplateId); + + componentLogService.revertOverrides(dossierId, fileId, revertOverrideRequest); + } + } diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/mapper/ComponentMapper.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/mapper/ComponentMapper.java new file mode 100644 index 000000000..da9eabe0f --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/mapper/ComponentMapper.java @@ -0,0 +1,75 @@ +package com.iqser.red.persistence.service.v2.external.api.impl.mapper; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +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; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue; +import com.iqser.red.service.persistence.service.v2.api.external.model.Component; +import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentValue; +import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents; + +@Mapper +public interface ComponentMapper { + + ComponentMapper INSTANCE = Mappers.getMapper(ComponentMapper.class); + + + @Mapping(source = "componentLogEntityReferences", target = "entityReferences") + ComponentValue toComponentValue(ComponentLogEntryValue entry); + + + @Mapping(source = "entityReferences", target = "componentLogEntityReferences") + ComponentLogEntryValue toComponentLogEntry(ComponentValue value); + + + List toComponentValues(List entries); + + + List toComponentLogEntries(List values); + + @Mapping(source = "componentValues", target = "componentValues") + Component toComponent(ComponentLogEntry entry); + + + List toComponents(List entries); + + @Mapping(source = "componentValues", target = "componentValues") + ComponentLogEntry toComponentLogEntry(Component component); + + + default FileComponents toFileComponents(ComponentLog componentLog, String dossierTemplateId, String dossierId, String fileId, String fileName, boolean includeDetails) { + + Map> basicComponent = new LinkedHashMap<>(); + for (ComponentLogEntry componentLogEntry : componentLog.getComponentLogEntries()) { + basicComponent.put(componentLogEntry.getName(), + componentLogEntry.getComponentValues() + .stream() + .map(ComponentLogEntryValue::getValue) + .toList()); + } + + Map componentsDetails = new LinkedHashMap<>(); + if (includeDetails) { + for (ComponentLogEntry entry : componentLog.getComponentLogEntries()) { + componentsDetails.put(entry.getName(), toComponent(entry)); + } + } + + return FileComponents.builder() + .dossierTemplateId(dossierTemplateId) + .dossierId(dossierId) + .filename(fileName) + .fileId(fileId) + .components(basicComponent) + .componentDetails(componentsDetails) + .build(); + } + +} diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ComponentLogResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ComponentLogResource.java index d51f9853d..ea2bcc1f6 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ComponentLogResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ComponentLogResource.java @@ -9,9 +9,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.servlet.view.RedirectView; 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.component.ComponentsOverrides; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest; import io.swagger.v3.oas.annotations.Operation; @@ -25,11 +26,13 @@ public interface ComponentLogResource { String OVERRIDE_PATH = "/override"; + String DOSSIER_TEMPLATE_ID = "dossierTemplateId"; + String DOSSIER_TEMPLATE_ID_PATH_VARIABLE = "/{" + DOSSIER_TEMPLATE_ID + "}"; + String DOSSIER_ID = "dossierId"; String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}"; String FILE_ID = "fileId"; - String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}"; @@ -46,7 +49,7 @@ public interface ComponentLogResource { @PostMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Adds overrides for components", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")}) - void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides); + RedirectView addOverride(String dossierTemplateId, @PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentLogEntry override); @ResponseBody @@ -54,7 +57,7 @@ public interface ComponentLogResource { @GetMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Gets overrides for components", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")}) - ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); + RedirectView getOverrides(String dossierTemplateId, @PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); @ResponseBody @@ -62,6 +65,6 @@ public interface ComponentLogResource { @PostMapping(value = COMPONENT_LOG_PATH + OVERRIDE_PATH + "/revert" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Reverts overrides for components", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")}) - void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest); + RedirectView revertOverrides(String dossierTemplateId, @PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest); } diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/RSSResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/RSSResource.java deleted file mode 100644 index 74d941076..000000000 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/RSSResource.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.iqser.red.service.persistence.service.v1.api.external.resource; - -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -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.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; - -import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides; -import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.rss.RSSResponse; -import com.iqser.red.service.redaction.report.v1.api.model.rss.DetailedRSSResponse; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; - -@Deprecated(forRemoval = true) -@ResponseStatus(value = HttpStatus.OK) -public interface RSSResource { - - String RSS_PATH = ExternalApi.BASE_PATH + "/rss"; - String OVERRIDE_PATH = "/override"; - - String DOSSIER_ID = "dossierId"; - String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}"; - - String FILE_ID = "fileId"; - String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}"; - - - @Deprecated(forRemoval = true) - @GetMapping(value = RSS_PATH + DOSSIER_ID_PATH_VARIABLE, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}) - @Operation(summary = "Returns the RSS response for a dossier", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - RSSResponse getRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId); - - - @Deprecated(forRemoval = true) - @GetMapping(value = RSS_PATH + "/detailed" + DOSSIER_ID_PATH_VARIABLE, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}) - @Operation(summary = "Returns the RSS response with more details for a dossier", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - DetailedRSSResponse getDetailedRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId); - - - @Deprecated(forRemoval = true) - @ResponseBody - @ResponseStatus(value = HttpStatus.OK) - @PostMapping(value = RSS_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Adds overrides for RSS components", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - void addOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody ComponentsOverrides componentsOverrides); - - - @Deprecated(forRemoval = true) - @ResponseBody - @ResponseStatus(value = HttpStatus.OK) - @GetMapping(value = RSS_PATH + OVERRIDE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Gets overrides for RSS components", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - ComponentsOverrides getOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); - - - @Deprecated(forRemoval = true) - @ResponseBody - @ResponseStatus(value = HttpStatus.OK) - @PostMapping(value = RSS_PATH + OVERRIDE_PATH + "/revert" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Reverts overrides for RSS components", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - void revertOverrides(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody RevertOverrideRequest revertOverrideRequest); - -} diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/Component.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/Component.java index d1646ac02..5d8bca92d 100644 --- a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/Component.java +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/Component.java @@ -19,5 +19,7 @@ public class Component { private String name; @JacksonXmlCData private List componentValues; + @JacksonXmlCData + private boolean overridden; } diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/ComponentOverrideModelList.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/ComponentOverrideModelList.java new file mode 100644 index 000000000..d16b4fd72 --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/ComponentOverrideModelList.java @@ -0,0 +1,22 @@ +package com.iqser.red.service.persistence.service.v2.api.external.model; + +import java.util.ArrayList; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ComponentOverrideModelList { + + String dossierTemplateId; + String dossierId; + String fileId; + + List componentOverrideModels = new ArrayList<>(); +} diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/ComponentValue.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/ComponentValue.java index 7293b04a0..be343606b 100644 --- a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/ComponentValue.java +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/ComponentValue.java @@ -18,6 +18,7 @@ public class ComponentValue { @JacksonXmlCData String value; @JacksonXmlCData + @Deprecated String originalValue; @JacksonXmlCData String valueDescription; diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/ComponentResource.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/ComponentResource.java index a67b78e9c..2b63f8148 100644 --- a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/ComponentResource.java +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/ComponentResource.java @@ -11,26 +11,22 @@ import static com.iqser.red.service.persistence.service.v2.api.external.resource import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; 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 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.v1.api.shared.model.component.RevertOverrideRequest; +import com.iqser.red.service.persistence.service.v2.api.external.model.Component; +import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentOverrideModelList; import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents; import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponentsList; 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; @@ -49,10 +45,15 @@ public interface ComponentResource { String INCLUDE_DETAILS_DESCRIPTION = """ A toggle to decide whether to include detailed component information in the response: + - true: The component object's field componentDetails stores detailed information about the source of its respective value(s). - false (default): The component object does not contain a field componentDetails. """; + String OVERRIDES_PATH = "/overrides"; + String REVERT_PATH = "/revert"; + + String COMPONENT_OVERRIDE_PARAM = "componentOverride"; @GetMapping(value = FILE_PATH + FILE_ID_PATH_VARIABLE + COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}) @@ -72,5 +73,35 @@ public interface ComponentResource { @Parameter(name = INCLUDE_DETAILS_PARAM, description = INCLUDE_DETAILS_DESCRIPTION) @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails); + @ResponseBody + @ResponseStatus(value = HttpStatus.NO_CONTENT) + @PostMapping(value = PATH + FILE_ID_PATH_VARIABLE + OVERRIDES_PATH, consumes = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Adds overrides for components", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")}) + void addOverride(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId, + @Parameter(name = FILE_ID_PARAM, description = "The identifier of the file that the components are requested for.", required = true) @PathVariable(FILE_ID_PARAM) String fileId, + @Parameter(name = COMPONENT_OVERRIDE_PARAM, description = "The object to override the component.", required = true) @RequestBody Component componentOverrideModel); + + + @ResponseBody + @ResponseStatus(value = HttpStatus.OK) + @GetMapping(value = PATH + FILE_ID_PATH_VARIABLE + OVERRIDES_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}) + @Operation(summary = "Gets overrides for components", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")}) + ComponentOverrideModelList getOverrides(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId, + @Parameter(name = FILE_ID_PARAM, description = "The identifier of the file that the components are requested for.", required = true) @PathVariable(FILE_ID_PARAM) String fileId); + + + @ResponseBody + @ResponseStatus(value = HttpStatus.NO_CONTENT) + @PostMapping(value = PATH + FILE_ID_PATH_VARIABLE + OVERRIDES_PATH + REVERT_PATH, consumes = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Reverts overrides for components", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "403", description = "Forbidden")}) + void revertOverrides(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId, + @Parameter(name = FILE_ID_PARAM, description = "The identifier of the file that the components are requested for.", required = true) @PathVariable(FILE_ID_PARAM) String fileId, + @RequestBody RevertOverrideRequest revertOverrideRequest); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/ComponentOverride.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/ComponentOverride.java new file mode 100644 index 000000000..5a06c3994 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/ComponentOverride.java @@ -0,0 +1,21 @@ +package com.iqser.red.service.persistence.management.v1.processor.model; + +import java.util.ArrayList; +import java.util.List; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ComponentOverride { + + String name; + List componentOverrideValues = new ArrayList<>(); +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java index 54d907efa..b2e2ab860 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java @@ -2,13 +2,19 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import java.util.Comparator; import java.util.List; -import java.util.Objects; +import java.util.Map; import org.springframework.stereotype.Service; +import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; +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; -import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides; +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.RevertOverrideRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.ComponentLogMongoService; +import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -19,7 +25,8 @@ import lombok.experimental.FieldDefaults; public class ComponentLogService { private final FileManagementStorageService fileManagementStorageService; - private final ComponentOverrideService componentOverrideService; + private final ComponentLogMongoService componentLogMongoService; + private final AuditPersistenceService auditPersistenceService; // TODO: make this DB changeable! private static final List ORDER = List.of("Study_Title", @@ -65,30 +72,43 @@ public class ComponentLogService { public ComponentLog getComponentLog(String dossierId, String fileId, boolean includeOverrides) { - ComponentLog componentLog = sortComponentLogEntriesByOrderList(fileManagementStorageService.getComponentLog(dossierId, fileId), ORDER); + ComponentLog componentLog; + try { + componentLog = fileManagementStorageService.getComponentLog(dossierId, fileId); + } catch (NotFoundException e) { + var componentLogOptional = componentLogMongoService.findComponentLogByDossierIdAndFileId(dossierId, fileId); + if (componentLogOptional.isEmpty()) { + throw new NotFoundException(e.getMessage()); + } + componentLog = componentLogOptional.get(); + } if (!includeOverrides) { + componentLog = sortComponentLogEntriesByOrderList(componentLog, ORDER); return componentLog; } - ComponentsOverrides componentsOverrides = componentOverrideService.getOverrides(dossierId, fileId); - if (Objects.isNull(componentsOverrides.getComponentOverrides()) || componentsOverrides.getComponentOverrides().isEmpty()) { - return componentLog; - } + List componentOverrides = getOverrides(dossierId, fileId); - List overriddenComponentLogEntries = componentLog.getComponentLogEntries() - .stream() - .map(componentLogEntry -> applyOverride(componentLogEntry, - componentsOverrides.getComponentOverrides() - .get(componentLogEntry.getName()))) - .toList(); + replaceOverriddenComponentLogEntries(componentLog, componentOverrides); - componentLog.setComponentLogEntries(overriddenComponentLogEntries); + componentLog = sortComponentLogEntriesByOrderList(componentLog, ORDER); return componentLog; } + private void replaceOverriddenComponentLogEntries(ComponentLog componentLog, List componentOverrides) { + // remove override entries from componentLog + componentLog.getComponentLogEntries() + .removeIf(entry -> componentOverrides.stream() + .anyMatch(override -> entry.getName().equals(override.getName()))); + + // insert overrides to Component log + componentLog.getComponentLogEntries().addAll(componentOverrides); + } + + private ComponentLog sortComponentLogEntriesByOrderList(ComponentLog componentLog, List order) { return new ComponentLog(componentLog.getAnalysisNumber(), @@ -107,14 +127,93 @@ public class ComponentLogService { } - private ComponentLogEntry applyOverride(ComponentLogEntry componentLogEntry, String override) { + public void addOverride(String dossierId, String fileId, ComponentLogEntry componentOverride) { - if (Objects.isNull(override)) { - return componentLogEntry; + var optionalComponentLogEntry = componentLogMongoService.findComponentLogEntryById(dossierId, fileId, componentOverride.getName()); + + if (optionalComponentLogEntry.isPresent()) { + ComponentLogEntry componentToUpdate = optionalComponentLogEntry.get(); + componentToUpdate.setComponentValues(componentOverride.getComponentValues()); + saveOverride(dossierId, fileId, componentToUpdate); + auditOverride(dossierId, fileId, componentToUpdate); + } else { + insertOverride(dossierId, fileId, componentOverride); + auditOverride(dossierId, fileId, componentOverride); } - componentLogEntry.getComponentValues() - .forEach(componentValue -> componentValue.setValue(override)); - return componentLogEntry; + + } + + + private void saveOverride(String dossierId, String fileId, ComponentLogEntry componentToUpdate) { + + componentLogMongoService.saveComponentLogEntries(dossierId, fileId, List.of(componentToUpdate)); + + } + + + private void insertOverride(String dossierId, String fileId, ComponentLogEntry componentToAdd) { + + componentLogMongoService.insertComponentLogEntries(dossierId, fileId, List.of(componentToAdd)); + } + + + public List getOverrides(String dossierId, String fileId) { + + return componentLogMongoService.findOverrides(dossierId, fileId); + } + + + public void revertOverrides(String dossierId, String fileId, RevertOverrideRequest revertOverrideRequest) { + + revertOverrideRequest.getComponents() + .forEach(componentName -> { + var componentLogEntry = componentLogMongoService.findComponentLogEntryById(dossierId, fileId, componentName) + .orElseThrow(() -> new NotFoundException(String.format("Component %s was not found.", componentName))); + + auditOverrideRevert(dossierId, fileId, componentLogEntry); + }); + } + + + private void auditOverride(String dossierId, String fileId, ComponentLogEntry entry) { + + auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("The component is overwritten with value") + .details(Map.of("dossierId", + dossierId, + "fileId", + fileId, + "ComponentName", + entry.getName(), + "Action", + "MODIFY", + "Values", + entry.getComponentValues())) + .build()); + } + + + private void auditOverrideRevert(String dossierId, String fileId, ComponentLogEntry entry) { + + auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("The component override for was reverted") + .details(Map.of("dossierId", + dossierId, + "fileId", + fileId, + "ComponentName", + entry.getName(), + "Action", + "REVERT", + "Values", + entry.getComponentValues())) + .build()); } @@ -148,4 +247,4 @@ public class ComponentLogService { } -} +} \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentOverrideService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentOverrideService.java deleted file mode 100644 index b61aea6df..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentOverrideService.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.service; - -import java.io.ByteArrayInputStream; -import java.util.Collections; - -import org.springframework.stereotype.Service; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides; -import com.iqser.red.service.persistence.service.v1.api.shared.model.component.RevertOverrideRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; - -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; - -@Service -@RequiredArgsConstructor -public class ComponentOverrideService { - - private final FileManagementStorageService fileManagementStorageService; - private final ObjectMapper objectMapper; - - - @SneakyThrows - public void addOverrides(String dossierId, String fileId, ComponentsOverrides componentsOverrides) { - - if (!fileManagementStorageService.objectExists(dossierId, fileId, FileType.COMPONENTS)) { - fileManagementStorageService.storeObject(dossierId, fileId, FileType.COMPONENTS, new ByteArrayInputStream(objectMapper.writeValueAsBytes(componentsOverrides))); - return; - } - - var existingComponentsBytes = fileManagementStorageService.getStoredObjectBytes(dossierId, fileId, FileType.COMPONENTS); - var existingComponents = objectMapper.readValue(existingComponentsBytes, ComponentsOverrides.class); - existingComponents.getComponentOverrides().putAll(componentsOverrides.getComponentOverrides()); - - fileManagementStorageService.storeObject(dossierId, fileId, FileType.COMPONENTS, new ByteArrayInputStream(objectMapper.writeValueAsBytes(existingComponents))); - } - - - @SneakyThrows - public ComponentsOverrides getOverrides(String dossierId, String fileId) { - - var exists = fileManagementStorageService.objectExists(dossierId, fileId, FileType.COMPONENTS); - if (!exists) { - return ComponentsOverrides.builder().componentOverrides(Collections.emptyMap()).build(); - } - var existingComponentsBytes = fileManagementStorageService.getStoredObjectBytes(dossierId, fileId, FileType.COMPONENTS); - return objectMapper.readValue(existingComponentsBytes, ComponentsOverrides.class); - } - - - @SneakyThrows - public void revertOverrides(String dossierId, String fileId, RevertOverrideRequest revertOverrideRequest) { - - if (!fileManagementStorageService.objectExists(dossierId, fileId, FileType.COMPONENTS)) { - return; - } - - var existingComponentsBytes = fileManagementStorageService.getStoredObjectBytes(dossierId, fileId, FileType.COMPONENTS); - var existingComponents = objectMapper.readValue(existingComponentsBytes, ComponentsOverrides.class); - - revertOverrideRequest.getComponents() - .forEach(c -> existingComponents.getComponentOverrides().remove(c)); - - fileManagementStorageService.storeObject(dossierId, fileId, FileType.COMPONENTS, new ByteArrayInputStream(objectMapper.writeValueAsBytes(existingComponents))); - } - -} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/mongo/changelog/mongo.changelog-tenant.xml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/mongo/changelog/mongo.changelog-tenant.xml index a7f704703..e3cb9067d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/mongo/changelog/mongo.changelog-tenant.xml +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/mongo/changelog/mongo.changelog-tenant.xml @@ -5,4 +5,5 @@ + diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/mongo/changelog/tenant/3-create-component-entities.xml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/mongo/changelog/tenant/3-create-component-entities.xml new file mode 100644 index 000000000..eca068400 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/mongo/changelog/tenant/3-create-component-entities.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentLogDocumentMapperTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentLogDocumentMapperTest.java new file mode 100644 index 000000000..d1b3b1471 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentLogDocumentMapperTest.java @@ -0,0 +1,62 @@ +//package com.iqser.red.service.peristence.v1.server.integration.tests; +// +//import static com.mongodb.assertions.Assertions.assertNotNull; +//import static com.mongodb.assertions.Assertions.assertTrue; +//import static org.junit.jupiter.api.Assertions.assertEquals; +// +//import java.util.List; +//import java.util.Optional; +// +//import org.junit.jupiter.api.Test; +//import org.springframework.core.io.ClassPathResource; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +//import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentDocument; +//import com.iqser.red.service.persistence.service.v1.api.shared.mongo.mapper.ComponentLogDocumentMapper; +// +//import lombok.SneakyThrows; +// +//public class ComponentLogDocumentMapperTest { +// +// private final ComponentLogDocumentMapper mapper = ComponentLogDocumentMapper.INSTANCE; +// +// private final String COMPONENT_LOG = "files/componentlog/componentLogExample.json"; +// private final String COMPONENT_OVERRIDE = "files/componentlog/componentOverrideExample.json"; +// private static final String TEST_DOSSIER_ID = "91ce8e90-9aec-473c-b8c3-cbe16443ad34"; +// private static final String TEST_FILE_ID = "b2cbdd4dca0aa1aa0ebbfc5cc1462df0"; +// +// +// @Test +// @SneakyThrows +// public void ComponentOverrideMapper() { +// +// var overrideFile = new ClassPathResource(String.format(COMPONENT_OVERRIDE)); +// ObjectMapper objectMapper = new ObjectMapper(); +// objectMapper.registerModule(new JavaTimeModule()); +// +// ComponentsOverrides componentsOverridesBefore = objectMapper.readValue(overrideFile.getInputStream(), ComponentsOverrides.class); +// +// List componentDocument = mapper.toComponentOverrideDocuments(componentsOverridesBefore, TEST_DOSSIER_ID, TEST_FILE_ID); +// +// assertEquals(componentDocument.get(0).getDossierId(), TEST_DOSSIER_ID); +// assertEquals(componentDocument.get(0).getFileId(), TEST_FILE_ID); +// assertEquals(componentDocument.get(0).getId(), mapper.getComponentId(TEST_DOSSIER_ID, TEST_FILE_ID, componentDocument.get(0).getName())); +// +// Optional optionalComponentValueDocument = componentDocument.get(0).getOverrideValues() +// .stream() +// .findFirst(); +// +// assertTrue(optionalComponentValueDocument.isPresent()); +// assertNotNull(optionalComponentValueDocument.get().getValueId()); +// assertNotNull(optionalComponentValueDocument.get().getComponentOverrideId()); +// +// ComponentsOverrides componentsOverridesAfter = mapper.fromComponentOverrideDocument(componentDocument.get(0)); +// +// assertEquals(mapper.buildComponentOverrideMap(componentDocument.get(0).getName(), +// componentsOverridesBefore.getComponentOverrides() +// .get(componentDocument.get(0).getName())), componentsOverridesAfter); +// +// } +// +//} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentlog/componentLogExample.json b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentlog/componentLogExample.json new file mode 100644 index 000000000..9c51139c2 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentlog/componentLogExample.json @@ -0,0 +1,266 @@ +{ + "analysisNumber": 3, + "componentRulesVersion": 1, + "componentLogEntries": [ + { + "name": "Study_Title", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "StudyTitle.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Performing_Laboratory", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "fallback", + "componentRuleId": "PerformingLaboratory.0.2", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Report_Number", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "ReportNumber.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "GLP_Study", + "componentValues": [ + { + "valueId": null, + "value": "No", + "originalValue": "No", + "valueDescription": "Yes if present, No if not", + "componentRuleId": "GLPStudy.1.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Test_Guidelines_2", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all values of type with ', '", + "componentRuleId": "TestGuideline.2.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Experimental_Starting_Date", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Convert values of type '' to dd/MM/yyyy joined with ', '", + "componentRuleId": "StartDate.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Experimental_Completion_Date", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Convert values of type '' to dd/MM/yyyy joined with ', '", + "componentRuleId": "CompletionDate.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Certificate_of_Analysis_Batch_Identification", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "AnalysisCertificate.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Species", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "Species.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Strain", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "Strain.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Doses_mg_per_kg_bw", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "Necropsy.1.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Mortality_Statement", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "MortalityStatement.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Weight_Behavior_Changes", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all values of type with '\n'", + "componentRuleId": "WeightBehavior.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Necropsy_Findings", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "Necropsy.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Deviation_from_the_Guideline", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all values of type with '\n'", + "componentRuleId": "GuidelineDeviation.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_LD50_Greater_than", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "No entity of type 'ld50_greater' found", + "componentRuleId": "Conclusion.1.1", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_LD50_mg_per_kg", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "Conclusion.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_Minimum_Confidence", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "Conclusion.2.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_Maximum_Confidence", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "Conclusion.3.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Study_Conclusion", + "componentValues": [ + { + "valueId": null, + "value": "", + "originalValue": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "StudyConclusion.0.0", + "componentLogEntityReferences": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentlog/componentOverrideExample.json b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentlog/componentOverrideExample.json new file mode 100644 index 000000000..e78ce1ef0 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/componentlog/componentOverrideExample.json @@ -0,0 +1,244 @@ +{ + "componentOverrides": [ + { + "name": "Study_Title", + "componentValues": [ + { + "valueId": "1", + "value": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "StudyTitle.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Performing_Laboratory", + "componentValues": [ + { + "valueId": "2", + "value": "", + "valueDescription": "fallback", + "componentRuleId": "PerformingLaboratory.0.2", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Report_Number", + "componentValues": [ + { + "valueId": "3", + "value": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "ReportNumber.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "GLP_Study", + "componentValues": [ + { + "valueId": "4", + "value": "No", + "valueDescription": "Yes if present, No if not", + "componentRuleId": "GLPStudy.1.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Test_Guidelines_2", + "componentValues": [ + { + "valueId": "5", + "value": "", + "valueDescription": "Joining all values of type with ', '", + "componentRuleId": "TestGuideline.2.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Experimental_Starting_Date", + "componentValues": [ + { + "valueId": "6", + "value": "", + "valueDescription": "Convert values of type '' to dd/MM/yyyy joined with ', '", + "componentRuleId": "StartDate.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Experimental_Completion_Date", + "componentValues": [ + { + "valueId": "7", + "value": "", + "valueDescription": "Convert values of type '' to dd/MM/yyyy joined with ', '", + "componentRuleId": "CompletionDate.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Certificate_of_Analysis_Batch_Identification", + "componentValues": [ + { + "valueId": "8", + "value": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "AnalysisCertificate.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Species", + "componentValues": [ + { + "valueId": "9", + "value": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "Species.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Strain", + "componentValues": [ + { + "valueId": "10", + "value": "", + "valueDescription": "First found value of type or else ''", + "componentRuleId": "Strain.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Doses_mg_per_kg_bw", + "componentValues": [ + { + "valueId": "11", + "value": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "Necropsy.1.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Mortality_Statement", + "componentValues": [ + { + "valueId": "12", + "value": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "MortalityStatement.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Weight_Behavior_Changes", + "componentValues": [ + { + "valueId": "13", + "value": "", + "valueDescription": "Joining all values of type with '\n'", + "componentRuleId": "WeightBehavior.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Necropsy_Findings", + "componentValues": [ + { + "valueId": "14", + "value": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "Necropsy.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Deviation_from_the_Guideline", + "componentValues": [ + { + "valueId": "15", + "value": "", + "valueDescription": "Joining all values of type with '\n'", + "componentRuleId": "GuidelineDeviation.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_LD50_Greater_than", + "componentValues": [ + { + "valueId": "16", + "value": "", + "valueDescription": "No entity of type 'ld50_greater' found", + "componentRuleId": "Conclusion.1.1", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_LD50_mg_per_kg", + "componentValues": [ + { + "valueId": "17", + "value": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "Conclusion.0.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_Minimum_Confidence", + "componentValues": [ + { + "valueId": "18", + "value": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "Conclusion.2.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Conclusion_Maximum_Confidence", + "componentValues": [ + { + "valueId": "19", + "value": "", + "valueDescription": "Joining all unique values of type with ', '", + "componentRuleId": "Conclusion.3.0", + "componentLogEntityReferences": [] + } + ] + }, + { + "name": "Study_Conclusion", + "componentValues": [ + { + "valueId": "20", + "value": "", + "valueDescription": "Joining all values of type with ' '", + "componentRuleId": "StudyConclusion.0.0", + "componentLogEntityReferences": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/componentlog/ComponentLogEntry.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/componentlog/ComponentLogEntry.java index 143bc55b1..1ab54b8c6 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/componentlog/ComponentLogEntry.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/componentlog/ComponentLogEntry.java @@ -16,5 +16,5 @@ public class ComponentLogEntry { String name; List componentValues; - + boolean overridden; } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/component/ComponentsOverrides.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/component/ComponentsOverrides.java deleted file mode 100644 index ead7333cb..000000000 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/component/ComponentsOverrides.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.iqser.red.service.persistence.service.v1.api.shared.model.component; - -import java.util.HashMap; -import java.util.Map; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ComponentsOverrides { - - private Map componentOverrides = new HashMap<>(); - -} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/document/ComponentDocument.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/document/ComponentDocument.java new file mode 100644 index 000000000..e2ef280f3 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/document/ComponentDocument.java @@ -0,0 +1,39 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.document; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@FieldDefaults(level = AccessLevel.PRIVATE) +@Document(collection = "components") +public class ComponentDocument { + + @Id + @EqualsAndHashCode.Include + String id; // componentLogId/name = componentOverrideId + + String componentLogId; + + String name; + + List overrideValues = new ArrayList<>(); + + // these parameters will be needed later + // List values = new ArrayList<>(); + // boolean overridden; +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/document/ComponentLogDocument.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/document/ComponentLogDocument.java new file mode 100644 index 000000000..e230689f2 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/document/ComponentLogDocument.java @@ -0,0 +1,38 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.document; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@FieldDefaults(level = AccessLevel.PRIVATE) +@Document(collection = "component-logs") +public class ComponentLogDocument { + + @Id + @EqualsAndHashCode.Include + String id; // dossierId/fileId = componentLogId + + String dossierId; + String fileId; + + int analysisNumber; + long componentRulesVersion = -1; + + @DBRef + List components = new ArrayList<>(); + +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/exception/ComponentLogDocumentNotFoundException.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/exception/ComponentLogDocumentNotFoundException.java new file mode 100644 index 000000000..05e56d25e --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/exception/ComponentLogDocumentNotFoundException.java @@ -0,0 +1,10 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.exception; + +public class ComponentLogDocumentNotFoundException extends RuntimeException { + + public ComponentLogDocumentNotFoundException(String errorMessage) { + + super(errorMessage); + } + +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/mapper/ComponentLogDocumentMapper.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/mapper/ComponentLogDocumentMapper.java new file mode 100644 index 000000000..67dafef80 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/mapper/ComponentLogDocumentMapper.java @@ -0,0 +1,56 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.mapper; + +import java.util.List; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +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; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentDocument; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentLogDocument; + +@Mapper +public interface ComponentLogDocumentMapper { + + ComponentLogDocumentMapper INSTANCE = Mappers.getMapper(ComponentLogDocumentMapper.class); + + + @Mapping(source = "components", target = "componentLogEntries") + ComponentLog fromComponentLogDocument(ComponentLogDocument componentLogDocument); + + + List toComponentDocuments(List componentLogEntries); + + + @Mapping(source = "overrideValues", target = "componentValues") + ComponentLogEntry fromComponentDocument(ComponentDocument componentDocument); + + + @Mapping(expression = "java(getComponentLogId(dossierId, fileId))", target = "id") + ComponentLogDocument toComponentLogDocument(String dossierId, String fileId, ComponentLog componentLog); + + + @Mapping(expression = "java(getComponentId(componentLogId, componentLogEntry.getName()))", target = "id") + ComponentDocument toComponentDocument(String componentLogId, ComponentLogEntry componentLogEntry); + + + default String getComponentLogId(String dossierId, String fileId) { + + return dossierId + "/" + fileId; + } + + + default String getComponentId(String componentLogId, String componentName) { + + return componentLogId + "/" + componentName; + } + + + default String getComponentId(String dossierId, String fileId, String componentName) { + + return getComponentLogId(dossierId, fileId) + "/" + componentName; + } + +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/ComponentDocumentRepository.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/ComponentDocumentRepository.java new file mode 100644 index 000000000..1e48abcaf --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/ComponentDocumentRepository.java @@ -0,0 +1,22 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; +import org.springframework.stereotype.Repository; + +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentDocument; + +@Repository +public interface ComponentDocumentRepository extends MongoRepository { + + @Query(value = "{ 'componentLogId' : ?0}", delete = true) + void deleteByComponentLogId(String componentLogId); + + + @Query(value = "{ 'componentLogId': ?0, 'componentName': ?1 }") + Optional findComponentDocumentByName(String componentLogId, String componentName); + +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/ComponentLogDocumentRepository.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/ComponentLogDocumentRepository.java new file mode 100644 index 000000000..262e23842 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/ComponentLogDocumentRepository.java @@ -0,0 +1,22 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository; + +import java.util.Optional; + +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; +import org.springframework.stereotype.Repository; + +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentLogDocument; + +@Repository +public interface ComponentLogDocumentRepository extends MongoRepository, CustomComponentRepository { + + @Query(value = "{ 'id' : ?0 }", fields = "{ 'analysisNumber' : 1 }") + Optional findAnalysisNumberById(String id); + + + @Query(value = "{ 'id': ?0 }", fields = "{ 'components': 0 }") + Optional findComponentLogDocumentWithoutEntriesById(String id); + +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/CustomComponentRepository.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/CustomComponentRepository.java new file mode 100644 index 000000000..32199d5f8 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/CustomComponentRepository.java @@ -0,0 +1,14 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository; + +import java.util.List; + +import org.springframework.stereotype.Repository; + +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentDocument; + +@Repository +public interface CustomComponentRepository { + + List findOverrides(String fileId, String dossierId); + +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/CustomComponentRepositoryImpl.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/CustomComponentRepositoryImpl.java new file mode 100644 index 000000000..344e0f8ca --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/repository/CustomComponentRepositoryImpl.java @@ -0,0 +1,49 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository; + +import static org.springframework.data.mongodb.core.aggregation.Aggregation.match; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.replaceRoot; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.unwind; + +import java.util.List; + +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.data.mongodb.core.aggregation.AggregationResults; +import org.springframework.data.mongodb.core.aggregation.LookupOperation; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.stereotype.Repository; + +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentDocument; + +import lombok.RequiredArgsConstructor; + +@Repository +@RequiredArgsConstructor +public class CustomComponentRepositoryImpl implements CustomComponentRepository { + + private final MongoTemplate mongoTemplate; + + + @Override + public List findOverrides(String fileId, String dossierId) { + + LookupOperation lookupOperation = LookupOperation.newLookup().from("componentDocument").localField("components").foreignField("_id").as("componentDocs"); + + AggregationOperation matchOperation = match(Criteria.where("fileId").is(fileId).and("dossierId").is(dossierId)); + + AggregationOperation unwindOperation = unwind("componentDocs"); + + AggregationOperation matchNonEmptyOverrides = match(Criteria.where("componentDocs.overrideValues").ne(null)); + + AggregationOperation replaceRootOperation = replaceRoot("componentDocs"); + + Aggregation aggregation = newAggregation(matchOperation, lookupOperation, unwindOperation, matchNonEmptyOverrides, replaceRootOperation); + + AggregationResults results = mongoTemplate.aggregate(aggregation, "componentLogDocument", ComponentDocument.class); + + return results.getMappedResults(); + } + +} diff --git a/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/service/ComponentLogMongoService.java b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/service/ComponentLogMongoService.java new file mode 100644 index 000000000..a4d728e11 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-mongo-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/mongo/service/ComponentLogMongoService.java @@ -0,0 +1,229 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.mongo.service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +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; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentDocument; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.ComponentLogDocument; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.exception.ComponentLogDocumentNotFoundException; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.mapper.ComponentLogDocumentMapper; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.ComponentDocumentRepository; +import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.ComponentLogDocumentRepository; + +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@Service +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +public class ComponentLogMongoService { + + ComponentLogDocumentRepository componentLogDocumentRepository; + ComponentDocumentRepository componentDocumentRepository; + ComponentLogDocumentMapper mapper = ComponentLogDocumentMapper.INSTANCE; + + + public ComponentLogMongoService(ComponentLogDocumentRepository componentLogDocumentRepository, ComponentDocumentRepository componentDocumentRepository) { + + this.componentLogDocumentRepository = componentLogDocumentRepository; + this.componentDocumentRepository = componentDocumentRepository; + } + + + public void insertComponentLog(String dossierId, String fileId, ComponentLog componentLog) { + + ComponentLogDocument componentLogDocument = componentLogDocumentRepository.insert(mapper.toComponentLogDocument(dossierId, fileId, componentLog)); + componentDocumentRepository.insert(componentLog.getComponentLogEntries() + .stream() + .map(componentLogEntry -> mapper.toComponentDocument(componentLogDocument.getId(), componentLogEntry)) + .toList()); + } + + + public void saveComponentLog(String dossierId, String fileId, ComponentLog componentLog) { + + ComponentLogDocument componentLogDocument = componentLogDocumentRepository.save(mapper.toComponentLogDocument(dossierId, fileId, componentLog)); + componentDocumentRepository.saveAll(componentLog.getComponentLogEntries() + .stream() + .map(componentLogEntry -> mapper.toComponentDocument(componentLogDocument.getId(), componentLogEntry)) + .toList()); + } + + + public void upsertComponentLog(String dossierId, String fileId, ComponentLog componentLog) { + + Optional optionalComponentLogDocument = componentLogDocumentRepository.findById(mapper.getComponentLogId(dossierId, fileId)); + if (optionalComponentLogDocument.isEmpty()) { + insertComponentLog(dossierId, fileId, componentLog); + return; + } + + ComponentLogDocument oldComponentLogDocument = optionalComponentLogDocument.get(); + List oldComponentDocuments = oldComponentLogDocument.getComponents(); + + ComponentLogDocument newComponentLogDocument = mapper.toComponentLogDocument(dossierId, fileId, componentLog); + List newComponentDocuments = newComponentLogDocument.getComponents(); + + List toUpdate = new ArrayList<>(newComponentDocuments); + toUpdate.retainAll(oldComponentDocuments); + + List toRemove = new ArrayList<>(oldComponentDocuments); + toRemove.removeAll(toUpdate); + + List toInsert = new ArrayList<>(newComponentDocuments); + toInsert.removeAll(toUpdate); + + componentDocumentRepository.saveAll(toUpdate); + componentDocumentRepository.deleteAll(toRemove); + componentDocumentRepository.insert(toInsert); + + componentLogDocumentRepository.save(newComponentLogDocument); + + } + + + public void deleteComponentLog(String dossierId, String fileId) { + + String componentLogId = mapper.getComponentLogId(dossierId, fileId); + + componentLogDocumentRepository.deleteById(componentLogId); + + componentDocumentRepository.deleteByComponentLogId(componentLogId); + } + + + public void insertComponentLogEntries(String dossierId, String fileId, List componentLogEntries) { + + String componentLogId = mapper.getComponentLogId(dossierId, fileId); + + ComponentLogDocument componentLogDocument = getComponentLogDocument(componentLogId); + + List componentDocuments = componentLogEntries.stream() + .map(componentLogEntry -> mapper.toComponentDocument(componentLogId, componentLogEntry)) + .toList(); + + componentLogDocument.getComponents().addAll(componentDocuments); + + componentDocumentRepository.insert(componentDocuments); + componentLogDocumentRepository.save(componentLogDocument); + } + + + private ComponentLogDocument getComponentLogDocument(String componentLogId) { + + Optional optionalComponentLogDocument = componentLogDocumentRepository.findById(componentLogId); + + if (optionalComponentLogDocument.isEmpty()) { + throw new ComponentLogDocumentNotFoundException(String.format("Component log not found for %s", componentLogId)); + } + + return optionalComponentLogDocument.get(); + } + + + public void saveComponentLogEntries(String dossierId, String fileId, List componentLogEntries) { + + String componentLogId = mapper.getComponentLogId(dossierId, fileId); + + ComponentLogDocument componentLogDocument = getComponentLogDocument(componentLogId); + + List componentDocuments = componentLogEntries.stream() + .map(componentLogEntry -> mapper.toComponentDocument(componentLogId, componentLogEntry)) + .toList(); + + componentLogDocument.getComponents().addAll(componentDocuments); + + componentDocumentRepository.saveAll(componentDocuments); + componentLogDocumentRepository.save(componentLogDocument); + } + + + public void updateComponentLogEntries(String dossierId, String fileId, List componentLogEntries) { + + String componentLogId = mapper.getComponentLogId(dossierId, fileId); + + componentDocumentRepository.saveAll(componentLogEntries.stream() + .map(componentLogEntry -> mapper.toComponentDocument(componentLogId, componentLogEntry)) + .toList()); + } + + + public void deleteComponentLogEntries(String dossierId, String fileId, List componentLogEntries) { + + String componentLogId = mapper.getComponentLogId(dossierId, fileId); + + ComponentLogDocument componentLogDocument = getComponentLogDocument(componentLogId); + + List componentDocuments = componentLogEntries.stream() + .map(componentLogEntry -> mapper.toComponentDocument(componentLogId, componentLogEntry)) + .toList(); + + componentLogDocument.getComponents().removeAll(componentDocuments); + + componentDocumentRepository.deleteAll(componentDocuments); + componentLogDocumentRepository.save(componentLogDocument); + } + + + public Optional findComponentLogByDossierIdAndFileId(String dossierId, String fileId) { + + return componentLogDocumentRepository.findById(mapper.getComponentLogId(dossierId, fileId)) + .map(mapper::fromComponentLogDocument); + } + + + public Optional findComponentLogEntryById(String dossierId, String fileId, String componentName) { + + return componentDocumentRepository.findComponentDocumentByName(mapper.getComponentLogId(dossierId, fileId), componentName) + .map(mapper::fromComponentDocument); + } + + + public List findOverrides(String dossierId, String fileId) { + + return componentLogDocumentRepository.findOverrides(dossierId, fileId) + .stream() + .map(mapper::fromComponentDocument) + .toList(); + } + + + public boolean componentLogDocumentExists(String dossierId, String fileId) { + + return componentLogDocumentRepository.existsById(mapper.getComponentLogId(dossierId, fileId)); + } + + + public Optional findLatestAnalysisNumber(String dossierId, String fileId) { + + return componentLogDocumentRepository.findAnalysisNumberById(mapper.getComponentLogId(dossierId, fileId)) + .map(ComponentLogDocument::getAnalysisNumber); + } + + + public List findComponentLogEntriesWithComponentNameIn(String dossierId, String fileId, Collection componentNames) { + + String componentLogId = mapper.getComponentLogId(dossierId, fileId); + List names = componentNames.stream() + .map(name -> mapper.getComponentId(componentLogId, name)) + .toList(); + + return componentDocumentRepository.findAllById(names) + .stream() + .map(mapper::fromComponentDocument) + .toList(); + } + + + public Optional findComponentLogWithoutEntries(String dossierId, String fileId) { + + return componentLogDocumentRepository.findComponentLogDocumentWithoutEntriesById(mapper.getComponentLogId(dossierId, fileId)) + .map(mapper::fromComponentLogDocument); + } + +}