diff --git a/build.gradle b/build.gradle index 788db2c..4277882 100644 --- a/build.gradle +++ b/build.gradle @@ -13,6 +13,13 @@ java { } } +//dependencyManagement { +// imports { +// mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4" +// } +//} + + configurations { compileOnly { extendsFrom annotationProcessor @@ -49,9 +56,10 @@ dependencies { testImplementation 'org.mockito:mockito-core:5.3.1' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0' - - implementation name: 'testlib-0.1.2' +// implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.8.21' +// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4' +// implementation 'io.insert-koin:koin-core:3.5.0' + implementation name: 'testlib-fat-0.1.2-all (1)' } tasks.named('test') { diff --git a/libs/testlib-0.1.2.jar b/libs/testlib-0.1.2.jar deleted file mode 100644 index 28fcd06..0000000 Binary files a/libs/testlib-0.1.2.jar and /dev/null differ diff --git a/libs/testlib-fat-0.1.2-all (1).jar b/libs/testlib-fat-0.1.2-all (1).jar new file mode 100644 index 0000000..0bfd6bf Binary files /dev/null and b/libs/testlib-fat-0.1.2-all (1).jar differ diff --git a/libs/testlib-fat-0.1.2-all.jar b/libs/testlib-fat-0.1.2-all.jar new file mode 100644 index 0000000..aab9092 Binary files /dev/null and b/libs/testlib-fat-0.1.2-all.jar differ diff --git a/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java b/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java index 2817654..b0cc444 100644 --- a/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/ApplicationConfig.java @@ -1,17 +1,14 @@ package ru.soune.nocopy.configuration; -import com.vrt.NoCopyFileService; -import com.vrt.fileprocessor.FileProcessor; +import com.vrt.fileprotection.FileProtector; import lombok.AllArgsConstructor; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import java.util.Collections; -import java.util.List; @Configuration @EnableAutoConfiguration @@ -24,11 +21,15 @@ public class ApplicationConfig { } @Bean - @Scope("singleton") - public NoCopyFileService noCopyFileService(FileProcessor.FileProvider fileProvider, - FileProcessor.ProcessingListener processingListener) { - List initialQueue = Collections.emptyList(); + public com.vrt.NoCopyFileService noCopyFileService( + FileProtector.FileProvider fileProvider, + FileProtector.ProcessingListener processingListener) { - return new NoCopyFileService(initialQueue, fileProvider, processingListener); + return new com.vrt.NoCopyFileService( + Collections.emptyList(), + fileProvider, + processingListener + ); } } + diff --git a/src/main/java/ru/soune/nocopy/controller/ApiController.java b/src/main/java/ru/soune/nocopy/controller/ApiController.java index 4f9239d..1528058 100644 --- a/src/main/java/ru/soune/nocopy/controller/ApiController.java +++ b/src/main/java/ru/soune/nocopy/controller/ApiController.java @@ -1,5 +1,7 @@ package ru.soune.nocopy.controller; +import com.vrt.NoCopyFileService; +import com.vrt.fileprotection.FileProtector; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.Resource; @@ -20,11 +22,14 @@ import ru.soune.nocopy.dto.file.CompleteUploadResponse; import ru.soune.nocopy.dto.file.FileEntityResponse; import ru.soune.nocopy.dto.file.UploadProgress; import ru.soune.nocopy.entity.AuthToken; +import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.file.FileStatus; +import ru.soune.nocopy.entity.file.ProtectionStatus; import ru.soune.nocopy.entity.file.UploadStatus; import ru.soune.nocopy.exception.*; import ru.soune.nocopy.handler.*; import ru.soune.nocopy.repository.AuthTokenRepository; +import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.service.file.FileEntityService; import ru.soune.nocopy.service.file.FileUploadService; @@ -35,6 +40,7 @@ import java.nio.file.Paths; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; @Slf4j @@ -50,6 +56,10 @@ public class ApiController { private final AuthTokenRepository authTokenRepository; + private final FileEntityRepository fileEntityRepository; + + private final NoCopyFileService noCopyFileService; + @PostMapping("/v{version}/data") public ResponseEntity handlePostRequest(@RequestBody BaseRequest request, @PathVariable("version") int version) { @@ -332,6 +342,47 @@ public class ApiController { } } + @GetMapping("/protect/{fileId}") + public ResponseEntity protect( @PathVariable(required = false) String fileId) { + Optional fileEntity = fileEntityRepository.findById(fileId); + + if (!fileEntity.isPresent()) { + return ResponseEntity.notFound().build(); + } + + FileProtector.FileInfo fileInfo = createFileInfo(fileEntity.get()); + + noCopyFileService.addFile(fileInfo); + + fileEntity.get().setProtectionStatus(ProtectionStatus.PROCESSING); + + fileEntityRepository.save(fileEntity.get()); + + return ResponseEntity.ok().build(); + } + + private FileProtector.FileInfo createFileInfo(FileEntity fileEntity) { + FileProtector.Type type = determineFileType(fileEntity.getMimeType()); + + return new FileProtector.FileInfo(type, fileEntity.getId(), String.valueOf(fileEntity.getUserId())); + } + + private FileProtector.Type determineFileType(String mimeType) { + if (mimeType == null) { + return FileProtector.Type.IMAGE; + } + + if (mimeType.startsWith("image")) { + return FileProtector.Type.IMAGE; + } else if (mimeType.startsWith("video")) { + return FileProtector.Type.VIDEO; + } else if (mimeType.startsWith("audio")) { + return FileProtector.Type.AUDIO; + } else { + return FileProtector.Type.IMAGE; + } + } + private ResponseEntity createValidationErrorResponse(BindingResult bindingResult, Integer msgId) { List> fieldErrors = bindingResult.getFieldErrors() .stream() diff --git a/src/main/java/ru/soune/nocopy/entity/file/ProtectionStatus.java b/src/main/java/ru/soune/nocopy/entity/file/ProtectionStatus.java index 4ffa30c..18fc726 100644 --- a/src/main/java/ru/soune/nocopy/entity/file/ProtectionStatus.java +++ b/src/main/java/ru/soune/nocopy/entity/file/ProtectionStatus.java @@ -4,5 +4,6 @@ public enum ProtectionStatus { NOT_PROTECTED, PROCESSING, PROTECTED, - FAILED + FAILED, + FAILED_SAVE } diff --git a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java index f3dbda7..9b7ca63 100644 --- a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java +++ b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java @@ -1,14 +1,11 @@ package ru.soune.nocopy.handler.validator; -import org.apache.commons.validator.routines.DomainValidator; import org.apache.commons.validator.routines.EmailValidator; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import ru.soune.nocopy.dto.RegRequest; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.*; @Component @@ -156,15 +153,6 @@ public class RegRequestValidator implements Validator { errors.rejectValue("password", "password.contains.spaces", "Password cannot contain spaces"); } - -// recomment if need complexity -// checkPasswordComplexity(password, errors); - -// reccoment if need check simply standart password -// checkCommonPasswords(password, errors); - -// reccoment if need check simply standart password -// checkForSequences(password, errors); } private void checkPasswordComplexity(String password, Errors errors) { diff --git a/src/main/java/ru/soune/nocopy/repository/FileEntityRepository.java b/src/main/java/ru/soune/nocopy/repository/FileEntityRepository.java index d2788d8..d806273 100644 --- a/src/main/java/ru/soune/nocopy/repository/FileEntityRepository.java +++ b/src/main/java/ru/soune/nocopy/repository/FileEntityRepository.java @@ -29,6 +29,10 @@ public interface FileEntityRepository extends JpaRepository @Query("SELECT SUM(f.fileSize) FROM FileEntity f WHERE f.userId = :userId AND f.status = 'ACTIVE'") Long getTotalSizeByUserId(@Param("userId") Long userId); + @Query("SELECT f FROM FileEntity f WHERE f.protectionStatus = null AND f.status = 'ACTIVE' OR " + + "f.protectionStatus = 'NOT_PROTECTED' AND f.status = 'ACTIVE'") + List findAllActiveFilesAndNotProtected(); + @Query("SELECT f FROM FileEntity f WHERE f.userId = :userId AND f.originalFileName LIKE %:keyword%") List searchByFileName(@Param("userId") Long userId, @Param("keyword") String keyword); diff --git a/src/main/java/ru/soune/nocopy/service/file/FileProcessingOrchestrator.java b/src/main/java/ru/soune/nocopy/service/file/FileProcessingOrchestrator.java index 6fe56cf..d16c944 100644 --- a/src/main/java/ru/soune/nocopy/service/file/FileProcessingOrchestrator.java +++ b/src/main/java/ru/soune/nocopy/service/file/FileProcessingOrchestrator.java @@ -1,7 +1,7 @@ package ru.soune.nocopy.service.file; import com.vrt.NoCopyFileService; -import com.vrt.fileprocessor.FileProcessor; +import com.vrt.fileprotection.FileProtector; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; @@ -16,6 +16,7 @@ import java.util.List; @Service @RequiredArgsConstructor public class FileProcessingOrchestrator { + private final NoCopyFileService noCopyFileService; private final FileEntityRepository fileRepository; @@ -25,7 +26,7 @@ public class FileProcessingOrchestrator { for (FileEntity fileEntity : filesToProtect) { try { - FileProcessor.FileInfo fileInfo = createFileInfo(fileEntity); + FileProtector.FileInfo fileInfo = createFileInfo(fileEntity); noCopyFileService.addFile(fileInfo); @@ -38,36 +39,34 @@ public class FileProcessingOrchestrator { @Scheduled(fixedDelay = 120000) public void checkNewFilesForProtection() { - List newFiles = fileRepository.findByProtectionStatus(ProtectionStatus.NOT_PROTECTED); + List newFiles = fileRepository.findAllActiveFilesAndNotProtected(); for (FileEntity fileEntity : newFiles) { - FileProcessor.FileInfo fileInfo = createFileInfo(fileEntity); - noCopyFileService.addFile(fileInfo); + FileProtector.FileInfo fileInfo = createFileInfo(fileEntity); - fileEntity.setProtectionStatus(ProtectionStatus.PROCESSING); - fileRepository.save(fileEntity); + noCopyFileService.addFile(fileInfo); } } - private FileProcessor.FileInfo createFileInfo(FileEntity fileEntity) { - FileProcessor.Type type = determineFileType(fileEntity.getMimeType()); + private FileProtector.FileInfo createFileInfo(FileEntity fileEntity) { + FileProtector.Type type = determineFileType(fileEntity.getMimeType()); - return new FileProcessor.FileInfo(type, fileEntity.getId()); + return new FileProtector.FileInfo(type, fileEntity.getId(), String.valueOf(fileEntity.getUserId())); } - private FileProcessor.Type determineFileType(String mimeType) { + private FileProtector.Type determineFileType(String mimeType) { if (mimeType == null) { - return FileProcessor.Type.IMAGE; + return FileProtector.Type.IMAGE; } if (mimeType.startsWith("image")) { - return FileProcessor.Type.IMAGE; + return FileProtector.Type.IMAGE; } else if (mimeType.startsWith("video")) { - return FileProcessor.Type.VIDEO; + return FileProtector.Type.VIDEO; } else if (mimeType.startsWith("audio")) { - return FileProcessor.Type.AUDIO; + return FileProtector.Type.AUDIO; } else { - return FileProcessor.Type.IMAGE; + return FileProtector.Type.IMAGE; } } } diff --git a/src/main/java/ru/soune/nocopy/service/file/NoCopyProcessingListener.java b/src/main/java/ru/soune/nocopy/service/file/NoCopyProcessingListener.java index 244d26f..684a460 100644 --- a/src/main/java/ru/soune/nocopy/service/file/NoCopyProcessingListener.java +++ b/src/main/java/ru/soune/nocopy/service/file/NoCopyProcessingListener.java @@ -1,26 +1,46 @@ package ru.soune.nocopy.service.file; -import com.vrt.fileprocessor.FileProcessor; +import com.vrt.fileprotection.FileProtector; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -//Менять статус защиты +import ru.soune.nocopy.entity.file.FileEntity; +import ru.soune.nocopy.entity.file.ProtectionStatus; +import ru.soune.nocopy.exception.FileEntityNotFoundException; +import ru.soune.nocopy.repository.FileEntityRepository; + @Slf4j @Component -public class NoCopyProcessingListener implements FileProcessor.ProcessingListener { +@AllArgsConstructor +public class NoCopyProcessingListener implements FileProtector.ProcessingListener { + + private final FileEntityRepository fileEntityRepository; @Override - public void onStartProcessing(FileProcessor.FileInfo fileInfo) { + public void onStartProcessing(FileProtector.FileInfo fileInfo) { + changeStatus(ProtectionStatus.PROCESSING, fileInfo.getId()); } @Override - public void onProcessingFailed(FileProcessor.FileInfo fileInfo) { + public void onProcessingFailed(FileProtector.FileInfo fileInfo) { + changeStatus(ProtectionStatus.FAILED, fileInfo.getId()); } @Override - public void onSavingFailed(FileProcessor.FileInfo fileInfo) { + public void onSavingFailed(FileProtector.FileInfo fileInfo) { + changeStatus(ProtectionStatus.FAILED_SAVE, fileInfo.getId()); } @Override - public void onFinish(FileProcessor.FileInfo fileInfo) { + public void onFinish(FileProtector.FileInfo fileInfo) { + changeStatus(ProtectionStatus.PROTECTED, fileInfo.getId());; + } + + private void changeStatus(ProtectionStatus newStatus, String fileId) { + FileEntity fileEntity = fileEntityRepository.findById(fileId) + .orElseThrow(() -> new FileEntityNotFoundException(fileId)); + fileEntity.setProtectionStatus(newStatus); + + fileEntityRepository.save(fileEntity); } } diff --git a/src/main/java/ru/soune/nocopy/service/file/ProtectionFileProvider.java b/src/main/java/ru/soune/nocopy/service/file/ProtectionFileProvider.java index 33aea6c..7f106c3 100644 --- a/src/main/java/ru/soune/nocopy/service/file/ProtectionFileProvider.java +++ b/src/main/java/ru/soune/nocopy/service/file/ProtectionFileProvider.java @@ -1,13 +1,13 @@ package ru.soune.nocopy.service.file; -import com.vrt.fileprocessor.FileProcessor; -import kotlin.Result; -import kotlin.Unit; +import com.vrt.fileprotection.FileProtector; +import com.vrt.fileprotection.OperationResult; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.springframework.stereotype.Component; import ru.soune.nocopy.entity.file.FileEntity; -import ru.soune.nocopy.entity.file.ProtectionStatus; import ru.soune.nocopy.repository.FileEntityRepository; import java.io.File; @@ -16,62 +16,80 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; -//Сохранение и запись защищенных файлов + @Slf4j @Component @RequiredArgsConstructor -public class ProtectionFileProvider implements FileProcessor.FileProvider { +public class ProtectionFileProvider implements FileProtector.FileProvider { + private final FileEntityRepository fileRepository; -// @Override - public Result writeAudioFile(String id, byte[] data, String fileExt) { - try { - writeProtectedFile(id, data, fileExt); - return new Result<>(); - } catch (Exception e) { - log.error("Failed to create protected file: {}", id, e); - return new Result<>(); - } - } - - // @Override - public Result writeImageFile(String id, byte[] data, String fileExt) { - try { - writeProtectedFile(id, data, fileExt); - return new Result<>(); - } catch (Exception e) { - log.error("Failed to create protected file: {}", id, e); - return new Result<>(); - } - } - - // @Override - public Result writeVideoFile(String id, byte[] data, String fileExt) { - try { - writeProtectedFile(id, data, fileExt); - return new Result<>(); - } catch (Exception e) { - log.error("Failed to create protected file: {}", id, e); - return new Result<>(); - } - } - + @Nullable @Override - public File getImageFile(String id) { + public File getImageFile(@NotNull String id) { return getFileById(id); } + @Nullable @Override - public File getVideoFile(String id) { + public File getVideoFile(@NotNull String id) { return getFileById(id); } + @Nullable @Override - public File getAudioFile(String id) { + public File getAudioFile(@NotNull String id) { return getFileById(id); } + @NotNull + @Override + public com.vrt.fileprotection.OperationResult writeSignature(@NotNull String s, @NotNull byte[] bytes) { + return null; + } + + @NotNull + @Override + public com.vrt.fileprotection.OperationResult writeAudioFile(@NotNull String id, @NotNull byte[] data, @Nullable String fileExt) { + try { + writeProtectedFile(id, data, fileExt); + return OperationResult.Companion.success(); + } catch (Exception e) { + log.error("Failed to create protected file: {}", id, e); + return OperationResult.Companion.failure("Failed to create protected file"); + } + } + + @NotNull + @Override + public com.vrt.fileprotection.OperationResult writeVideoFile(@NotNull String id, @NotNull byte[] data, @Nullable String fileExt) { + try { + writeProtectedFile(id, data, fileExt); + return OperationResult.Companion.success(); + } catch (Exception e) { + log.error("Failed to create protected file: {}", id, e); + return OperationResult.Companion.failure("Failed to create protected file"); + } + } + + @NotNull + @Override + public com.vrt.fileprotection.OperationResult writeImageFile(@NotNull String id, @NotNull byte[] data, @Nullable String fileExt) { + try { + writeProtectedFile(id, data, fileExt); + return OperationResult.Companion.success(); + } catch (Exception e) { + log.error("Failed to create protected file: {}", id, e); + return OperationResult.Companion.failure("Failed to create protected file"); + } + } + + @Nullable + @Override + public File getSignature(@NotNull String s) { + return null; + } private void writeProtectedFile(String id, byte[] data, String fileExt) throws IOException { FileEntity fileEntity = fileRepository.findById(id) @@ -87,7 +105,6 @@ public class ProtectionFileProvider implements FileProcessor.FileProvider { Files.write(protectedFilePath, data); fileEntity.setProtectedFilePath(protectedFilePath.toString()); - fileEntity.setProtectionStatus(ProtectionStatus.PROTECTED); fileEntity.setProtectedAt(LocalDateTime.now()); fileEntity.setUpdatedAt(LocalDateTime.now()); fileEntity.setFileExtension(extension); @@ -126,7 +143,7 @@ public class ProtectionFileProvider implements FileProcessor.FileProvider { Path originalPath = Paths.get(fileEntity.getFilePath()); String pathStr = originalPath.toString(); - pathStr = pathStr.replaceFirst("/uploads/", "/protected/"); + pathStr = pathStr.replaceFirst("/uploads/uploads/", "/uploads/protected/"); Path protectedPath = Paths.get(pathStr); String fileName = protectedPath.getFileName().toString();