From ea33e9cfe37ea2370058ee5c69502086f9e98643 Mon Sep 17 00:00:00 2001 From: backdev-1 Date: Thu, 28 May 2026 12:18:46 +0700 Subject: [PATCH] dev add tariff info and control --- .../nocopy/controller/ApiController.java | 68 ++++++++++++++++++- .../soune/nocopy/util/InternalApiFilter.java | 3 +- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/controller/ApiController.java b/src/main/java/ru/soune/nocopy/controller/ApiController.java index 864f5e4..2023da8 100644 --- a/src/main/java/ru/soune/nocopy/controller/ApiController.java +++ b/src/main/java/ru/soune/nocopy/controller/ApiController.java @@ -1,5 +1,6 @@ package ru.soune.nocopy.controller; +import com.google.common.io.ByteStreams; import com.vrt.NoCopyFileService; import com.vrt.fileprotection.FileProtector; import com.vrt.fileprotection.NoCopyCheckResult; @@ -10,13 +11,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import ru.soune.nocopy.dto.BaseRequest; import ru.soune.nocopy.dto.BaseResponse; import ru.soune.nocopy.dto.MessageCode; @@ -43,8 +43,12 @@ import ru.soune.nocopy.service.file.ProtectionsLimitService; import ru.soune.nocopy.service.file.cloud.CloudStorageService; import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.util.FileUtil; +import software.amazon.awssdk.services.s3.model.NoSuchKeyException; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.*; @@ -159,6 +163,45 @@ public class ApiController { } } + @GetMapping("/internal/data-download/{fileId}") + public ResponseEntity getPublicFile(@PathVariable String fileId) { + try { + FileEntity fileEntity = fileEntityRepository.findById(fileId) + .orElseThrow(() -> new FileNotFoundException("Not found in DB: " + fileId)); + + MediaType mediaType = getMediaType(fileEntity); + + ContentDisposition contentDisposition = ContentDisposition.inline() + .filename(fileEntity.getOriginalFileName(), StandardCharsets.UTF_8) + .build(); + + StreamingResponseBody responseBody = outputStream -> { + try (InputStream inputStream = cloudStorageService.readFileFromStorage(fileEntity.getFilePath())) { + ByteStreams.copy(inputStream, outputStream); + } catch (NoSuchKeyException e) { + log.error("File disappeared from S3 during streaming: {}", fileId, e); + throw new IOException("File not found in storage", e); + } + }; + + return ResponseEntity.ok() + .contentType(mediaType) + .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString()) + .header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600") + .body(responseBody); + } catch (FileNotFoundException e) { + log.warn("File not found in DB: {}", fileId); + return ResponseEntity.notFound().build(); + } catch (NoSuchKeyException e) { + log.warn("File not found in S3: {}", fileId); + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + log.error("Error reading file: {}", fileId, e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + @PostMapping("/internal/data-control") public ResponseEntity handleInternalControlPostRequest(@RequestBody BaseRequest request) { Integer msgId = request.getMsgId(); @@ -767,4 +810,23 @@ public class ApiController { return errorDetail; } + + private MediaType getMediaType(FileEntity fileEntity) { + try { + return MediaType.parseMediaType(fileEntity.getMimeType()); + } catch (InvalidMediaTypeException e) { + String extension = fileEntity.getFileExtension().toLowerCase(); + switch (extension) { + case "jpg": + case "jpeg": + return MediaType.IMAGE_JPEG; + case "png": + return MediaType.IMAGE_PNG; + case "pdf": + return MediaType.APPLICATION_PDF; + default: + return MediaType.APPLICATION_OCTET_STREAM; + } + } + } } \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/util/InternalApiFilter.java b/src/main/java/ru/soune/nocopy/util/InternalApiFilter.java index 9b9922a..4a7c323 100644 --- a/src/main/java/ru/soune/nocopy/util/InternalApiFilter.java +++ b/src/main/java/ru/soune/nocopy/util/InternalApiFilter.java @@ -20,7 +20,8 @@ public class InternalApiFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - if (request.getRequestURI().startsWith("api/internal/")) { + if (request.getRequestURI().startsWith("api/internal/") || + request.getRequestURI().startsWith("api/internal/download")) { String providedKey = request.getHeader("X-Internal-Key"); if (!internalApiKey.equals(providedKey)) {