NCBACK-34 need fix delete filentity and hash
Test Workflow / test (push) Successful in 4s

This commit is contained in:
vladp
2026-01-15 20:41:35 +07:00
parent bbb0d7b17a
commit 4a45f40e9f
4 changed files with 104 additions and 64 deletions
@@ -1,7 +1,10 @@
package ru.soune.nocopy.controller;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
@@ -17,12 +20,15 @@ import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.RegAnswer;
import ru.soune.nocopy.dto.file.*;
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.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.FileSimilarityService;
import ru.soune.nocopy.service.ImageHashService;
import ru.soune.nocopy.service.file.FileEntityService;
import ru.soune.nocopy.service.file.FileUploadService;
@@ -33,6 +39,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 +57,8 @@ public class ApiController {
private final FileSimilarityService fileSimilarityService;
private final FileEntityRepository fileEntityRepository;
@PostMapping("/v{version}/data")
public ResponseEntity<?> handlePostRequest(@RequestBody BaseRequest request,
@PathVariable("version") int version) {
@@ -93,62 +102,72 @@ public class ApiController {
@RequestParam(value = "chunk", required = false) MultipartFile chunk) {
try {
if (chunk == null || chunk.isEmpty()) {
return ResponseEntity.ok().body(new BaseResponse(20004, MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Chunk file null or empty", ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.build()));
return buildErrorResponse(uploadId, chunkNumber, "Chunk file null or empty");
}
if (uploadId == null || uploadId.isBlank()) {
return ResponseEntity.ok().body(new BaseResponse(20004, MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Upload ID is required", ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.build()));
return buildErrorResponse(uploadId, chunkNumber, "Upload ID is required");
}
if (chunkNumber == null || chunkNumber < 0) {
return ResponseEntity.ok().body(new BaseResponse(20004, MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Valid chunk number is required", ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.build()));
return buildErrorResponse(uploadId, chunkNumber, "Valid chunk number is required");
}
fileUploadService.uploadChunk(uploadId, chunkNumber, chunk);
UploadProgressResponse uploadProgressResponse = fileUploadService.uploadChunk(uploadId, chunkNumber, chunk);
ChunkUploadResponse responseBody = ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.chunkSize(chunk.getSize())
.message("Chunk uploaded successfully")
.build();
if (uploadProgressResponse.getStatus().equals(UploadStatus.COMPLETED)) {
ResponseEntity<BaseResponse> duplicateCheckResult = checkForDuplicates(uploadProgressResponse.getUploadId());
if (duplicateCheckResult != null) {
return duplicateCheckResult;
}
}
return ResponseEntity.ok().body(new BaseResponse(20004, MessageCode.SUCCESS.getCode(),
"Chunk uploaded successfully", responseBody));
} catch (DuplicateImageException e) {
log.error("Error uploading chunk", e);
ChunkUploadResponse responseBody = ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.build();
return buildSuccessResponse(uploadId, chunkNumber, chunk);
return ResponseEntity.ok().body(new BaseResponse(
20004, MessageCode.DUPLICATE_FILE_UPLOAD.getCode(),
"Failed to upload chunk: " + e.getMessage(), responseBody));
} catch (Exception e) {
log.error("Error uploading chunk", e);
return buildErrorResponse(uploadId, chunkNumber, "Failed to upload chunk: " + e.getMessage());
}
}
ChunkUploadResponse responseBody = ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.build();
private ResponseEntity<BaseResponse> checkForDuplicates(String uploadId) throws IOException {
Optional<FileEntity> uploadedFile = fileEntityRepository.findByUploadSessionId(uploadId);
if (uploadedFile.isEmpty() || !uploadedFile.get().getMimeType().equals("image")) {
return null;
}
FileEntity fileEntity = uploadedFile.get();
List<SimilarFileResponse> similarFiles = fileSimilarityService.findSimilarFiles(fileEntity.getId());
if (hasDuplicate(similarFiles)) {
return handleDuplicate(fileEntity, similarFiles);
}
return null;
}
private boolean hasDuplicate(List<SimilarFileResponse> similarFiles) {
return similarFiles.stream().anyMatch(f -> f.getHammingDistance() <= 5);
}
private ResponseEntity<BaseResponse> handleDuplicate(FileEntity fileEntity, List<SimilarFileResponse> similarFiles)
throws IOException {
fileEntityService.deleteFromDisk(fileEntity);
Optional<FileEntity> originalFile = fileEntityRepository.findById(similarFiles.get(0).getFileId());
if (originalFile.isPresent()) {
Map<String, String> duplicateInfo = Map.of(
"duplicate_file_id", originalFile.get().getId(),
"owner_user_id", String.valueOf(originalFile.get().getUserId()));
return ResponseEntity.ok().body(new BaseResponse(
20004, MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to upload chunk: " + e.getMessage(), responseBody));
20004,
MessageCode.DUPLICATE_FILE_UPLOAD.getCode(),
"Failed to upload chunk, duplicate",
duplicateInfo));
}
return null;
}
@GetMapping("/files/{fileId}/similar")
@@ -179,7 +198,6 @@ public class ApiController {
return ResponseEntity.ok().body(new BaseResponse(
20004, MessageCode.SUCCESS.getCode(), MessageCode.SUCCESS.getDescription(), responseBody));
} catch (Exception e) {
log.error("Error getting progress for upload: {}", uploadId, e);
@@ -187,8 +205,7 @@ public class ApiController {
.uploadId(uploadId)
.build();
return ResponseEntity.ok().body(new BaseResponse(
20004, MessageCode.FILE_UPLOAD_ERROR.getCode(),
return ResponseEntity.ok().body(new BaseResponse(20004, MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get upload progress: " + e.getMessage(), responseBody));
}
}
@@ -347,6 +364,34 @@ public class ApiController {
}
}
private ResponseEntity<BaseResponse> buildSuccessResponse(String uploadId, Integer chunkNumber, MultipartFile chunk) {
ChunkUploadResponse responseBody = ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.chunkSize(chunk.getSize())
.message("Chunk uploaded successfully")
.build();
return ResponseEntity.ok().body(new BaseResponse(
20000,
MessageCode.SUCCESS.getCode(),
"Chunk uploaded successfully",
responseBody));
}
private ResponseEntity<BaseResponse> buildErrorResponse(String uploadId, Integer chunkNumber, String errorMessage) {
ChunkUploadResponse responseBody = ChunkUploadResponse.builder()
.uploadId(uploadId)
.chunkNumber(chunkNumber)
.build();
return ResponseEntity.ok().body(new BaseResponse(
20004,
MessageCode.FILE_UPLOAD_ERROR.getCode(),
errorMessage,
responseBody));
}
private ResponseEntity<BaseResponse> createValidationErrorResponse(BindingResult bindingResult, Integer msgId) {
List<Map<String, String>> fieldErrors = bindingResult.getFieldErrors()
.stream()