Commit 2f89a8c1 authored by Enriko Käsper's avatar Enriko Käsper
Browse files

Merge branch 'develop' into 'master'

Release: merge 'develop' into 'master' created by Enriko Käsper

See merge request teis/files-service!47
parents 3966d153 b6a82a82
theGroup=ee.sm.ti.teis
theVersion=1.13.1
commonsVersion=1.16.0
commonApiGatewayVersion=1.16.0
theVersion=1.14.0
commonsVersion=1.17.0
commonApiGatewayVersion=1.17.0
pluginVersion=1.2.0
schedulerVersion=1.12.0
......@@ -88,11 +88,13 @@ public class FileReferenceBusinessService {
}
public void update(FileMetadata domain) {
FileReferenceEntity entity = dataService.getCurrentByFileIdAndObjectId(domain.getFileId(), domain.getObjectId());
entity.setFileName(domain.getFileName());
entity.setFileStatus(ACTIVE);
entity.setScanStatus(domain.getScanStatus());
dataService.save(entity);
List<FileReferenceEntity> entities = dataService.getCurrentByFileId(domain.getFileId());
entities.forEach(entity -> {
entity.setFileName(domain.getFileName());
entity.setFileStatus(ACTIVE);
entity.setScanStatus(domain.getScanStatus());
dataService.save(entity);
});
}
public void updateFilesObjectId(UUID previousObjectId, UUID newObjectId, String objectType) {
......@@ -141,8 +143,7 @@ public class FileReferenceBusinessService {
Optional<FileReferenceEntity> fileReference = dataService.getByFileIdAndObjectId(fileId, objectId);
if (fileReference.isEmpty()) {
throw new TeisResourceNotFoundException("File reference not found with file ID and object ID", List.of(
fileId, objectId));
throw new TeisResourceNotFoundException("File reference not found with file ID and object ID", List.of(fileId, objectId));
}
return fileReference;
......@@ -158,24 +159,17 @@ public class FileReferenceBusinessService {
} else {
List<FileReferenceEntity> fileReferences = dataService.getByObjectId(objectId);
dataService.delete(fileReferences);
fileReferences.forEach(file -> fileNotifyService.notifyDelete(file.getFileId(), file.getObjectId(),
true, requestMetaDTO));
fileReferences.forEach(file -> fileNotifyService.notifyDelete(file.getFileId(), file.getObjectId(), true, requestMetaDTO));
}
}
private void softDelete(UUID objectId, UUID fileId, RequestMetaDTO requestMetaDTO) {
if (fileId != null) {
FileReferenceEntity file = dataService.getActiveByFileIdAndObjectId(fileId, objectId);
file.setObjectStatus(DELETED);
dataService.save(file);
fileNotifyService.notifyDelete(fileId, objectId, false, requestMetaDTO);
} else {
List<FileReferenceEntity> files = dataService.getByObjectId(objectId);
files.forEach(file -> file.setObjectStatus(DELETED));
dataService.saveAll(files);
files.forEach(file -> fileNotifyService.notifyDelete(file.getFileId(), file.getObjectId(),
false, requestMetaDTO));
}
List<FileReferenceEntity> fileReferencesToDelete =
fileId != null ? dataService.getActiveByFileIdAndObjectId(fileId, objectId) : dataService.getByObjectId(objectId);
fileReferencesToDelete.forEach(file -> file.setObjectStatus(DELETED));
dataService.saveAll(fileReferencesToDelete);
fileReferencesToDelete.forEach(file -> fileNotifyService.notifyDelete(file.getFileId(), file.getObjectId(), false, requestMetaDTO));
}
public void handleFileFailure(UUID fileId) {
......
......@@ -36,22 +36,24 @@ public class FileReferenceDataService {
public FileReferenceEntity getCurrentByFileIdAndObjectId(UUID fileId, UUID objectId) {
return repository.findCurrentByFileIdAndObjectId(fileId, objectId)
.orElseThrow(() -> new TeisResourceNotFoundException(FILE_NOT_FOUND_ERROR_MSG,
List.of(fileId, objectId)));
.orElseThrow(() -> new TeisResourceNotFoundException(FILE_NOT_FOUND_ERROR_MSG, List.of(fileId, objectId)));
}
public List<FileReferenceEntity> getCurrentByObjectTypeAndObjectId(UUID objectId, String objectType) {
return repository.findByObjectIdAndObjectStatusAndObjectType(objectId, CURRENT, objectType);
return repository.findByObjectIdAndObjectStatusAndObjectTypeOrderByCreatedAtAsc(objectId, CURRENT, objectType);
}
public List<FileReferenceEntity> getFileReferenceByContextObjectAndStatus(FileReferenceDto dto) {
return repository.findByObjectIdAndObjectStatusAndContextTypeAndFileStatus(dto.getObjectId(),
CURRENT, dto.getContextType().getId(), dto.getFileStatus());
return repository
.findByObjectIdAndObjectStatusAndContextTypeAndFileStatus(dto.getObjectId(), CURRENT, dto.getContextType().getId(), dto.getFileStatus());
}
public FileReferenceEntity getActiveByFileIdAndObjectId(UUID fileId, UUID objectId) {
return repository.findByFileIdAndObjectIdAndFileStatus(fileId, objectId, ACTIVE)
.orElseThrow(() -> new TeisResourceNotFoundException(FILE_NOT_FOUND_ERROR_MSG, List.of(fileId, objectId)));
public List<FileReferenceEntity> getActiveByFileIdAndObjectId(UUID fileId, UUID objectId) {
List<FileReferenceEntity> files = repository.findByFileIdAndObjectIdAndFileStatus(fileId, objectId, ACTIVE);
if (files.isEmpty()) {
throw new TeisResourceNotFoundException(FILE_NOT_FOUND_ERROR_MSG, List.of(fileId, objectId));
}
return files;
}
public Optional<FileReferenceEntity> getByFileIdAndObjectId(UUID fileId, UUID objectId) {
......
......@@ -15,7 +15,7 @@ public interface FileReferenceRepository extends JpaRepository<FileReferenceEnti
Optional<FileReferenceEntity> findByFileIdAndObjectIdAndObjectStatus(UUID fileId, UUID objectId, ObjectStatus objectStatus);
Optional<FileReferenceEntity> findByFileIdAndObjectIdAndFileStatus(UUID fileId, UUID objectId, FileStatusType fileStatus);
List<FileReferenceEntity> findByFileIdAndObjectIdAndFileStatus(UUID fileId, UUID objectId, FileStatusType fileStatus);
default Optional<FileReferenceEntity> findCurrentByFileIdAndObjectId(UUID fileId, UUID objectId) {
return findByFileIdAndObjectIdAndObjectStatus(fileId, objectId, CURRENT);
......@@ -26,8 +26,8 @@ public interface FileReferenceRepository extends JpaRepository<FileReferenceEnti
List<FileReferenceEntity> findByObjectId(UUID objectId);
List<FileReferenceEntity> findByObjectIdAndObjectStatusAndObjectType(UUID objectId, ObjectStatus objectStatus,
String objectType);
List<FileReferenceEntity> findByObjectIdAndObjectStatusAndObjectTypeOrderByCreatedAtAsc(UUID objectId, ObjectStatus objectStatus,
String objectType);
List<FileReferenceEntity> findByObjectIdAndObjectStatusAndContextTypeAndFileStatus(UUID objectId, ObjectStatus objectStatus,
String contextType, FileStatusType fileStatus);
......
......@@ -250,7 +250,7 @@ class FileReferenceBusinessServiceTest {
@Test
void update() {
when(dataService.getCurrentByFileIdAndObjectId(FILE_ID, OBJECT_ID)).thenReturn(fileReferenceEntity);
when(dataService.getCurrentByFileId(FILE_ID)).thenReturn(List.of(fileReferenceEntity));
FileMetadata fileMetadata = new FileMetadata();
fileMetadata.setFileId(FILE_ID);
......@@ -278,12 +278,12 @@ class FileReferenceBusinessServiceTest {
void deleteSoft() {
UUID objectId = UUID.randomUUID();
when(dataService.getByFileIdAndObjectId(FILE_ID, objectId)).thenReturn(Optional.of(fileReferenceEntity));
when(dataService.getActiveByFileIdAndObjectId(FILE_ID, objectId)).thenReturn(fileReferenceEntity);
when(dataService.getActiveByFileIdAndObjectId(FILE_ID, objectId)).thenReturn(List.of(fileReferenceEntity));
service.delete(objectId, FILE_ID, false, requestMetaDTO);
verify(dataService).save(fileReferenceEntityArgumentCaptor.capture());
FileReferenceEntity capturedFileReferenceEntity = fileReferenceEntityArgumentCaptor.getValue();
verify(dataService).saveAll(fileReferenceEntitiesArgumentCaptor.capture());
FileReferenceEntity capturedFileReferenceEntity = fileReferenceEntitiesArgumentCaptor.getValue().get(0);
assertThat(capturedFileReferenceEntity.getObjectStatus()).isEqualTo(DELETED);
......@@ -346,4 +346,4 @@ class FileReferenceBusinessServiceTest {
assertThat(capturedFileReferenceEntity.getFileStatus()).isEqualTo(fileReferenceEntity.getFileStatus());
assertThat(capturedFileReferenceEntity.getCreatorType()).isEqualTo(fileReferenceEntity.getCreatorType());
}
}
\ No newline at end of file
}
......@@ -10,6 +10,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.util.UUID;
import static ee.sm.ti.teis.types.enums.FileStatusType.ACTIVE;
import static java.util.Collections.emptyList;
import static java.util.Optional.empty;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
......@@ -32,7 +33,7 @@ class FileReferenceDataServiceTest {
@Test
void get_activeByFileAndObject_throws_exception_when_not_found() {
when(repository.findByFileIdAndObjectIdAndFileStatus(any(), any(), eq(ACTIVE))).thenReturn(empty());
when(repository.findByFileIdAndObjectIdAndFileStatus(any(), any(), eq(ACTIVE))).thenReturn(emptyList());
assertThrows(TeisResourceNotFoundException.class, () -> service.getActiveByFileIdAndObjectId(UUID.randomUUID(), UUID.randomUUID()));
}
......
......@@ -23,7 +23,7 @@ public class StartVirusScanJob extends SystemJobExecutor {
private final FilePointerDataService filePointerDataService;
public StartVirusScanJob(RabbitTemplate msRabbitTemplate, VirusScanProcessService virusScanProcessService,
FileDataService fileDataService, FilePointerDataService filePointerDataService) {
FileDataService fileDataService, FilePointerDataService filePointerDataService) {
super(msRabbitTemplate);
this.virusScanProcessService = virusScanProcessService;
this.fileDataService = fileDataService;
......@@ -43,7 +43,7 @@ public class StartVirusScanJob extends SystemJobExecutor {
files.forEach(file -> {
List<FilePointerEntity> filePointers = filePointerDataService.getByFileId(file.getId());
filePointers.forEach(pointer -> {
virusScanProcessService.startProcess(file.getId(), pointer.getObjectId(), requestMetaDto);
virusScanProcessService.startProcess(file.getId(), requestMetaDto);
counter.getAndIncrement();
});
});
......
......@@ -15,12 +15,10 @@ import org.springframework.stereotype.Component;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static ee.sm.ti.teis.file.virusscan.bpm.VirusScanProcessInstanceContext.OBJECT_ID;
import static ee.sm.ti.teis.file.bpm.FileDeleteProcessInstanceContext.OBJECT_ID;
import static ee.sm.ti.teis.types.enums.FileStatusType.FAILED;
import static ee.sm.ti.teis.types.enums.ObjectStatus.CURRENT;
@Component
@RequiredArgsConstructor
......@@ -36,35 +34,29 @@ public class DeleteFileTask implements JavaDelegate {
@Override
@Transactional
public void execute(DelegateExecution execution) throws Exception {
public void execute(DelegateExecution execution) {
UUID fileId = UUID.fromString(execution.getBusinessKey());
UUID objectId = (UUID) execution.getVariable(OBJECT_ID);
Optional<FilePointerEntity> filePointer = filePointerDataService.getOrReturnEmptyByFileIdAndObjectId(
fileId, objectId);
if (filePointer.isPresent()) {
List<FilePointerEntity> objectFilePointers = filePointerDataService.getOrReturnEmptyByFileIdAndObjectId(fileId, objectId);
if (!objectFilePointers.isEmpty()) {
FileEntity file = fileDataService.getById(fileId);
List<FilePointerEntity> filePointers = filePointerDataService.getByFileId(fileId);
hardDeleteFileAndPointer(fileId, filePointer.get(), file, filePointers);
hardDeleteFileAndPointer(fileId, objectFilePointers, file);
}
}
private void hardDeleteFileAndPointer(UUID fileId, FilePointerEntity filePointer, FileEntity file,
List<FilePointerEntity> filePointers) {
filePointerDataService.delete(filePointer);
private void hardDeleteFileAndPointer(UUID fileId, List<FilePointerEntity> objectFilePointers, FileEntity file) {
objectFilePointers.forEach(filePointerDataService::delete);
if (!hasReferencingFilePointers(filePointers, filePointer)) {
List<FilePointerEntity> relatedFilePointers = filePointerDataService.getCurrentByFileId(fileId);
if (relatedFilePointers.isEmpty()) {
hardDeleteFile(fileId.toString(), file);
} else {
log.info("File with id [{}] will not be deleted due to existing file pointer references", fileId);
}
}
private boolean hasReferencingFilePointers(List<FilePointerEntity> filePointers, FilePointerEntity deletedFilePointer) {
return filePointers.stream().anyMatch(filePointer ->
!filePointer.getId().equals(deletedFilePointer.getId()) && filePointer.getObjectStatus().equals(CURRENT));
}
private void hardDeleteFile(String fileId, FileEntity file) {
if (file.getFileStatus().equals(FAILED)) {
log.info("File with id [{}] will not be deleted because file status is FAILED", fileId);
......
......@@ -6,7 +6,6 @@ import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Service
......@@ -21,12 +20,14 @@ public class FilePointerDataService {
.orElseThrow(() -> new TeisResourceNotFoundException("Current file pointer not found", List.of(objectId, fileId)));
}
public FilePointerEntity getByFileIdAndObjectId(UUID fileId, UUID objectId) {
return repository.findByFileIdAndObjectId(fileId, objectId)
.orElseThrow(() -> new TeisResourceNotFoundException("File pointer not found", List.of(fileId, objectId)));
public List<FilePointerEntity> getByFileIdAndObjectId(UUID fileId, UUID objectId) {
List<FilePointerEntity> files = repository.findByFileIdAndObjectId(fileId, objectId);
if (files.isEmpty()) {
throw new TeisResourceNotFoundException("File pointer not found", List.of(fileId, objectId));
} return files;
}
public Optional<FilePointerEntity> getOrReturnEmptyByFileIdAndObjectId(UUID fileId, UUID objectId) {
public List<FilePointerEntity> getOrReturnEmptyByFileIdAndObjectId(UUID fileId, UUID objectId) {
return repository.findByFileIdAndObjectId(fileId, objectId);
}
......@@ -45,4 +46,8 @@ public class FilePointerDataService {
public List<FilePointerEntity> getByFileId(UUID fileId) {
return repository.findByFileId(fileId);
}
public List<FilePointerEntity> getCurrentByFileId(UUID fileId) {
return repository.findCurrentByFileId(fileId);
}
}
......@@ -19,7 +19,13 @@ public interface FilePointerRepository extends JpaRepository<FilePointerEntity,
List<FilePointerEntity> findAllByObjectId(UUID objectId);
Optional<FilePointerEntity> findByFileIdAndObjectId(UUID fileId, UUID objectId);
List<FilePointerEntity> findByFileIdAndObjectId(UUID fileId, UUID objectId);
List<FilePointerEntity> findByFileId(UUID fileId);
List<FilePointerEntity> findByFileIdAndObjectStatus(UUID fileId, ObjectStatus objectStatus);
default List<FilePointerEntity> findCurrentByFileId(UUID fileId) {
return findByFileIdAndObjectStatus(fileId, CURRENT);
}
}
......@@ -30,7 +30,6 @@ import static ee.sm.ti.teis.file.FileErrorCode.VIRUS_SCAN_RESULT_UNCHECKED;
import static ee.sm.ti.teis.types.enums.FileScanStatusType.INFECTED;
import static ee.sm.ti.teis.types.enums.FileScanStatusType.UNCHECKED;
import static ee.sm.ti.teis.types.enums.FileStatusType.FAILED;
import static ee.sm.ti.teis.types.enums.ObjectStatus.CURRENT;
import static ee.sm.ti.teis.types.enums.ObjectStatus.DELETED;
@Service
......@@ -111,11 +110,9 @@ public class FileBusinessService {
if (domain.isHardDelete()) {
fileDeleteProcessService.startProcess(domain.getFileId(), domain.getObjectId(), requestMetaDTO);
} else {
FilePointerEntity filePointer = filePointerDataService.getByFileIdAndObjectId(
domain.getFileId(), domain.getObjectId());
List<FilePointerEntity> filePointers = filePointerDataService.getByFileIdAndObjectId(domain.getFileId(), domain.getObjectId());
FileEntity file = dataService.getById(domain.getFileId());
List<FilePointerEntity> filePointers = filePointerDataService.getByFileId(domain.getFileId());
deleteFileAndPointer(domain, filePointer, file, filePointers);
deleteFileAndPointer(domain, filePointers, file);
}
}
......@@ -135,23 +132,22 @@ public class FileBusinessService {
}
}
private void deleteFileAndPointer(DeleteFile domain, FilePointerEntity filePointer, FileEntity file,
List<FilePointerEntity> filePointers) {
filePointer.setObjectStatus(DELETED);
filePointerDataService.save(filePointer);
private void deleteFileAndPointer(DeleteFile domain, List<FilePointerEntity> filePointers, FileEntity file) {
filePointers.forEach(filePointer -> {
if (filePointer.getObjectStatus() != DELETED) {
filePointer.setObjectStatus(DELETED);
filePointerDataService.save(filePointer);
}
});
if (!hasReferencingFilePointers(filePointers, filePointer)) {
List<FilePointerEntity> relatedCurrentFilePointers = filePointerDataService.getCurrentByFileId(domain.getFileId());
if (relatedCurrentFilePointers.isEmpty()) {
deleteFile(file);
} else {
log.info("File with id [{}] will not be deleted due to existing file pointer references", domain.getFileId());
}
}
private boolean hasReferencingFilePointers(List<FilePointerEntity> filePointers, FilePointerEntity deletedFilePointer) {
return filePointers.stream().anyMatch(filePointer ->
!filePointer.getId().equals(deletedFilePointer.getId()) && filePointer.getObjectStatus().equals(CURRENT));
}
private void deleteFile(FileEntity file) {
file.setObjectStatus(DELETED);
dataService.save(file);
......
......@@ -38,7 +38,7 @@ public class FileMetadataService {
fileMetadataNotifyService.notifyMetadataSaved(fileMetadata, requestMetaDTO);
if (CURRENT.equals(savedEntity.getObjectStatus())) {
virusScanProcessService.startProcess(dto.getFileId(), dto.getObjectId(), requestMetaDTO);
virusScanProcessService.startProcess(dto.getFileId(), requestMetaDTO);
}
return composeService.composeDto(savedEntity);
......
......@@ -53,8 +53,6 @@ public class UpdateVirusScanResultTask implements JavaDelegate {
file = fileDataService.save(file);
FileMetadata fileMetadata = fileComposeService.composeFileMetadataDomain(file);
UUID objectId = (UUID) execution.getVariable(OBJECT_ID);
fileMetadata.setObjectId(objectId);
RequestMetaDTO requestMetaDto = objectMapper.readValue(requestMetaJson, RequestMetaDTO.class);
fileMetadataNotifyService.notifyMetadataSaved(fileMetadata, requestMetaDto);
......
......@@ -30,7 +30,6 @@ public class VirusScanProcessInstanceContext {
public static final String REQUEST_META_DTO = "requestMetaDto";
public static final String FILE_ID = "fileId";
public static final String OBJECT_ID = "objectId";
private static final String PROCESS_INSTANCE_BUSINESS_KEY_SEPARATOR = "::";
private static final String UNEXPECTED_ERROR_CODE = "timeoutOrException";
......@@ -39,13 +38,12 @@ public class VirusScanProcessInstanceContext {
// utility class
}
public static Map<String, Object> initProcessVariables(String requestMetaDTO, UUID fileId, UUID objectId,
VirusScanBpmPropertiesService propertiesService) {
public static Map<String, Object> initProcessVariables(String requestMetaDTO, UUID fileId,
VirusScanBpmPropertiesService propertiesService) {
Map<String, Object> bpmInstanceVariables = new HashMap<>();
bpmInstanceVariables.put(REQUEST_META_DTO, requestMetaDTO);
bpmInstanceVariables.put(FILE_ID, fileId);
bpmInstanceVariables.put(OBJECT_ID, objectId);
bpmInstanceVariables.put(RETRY_TIMEOUT, propertiesService.getRetryTimeout());
bpmInstanceVariables.put(UPLOAD_RETRY_TIME_DELAY, propertiesService.getUploadRetryTimeDelay());
bpmInstanceVariables.put(POLL_SCAN_STATUS_DELAY, propertiesService.getPollScanStatusDelay());
......
......@@ -23,11 +23,11 @@ public class VirusScanProcessService {
private final ObjectMapper objectMapper;
private final VirusScanBpmPropertiesService propertiesService;
public void startProcess(UUID fileId, UUID objectId, RequestMetaDTO requestMetaDTO) {
public void startProcess(UUID fileId, RequestMetaDTO requestMetaDTO) {
Map<String, Object> bpmInstanceVariables;
try {
bpmInstanceVariables = initProcessVariables(objectMapper.writeValueAsString(requestMetaDTO),
fileId, objectId, propertiesService);
fileId, propertiesService);
} catch (JsonProcessingException e) {
logAdminAlertError("Error when initiating Camunda process for virus scan: {}", e.getMessage());
throw new TeisBusinessException(SYSTEM_ERROR, e.getMessage());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment