Pull request #50: RED-2325 Dossier Stats Endpoint

Merge in RED/persistence-service from RED-2325-dossier-stats-endpoint to master

* commit '43f7bc03273de5c4356a776b2265ff605131328e':
  RED-2325 Dossier Stats Endpoint
  RED-2325 Dossier Stats Endpoint
This commit is contained in:
Corina Olariu 2021-10-11 09:55:19 +02:00 committed by Timo Bejan
commit ed4db16f6f
8 changed files with 282 additions and 5 deletions

View File

@ -0,0 +1,26 @@
package com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DossierStats {
private String dossierId;
private int numberOfFiles;
private int numberOfAnalysedPages; // sum of analysedPages
private boolean hasRedactionsFilePresent; // true if at least one file in the dossier has redactions
private boolean hasHintsNoRedactionsFilePresent; // true if at least one file in the dossier has hints but doesn't have redactions
private boolean hasSuggestionsFilePresent; // true if at least one file in the dossier has suggestions
private boolean hasUpdatesFilePresent; //true if at least one file in the dossier has updates
private boolean hasNoFlagsFilePresent; // true if at least one file in the dossier has none of the other flags
private Map<FileStatus,Integer> fileCountPerStatus;
}

View File

@ -0,0 +1,24 @@
package com.iqser.red.service.persistence.service.v1.api.resources;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierStats;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Map;
import java.util.Set;
public interface DossierStatsResource {
String REST_PATH = "/dossier-stats";
String DOSSIER_ID_PARAM = "dossierId";
String DOSSIER_ID_PATH_PARAM = "/{" + DOSSIER_ID_PARAM + "}";
@GetMapping(value = REST_PATH + DOSSIER_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
DossierStats getDossierStats(@PathVariable(DOSSIER_ID_PARAM) String dossierId);
@GetMapping(value = REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
Map<String, DossierStats> getDossierStats(@RequestBody Set<String> dossierIds);
}

View File

@ -0,0 +1,29 @@
package com.iqser.red.service.peristence.v1.server.controller;
import com.iqser.red.service.peristence.v1.server.service.DossierStatsService;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierStats;
import com.iqser.red.service.persistence.service.v1.api.resources.DossierStatsResource;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@RestController
@RequiredArgsConstructor
public class DossierStatsController implements DossierStatsResource {
private final DossierStatsService dossierStatsService;
@Override
public DossierStats getDossierStats(String dossierId) {
return dossierStatsService.getDossierStats(dossierId);
}
@Override
public Map<String, DossierStats> getDossierStats(Set<String> dossierIds) {
return dossierIds.stream().collect(Collectors.toMap(Function.identity(), dossierStatsService::getDossierStats));
}
}

View File

@ -0,0 +1,63 @@
package com.iqser.red.service.peristence.v1.server.service;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierStats;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierStatus;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException.DOSSIER_NOT_FOUND_MESSAGE;
@Slf4j
@Service
@RequiredArgsConstructor
public class DossierStatsService {
private final DossierService dossierService;
private final FileStatusService fileStatusService;
public DossierStats getDossierStats(String dossierId) {
DossierStats dossierStats = new DossierStats();
// get the dossier
DossierEntity dossierEntity = dossierService.getDossierById(dossierId);
if (dossierEntity.getStatus().equals(DossierStatus.DELETED)) {
throw new DossierNotFoundException(String.format(DOSSIER_NOT_FOUND_MESSAGE, dossierId));
}
dossierStats.setDossierId(dossierId);
// get the associated files
List<FileEntity> files = fileStatusService.getDossierStatus(dossierId);
dossierStats.setNumberOfFiles(files.size());
dossierStats.setNumberOfAnalysedPages(files.stream().mapToInt(FileEntity::getNumberOfAnalyses).sum());
files.stream().filter(FileEntity::isHasRedactions).findAny().ifPresent(
(v) -> dossierStats.setHasRedactionsFilePresent(true)
);
files.stream().filter(FileEntity::isHasHints).filter(f -> !f.isHasRedactions()).findAny().ifPresent(
(v) -> dossierStats.setHasHintsNoRedactionsFilePresent(true)
);
files.stream().filter(FileEntity::isHasSuggestions).findAny().ifPresent(
(v) -> dossierStats.setHasSuggestionsFilePresent(true)
);
files.stream().filter(FileEntity::isHasUpdates).findAny().ifPresent(
(v) -> dossierStats.setHasUpdatesFilePresent(true)
);
files.stream().filter(f -> !f.isHasRedactions())
.filter(f -> !f.isHasHints())
.filter(f -> !f.isHasSuggestions())
.filter(f -> !f.isHasUpdates())
.findAny().ifPresent(
(v) -> dossierStats.setHasNoFlagsFilePresent(true)
);
Map<FileStatus, Integer> fileCountPerStatus = files.stream().collect(Collectors.toMap(FileEntity::getStatus, e -> 1, Math::addExact));
dossierStats.setFileCountPerStatus(fileCountPerStatus);
return dossierStats;
}
}

View File

@ -0,0 +1,8 @@
package com.iqser.red.service.peristence.v1.server.integration.client;
import com.iqser.red.service.persistence.service.v1.api.resources.DossierStatsResource;
import org.springframework.cloud.openfeign.FeignClient;
@FeignClient(name = "DossierStats", url = "http://localhost:${server.port}")
public interface DossierStatsClient extends DossierStatsResource {
}

View File

@ -6,6 +6,7 @@ import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.Do
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.DownloadFileType;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.CreateOrUpdateDossierRequest;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.Dossier;
import org.assertj.core.api.AssertionsForClassTypes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -24,11 +25,14 @@ public class DossierTesterAndProvider {
private DossierClient dossierClient;
public Dossier provideTestDossier(DossierTemplate testTemplate) {
return provideTestDossier(testTemplate, "Dossier1");
}
public Dossier provideTestDossier(DossierTemplate testTemplate, String filename) {
CreateOrUpdateDossierRequest cru = new CreateOrUpdateDossierRequest();
cru.setDownloadFileTypes(Sets.newHashSet(DownloadFileType.ORIGINAL));
cru.setDossierName("Dossier 1");
cru.setDescription("Dossier 1");
cru.setDossierName(filename);
cru.setDescription(filename);
cru.setWatermarkEnabled(true);
cru.setMemberIds(Sets.newHashSet("1"));
cru.setOwnerId("1");
@ -39,7 +43,7 @@ public class DossierTesterAndProvider {
Dossier result = dossierClient.addDossier(cru);
assertThat(result.getDossierName()).isEqualTo("Dossier 1");
assertThat(result.getDossierName()).isEqualTo(filename);
Dossier loadedDossier = dossierClient.getDossierById(result.getId(),false);
@ -52,8 +56,16 @@ public class DossierTesterAndProvider {
var testTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
return provideTestDossier(testTemplate);
return provideTestDossier(testTemplate, "Dossier1");
}
public Dossier provideTestDossier(String filename) {
var testTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
return provideTestDossier(testTemplate, filename);
}
}

View File

@ -0,0 +1,115 @@
package com.iqser.red.service.peristence.v1.server.integration.tests;
import com.iqser.red.service.peristence.v1.server.integration.client.DossierStatsClient;
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
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.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.Dossier;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierStats;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileStatus;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
public class DossierStatsTest extends AbstractPersistenceServerServiceTest {
private static final int NUMBER_PAGES_ANALYZED = 5;
@Autowired
private DossierTesterAndProvider dossierTesterAndProvider;
@Autowired
private FileTesterAndProvider fileTesterAndProvider;
@Autowired
private FileClient fileClient;
@Autowired
private DossierStatsClient dossierStatsClient;
private Dossier dossier1;
private Dossier dossier2;
@Before
public void setupData() {
dossier1 = dossierTesterAndProvider.provideTestDossier();
//provides 2 files
var file1 = fileTesterAndProvider.testAndProvideFile(dossier1, "file1");
var file2 = fileTesterAndProvider.testAndProvideFile(dossier1, "file2");
assertThat(fileClient.getAllStatuses().size()).isEqualTo(2);
// alter file 1
var loadedFile1 = fileClient.getFileStatus(dossier1.getId(), file1.getId());
assertThat(loadedFile1.isHasRedactions()).isFalse();
fileRepository.findById(file1.getId()).ifPresent((file)->{
file.setNumberOfAnalyses(NUMBER_PAGES_ANALYZED);
file.setHasRedactions(true);
file.setHasHints(true);
file.setHasUpdates(true);
fileRepository.save(file);
});
loadedFile1 = fileClient.getFileStatus(dossier1.getId(), file1.getId());
assertThat(loadedFile1.isHasRedactions()).isTrue();
// alter file 2
fileRepository.findById(file2.getId()).ifPresent((file)->{
file.setHasSuggestions(true);
fileRepository.save(file);
});
// second dossier
dossier2 = dossierTesterAndProvider.provideTestDossier("Dossier2");
var file3 = fileTesterAndProvider.testAndProvideFile(dossier2, "file3");
var file4 = fileTesterAndProvider.testAndProvideFile(dossier2, "file4");
//alter file 4
fileRepository.findById(file4.getId()).ifPresent((file)->{
file.setHasHints(true);
file.setStatus(FileStatus.APPROVED);
fileRepository.save(file);
});
}
@Test
public void testDossierStatsWithOneDossierId() {
DossierStats dossierStats = dossierStatsClient.getDossierStats(dossier1.getId());
assertThat(dossierStats.getDossierId()).isEqualTo(dossier1.getId());
assertThat(dossierStats.getNumberOfFiles()).isEqualTo(2);
assertThat(dossierStats.getNumberOfAnalysedPages()).isEqualTo(NUMBER_PAGES_ANALYZED);
assertThat(dossierStats.isHasRedactionsFilePresent()).isTrue();
assertThat(dossierStats.isHasHintsNoRedactionsFilePresent()).isFalse();
assertThat(dossierStats.isHasSuggestionsFilePresent()).isTrue();
assertThat(dossierStats.isHasUpdatesFilePresent()).isTrue();
assertThat(dossierStats.isHasNoFlagsFilePresent()).isFalse();
assertThat(dossierStats.getFileCountPerStatus().get(FileStatus.PROCESSING)).isEqualTo(2);
}
@Test
public void testDossierStatsWithMoreDossierIds() {
Set<String> dossierIds = new HashSet<>();
dossierIds.add(dossier1.getId());
dossierIds.add(dossier2.getId());
Map<String, DossierStats> dossierStatsMap = dossierStatsClient.getDossierStats(dossierIds);
// get the result for dossier2
DossierStats dossierStats2 = dossierStatsMap.get(dossier2.getId());
assertThat(dossierStats2.getNumberOfFiles()).isEqualTo(2);
assertThat(dossierStats2.getNumberOfAnalysedPages()).isEqualTo(0);
assertThat(dossierStats2.isHasRedactionsFilePresent()).isFalse();
assertThat(dossierStats2.isHasHintsNoRedactionsFilePresent()).isTrue();
assertThat(dossierStats2.isHasSuggestionsFilePresent()).isFalse();
assertThat(dossierStats2.isHasUpdatesFilePresent()).isFalse();
assertThat(dossierStats2.isHasNoFlagsFilePresent()).isTrue();
assertThat(dossierStats2.getFileCountPerStatus().get(FileStatus.PROCESSING)).isEqualTo(1);
assertThat(dossierStats2.getFileCountPerStatus().get(FileStatus.APPROVED)).isEqualTo(1);
}
}

View File

@ -62,7 +62,7 @@ public abstract class AbstractPersistenceServerServiceTest {
@Autowired
private DossierRepository dossierRepository;
@Autowired
private FileRepository fileRepository;
protected FileRepository fileRepository;
@Autowired
private ViewedPagesRepository viewedPagesRepository;
@Autowired