Merge branch 'RED-9717' into 'master'

RED-9717 - Add warnings on approval

Closes RED-9717

See merge request redactmanager/persistence-service!632
This commit is contained in:
Andrei Isvoran 2024-08-19 14:27:38 +02:00
commit 4eeee75f33
12 changed files with 435 additions and 34 deletions

View File

@ -26,6 +26,7 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.BadRe
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
import com.iqser.red.service.persistence.management.v1.processor.service.ApprovalVerificationService;
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;
@ -42,6 +43,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
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;
import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
import jakarta.transaction.Transactional;
@ -64,6 +66,7 @@ public class StatusController implements StatusResource {
private final AccessControlService accessControlService;
private final NotificationPersistenceService notificationPersistenceService;
private final DossierACLService dossierACLService;
private final ApprovalVerificationService approvalVerificationService;
@Override
@ -299,31 +302,40 @@ public class StatusController implements StatusResource {
@PreAuthorize("hasAuthority('" + SET_STATUS_APPROVED + "')")
public void setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
public ApproveResponse setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force) {
accessControlService.checkAccessPermissionsToDossier(dossierId);
accessControlService.verifyUserIsApprover(dossierId);
setStatusApprovedForFile(dossierId, fileId);
auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Document status was changed to Approved")
.details(Map.of(DOSSIER_ID, dossierId))
.build());
var dossier = dossierACLService.enhanceDossierWithACLData(dossierManagementService.getDossierById(dossierId, false, false));
if (!dossier.getOwnerId().equals(KeycloakSecurity.getUserId())) {
var fileStatus = fileStatusManagementService.getFileStatus(fileId);
notificationPersistenceService.insertNotification(AddNotificationRequest.builder()
.userId(dossier.getOwnerId())
.issuerId(KeycloakSecurity.getUserId())
.notificationType(NotificationType.DOCUMENT_APPROVED.name())
.target(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, FILE_NAME, fileStatus.getFilename()))
.build());
ApproveResponse approveResponse = new ApproveResponse(false, new HashMap<>());
if (!force) {
approveResponse = approvalVerificationService.verifyApprovalOfFile(dossierId, fileId);
}
if (!approveResponse.isHasWarnings()) {
setStatusApprovedForFile(dossierId, fileId);
auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Document status was changed to Approved")
.details(Map.of(DOSSIER_ID, dossierId))
.build());
var dossier = dossierACLService.enhanceDossierWithACLData(dossierManagementService.getDossierById(dossierId, false, false));
if (!dossier.getOwnerId().equals(KeycloakSecurity.getUserId())) {
var fileStatus = fileStatusManagementService.getFileStatus(fileId);
notificationPersistenceService.insertNotification(AddNotificationRequest.builder()
.userId(dossier.getOwnerId())
.issuerId(KeycloakSecurity.getUserId())
.notificationType(NotificationType.DOCUMENT_APPROVED.name())
.target(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, FILE_NAME, fileStatus.getFilename()))
.build());
}
}
return approveResponse;
}
@ -398,14 +410,22 @@ public class StatusController implements StatusResource {
@Override
@PreAuthorize("hasAuthority('" + SET_STATUS_APPROVED + "')")
public void setStatusApprovedForList(String dossierId, List<String> fileIds) {
public List<ApproveResponse> setStatusApprovedForList(String dossierId,
List<String> fileIds,
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force) {
List<ApproveResponse> approveResponses = new ArrayList<>();
accessControlService.checkAccessPermissionsToDossier(dossierId);
accessControlService.verifyUserIsApprover(dossierId);
dossierManagementService.getDossierById(dossierId, false, false);
fileIds.forEach(fileId -> setStatusApproved(dossierId, fileId));
if (fileIds.size() > 50) {
throw new BadRequestException("Maximum amount of files that can be approved at once is 50.");
}
fileIds.forEach(fileId -> approveResponses.add(setStatusApproved(dossierId, fileId, force)));
return approveResponses;
}

View File

@ -16,6 +16,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.warning.ApproveResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@ -35,6 +36,7 @@ public interface StatusResource {
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
String ASSIGNEE_ID_REQUEST_PARAM = "assigneeId";
String FORCE_REQUEST_PARAM = "force";
String DELETED_PATH = "/softdeleted";
@ -105,11 +107,13 @@ public interface StatusResource {
@RequestParam(value = ASSIGNEE_ID_REQUEST_PARAM, required = false) String assigneeId);
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = STATUS_REST_PATH + "/approved" + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Sets the status APPROVED for a file.", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")})
void setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden")})
ApproveResponse setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force);
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@ -139,11 +143,13 @@ public interface StatusResource {
@RequestParam(value = ASSIGNEE_ID_REQUEST_PARAM, required = false) String assigneeId);
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = STATUS_REST_PATH + "/approved" + DOSSIER_ID_PATH_VARIABLE + BULK_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Sets the status APPROVED for a list of files.", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
void setStatusApprovedForList(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody List<String> fileIds);
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
List<ApproveResponse> setStatusApprovedForList(@PathVariable(DOSSIER_ID) String dossierId,
@RequestBody List<String> fileIds,
@RequestParam(value = FORCE_REQUEST_PARAM, required = false, defaultValue = "false") boolean force);
@ResponseStatus(value = HttpStatus.NO_CONTENT)

View File

@ -0,0 +1,89 @@
package com.iqser.red.service.persistence.management.v1.processor.service;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position;
import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.ApproveResponse;
import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningType;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
@Service
@RequiredArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class ApprovalVerificationService {
EntityLogService entityLogService;
LegalBasisMappingPersistenceService legalBasisMappingPersistenceService;
DossierRepository dossierRepository;
public ApproveResponse verifyApprovalOfFile(String dossierId, String fileId) {
ApproveResponse approveResponse = new ApproveResponse();
EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, true);
List<EntityLogEntry> entityLogEntries = entityLog.getEntityLogEntry();
List<LegalBasisEntity> legalBasisMappings = legalBasisMappingPersistenceService.getLegalBasisMapping(dossierRepository.findDossierTemplateId(dossierId));
for (EntityLogEntry entry : entityLogEntries) {
if (entry.getState().equals(EntryState.APPLIED) && !entry.getEntryType().equals(EntryType.IMAGE) && !entry.getEntryType().equals(EntryType.IMAGE_HINT)) {
if (StringUtils.isEmpty(entry.getLegalBasis())) {
addWarning(entry, fileId, WarningType.LEGAL_BASIS_MISSING, approveResponse);
} else {
var legalBasisEntity = legalBasisMappings.stream()
.filter(mapping -> mapping.getReason().equals(entry.getLegalBasis()))
.findFirst();
if (legalBasisEntity.isEmpty() || StringUtils.isEmpty(legalBasisEntity.get().getTechnicalName())) {
addWarning(entry, fileId, WarningType.UNMAPPED_JUSTIFICATION, approveResponse);
}
}
}
if (entry.getState().equals(EntryState.PENDING)) {
addWarning(entry, fileId, WarningType.PENDING_CHANGE, approveResponse);
}
}
approveResponse.setHasWarnings(approveResponse.getFileWarnings() != null && !approveResponse.getFileWarnings().isEmpty());
return approveResponse;
}
private void addWarning(EntityLogEntry entry, String fileId, WarningType warningType, ApproveResponse approveResponse) {
approveResponse.addFileWarning(fileId,
WarningModel.builder()
.id(entry.getId())
.pages(entry.getPositions()
.stream()
.map(Position::getPageNumber)
.collect(Collectors.toSet()))
.value(shortenValue(entry.getValue()))
.warningType(warningType)
.type(entry.getType())
.build());
}
private String shortenValue(String value) {
if (value.length() > 100) {
return value.substring(0, 97) + "...";
}
return value;
}
}

View File

@ -0,0 +1,189 @@
package com.iqser.red.service.peristence.v1.server.integration.tests;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
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.TypeProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position;
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 com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningType;
public class ApprovalTest extends AbstractPersistenceServerServiceTest {
@Autowired
private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;
@Autowired
private FileTesterAndProvider fileTesterAndProvider;
@Autowired
private DossierTesterAndProvider dossierTesterAndProvider;
@Autowired
private TypeProvider typeProvider;
@Autowired
private FileClient fileClient;
@SpyBean
private LegalBasisMappingPersistenceService legalBasisMappingPersistenceService;
@Test
public void testApprovalNoWarnings() {
DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());
when(legalBasisMappingPersistenceService.getLegalBasisMapping(anyString())).thenReturn(List.of(LegalBasisEntity.builder()
.technicalName("legal_basis")
.reason("legalBasis")
.build()));
EntityLog entityLog = new EntityLog();
entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
.id("id1")
.positions(List.of(new Position(1, 1, 1, 1, 1)))
.state(EntryState.APPLIED)
.legalBasis("legalBasis")
.entryType(EntryType.ENTITY)
.value("value")
.build()));
when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);
ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false);
assertFalse(approveResponse.isHasWarnings());
assertTrue(approveResponse.getFileWarnings().isEmpty());
}
@Test
public void testApprovalWithWarnings() {
DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());
EntityLog entityLog = new EntityLog();
entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
.id("id1")
.positions(List.of(new Position(1, 1, 1, 1, 1)))
.state(EntryState.APPLIED)
.entryType(EntryType.ENTITY)
.value("value")
.build(),
EntityLogEntry.builder()
.id("id2")
.positions(List.of(new Position(1, 1, 1, 1, 2)))
.state(EntryState.PENDING)
.entryType(EntryType.ENTITY)
.legalBasis("legalBasis")
.value("value")
.build()));
when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);
ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false);
assertTrue(approveResponse.isHasWarnings());
assertFalse(approveResponse.getFileWarnings().isEmpty());
assertEquals(approveResponse.getFileWarnings()
.get(file.getFileId())
.stream()
.filter(c -> c.getWarningType().equals(WarningType.PENDING_CHANGE))
.count(), 1);
assertEquals(approveResponse.getFileWarnings()
.get(file.getFileId())
.stream()
.filter(c -> c.getWarningType().equals(WarningType.LEGAL_BASIS_MISSING))
.count(), 1);
}
@Test
public void testApprovalWithWarningValueTooLoong() {
DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());
EntityLog entityLog = new EntityLog();
entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
.id("id2")
.positions(List.of(new Position(1, 1, 1, 1, 2)))
.state(EntryState.PENDING)
.legalBasis("legalBasis")
.value(StringUtils.repeat("a", 1000))
.build()));
when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);
ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false);
assertTrue(approveResponse.isHasWarnings());
assertFalse(approveResponse.getFileWarnings().isEmpty());
assertEquals(approveResponse.getFileWarnings()
.get(file.getFileId())
.get(0).getValue().length(), 100);
assertEquals(approveResponse.getFileWarnings()
.get(file.getFileId())
.get(0).getWarningType(), WarningType.PENDING_CHANGE);
}
@Test
public void testForceApprovalWithIssues() {
DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());
EntityLog entityLog = new EntityLog();
entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
.id("id2")
.positions(List.of(new Position(1, 1, 1, 1, 2)))
.state(EntryState.PENDING)
.legalBasis("legalBasis")
.value(StringUtils.repeat("a", 1000))
.build()));
when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);
ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), true);
assertFalse(approveResponse.isHasWarnings());
assertTrue(approveResponse.getFileWarnings().isEmpty());
}
}

View File

@ -255,7 +255,7 @@ public class DownloadPreparationTest extends AbstractPersistenceServerServiceTes
fileTesterAndProvider.markFileAsProcessed(getDossierId(), getFileId());
fileClient.setStatusApproved(getDossierId(), getFileId());
fileClient.setStatusApproved(getDossierId(), getFileId(), true);
assertThatTestFileIsApproved();
}

View File

@ -83,7 +83,7 @@ public class DownloadTest extends AbstractPersistenceServerServiceTest {
fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file2.getFileId());
fileClient.setStatusApproved(dossier.getId(), file2.getId());
fileClient.setStatusApproved(dossier.getId(), file2.getId(), true);
var file22 = fileClient.getFileStatus(dossier.getId(), file2.getId());
assertThat(file22.getWorkflowStatus()).isEqualTo(WorkflowStatus.APPROVED);

View File

@ -299,7 +299,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
assertThat(loadedFile.getLastApprover()).isEqualTo(userId);
fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());
fileClient.setStatusApproved(dossier.getId(), file.getId());
fileClient.setStatusApproved(dossier.getId(), file.getId(), true);
loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.APPROVED);
assertThat(loadedFile.getAssignee()).isEqualTo(userId);
@ -322,7 +322,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
assertThat(loadedFile.getLastReviewer()).isEqualTo(userId);
assertThat(loadedFile.getLastApprover()).isEqualTo(altUserId);
fileClient.setStatusApproved(dossier.getId(), file.getId());
fileClient.setStatusApproved(dossier.getId(), file.getId(), true);
loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.APPROVED);
assertThat(loadedFile.getAssignee()).isEqualTo(userId);

View File

@ -373,7 +373,7 @@ public class ReportTemplateTest extends AbstractPersistenceServerServiceTest {
var file = fileTesterAndProvider.testAndProvideFile(dossier);
fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());
fileClient.setStatusApproved(dossier.getId(), file.getId());
fileClient.setStatusApproved(dossier.getId(), file.getId(), true);
// Act & Assert
var availableTemplates = reportTemplateClient.getAvailableReportTemplates(dossier.getDossierTemplateId());

View File

@ -0,0 +1,39 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.warning;
import static com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningsComparatorUtils.WARNING_MODEL_COMPARATOR;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class ApproveResponse {
private boolean hasWarnings;
private Map<String, List<WarningModel>> fileWarnings = new HashMap<>();
public void addFileWarning(String fileId, WarningModel warningModel) {
if (fileWarnings.containsKey(fileId)) {
fileWarnings.get(fileId).add(warningModel);
} else {
List<WarningModel> warningModels = new ArrayList<>();
warningModels.add(warningModel);
fileWarnings.put(fileId, warningModels);
}
fileWarnings.get(fileId).sort(WARNING_MODEL_COMPARATOR);
}
}

View File

@ -0,0 +1,26 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.warning;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class WarningModel {
private String id;
private String value;
private Set<Integer> pages;
private String type;
private WarningType warningType;
}

View File

@ -0,0 +1,16 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.warning;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum WarningType {
PENDING_CHANGE("pending change"),
LEGAL_BASIS_MISSING("legal basis missing"),
UNMAPPED_JUSTIFICATION("unmapped justification");
private final String name;
}

View File

@ -0,0 +1,16 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.warning;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import lombok.experimental.UtilityClass;
@UtilityClass
public class WarningsComparatorUtils {
public static final Comparator<Set<Integer>> LIST_COMPARATOR = Comparator.comparingInt(Collections::min);
public static final Comparator<WarningModel> WARNING_MODEL_COMPARATOR = (wm1, wm2) -> LIST_COMPARATOR.compare(wm1.getPages(), wm2.getPages());
}