Merge branch 'dev' into NCBACK-35
# Conflicts: # README.md # src/main/java/ru/soune/nocopy/controller/ApiController.java # src/main/java/ru/soune/nocopy/handler/FileEntityHandler.java # src/main/java/ru/soune/nocopy/service/file/FileCleanupService.java # src/main/java/ru/soune/nocopy/service/file/FileEntityService.java # src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java # src/main/java/ru/soune/nocopy/service/file/impl/ProtectionFileProviderImpl.java
This commit is contained in:
@@ -3,6 +3,8 @@ package ru.soune.nocopy.controller;
|
||||
import com.vrt.NoCopyFileService;
|
||||
import com.vrt.fileprotection.FileProtector;
|
||||
import com.vrt.fileprotection.NoCopyCheckResult;
|
||||
import com.vrt.fileprotection.audio.AudioCheckResult;
|
||||
import com.vrt.fileprotection.documents.DocumentCheckResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
@@ -21,16 +23,20 @@ import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.file.*;
|
||||
import ru.soune.nocopy.dto.register.RegAnswer;
|
||||
import ru.soune.nocopy.entity.company.Company;
|
||||
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.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.entity.user.User;
|
||||
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.repository.UserRepository;
|
||||
import ru.soune.nocopy.service.FileSimilarityService;
|
||||
import ru.soune.nocopy.service.file.CheckCounterService;
|
||||
import ru.soune.nocopy.service.file.ProtectionsLimitService;
|
||||
import ru.soune.nocopy.service.file.cloud.CloudStorageService;
|
||||
import ru.soune.nocopy.service.register.AuthService;
|
||||
@@ -74,6 +80,10 @@ public class ApiController {
|
||||
|
||||
private final AuthTokenRepository authTokenRepository;
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final CheckCounterService checkCounterService;
|
||||
|
||||
private final CloudStorageService cloudStorageService;
|
||||
|
||||
@PostMapping("/v{version}/data")
|
||||
@@ -156,46 +166,124 @@ public class ApiController {
|
||||
MessageCode.DUPLICATE_FILE_UPLOAD.getDescription(),
|
||||
duplicateData
|
||||
));
|
||||
} catch (FileFormatException e){
|
||||
return buildErrorResponse(uploadId, chunkNumber, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("Error uploading chunk", e);
|
||||
return buildErrorResponse(uploadId, chunkNumber, "Failed to upload chunk: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private final NoCopyFileService noCopyFileService;
|
||||
|
||||
@GetMapping("/v{version}/files/{fileId}/similar")
|
||||
public ResponseEntity<BaseResponse> findSimilarFiles(
|
||||
@PathVariable("version") int version,
|
||||
@PathVariable String fileId,
|
||||
@RequestParam(value = "auth_token",required = false) String authToken,
|
||||
@RequestParam(value = "auth_token", required = false) String authToken,
|
||||
@RequestParam(required = false) List<String> similarityLevels,
|
||||
@PageableDefault(size = 20, sort = "hammingDistance") Pageable pageable) {
|
||||
SimilarityFilter filter = SimilarityFilter.builder()
|
||||
.similarityLevels(similarityLevels)
|
||||
.build();
|
||||
Page<SimilarFileDTO> similarFiles = fileSimilarityService.findSimilarFiles(fileId, filter, pageable, authToken);
|
||||
|
||||
String messageDesc;
|
||||
MessageCode success;
|
||||
try {
|
||||
FileEntity fileEntity = fileEntityRepository.findByFileId(fileId);
|
||||
|
||||
if (similarFiles.isEmpty()) {
|
||||
messageDesc = MessageCode.FILE_NOT_FOUND.getDescription();
|
||||
success = MessageCode.SUCCESS;
|
||||
} else {
|
||||
messageDesc = MessageCode.SIMILAR_FILES_FOUND.getDescription();
|
||||
success = MessageCode.SUCCESS;
|
||||
if (fileEntity == null) {
|
||||
return ResponseEntity.ok().body(new BaseResponse(0, MessageCode.INVALID_FIELD.getCode(),
|
||||
MessageCode.INVALID_FIELD.getDescription(), null));
|
||||
}
|
||||
|
||||
BaseResponse response;
|
||||
if ("image".equals(fileEntity.getMimeType())) {
|
||||
Page<SimilarFileDTO> similarFilesPage = fileSimilarityService.findSimilarFiles(
|
||||
fileId, similarityLevels, pageable, authToken);
|
||||
response = buildSuccessResponse(similarFilesPage, MessageCode.SIMILAR_FILES_FOUND);
|
||||
} else {
|
||||
List<SimilarFileDTO> results = processNonImageFile(fileEntity, authToken);
|
||||
log.info("results: {}", results);
|
||||
response = buildSuccessResponse(results, MessageCode.SIMILAR_FILES_FOUND);
|
||||
checkCounterService.incrementCheckCount(fileEntity.getUserId(), fileEntity.getMimeType());
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
|
||||
} catch(IllegalArgumentException e) {
|
||||
log.error("Error with file extensions : {}", e.getMessage(), e);
|
||||
return ResponseEntity.ok().body(new BaseResponse(MessageCode.FILE_FOR_SEARCH_NOT_VALID.getCode(),
|
||||
MessageCode.FILE_FOR_SEARCH_NOT_VALID.getCode(),
|
||||
MessageCode.FILE_FOR_SEARCH_NOT_VALID.getDescription(), null));
|
||||
} catch (Exception e) {
|
||||
log.error("Error finding similar files: {}", e.getMessage(), e);
|
||||
return ResponseEntity.ok().body(new BaseResponse(MessageCode.INVALID_FIELD.getCode(),
|
||||
MessageCode.INVALID_FIELD.getCode(),
|
||||
MessageCode.INVALID_FIELD.getDescription(), null));
|
||||
}
|
||||
}
|
||||
|
||||
private List<SimilarFileDTO> processNonImageFile(FileEntity fileEntity, String authToken) throws Exception {
|
||||
List<SimilarFileDTO> results = new ArrayList<>();
|
||||
|
||||
FileEntity duplicateByHash = fileSimilarityService.findDuplicateByHash(fileEntity.getFilePath(),
|
||||
fileEntity.getMimeType(), fileEntity.getUserId());
|
||||
log.info("duplicateByHash: {}", duplicateByHash);
|
||||
if (duplicateByHash != null) {
|
||||
results.add(fileSimilarityService.buildDTO(duplicateByHash));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
Map<String, Object> responseData = new HashMap<>();
|
||||
responseData.put("content", similarFiles.getContent());
|
||||
responseData.put("page", similarFiles.getNumber());
|
||||
responseData.put("size", similarFiles.getSize());
|
||||
responseData.put("totalElements", similarFiles.getTotalElements());
|
||||
responseData.put("totalPages", similarFiles.getTotalPages());
|
||||
responseData.put("hasNext", similarFiles.hasNext());
|
||||
responseData.put("hasPrevious", similarFiles.hasPrevious());
|
||||
File file = new File(fileEntity.getFilePath());
|
||||
FileProtector.Type type = "document".equals(fileEntity.getMimeType()) ?
|
||||
FileProtector.Type.DOC : FileProtector.Type.AUDIO;
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.body(new BaseResponse(20004, success.getCode(), messageDesc, responseData));
|
||||
NoCopyCheckResult checkResult = noCopyFileService.checkFile(file, type);
|
||||
log.info("checkResult: {}", checkResult);
|
||||
|
||||
switch (checkResult) {
|
||||
case DocumentCheckResult.Success success -> {
|
||||
FileProtector.FileInfo info = success.getInfo();
|
||||
FileEntity entity = fileEntityRepository.findByFileId(info.getId());
|
||||
if (entity != null) {
|
||||
results.add(fileSimilarityService.buildDTO(entity));
|
||||
}
|
||||
}
|
||||
case AudioCheckResult.Success success -> {
|
||||
FileProtector.FileInfo info = success.getInfo();
|
||||
FileEntity entity = fileEntityRepository.findByFileId(info.getId());
|
||||
if (entity != null) {
|
||||
results.add(fileSimilarityService.buildDTO(entity));
|
||||
}
|
||||
}
|
||||
case DocumentCheckResult.Failed failed ->
|
||||
log.warn("Document check failed: {}", failed.getMessage());
|
||||
case AudioCheckResult.Failed failed ->
|
||||
log.warn("Audio check failed: {}", failed.getMessage());
|
||||
default -> log.warn("Unexpected result type: {}", checkResult.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private BaseResponse buildSuccessResponse(Page<SimilarFileDTO> page, MessageCode messageCode) {
|
||||
Map<String, Object> responseData = new HashMap<>();
|
||||
responseData.put("content", page.getContent());
|
||||
responseData.put("page", page.getNumber());
|
||||
responseData.put("size", page.getSize());
|
||||
responseData.put("totalElements", page.getTotalElements());
|
||||
responseData.put("totalPages", page.getTotalPages());
|
||||
responseData.put("hasNext", page.hasNext());
|
||||
responseData.put("hasPrevious", page.hasPrevious());
|
||||
|
||||
return new BaseResponse(20004, messageCode.getCode(),
|
||||
messageCode.getDescription(), responseData);
|
||||
}
|
||||
|
||||
private BaseResponse buildSuccessResponse(List<SimilarFileDTO> list, MessageCode messageCode) {
|
||||
Map<String, Object> responseData = new HashMap<>();
|
||||
responseData.put("content", list);
|
||||
responseData.put("totalElements", list.size());
|
||||
|
||||
return new BaseResponse(20004, messageCode.getCode(),
|
||||
messageCode.getDescription(), responseData);
|
||||
}
|
||||
|
||||
@GetMapping("/v{version}/files/progress/{uploadId}")
|
||||
@@ -300,28 +388,52 @@ public class ApiController {
|
||||
@PathVariable(required = false) Integer version,
|
||||
@RequestHeader(value = "Authorization", required = false) String tokenHeader) {
|
||||
try {
|
||||
if (tokenHeader == null) {
|
||||
if (tokenHeader == null || tokenHeader.isBlank()) {
|
||||
Map<String, Object> errorData = new HashMap<>();
|
||||
errorData.put("token", tokenHeader);
|
||||
errorData.put("fileId", fileId);
|
||||
errorData.put("version", version);
|
||||
|
||||
return ResponseEntity.ok().body(new BaseResponse(20004,
|
||||
MessageCode.FILE_DOWNLOAD_ERROR_NOT_CORRECT_FIELD.getCode(),
|
||||
MessageCode.FILE_DOWNLOAD_ERROR_NOT_CORRECT_FIELD.getDescription(),
|
||||
MessageCode.TOKEN_IS_NULL.getCode(),
|
||||
MessageCode.TOKEN_IS_NULL.getDescription(),
|
||||
errorData));
|
||||
}
|
||||
|
||||
Long userId = authService.useUserAuthToken(tokenHeader);
|
||||
FileEntityResponse entityResponse = fileEntityService.getById(fileId, version);
|
||||
FileStatus status = entityResponse.getStatus();
|
||||
|
||||
if (!entityResponse.getUserId().equals(userId)) {
|
||||
if (status.equals(FileStatus.BLOCKED) || status.equals(FileStatus.DELETED) ||
|
||||
status.equals(FileStatus.REMOVED)) {
|
||||
Map<String, Object> errorData = new HashMap<>();
|
||||
errorData.put("fileId", entityResponse.getId());
|
||||
|
||||
return ResponseEntity.ok().body(new BaseResponse(20004,
|
||||
MessageCode.FILE_IS_BLOCKED.getCode(),
|
||||
MessageCode.FILE_IS_BLOCKED.getDescription(),
|
||||
errorData));
|
||||
}
|
||||
|
||||
User fileUser = userRepository.findById(entityResponse.getUserId()).orElseThrow();
|
||||
User user = userRepository.findById(userId).orElseThrow();
|
||||
Company companyUser = user.getCompany();
|
||||
|
||||
if (companyUser != null && !fileUser.getCompany().getId().equals(companyUser.getId())) {
|
||||
Map<String, Object> errorData = new HashMap<>();
|
||||
errorData.put("token", tokenHeader);
|
||||
|
||||
return ResponseEntity.ok().body(new BaseResponse(20004,
|
||||
MessageCode.FILE_DOWNLOAD_ERROR.getCode(),
|
||||
MessageCode.FILE_DOWNLOAD_ERROR.getDescription(),
|
||||
MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
|
||||
MessageCode.USER_NOT_HAD_PERMISSION.getDescription(),
|
||||
errorData));
|
||||
}
|
||||
|
||||
if (companyUser == null && !entityResponse.getUserId().equals(userId)) {
|
||||
Map<String, Object> errorData = new HashMap<>();
|
||||
errorData.put("token", tokenHeader);
|
||||
|
||||
return ResponseEntity.ok().body(new BaseResponse(20004,
|
||||
MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
|
||||
MessageCode.USER_NOT_HAD_PERMISSION.getDescription(),
|
||||
errorData));
|
||||
}
|
||||
|
||||
@@ -330,8 +442,8 @@ public class ApiController {
|
||||
errorData.put("file_status", entityResponse.getStatus());
|
||||
|
||||
return ResponseEntity.ok().body(new BaseResponse(20004,
|
||||
MessageCode.FILE_DOWNLOAD_ERROR.getCode(),
|
||||
MessageCode.FILE_DOWNLOAD_ERROR.getDescription(),
|
||||
MessageCode.FILE_DELETE.getCode(),
|
||||
MessageCode.FILE_DELETE.getDescription(),
|
||||
errorData));
|
||||
}
|
||||
|
||||
@@ -340,8 +452,8 @@ public class ApiController {
|
||||
errorData.put("onDisk", entityResponse.isExistsOnDisk());
|
||||
|
||||
return ResponseEntity.ok().body(new BaseResponse(20004,
|
||||
MessageCode.FILE_DOWNLOAD_ERROR.getCode(),
|
||||
MessageCode.FILE_DOWNLOAD_ERROR.getDescription(),
|
||||
MessageCode.FILE_NOT_EXIST.getCode(),
|
||||
MessageCode.FILE_NOT_EXIST.getDescription(),
|
||||
errorData));
|
||||
}
|
||||
|
||||
@@ -376,7 +488,15 @@ public class ApiController {
|
||||
MessageCode.FILE_NOT_FOUND.getCode(),
|
||||
MessageCode.FILE_NOT_FOUND.getDescription(),
|
||||
errorData));
|
||||
} catch (NotFoundAuthToken | IOException e) {
|
||||
} catch (NotFoundAuthToken e) {
|
||||
Map<String, Object> errorData = new HashMap<>();
|
||||
errorData.put("token", tokenHeader);
|
||||
|
||||
return ResponseEntity.ok().body(new BaseResponse(20004,
|
||||
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
|
||||
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
|
||||
errorData));
|
||||
} catch (IOException e) {
|
||||
Map<String, Object> errorData = new HashMap<>();
|
||||
errorData.put("token", tokenHeader);
|
||||
errorData.put("fileId", fileId);
|
||||
@@ -389,45 +509,6 @@ public class ApiController {
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/protect/{fileId}")
|
||||
public ResponseEntity<?> protect( @PathVariable(required = false) String fileId) {
|
||||
Optional<FileEntity> optionalFileEntity = fileEntityRepository.findById(fileId);
|
||||
|
||||
if (!optionalFileEntity.isPresent()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
FileEntity fileEntity = optionalFileEntity.get();
|
||||
FileProtector.FileInfo fileInfo = fileUtil.createFileInfo(fileEntity);
|
||||
|
||||
noCopyFileService.addFile(fileInfo);
|
||||
|
||||
fileEntity.setProtectionStatus(ProtectionStatus.PROCESSING);
|
||||
fileEntityRepository.save(fileEntity);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@GetMapping("/check/{fileId}/{type}")
|
||||
public ResponseEntity<?> check(@PathVariable(required = false) String fileId,
|
||||
@PathVariable(required = false) String type) {
|
||||
Optional<FileEntity> optionalFileEntity = fileEntityRepository.findById(fileId);
|
||||
|
||||
if (!optionalFileEntity.isPresent()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
FileEntity fileEntity = optionalFileEntity.get();
|
||||
|
||||
Path path = Paths.get(fileEntity.getProtectedFilePath());
|
||||
|
||||
File file = path.toFile();
|
||||
|
||||
NoCopyCheckResult noCopyCheckResult = noCopyFileService.checkFile(file,
|
||||
FileProtector.Type.valueOf(type.toUpperCase()));
|
||||
|
||||
return ResponseEntity.ok().body(noCopyCheckResult);
|
||||
}
|
||||
|
||||
@GetMapping("/check/file_stats")
|
||||
public ResponseEntity<?> checkFileProtectStats(@RequestHeader("Authorization") String tokenHeader) {
|
||||
String token = tokenHeader.replace("Bearer ", "");
|
||||
|
||||
Reference in New Issue
Block a user