From 85b0b9fd431ab047af935ed7e0f2370d0fa09cb0 Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Thu, 7 Nov 2024 13:24:06 +0200 Subject: [PATCH] RED-10422 - improved number of requests with help of new changes endpoint --- .../impl/controller/DossierController.java | 113 +++++++++----- .../api/impl/controller/StatusController.java | 28 ++++ .../external/resource/DossierResource.java | 17 +++ .../api/external/resource/StatusResource.java | 11 ++ .../RedObjectIdentityRetrievalStrategy.java | 5 +- .../processor/model/DossierIdFilterable.java | 6 + .../service/DossierManagementService.java | 13 ++ .../v1/processor/service/DossierService.java | 7 +- .../service/FileStatusManagementService.java | 5 + .../processor/service/FileStatusService.java | 13 ++ .../service/FilterByPermissionsService.java | 15 ++ .../DossierAttributePersistenceService.java | 6 + .../DossierPersistenceService.java | 18 ++- .../FileStatusPersistenceService.java | 6 + .../projection/DossierChangeProjection.java | 9 ++ .../projection/FileChangeProjection.java | 10 ++ .../DossierAttributeRepository.java | 3 + .../repository/DossierRepository.java | 4 + .../repository/FileRepository.java | 11 ++ .../tests/DossierStatsAndGetByIdsTest.java | 138 ++++++++++++++++++ .../AbstractPersistenceServerServiceTest.java | 7 +- .../api/shared/model/DossierChangeEntry.java | 2 +- .../shared/model/DossierChangeEntryV2.java | 15 ++ .../shared/model/DossierChangeResponseV2.java | 18 +++ .../api/shared/model/FileChangeEntryV2.java | 18 +++ .../v1/api/shared/model/IHavingDossierId.java | 6 + .../dossiertemplate/dossier/Dossier.java | 1 + 27 files changed, 463 insertions(+), 42 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DossierIdFilterable.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/DossierChangeProjection.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/FileChangeProjection.java create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierStatsAndGetByIdsTest.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntryV2.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeResponseV2.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/FileChangeEntryV2.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/IHavingDossierId.java 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/DossierController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DossierController.java index 8ef0cda94..fb90004c7 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DossierController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DossierController.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -23,7 +24,11 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.dossier. import com.iqser.red.service.persistence.management.v1.processor.model.websocket.DossierEventType; import com.iqser.red.service.persistence.management.v1.processor.service.DossierCreatorService; +import com.iqser.red.service.persistence.management.v1.processor.service.FilterByPermissionsService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeResponseV2; +import com.iqser.red.service.persistence.service.v1.api.shared.model.JsonNode; import org.apache.commons.lang3.StringUtils; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -76,6 +81,7 @@ public class DossierController implements DossierResource { private final DossierManagementService dossierManagementService; private final UserService userService; + private final FilterByPermissionsService filterByPermissionsService; private final FileStatusManagementService fileStatusManagementService; private final AuditPersistenceService auditPersistenceService; private final NotificationPersistenceService notificationPersistenceService; @@ -106,6 +112,20 @@ public class DossierController implements DossierResource { } + @Override + @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") + public DossierChangeResponseV2 changesSinceV2(@RequestBody JSONPrimitive since) { + + DossierChangeResponseV2 changes = dossierManagementService.changesSinceV2(since); + + // filter only viewables + changes.setFileChanges(filterByPermissionsService.onlyViewableHavingDossierId(changes.getFileChanges())); + changes.setDossierChanges(filterByPermissionsService.onlyViewableHavingDossierId(changes.getDossierChanges())); + + return changes; + } + + @Override @PreAuthorize("hasAuthority('" + ADD_UPDATE_DOSSIER + "') && (#dossierRequest.dossierId == null || hasPermission(#dossierRequest.dossierId, 'Dossier', 'ACCESS_OBJECT') )") public ResponseEntity createDossierOrUpdateDossier(@RequestBody DossierRequest dossierRequest) { @@ -405,6 +425,28 @@ public class DossierController implements DossierResource { } + @Override + @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") + public JSONPrimitive> getDossiersByIds(@RequestBody JSONPrimitive> dossierIds) { + + // filter dossiers based on view + var viewableDossierIds = filterByPermissionsService.onlyViewableDossierIds(dossierIds.getValue()); + // load dossiers + var dossiers = dossierManagementService.getDossiersByIds(viewableDossierIds); + + // add attributes and ACL - already filtered before loading + enhanceDossiersWithAttributeAndACLData(dossiers,false); + + // build response + var responseMap = new LinkedHashMap(); + for (var dossier : dossiers) { + responseMap.put(dossier.getId(), dossier); + } + + return new JSONPrimitive<>(responseMap); + } + + @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") public Dossier getDossier(@PathVariable(DOSSIER_ID_PARAM) String dossierId, @RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived, @@ -418,70 +460,45 @@ public class DossierController implements DossierResource { @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") - @PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')") public List getDossiers(@RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived, @RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted) { - var dossiers = dossierManagementService.getAllDossiers(includeArchived, includeDeleted) - .stream() - .map(dossierACLService::enhanceDossierWithACLData) - .collect(Collectors.toList()); - dossiers.forEach(dossier -> dossier.setDossierAttributes(convertDossierAttributes(dossierAttributePersistenceService.getDossierAttributes(dossier.getId())))); - return dossiers; + var dossiers = dossierManagementService.getAllDossiers(includeArchived, includeDeleted); + return enhanceDossiersWithAttributeAndACLData(dossiers); } @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") - @PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')") public List getDossiersForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived, @RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted) { - var dossiers = dossierManagementService.getAllDossiersForDossierTemplateId(dossierTemplateId, includeArchived, includeDeleted) - .stream() - .map(dossierACLService::enhanceDossierWithACLData) - .collect(Collectors.toList()); - dossiers.forEach(dossier -> dossier.setDossierAttributes(convertDossierAttributes(dossierAttributePersistenceService.getDossierAttributes(dossier.getId())))); - return dossiers; + var dossiers = dossierManagementService.getAllDossiersForDossierTemplateId(dossierTemplateId, includeArchived, includeDeleted); + return enhanceDossiersWithAttributeAndACLData(dossiers); } @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") - @PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')") public List getSoftDeletedDossiers() { - var dossiers = dossierManagementService.getSoftDeletedDossiers() - .stream() - .map(dossierACLService::enhanceDossierWithACLData) - .collect(Collectors.toList()); - dossiers.forEach(dossier -> dossier.setDossierAttributes(convertDossierAttributes(dossierAttributePersistenceService.getDossierAttributes(dossier.getId())))); - return dossiers; + var dossiers = dossierManagementService.getSoftDeletedDossiers(); + return enhanceDossiersWithAttributeAndACLData(dossiers); } @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") - @PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')") public List getArchivedDossiers() { - var dossiers = dossierManagementService.getArchivedDossiers() - .stream() - .map(dossierACLService::enhanceDossierWithACLData) - .collect(Collectors.toList()); - dossiers.forEach(dossier -> dossier.setDossierAttributes(convertDossierAttributes(dossierAttributePersistenceService.getDossierAttributes(dossier.getId())))); - return dossiers; + var dossiers = dossierManagementService.getArchivedDossiers(); + return enhanceDossiersWithAttributeAndACLData(dossiers); } @PreAuthorize("hasAuthority('" + READ_DOSSIER + "')") - @PostFilter("hasPermission(filterObject.id, 'Dossier', 'VIEW_OBJECT')") public List getArchivedDossiersForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) { - var dossiers = dossierManagementService.getArchivedDossiersForDossierTemplateId(dossierTemplateId) - .stream() - .map(dossierACLService::enhanceDossierWithACLData) - .collect(Collectors.toList()); - dossiers.forEach(dossier -> dossier.setDossierAttributes(convertDossierAttributes(dossierAttributePersistenceService.getDossierAttributes(dossier.getId())))); - return dossiers; + var dossiers = dossierManagementService.getArchivedDossiersForDossierTemplateId(dossierTemplateId); + return enhanceDossiersWithAttributeAndACLData(dossiers); } @@ -586,5 +603,31 @@ public class DossierController implements DossierResource { return new DossierAttributes(attributeIdToValue); } + private List enhanceDossiersWithAttributeAndACLData(List dossiers) { + + return enhanceDossiersWithAttributeAndACLData(dossiers, true); + } + + private List enhanceDossiersWithAttributeAndACLData(List dossiers, boolean filter) { + + // filter first, only load attributes and ACL for viewable dossiers + List filteredDossiers = filter ? filterByPermissionsService.onlyViewableDossiers(dossiers) : dossiers; + + // load all attributes at once + var attributes = dossierAttributePersistenceService.getDossierAttributes(filteredDossiers.stream().map(Dossier::getId).collect(Collectors.toSet())); + var attributesMap = new HashMap>(); + for (DossierAttributeEntity attribute : attributes) { + attributesMap.computeIfAbsent(attribute.getId().getDossierId(), k -> new ArrayList<>()).add(attribute); + } + + for (var dossier : filteredDossiers) { + // set attributes + dossier.setDossierAttributes(convertDossierAttributes(attributesMap.getOrDefault(dossier.getId(), new ArrayList<>()))); + // set ACL data + dossierACLService.enhanceDossierWithACLData(dossier); + } + return filteredDossiers; + } + } 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/StatusController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/StatusController.java index 126cbf294..31bb0ec38 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/StatusController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/StatusController.java @@ -14,11 +14,16 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; 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 org.springframework.web.bind.annotation.RestController; import com.iqser.red.service.persistence.management.v1.processor.acl.custom.dossier.DossierACLService; @@ -30,6 +35,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.Approva import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusMapper; +import com.iqser.red.service.persistence.management.v1.processor.service.FilterByPermissionsService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; @@ -39,6 +45,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AddNotificationRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; @@ -46,6 +53,9 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.notificatio import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -67,6 +77,7 @@ public class StatusController implements StatusResource { private final NotificationPersistenceService notificationPersistenceService; private final DossierACLService dossierACLService; private final ApprovalVerificationService approvalVerificationService; + private final FilterByPermissionsService filterByPermissionsService; @Override @@ -82,6 +93,23 @@ public class StatusController implements StatusResource { } + @Override + @PreAuthorize("hasAuthority('" + READ_FILE_STATUS + "')") + public JSONPrimitive>> getFilesByIds(@RequestBody JSONPrimitive>> filesByDossier) { + + // filter dossiers by view + var accessibleDossierIds = filterByPermissionsService.onlyViewableDossierIds(new ArrayList<>(filesByDossier.getValue().keySet())); + var response = new HashMap>(); + for (var dossierId : accessibleDossierIds) { + var allFoundFiles = fileStatusManagementService.findAllDossierIdAndIds(dossierId, filesByDossier.getValue().get(dossierId)); + response.put(dossierId, allFoundFiles.stream().map(FileStatusMapper::toFileStatus).collect(Collectors.toList())); + } + + return new JSONPrimitive<>(response); + + } + + @Override @PreAuthorize("hasAuthority('" + READ_FILE_STATUS + "')") public Map> getDossierStatus(@RequestBody List dossierIds) { diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DossierResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DossierResource.java index dc53419f0..73b2a7e39 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DossierResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DossierResource.java @@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.service.v1.api.external.resource; import java.time.OffsetDateTime; import java.util.List; +import java.util.Map; import java.util.Set; import org.springframework.http.HttpStatus; @@ -17,6 +18,7 @@ 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.DossierChangeEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeResponseV2; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierInformation; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; @@ -29,10 +31,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; public interface DossierResource { String DOSSIER_REST_PATH = ExternalApi.BASE_PATH + "/dossier"; + String BY_ID_PATH = "/by-id"; String DOSSIER_TEMPLATE_PATH = "/dossier-template"; String DOSSIER_INFO_PATH = "/info"; String DELETED_DOSSIERS_PATH = ExternalApi.BASE_PATH + "/deleted-dossiers"; String CHANGES_DETAILS_PATH = "/changes/details"; + String CHANGES_DETAILS_V2_PATH = "/changes/details/v2"; String HARD_DELETE_PATH = "/hard-delete"; String UNDELETE_PATH = "/restore"; @@ -62,6 +66,12 @@ public interface DossierResource { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success")}) List changesSince(@RequestBody JSONPrimitive since); + @ResponseBody + @PostMapping(value = DOSSIER_REST_PATH + CHANGES_DETAILS_V2_PATH, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "See if there are changes to dossiers since param", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success")}) + DossierChangeResponseV2 changesSinceV2(@RequestBody JSONPrimitive since); + @ResponseBody @PostMapping(value = DOSSIER_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @@ -95,6 +105,13 @@ public interface DossierResource { List getDossiers(@RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived, @RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted); + @ResponseStatus(value = HttpStatus.OK) + @ResponseBody + @PostMapping(value = DOSSIER_REST_PATH+BY_ID_PATH, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Gets dossiers by ids.", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) + JSONPrimitive> getDossiersByIds(@RequestBody JSONPrimitive> dossierIds); + @ResponseStatus(value = HttpStatus.OK) @ResponseBody diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java index 6abd5cb84..8fba126c5 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/StatusResource.java @@ -3,6 +3,7 @@ package com.iqser.red.service.persistence.service.v1.api.external.resource; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; +import java.util.Set; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse; import io.swagger.v3.oas.annotations.Operation; @@ -25,6 +27,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; public interface StatusResource { String STATUS_REST_PATH = ExternalApi.BASE_PATH + "/status"; + String BY_ID_PATH = "/by-id"; String CHANGES_SINCE_PATH = "/changes"; String BULK_REST_PATH = "/bulk"; String ASSIGNEE_REST_PATH = "/set-assignee"; @@ -56,6 +59,14 @@ public interface StatusResource { Map> getDossierStatus(@RequestBody List dossierIds); + @ResponseStatus(value = HttpStatus.OK) + @ResponseBody + @PostMapping(value = STATUS_REST_PATH + BY_ID_PATH, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the status for files by dossierId and fileIds.", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) + JSONPrimitive>> getFilesByIds(@RequestBody JSONPrimitive>> filesByDossier); + + @ResponseStatus(value = HttpStatus.OK) @ResponseBody @PostMapping(value = STATUS_REST_PATH + DELETED_PATH, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/RedObjectIdentityRetrievalStrategy.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/RedObjectIdentityRetrievalStrategy.java index 49b891e76..6734639c4 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/RedObjectIdentityRetrievalStrategy.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/acl/RedObjectIdentityRetrievalStrategy.java @@ -5,6 +5,7 @@ import org.springframework.security.acls.model.ObjectIdentity; import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.IHavingDossierId; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import lombok.extern.slf4j.Slf4j; @@ -18,8 +19,8 @@ public class RedObjectIdentityRetrievalStrategy implements ObjectIdentityRetriev log.debug("Requesting data for object: {}", domainObject); if (domainObject instanceof Dossier) { return new ObjectIdentityImpl("Dossier", ((Dossier) domainObject).getId()); - } else if (domainObject instanceof DossierChangeEntry) { - return new ObjectIdentityImpl("Dossier", ((DossierChangeEntry) domainObject).getDossierId()); + } else if (domainObject instanceof IHavingDossierId) { + return new ObjectIdentityImpl("Dossier", ((IHavingDossierId) domainObject).getDossierId()); } else if (domainObject instanceof String) { // TODO ACL this will not work once we have more than one type. return new ObjectIdentityImpl("Dossier", (String) domainObject); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DossierIdFilterable.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DossierIdFilterable.java new file mode 100644 index 000000000..f4caf496a --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DossierIdFilterable.java @@ -0,0 +1,6 @@ +package com.iqser.red.service.persistence.management.v1.processor.model; + +public interface DossierIdFilterable { + + String getDossierId(); +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java index 48fd9d5b3..cd2bd6279 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java @@ -3,6 +3,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException; import com.iqser.red.service.persistence.management.v1.processor.utils.DossierMapper; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeResponseV2; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierInformation; import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierRequest; @@ -275,4 +276,16 @@ public class DossierManagementService { } + + public DossierChangeResponseV2 changesSinceV2(JSONPrimitive since) { + return dossierService.changesSinceV2(since.getValue()); + } + + + @Transactional + public List getDossiersByIds(Set viewableDossierIds) { + + return getConvertedAllDossiers(dossierService.getAllDossiers(viewableDossierIds), true,true); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java index 12c67769d..9a1d8ca94 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java @@ -1,6 +1,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import java.time.OffsetDateTime; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -14,6 +15,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeResponseV2; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierChange; @@ -147,7 +149,7 @@ public class DossierService { } - public List getAllDossiers(List dossierIds) { + public List getAllDossiers(Collection dossierIds) { return dossierPersistenceService.findAllDossiers(dossierIds); } @@ -188,5 +190,8 @@ public class DossierService { } + public DossierChangeResponseV2 changesSinceV2(OffsetDateTime value) { + return dossierPersistenceService.hasChangesSinceV2(value); + } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusManagementService.java index 58aa4cfc6..0df4d65a1 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusManagementService.java @@ -52,6 +52,11 @@ public class FileStatusManagementService { .collect(Collectors.toList()); } + public List findAllDossierIdAndIds(String dossierId, Set fileIds) { + + return fileStatusService.findAllDossierIdAndIds(dossierId,fileIds); + } + public List getDossierStatusIds(String dossierId, boolean includeDeleted) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index b7d4355ad..6b345735c 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -11,6 +11,7 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; + import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -1081,4 +1082,16 @@ public class FileStatusService { return fileStatusPersistenceService.findAllByDossierId(dossierId, includeDeleted); } + + @Transactional + public List findAllDossierIdAndIds(String dossierId, Set fileIds) { + + var fileModels = fileStatusPersistenceService.findAllDossierIdAndIds(dossierId, fileIds) + .stream() + .map(entity -> MagicConverter.convert(entity, FileModel.class, new FileModelMapper())) + .toList(); + + return reanalysisRequiredStatusService.enhanceFileStatusWithAnalysisRequirements(fileModels); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FilterByPermissionsService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FilterByPermissionsService.java index 10e4bb0a6..9f22cb26c 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FilterByPermissionsService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FilterByPermissionsService.java @@ -7,6 +7,7 @@ import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreFilter; import org.springframework.stereotype.Service; +import com.iqser.red.service.persistence.service.v1.api.shared.model.IHavingDossierId; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; /* @@ -17,6 +18,20 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp @Service public class FilterByPermissionsService { + @PreFilter("hasPermission(filterObject.getDossierId(), 'Dossier', 'VIEW_OBJECT')") + public List onlyViewableHavingDossierId(List items) { + + return items; + + } + + @PreFilter("hasPermission(filterObject, 'Dossier', 'VIEW_OBJECT')") + public Set onlyViewableDossierIds(Set dossierIds) { + + return dossierIds; + + } + @PreFilter("hasPermission(filterObject, 'Dossier', 'VIEW_OBJECT')") public List onlyViewableDossierIds(List dossierIds) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierAttributePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierAttributePersistenceService.java index 541df78b9..1f6e75412 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierAttributePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierAttributePersistenceService.java @@ -1,5 +1,6 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persistence; +import java.util.Collection; import java.util.List; import jakarta.transaction.Transactional; @@ -58,6 +59,11 @@ public class DossierAttributePersistenceService { return dossierAttributeRepository.findByIdDossierId(dossierId); } + public List getDossierAttributes(Collection dossierIds) { + + return dossierAttributeRepository.findByDossierIds(dossierIds); + } + public DossierAttributeEntity findOne(String dossierId, String dossierAttributeId) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierPersistenceService.java index e441eb099..b6ca5b4b8 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierPersistenceService.java @@ -24,6 +24,9 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ReportTemplateRepository; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeEntryV2; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeResponseV2; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FileChangeEntryV2; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierChange; @@ -180,7 +183,7 @@ public class DossierPersistenceService { } - public List findAllDossiers(List dossierIds) { + public List findAllDossiers(Collection dossierIds) { if (!dossierIds.isEmpty()) { return dossierRepository.findAllById(dossierIds); @@ -233,6 +236,19 @@ public class DossierPersistenceService { } + public DossierChangeResponseV2 hasChangesSinceV2(OffsetDateTime since) { + + var changedDossiers = dossierRepository.findDossierChangeProjectionByLastUpdatedIsAfter(since.truncatedTo(ChronoUnit.MILLIS)); + var changedFiles = fileRepository.findFileChangeProjectionByLastUpdatedIsAfter(since.truncatedTo(ChronoUnit.MILLIS)); + + var response = new DossierChangeResponseV2(); + response.setDossierChanges(changedDossiers.stream().map(d -> new DossierChangeEntryV2(d.getId(), d.getLastUpdated())).collect(Collectors.toList())); + response.setFileChanges(changedFiles.stream().map(f -> new FileChangeEntryV2(f.getId(), f.getDossierId(), f.getLastUpdated())).collect(Collectors.toList())); + + return response; + } + + public Set hasChangesSince(OffsetDateTime since) { var dossiersWithChanges = dossierRepository.findDossierChangeByLastUpdatedIsAfter(since.truncatedTo(ChronoUnit.MILLIS)); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java index 2e74953f0..7bfdfc599 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java @@ -3,6 +3,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persis import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -713,6 +714,11 @@ public class FileStatusPersistenceService { return fileRepository.findAllById(fileIds); } + public List findAllDossierIdAndIds(String dossierId, Set fileIds) { + + return fileRepository.findAllDossierIdAndIds(dossierId, fileIds); + } + public List findAllByDossierId(String dossierId, boolean includeDeleted) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/DossierChangeProjection.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/DossierChangeProjection.java new file mode 100644 index 000000000..b081bcb90 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/DossierChangeProjection.java @@ -0,0 +1,9 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection; + +import java.time.OffsetDateTime; + +public interface DossierChangeProjection { + + String getId(); + OffsetDateTime getLastUpdated(); +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/FileChangeProjection.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/FileChangeProjection.java new file mode 100644 index 000000000..897cc8df2 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/projection/FileChangeProjection.java @@ -0,0 +1,10 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection; + +import java.time.OffsetDateTime; + +public interface FileChangeProjection { + + String getId(); + String getDossierId(); + OffsetDateTime getLastUpdated(); +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierAttributeRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierAttributeRepository.java index d32747b92..cc5538736 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierAttributeRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierAttributeRepository.java @@ -1,5 +1,6 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository; +import java.util.Collection; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; @@ -13,6 +14,8 @@ public interface DossierAttributeRepository extends JpaRepository findByIdDossierId(String dossierId); + @Query("SELECT e FROM DossierAttributeEntity e WHERE e.id.dossierId IN :dossierIds") + List findByDossierIds(@Param("dossierIds") Collection dossierIds); @Modifying(clearAutomatically = true, flushAutomatically = true) @Query("DELETE FROM DossierAttributeEntity e WHERE e.id.dossierId = :dossierId") diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierRepository.java index d291a6df7..2c93617eb 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierRepository.java @@ -11,10 +11,14 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection.DossierChangeProjection; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection.DossierIdAndStatusProjection; public interface DossierRepository extends JpaRepository { + @Query("select d from DossierEntity d where d.lastUpdated > :since") + List findDossierChangeProjectionByLastUpdatedIsAfter(@Param("since") OffsetDateTime since); + @Query("select d.id from DossierEntity d where d.lastUpdated > :since") List findDossierChangeByLastUpdatedIsAfter(@Param("since") OffsetDateTime since); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java index 93cdfde12..f9a859e25 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java @@ -3,6 +3,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persis import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; +import java.util.Set; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -12,6 +13,8 @@ import org.springframework.data.repository.query.Param; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.projection.DossierStatsFileProjection; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection.DossierChangeProjection; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection.FileChangeProjection; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection.FilePageCountsProjection; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection.FileProcessingStatusProjection; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.projection.FileWorkflowStatusProjection; @@ -279,6 +282,10 @@ public interface FileRepository extends JpaRepository { int countSoftDeletedFilesPerDossierId(@Param("dossierId") String dossierId); + @Query("select f from FileEntity f where f.lastUpdated > :since") + List findFileChangeProjectionByLastUpdatedIsAfter(@Param("since") OffsetDateTime since); + + @Query("select distinct f.dossierId from FileEntity f where f.lastUpdated > :since") List findDossierChangeByLastUpdatedIsAfter(@Param("since") OffsetDateTime since); @@ -449,6 +456,10 @@ public interface FileRepository extends JpaRepository { @Query("SELECT f.id FROM FileEntity f WHERE f.dossierId = :dossierId AND f.hardDeletedTime IS NULL AND (f.deleted IS NULL or (f.deleted is not null and :includeDeleted = true))") List findAllByDossierId(@Param("dossierId") String dossierId, @Param("includeDeleted") boolean includeDeleted); + + @Query("SELECT f FROM FileEntity f WHERE f.id in :fileIds AND f.dossierId = :dossierId") + List findAllDossierIdAndIds(@Param("dossierId") String dossierId, @Param("fileIds") Set fileIds); + } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierStatsAndGetByIdsTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierStatsAndGetByIdsTest.java new file mode 100644 index 000000000..278644142 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierStatsAndGetByIdsTest.java @@ -0,0 +1,138 @@ +package com.iqser.red.service.peristence.v1.server.integration.tests; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.iqser.red.service.peristence.v1.server.integration.client.CustomPermissionClient; +import com.iqser.red.service.peristence.v1.server.integration.client.DossierClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.UserProvider; +import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.peristence.v1.server.integration.utils.TokenService; +import com.iqser.red.service.persistence.management.v1.processor.acl.RedPermission; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeEntryV2; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FileChangeEntryV2; +import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; +import com.iqser.red.service.persistence.service.v1.api.shared.model.permission.CustomPermissionMappingModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.permission.CustomPermissionModel; +import org.junit.jupiter.api.Test; + +public class DossierStatsAndGetByIdsTest extends AbstractPersistenceServerServiceTest { + + @Autowired + private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider; + + @Autowired + private FileTesterAndProvider fileTesterAndProvider; + + @Autowired + private DossierTesterAndProvider dossierTesterAndProvider; + + @Autowired + private CustomPermissionClient customPermissionClient; + + @Autowired + private TokenService tokenService; + + @Autowired + private UserProvider userProvider; + + @Autowired + private DossierClient dossierClient; + + @Autowired + private FileClient fileClient; + + + @Test + public void testDossierChangesGetByIdsAndViewPermissions() { + + var start = OffsetDateTime.now(); + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + dossierTemplateTesterAndProvider.provideDefaultColors(dossierTemplate.getId()); + IntStream.range(0, 5) + .forEach(x -> dossierTesterAndProvider.provideTestDossier(dossierTemplate, "test dossier: " + x)); + var allDossiers = dossierClient.getDossiers(true, true); + + var dossiersByIds = dossierClient.getDossiersByIds(new JSONPrimitive<>(allDossiers.stream().map(Dossier::getId).collect(Collectors.toSet()))); + assertThat(allDossiers).hasSameElementsAs(dossiersByIds.getValue().values()); + + // test changes for owner + var changes = dossierClient.changesSinceV2(new JSONPrimitive<>(start)); + assertThat(changes.getDossierChanges().stream().map(DossierChangeEntryV2::getDossierId)).hasSameElementsAs(allDossiers.stream() + .map(Dossier::getId) + .collect(Collectors.toSet())); + + // test changes for owner with new timestamp + var nextChanges = dossierClient.changesSinceV2(new JSONPrimitive<>(OffsetDateTime.now())); + assertThat(nextChanges.getDossierChanges()).isEmpty(); + + var before = OffsetDateTime.now(); + var testFile = fileTesterAndProvider.testAndProvideFile(allDossiers.iterator().next(), "testFile"); + nextChanges = dossierClient.changesSinceV2(new JSONPrimitive<>(before)); + assertThat(nextChanges.getDossierChanges()).isEmpty(); + assertThat(nextChanges.getFileChanges().stream().map(FileChangeEntryV2::getFileId)).containsExactly(testFile.getId()); + + var filesToLoad = new HashMap>(); + nextChanges.getFileChanges().forEach(fc -> { + filesToLoad.put(fc.getDossierId(), Set.of(fc.getFileId())); + }); + var loadedFiles = fileClient.getFilesByIds(new JSONPrimitive<>(filesToLoad)); + assertThat(loadedFiles.getValue().values().stream().flatMap(Collection::stream).collect(Collectors.toSet())).containsExactly(testFile); + + // test get byId for other user + tokenService.setUser(userProvider.getAltUserId(), "secret"); + dossiersByIds = dossierClient.getDossiersByIds(new JSONPrimitive<>(allDossiers.stream().map(Dossier::getId).collect(Collectors.toSet()))); + assertThat(allDossiers).hasSameElementsAs(dossiersByIds.getValue().values()); + + // test changes for other user + var changesUser2 = dossierClient.changesSinceV2(new JSONPrimitive<>(start)); + assertThat(changesUser2.getDossierChanges().stream().map(DossierChangeEntryV2::getDossierId)).hasSameElementsAs(allDossiers.stream() + .map(Dossier::getId) + .collect(Collectors.toSet())); + + // test changes for other user with new timestamp + var nextChangesUser2 = dossierClient.changesSinceV2(new JSONPrimitive<>(OffsetDateTime.now())); + assertThat(nextChangesUser2.getDossierChanges()).isEmpty(); + + setPermissionsNobodyExceptOwnerCanView(); + + dossiersByIds = dossierClient.getDossiersByIds(new JSONPrimitive<>(allDossiers.stream().map(Dossier::getId).collect(Collectors.toSet()))); + assertThat(dossiersByIds.getValue().values()).isEmpty(); + + // no visible changes either after permissions removed + changesUser2 = dossierClient.changesSinceV2(new JSONPrimitive<>(start)); + assertThat(changesUser2.getDossierChanges()).isEmpty(); + + } + + + private void setPermissionsNobodyExceptOwnerCanView() { + + CustomPermissionModel targetViewPermission = new CustomPermissionModel(RedPermission.VIEW_OBJECT.getMask(), + RedPermission.VIEW_OBJECT.getName(), + RedPermission.VIEW_OBJECT.getSort(), + false); + List mappedViewPermissions = new ArrayList<>(); + List customPermissionMappingModels = new ArrayList<>(); + customPermissionMappingModels.add(new CustomPermissionMappingModel(targetViewPermission, mappedViewPermissions)); + + customPermissionClient.saveCustomPermissionMappings("Dossier", customPermissionMappingModels); + customPermissionClient.syncAllCustomPermissions(); + } + +} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index f4491f27c..f18b4e5c9 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -645,7 +645,10 @@ public abstract class AbstractPersistenceServerServiceTest { public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) { var allRoles = getAllRoles(); - UserDetails user = User.withUsername("manageradmin1@test.com").password(passwordEncoder.encode("secret")).roles(allRoles).authorities(getAllRoles()).build(); + UserDetails user1 = User.withUsername("manageradmin1@test.com") + .password(passwordEncoder.encode("secret")).roles(allRoles).authorities(getAllRoles()).build(); + UserDetails user2 = User.withUsername("manageradmin2@test.com") + .password(passwordEncoder.encode("secret")).roles(allRoles).authorities(getAllRoles()).build(); var allRolesWithoutRedUserOrRedManager = Arrays.stream(allRoles) .filter(s -> !(s.equalsIgnoreCase(ApplicationRoles.RED_USER_ROLE) || s.equalsIgnoreCase(ApplicationRoles.RED_MANAGER_ROLE))) .collect(Collectors.toList()); @@ -654,7 +657,7 @@ public abstract class AbstractPersistenceServerServiceTest { .roles(allRolesWithoutRedUserOrRedManager.toArray(new String[0])) .authorities(getAllRoles()) .build(); - return new InMemoryUserDetailsManager(user, userWithoutRedUserOrRedManager); + return new InMemoryUserDetailsManager(user1,user2, userWithoutRedUserOrRedManager); } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntry.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntry.java index 17c511ce1..932e63e95 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntry.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntry.java @@ -5,7 +5,7 @@ import lombok.Data; @Data @AllArgsConstructor -public class DossierChangeEntry { +public class DossierChangeEntry implements IHavingDossierId { private String dossierId; private boolean dossierChanges; diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntryV2.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntryV2.java new file mode 100644 index 000000000..c584c8528 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeEntryV2.java @@ -0,0 +1,15 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model; + +import java.time.OffsetDateTime; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class DossierChangeEntryV2 implements IHavingDossierId { + + private String dossierId; + private OffsetDateTime lastUpdated; + +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeResponseV2.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeResponseV2.java new file mode 100644 index 000000000..a3ccbbb3f --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/DossierChangeResponseV2.java @@ -0,0 +1,18 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model; + +import java.util.ArrayList; +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DossierChangeResponseV2 { + + private List dossierChanges = new ArrayList<>(); + private List fileChanges = new ArrayList<>(); + +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/FileChangeEntryV2.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/FileChangeEntryV2.java new file mode 100644 index 000000000..10673dc0a --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/FileChangeEntryV2.java @@ -0,0 +1,18 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model; + +import java.time.OffsetDateTime; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class FileChangeEntryV2 implements IHavingDossierId { + + private String fileId; + private String dossierId; + private OffsetDateTime lastUpdated; + +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/IHavingDossierId.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/IHavingDossierId.java new file mode 100644 index 000000000..7c4162524 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/IHavingDossierId.java @@ -0,0 +1,6 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model; + +public interface IHavingDossierId { + + String getDossierId(); +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/Dossier.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/Dossier.java index e962ad6e0..eaab3e7e8 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/Dossier.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/Dossier.java @@ -35,6 +35,7 @@ public class Dossier { private OffsetDateTime startDate; private OffsetDateTime dueDate; private OffsetDateTime archivedTime; + private OffsetDateTime lastUpdated; private String dossierTemplateId; private String dossierStatusId; private DossierVisibility visibility;