Pull request #600: RED-5883 - duplicate dossier fix

Merge in RED/persistence-service from RED-5883 to master

* commit '1ba979a257d52a326ec0d814239786c71413abb8':
  RED-5883 - duplicate dossier fix
This commit is contained in:
Timo Bejan 2023-01-27 12:18:56 +01:00
commit 880f8a23e9
5 changed files with 65 additions and 3 deletions

View File

@ -10,8 +10,8 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@ -28,6 +28,8 @@ import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.do
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@ -42,6 +44,7 @@ public class DossierPersistenceService {
private final WatermarkService watermarkService;
@Transactional
public DossierEntity insert(CreateOrUpdateDossierRequest createOrUpdateDossierRequest) {
DossierEntity dossier = new DossierEntity();
@ -55,8 +58,8 @@ public class DossierPersistenceService {
dossier.setReportTemplates(reportTemplates);
this.handleDossierStatus(createOrUpdateDossierRequest, dossier);
this.handleWatermark(createOrUpdateDossierRequest, dossier);
return dossierRepository.save(dossier);
return dossierRepository.saveAndFlush(dossier);
}

View File

@ -20,6 +20,9 @@ import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.do
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.ConstraintViolationException;
/**
* Provides the internal interface between dossier request and the actual persistence.
@ -51,7 +54,16 @@ public class DossierService {
throw new BadRequestException("Dossier template is not active.");
}
return dossierPersistenceService.insert(createOrUpdateDossierRequest);
try {
return dossierPersistenceService.insert(createOrUpdateDossierRequest);
} catch (Exception e) {
if (e.getCause() instanceof ConstraintViolationException) {
throw new ConflictException("Dossier with this name already exists");
} else {
log.debug("Unknown error when creating a dossier: ", e);
throw new BadRequestException("Failed to save dossier!");
}
}
}

View File

@ -111,3 +111,5 @@ databaseChangeLog:
file: db/changelog/tenant/44-add-redaction-preview-color-column.changelog.yaml
- include:
file: db/changelog/tenant/sql/43-add-applied-redaction-color.sql
- include:
file: db/changelog/tenant/sql/45-unique-dossier-name.sql

View File

@ -0,0 +1,15 @@
-- update duplicate dossier names
update dossier d1 set dossier_name = (
select
case when cnt = 1 then dossier_name
else dossier_name || ' ' || rn
end as dossier_name
from
(
select *, row_number() over w rn, count(*) over w cnt
from dossier
window w as (partition by dossier_name)
) t where t.id = d1.id);
-- create unique index on dossier_name and hard_deleted_time
CREATE UNIQUE INDEX dossier_name_index ON dossier (dossier_name, (hard_deleted_time IS NULL)) WHERE hard_deleted_time IS NULL;

View File

@ -6,7 +6,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -50,6 +55,31 @@ public class DossierTest extends AbstractPersistenceServerServiceTest {
@Autowired
private WatermarkClient watermarkClient;
@Test
public void testDossierRaceCondition() {
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
IntStream.range(0, 30).parallel().forEach(x -> dossierTesterAndProvider.provideTestDossier(dossierTemplate, "dossier: " + x));
var allDossiers = dossierClient.getAllDossiers(true, true);
var dossierCount = allDossiers.size();
assertThat(dossierCount).isEqualTo(30);
}
@Test
public void testCreateDuplicateDossier() {
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
IntStream.range(0, 30).parallel().forEach(x -> {
try {
dossierTesterAndProvider.provideTestDossier(dossierTemplate, "sameNameDossier");
} catch (Exception e) {
// conflict exception is expected
}
});
var allDossiers = dossierClient.getAllDossiers(true, true);
var dossierCount = allDossiers.size();
assertThat(dossierCount).isEqualTo(1);
}
@Test
public void testDossier() {