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/DictionaryController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DictionaryController.java index d494dd61c..5afb9e2b2 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DictionaryController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DictionaryController.java @@ -30,6 +30,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.Diction import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils; import com.iqser.red.service.persistence.management.v1.processor.utils.TypeValueMapper; +import com.iqser.red.service.persistence.service.v1.api.external.model.UpdateEntries; import com.iqser.red.service.persistence.service.v1.api.external.resource.DictionaryResource; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; @@ -110,6 +111,31 @@ public class DictionaryController implements DictionaryResource { } + @Override + public void updateEntries(String type, String dossierTemplateId, UpdateEntries updateEntries, String dossierId, DictionaryEntryType dictionaryEntryType) { + + if (dossierId == null) { + dictionaryService.updateGlobalEntries(type, dossierTemplateId, updateEntries.entriesToAdd(), updateEntries.entriesToDelete(), dictionaryEntryType); + } else { + accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId); + dictionaryService.updateDossierEntries(type, dossierTemplateId, updateEntries.entriesToAdd(), updateEntries.entriesToDelete(), dossierId, dictionaryEntryType); + } + + auditClient.insertRecord(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(dossierTemplateId) + .category(AuditCategory.DICTIONARY.name()) + .message("Dictionary entries were updated.") + .details(Map.of("Type", + type, + "Number of added entries", + updateEntries.entriesToAdd().size(), + "Number of deleted entries", + updateEntries.entriesToDelete().size())) + .build()); + } + + @Override public void deleteEntries(@PathVariable(TYPE_PARAMETER_NAME) String type, @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/model/UpdateEntries.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/model/UpdateEntries.java new file mode 100644 index 000000000..7d95703b1 --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/model/UpdateEntries.java @@ -0,0 +1,7 @@ +package com.iqser.red.service.persistence.service.v1.api.external.model; + +import java.util.List; + +public record UpdateEntries(List entriesToAdd, List entriesToDelete) { + +} diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DictionaryResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DictionaryResource.java index 05ae8cf90..4d72f5e18 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DictionaryResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/DictionaryResource.java @@ -17,6 +17,7 @@ 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.v1.api.external.model.UpdateEntries; import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue; @@ -53,6 +54,7 @@ public interface DictionaryResource { String MERGED = "/merged"; String DELETE = "/delete"; String DIFFERENCE = "/difference"; + String UPDATE = "/update"; String UPDATE_FLAG = "/updateFlag"; @@ -101,6 +103,17 @@ public interface DictionaryResource { @RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType); + @ResponseStatus(HttpStatus.NO_CONTENT) + @PostMapping(value = DICTIONARY_REST_PATH + UPDATE + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Update dictionary entries with type.", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully updated the dictionary entries."), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The dossier or the entry type is not found."), @ApiResponse(responseCode = "403", description = "Forbidden")}) + void updateEntries(@PathVariable(TYPE_PARAMETER_NAME) String type, + @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, + @RequestBody UpdateEntries updateEntries, + @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId, + @RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType); + + @ResponseStatus(HttpStatus.NO_CONTENT) @PostMapping(value = TYPE_PATH + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Updates colors, hint and caseInsensitive of an entry type. Only label, colors and description are updatable for system managed entry types", description = "None") diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java index 9f937875e..f596613f9 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java @@ -24,6 +24,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import com.iqser.red.service.dictionarymerge.commons.CommonsDictionaryModel; import com.iqser.red.service.dictionarymerge.commons.DictionaryEntry; @@ -124,6 +125,37 @@ public class DictionaryService { } + @PreAuthorize("hasAuthority('" + ADD_DICTIONARY_ENTRY + "') and hasAuthority('" + DELETE_DICTIONARY_ENTRY + "')") + @Transactional + public void updateGlobalEntries(String type, String dossierTemplateId, List entriesToAdd, List entriesToDelete, DictionaryEntryType dictionaryEntryType) { + + if (entriesToDelete != null && !entriesToDelete.isEmpty()) { + deleteGlobalEntries(type, dossierTemplateId, entriesToDelete, dictionaryEntryType); + } + if (entriesToAdd != null && !entriesToAdd.isEmpty()) { + addGlobalEntries(type, dossierTemplateId, entriesToAdd, false, dictionaryEntryType); + } + } + + + @PreAuthorize("hasAuthority('" + ADD_DOSSIER_DICTIONARY_ENTRY + "') and hasAuthority('" + DELETE_DOSSIER_DICTIONARY_ENTRY + "')") + @Transactional + public void updateDossierEntries(String type, + String dossierTemplateId, + List entriesToAdd, + List entriesToDelete, + String dossierId, + DictionaryEntryType dictionaryEntryType) { + + if (entriesToDelete != null && !entriesToDelete.isEmpty()) { + deleteDossierEntries(type, dossierTemplateId, entriesToDelete, dossierId, dictionaryEntryType); + } + if (entriesToAdd != null && !entriesToAdd.isEmpty()) { + addDossierEntries(type, dossierTemplateId, entriesToAdd, false, dossierId, dictionaryEntryType); + } + } + + @PreAuthorize("hasAuthority('" + ADD_UPDATE_DICTIONARY_TYPE + "')") public void updateGlobalType(String type, String dossierTemplateId, UpdateTypeValue typeValue) { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java index 7a9888bf5..354c59727 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java @@ -24,6 +24,7 @@ import com.iqser.red.service.peristence.v1.server.integration.service.DossierTes import com.iqser.red.service.peristence.v1.server.integration.service.TypeProvider; import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryService; +import com.iqser.red.service.persistence.service.v1.api.external.model.UpdateEntries; import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue; import com.iqser.red.service.persistence.service.v1.api.shared.model.UpdateTypeValue; @@ -492,6 +493,108 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { } + @Test + public void testUpdateGlobalEntries() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "dossier"); + var createdType = createDossierRedactionsDictionary(dossierTemplate.getId()); + + var word1 = "Luke Skywalker"; + var word2 = "Anakin Skywalker"; + var word3 = "Yoda"; + + var entriesToAdd = new ArrayList(); + entriesToAdd.add(word1); + entriesToAdd.add(word2); + entriesToAdd.add(word3); + dictionaryClient.addEntry(createdType.getType(), createdType.getDossierTemplateId(), entriesToAdd, false, dossier.getId(), DictionaryEntryType.ENTRY); + + var dictionary = dictionaryClient.getDictionaryForType(createdType.getType(), createdType.getDossierTemplateId(), dossier.getId()); + assertThat(dictionary.getEntries().size()).isEqualTo(3); + + var word4 = "Padme"; + var word5 = "Obiwan"; + entriesToAdd.clear(); + entriesToAdd.add(word4); + entriesToAdd.add(word5); + var entriesToDelete = new ArrayList(); + entriesToDelete.add(word1); + entriesToDelete.add(word2); + UpdateEntries updateEntries = new UpdateEntries(entriesToAdd, entriesToDelete); + dictionaryClient.updateEntries(createdType.getType(), createdType.getDossierTemplateId(), updateEntries, dossier.getId(), DictionaryEntryType.ENTRY); + + dictionary = dictionaryClient.getDictionaryForType(createdType.getType(), createdType.getDossierTemplateId(), dossier.getId()); + assertThat(dictionary.getEntries().size()).isEqualTo(3); + assertTrue(dictionary.getEntries() + .stream() + .anyMatch(entry -> entry.equals("Yoda"))); + assertTrue(dictionary.getEntries() + .stream() + .anyMatch(entry -> entry.equals("Padme"))); + assertTrue(dictionary.getEntries() + .stream() + .anyMatch(entry -> entry.equals("Obiwan"))); + assertTrue(dictionary.getEntries() + .stream() + .noneMatch(entry -> entry.equals("Luke Skywalker"))); + assertTrue(dictionary.getEntries() + .stream() + .noneMatch(entry -> entry.equals("Anakin Skywalker"))); + } + + + @Test + public void testUpdateDossierEntries() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var createdType = createDossierRedactionsDictionary(dossierTemplate.getId()); + + var word1 = "Luke Skywalker"; + var word2 = "Anakin Skywalker"; + var word3 = "Yoda"; + + var entriesToAdd = new ArrayList(); + entriesToAdd.add(word1); + entriesToAdd.add(word2); + entriesToAdd.add(word3); + dictionaryClient.addEntry(createdType.getType(), createdType.getDossierTemplateId(), entriesToAdd, false, null, DictionaryEntryType.ENTRY); + + var dictionary = dictionaryClient.getDictionaryForType(createdType.getType(), createdType.getDossierTemplateId(), null); + assertThat(dictionary.getEntries().size()).isEqualTo(3); + + var word4 = "Padme"; + var word5 = "Obiwan"; + entriesToAdd.clear(); + entriesToAdd.add(word4); + entriesToAdd.add(word5); + var entriesToDelete = new ArrayList(); + entriesToDelete.add(word1); + entriesToDelete.add(word2); + UpdateEntries updateEntries = new UpdateEntries(entriesToAdd, entriesToDelete); + dictionaryClient.updateEntries(createdType.getType(), createdType.getDossierTemplateId(), updateEntries, null, DictionaryEntryType.ENTRY); + + dictionary = dictionaryClient.getDictionaryForType(createdType.getType(), createdType.getDossierTemplateId(), null); + assertThat(dictionary.getEntries().size()).isEqualTo(3); + assertTrue(dictionary.getEntries() + .stream() + .anyMatch(entry -> entry.equals("Yoda"))); + assertTrue(dictionary.getEntries() + .stream() + .anyMatch(entry -> entry.equals("Padme"))); + assertTrue(dictionary.getEntries() + .stream() + .anyMatch(entry -> entry.equals("Obiwan"))); + assertTrue(dictionary.getEntries() + .stream() + .noneMatch(entry -> entry.equals("Luke Skywalker"))); + assertTrue(dictionary.getEntries() + .stream() + .noneMatch(entry -> entry.equals("Anakin Skywalker"))); + } + + + @Test public void testDossierTemplateAndDossierMissmatched() {