refactor: standardize MIME handling via Spring MediaType (#4389)

This commit is contained in:
Ludy 2025-09-05 12:08:24 +02:00 committed by GitHub
parent f14955a019
commit 9a39aff19f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
82 changed files with 310 additions and 164 deletions

View File

@ -3,6 +3,7 @@ package stirling.software.common.annotations;
import java.lang.annotation.*; import java.lang.annotation.*;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
@ -37,7 +38,7 @@ public @interface AutoJobPostMapping {
/** MIME types this endpoint accepts. Defaults to {@code multipart/form-data}. */ /** MIME types this endpoint accepts. Defaults to {@code multipart/form-data}. */
@AliasFor(annotation = RequestMapping.class, attribute = "consumes") @AliasFor(annotation = RequestMapping.class, attribute = "consumes")
String[] consumes() default {"multipart/form-data"}; String[] consumes() default {MediaType.MULTIPART_FORM_DATA_VALUE};
/** /**
* Maximum execution time in milliseconds before the job is aborted. A negative value means "use * Maximum execution time in milliseconds before the job is aborted. A negative value means "use

View File

@ -1,5 +1,6 @@
package stirling.software.common.model.api; package stirling.software.common.model.api;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@ -14,7 +15,7 @@ import lombok.NoArgsConstructor;
public class PDFFile { public class PDFFile {
@Schema( @Schema(
description = "The input PDF file", description = "The input PDF file",
contentMediaType = "application/pdf", contentMediaType = MediaType.APPLICATION_PDF_VALUE,
format = "binary") format = "binary")
private MultipartFile fileInput; private MultipartFile fileInput;

View File

@ -227,7 +227,8 @@ public class JobExecutorService {
if (result instanceof byte[]) { if (result instanceof byte[]) {
// Store byte array directly to disk to avoid double memory consumption // Store byte array directly to disk to avoid double memory consumption
String fileId = fileStorage.storeBytes((byte[]) result, "result.pdf"); String fileId = fileStorage.storeBytes((byte[]) result, "result.pdf");
taskManager.setFileResult(jobId, fileId, "result.pdf", "application/pdf"); taskManager.setFileResult(
jobId, fileId, "result.pdf", MediaType.APPLICATION_PDF_VALUE);
log.debug("Stored byte[] result with fileId: {}", fileId); log.debug("Stored byte[] result with fileId: {}", fileId);
// Let the byte array get collected naturally in the next GC cycle // Let the byte array get collected naturally in the next GC cycle
@ -239,7 +240,7 @@ public class JobExecutorService {
if (body instanceof byte[]) { if (body instanceof byte[]) {
// Extract filename from content-disposition header if available // Extract filename from content-disposition header if available
String filename = "result.pdf"; String filename = "result.pdf";
String contentType = "application/pdf"; String contentType = MediaType.APPLICATION_PDF_VALUE;
if (response.getHeaders().getContentDisposition() != null) { if (response.getHeaders().getContentDisposition() != null) {
String disposition = String disposition =
@ -276,7 +277,7 @@ public class JobExecutorService {
if (fileId != null && !fileId.isEmpty()) { if (fileId != null && !fileId.isEmpty()) {
// Try to get filename and content type // Try to get filename and content type
String filename = "result.pdf"; String filename = "result.pdf";
String contentType = "application/pdf"; String contentType = MediaType.APPLICATION_PDF_VALUE;
try { try {
java.lang.reflect.Method getOriginalFileName = java.lang.reflect.Method getOriginalFileName =
@ -317,8 +318,7 @@ public class JobExecutorService {
// Store generic result // Store generic result
taskManager.setResult(jobId, body); taskManager.setResult(jobId, body);
} }
} else if (result instanceof MultipartFile) { } else if (result instanceof MultipartFile file) {
MultipartFile file = (MultipartFile) result;
String fileId = fileStorage.storeFile(file); String fileId = fileStorage.storeFile(file);
taskManager.setFileResult( taskManager.setFileResult(
jobId, fileId, file.getOriginalFilename(), file.getContentType()); jobId, fileId, file.getOriginalFilename(), file.getContentType());
@ -335,7 +335,7 @@ public class JobExecutorService {
if (fileId != null && !fileId.isEmpty()) { if (fileId != null && !fileId.isEmpty()) {
// Try to get filename and content type // Try to get filename and content type
String filename = "result.pdf"; String filename = "result.pdf";
String contentType = "application/pdf"; String contentType = MediaType.APPLICATION_PDF_VALUE;
try { try {
java.lang.reflect.Method getOriginalFileName = java.lang.reflect.Method getOriginalFileName =
@ -398,9 +398,8 @@ public class JobExecutorService {
HttpHeaders.CONTENT_DISPOSITION, HttpHeaders.CONTENT_DISPOSITION,
"form-data; name=\"attachment\"; filename=\"result.pdf\"") "form-data; name=\"attachment\"; filename=\"result.pdf\"")
.body(result); .body(result);
} else if (result instanceof MultipartFile) { } else if (result instanceof MultipartFile file) {
// Return MultipartFile content // Return MultipartFile content
MultipartFile file = (MultipartFile) result;
return ResponseEntity.ok() return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(file.getContentType())) .contentType(MediaType.parseMediaType(file.getContentType()))
.header( .header(

View File

@ -12,6 +12,8 @@ import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.springframework.http.MediaType;
import lombok.Data; import lombok.Data;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
@ -28,8 +30,8 @@ public class EmlParser {
Pattern.compile("=\\?([^?]+)\\?([BbQq])\\?([^?]*)\\?="); Pattern.compile("=\\?([^?]+)\\?([BbQq])\\?([^?]*)\\?=");
private static final String DISPOSITION_ATTACHMENT = "attachment"; private static final String DISPOSITION_ATTACHMENT = "attachment";
private static final String TEXT_PLAIN = "text/plain"; private static final String TEXT_PLAIN = MediaType.TEXT_PLAIN_VALUE;
private static final String TEXT_HTML = "text/html"; private static final String TEXT_HTML = MediaType.TEXT_HTML_VALUE;
private static final String MULTIPART_PREFIX = "multipart/"; private static final String MULTIPART_PREFIX = "multipart/";
private static final String HEADER_CONTENT_TYPE = "content-type:"; private static final String HEADER_CONTENT_TYPE = "content-type:";
@ -69,12 +71,12 @@ public class EmlParser {
if (isJakartaMailAvailable()) { if (isJakartaMailAvailable()) {
return extractEmailContentAdvanced(emlBytes, request, customHtmlSanitizer); return extractEmailContentAdvanced(emlBytes, request, customHtmlSanitizer);
} else { } else {
return extractEmailContentBasic(emlBytes, request, customHtmlSanitizer); return extractEmailContentBasic(emlBytes, customHtmlSanitizer);
} }
} }
private static EmailContent extractEmailContentBasic( private static EmailContent extractEmailContentBasic(
byte[] emlBytes, EmlToPdfRequest request, CustomHtmlSanitizer customHtmlSanitizer) { byte[] emlBytes, CustomHtmlSanitizer customHtmlSanitizer) {
String emlContent = new String(emlBytes, StandardCharsets.UTF_8); String emlContent = new String(emlBytes, StandardCharsets.UTF_8);
EmailContent content = new EmailContent(); EmailContent content = new EmailContent();
@ -121,7 +123,7 @@ public class EmlParser {
return extractFromMimeMessage(message, request, customHtmlSanitizer); return extractFromMimeMessage(message, request, customHtmlSanitizer);
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
return extractEmailContentBasic(emlBytes, request, customHtmlSanitizer); return extractEmailContentBasic(emlBytes, customHtmlSanitizer);
} }
} }

View File

@ -8,6 +8,8 @@ import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.springframework.http.MediaType;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import stirling.software.common.model.api.converters.EmlToPdfRequest; import stirling.software.common.model.api.converters.EmlToPdfRequest;
@ -33,10 +35,10 @@ public class EmlProcessingUtils {
// MIME type detection // MIME type detection
private static final Map<String, String> EXTENSION_TO_MIME_TYPE = private static final Map<String, String> EXTENSION_TO_MIME_TYPE =
Map.of( Map.of(
".png", "image/png", ".png", MediaType.IMAGE_PNG_VALUE,
".jpg", "image/jpeg", ".jpg", MediaType.IMAGE_JPEG_VALUE,
".jpeg", "image/jpeg", ".jpeg", MediaType.IMAGE_JPEG_VALUE,
".gif", "image/gif", ".gif", MediaType.IMAGE_GIF_VALUE,
".bmp", "image/bmp", ".bmp", "image/bmp",
".webp", "image/webp", ".webp", "image/webp",
".svg", "image/svg+xml", ".svg", "image/svg+xml",
@ -81,8 +83,8 @@ public class EmlProcessingUtils {
|| lowerContent.contains("bcc:"); || lowerContent.contains("bcc:");
boolean hasMimeStructure = boolean hasMimeStructure =
lowerContent.contains("multipart/") lowerContent.contains("multipart/")
|| lowerContent.contains("text/plain") || lowerContent.contains(MediaType.TEXT_PLAIN_VALUE)
|| lowerContent.contains("text/html") || lowerContent.contains(MediaType.TEXT_HTML_VALUE)
|| lowerContent.contains("boundary="); || lowerContent.contains("boundary=");
int headerCount = 0; int headerCount = 0;
@ -464,7 +466,7 @@ public class EmlProcessingUtils {
} }
} }
return "image/png"; return MediaType.IMAGE_PNG_VALUE; // Default MIME type
} }
public static String decodeUrlEncoded(String encoded) { public static String decodeUrlEncoded(String encoded) {

View File

@ -36,7 +36,7 @@ public class PDFToFile {
public ResponseEntity<byte[]> processPdfToMarkdown(MultipartFile inputFile) public ResponseEntity<byte[]> processPdfToMarkdown(MultipartFile inputFile)
throws IOException, InterruptedException { throws IOException, InterruptedException {
if (!"application/pdf".equals(inputFile.getContentType())) { if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} }
@ -153,7 +153,7 @@ public class PDFToFile {
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile) public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
throws IOException, InterruptedException { throws IOException, InterruptedException {
if (!"application/pdf".equals(inputFile.getContentType())) { if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} }
@ -223,7 +223,7 @@ public class PDFToFile {
MultipartFile inputFile, String outputFormat, String libreOfficeFilter) MultipartFile inputFile, String outputFormat, String libreOfficeFilter)
throws IOException, InterruptedException { throws IOException, InterruptedException {
if (!"application/pdf".equals(inputFile.getContentType())) { if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} }

View File

@ -37,6 +37,7 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition; import org.apache.pdfbox.text.TextPosition;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import lombok.Data; import lombok.Data;
@ -118,7 +119,7 @@ public class PdfAttachmentHandler {
public String getContentType() { public String getContentType() {
return attachment.getContentType() != null return attachment.getContentType() != null
? attachment.getContentType() ? attachment.getContentType()
: "application/octet-stream"; : MediaType.APPLICATION_OCTET_STREAM_VALUE;
} }
@Override @Override

View File

@ -29,6 +29,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames; import io.github.pixee.security.Filenames;
@ -156,7 +157,8 @@ public class PdfUtils {
if (DPI > maxSafeDpi) { if (DPI > maxSafeDpi) {
throw ExceptionUtils.createIllegalArgumentException( throw ExceptionUtils.createIllegalArgumentException(
"error.dpiExceedsLimit", "error.dpiExceedsLimit",
"DPI value {0} exceeds maximum safe limit of {1}. High DPI values can cause memory issues and crashes. Please use a lower DPI value.", "DPI value {0} exceeds maximum safe limit of {1}. High DPI values can cause"
+ " memory issues and crashes. Please use a lower DPI value.",
DPI, DPI,
maxSafeDpi); maxSafeDpi);
} }
@ -196,7 +198,9 @@ public class PdfUtils {
.contains("Maximum size of image exceeded")) { .contains("Maximum size of image exceeded")) {
throw ExceptionUtils.createIllegalArgumentException( throw ExceptionUtils.createIllegalArgumentException(
"error.pageTooBigForDpi", "error.pageTooBigForDpi",
"PDF page {0} is too large to render at {1} DPI. Please try a lower DPI value (recommended: 150 or less).", "PDF page {0} is too large to render at {1} DPI. Please"
+ " try a lower DPI value (recommended: 150 or"
+ " less).",
i + 1, i + 1,
DPI); DPI);
} }
@ -241,7 +245,10 @@ public class PdfUtils {
.contains("Maximum size of image exceeded")) { .contains("Maximum size of image exceeded")) {
throw ExceptionUtils.createIllegalArgumentException( throw ExceptionUtils.createIllegalArgumentException(
"error.pageTooBigExceedsArray", "error.pageTooBigExceedsArray",
"PDF page {0} is too large to render at {1} DPI. The resulting image would exceed Java's maximum array size. Please try a lower DPI value (recommended: 150 or less).", "PDF page {0} is too large to render at {1} DPI. The"
+ " resulting image would exceed Java's maximum"
+ " array size. Please try a lower DPI value"
+ " (recommended: 150 or less).",
i + 1, i + 1,
DPI); DPI);
} }
@ -282,7 +289,9 @@ public class PdfUtils {
.contains("Maximum size of image exceeded")) { .contains("Maximum size of image exceeded")) {
throw ExceptionUtils.createIllegalArgumentException( throw ExceptionUtils.createIllegalArgumentException(
"error.pageTooBigForDpi", "error.pageTooBigForDpi",
"PDF page {0} is too large to render at {1} DPI. Please try a lower DPI value (recommended: 150 or less).", "PDF page {0} is too large to render at {1} DPI. Please"
+ " try a lower DPI value (recommended: 150 or"
+ " less).",
i + 1, i + 1,
DPI); DPI);
} }
@ -315,7 +324,8 @@ public class PdfUtils {
&& e.getMessage().contains("Maximum size of image exceeded")) { && e.getMessage().contains("Maximum size of image exceeded")) {
throw ExceptionUtils.createIllegalArgumentException( throw ExceptionUtils.createIllegalArgumentException(
"error.pageTooBigForDpi", "error.pageTooBigForDpi",
"PDF page {0} is too large to render at {1} DPI. Please try a lower DPI value (recommended: 150 or less).", "PDF page {0} is too large to render at {1} DPI. Please try"
+ " a lower DPI value (recommended: 150 or less).",
i + 1, i + 1,
DPI); DPI);
} }
@ -366,7 +376,9 @@ public class PdfUtils {
&& e.getMessage().contains("Maximum size of image exceeded")) { && e.getMessage().contains("Maximum size of image exceeded")) {
throw ExceptionUtils.createIllegalArgumentException( throw ExceptionUtils.createIllegalArgumentException(
"error.pageTooBigFor300Dpi", "error.pageTooBigFor300Dpi",
"PDF page {0} is too large to render at 300 DPI. The resulting image would exceed Java's maximum array size. Please use a lower DPI value for PDF-to-image conversion.", "PDF page {0} is too large to render at 300 DPI. The resulting image"
+ " would exceed Java's maximum array size. Please use a lower DPI"
+ " value for PDF-to-image conversion.",
page + 1); page + 1);
} }
throw e; throw e;
@ -435,7 +447,7 @@ public class PdfUtils {
ImageProcessingUtils.convertColorType(image, colorType); ImageProcessingUtils.convertColorType(image, colorType);
// Use JPEGFactory if it's JPEG since JPEG is lossy // Use JPEGFactory if it's JPEG since JPEG is lossy
PDImageXObject pdImage = PDImageXObject pdImage =
(contentType != null && "image/jpeg".equals(contentType)) (contentType != null && MediaType.IMAGE_JPEG_VALUE.equals(contentType))
? JPEGFactory.createFromImage(doc, convertedImage) ? JPEGFactory.createFromImage(doc, convertedImage)
: LosslessFactory.createFromImage(doc, convertedImage); : LosslessFactory.createFromImage(doc, convertedImage);
addImageToDocument(doc, pdImage, fitOption, autoRotate); addImageToDocument(doc, pdImage, fitOption, autoRotate);

View File

@ -11,6 +11,7 @@ import java.nio.file.Path;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.MockWebServer;
@ -23,7 +24,7 @@ class ApplicationPropertiesSaml2HttpTest {
server.enqueue( server.enqueue(
new MockResponse() new MockResponse()
.setResponseCode(200) .setResponseCode(200)
.addHeader("Content-Type", "application/xml") .addHeader("Content-Type", MediaType.APPLICATION_XML_VALUE)
.setBody("<EntityDescriptor/>")); .setBody("<EntityDescriptor/>"));
server.start(); server.start();

View File

@ -1,12 +1,12 @@
package stirling.software.common.service; package stirling.software.common.service;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static stirling.software.common.service.SpyPDFDocumentFactory.*; import static stirling.software.common.service.SpyPDFDocumentFactory.*;
import java.io.*; import java.io.*;
import java.nio.file.*; import java.nio.file.*;
import java.nio.file.Files;
import java.util.Arrays; import java.util.Arrays;
import org.apache.pdfbox.Loader; import org.apache.pdfbox.Loader;
@ -18,9 +18,11 @@ import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode; import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import stirling.software.common.model.api.PDFFile; import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.SpyPDFDocumentFactory.StrategyType;
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -73,7 +75,7 @@ class CustomPDFDocumentFactoryTest {
void testStrategy_MultipartFile(int sizeMB, StrategyType expected) throws IOException { void testStrategy_MultipartFile(int sizeMB, StrategyType expected) throws IOException {
byte[] inflated = inflatePdf(basePdfBytes, sizeMB); byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
MockMultipartFile multipart = MockMultipartFile multipart =
new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated); new MockMultipartFile("file", "doc.pdf", MediaType.APPLICATION_PDF_VALUE, inflated);
try (PDDocument doc = factory.load(multipart)) { try (PDDocument doc = factory.load(multipart)) {
Assertions.assertEquals(expected, factory.lastStrategyUsed); Assertions.assertEquals(expected, factory.lastStrategyUsed);
} }
@ -84,7 +86,7 @@ class CustomPDFDocumentFactoryTest {
void testStrategy_PDFFile(int sizeMB, StrategyType expected) throws IOException { void testStrategy_PDFFile(int sizeMB, StrategyType expected) throws IOException {
byte[] inflated = inflatePdf(basePdfBytes, sizeMB); byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
MockMultipartFile multipart = MockMultipartFile multipart =
new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated); new MockMultipartFile("file", "doc.pdf", MediaType.APPLICATION_PDF_VALUE, inflated);
PDFFile pdfFile = new PDFFile(); PDFFile pdfFile = new PDFFile();
pdfFile.setFileInput(multipart); pdfFile.setFileInput(multipart);
try (PDDocument doc = factory.load(pdfFile)) { try (PDDocument doc = factory.load(pdfFile)) {

View File

@ -2,6 +2,8 @@ package stirling.software.common.service;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.AdditionalAnswers.*; import static org.mockito.AdditionalAnswers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import java.io.IOException; import java.io.IOException;
@ -15,6 +17,7 @@ import org.junit.jupiter.api.io.TempDir;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -36,7 +39,7 @@ class FileStorageTest {
// Create a mock MultipartFile // Create a mock MultipartFile
mockFile = mock(MultipartFile.class); mockFile = mock(MultipartFile.class);
when(mockFile.getOriginalFilename()).thenReturn("test.pdf"); when(mockFile.getOriginalFilename()).thenReturn("test.pdf");
when(mockFile.getContentType()).thenReturn("application/pdf"); when(mockFile.getContentType()).thenReturn(MediaType.APPLICATION_PDF_VALUE);
} }
@Test @Test

View File

@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import stirling.software.common.model.job.JobResult; import stirling.software.common.model.job.JobResult;
@ -77,7 +78,7 @@ class TaskManagerTest {
taskManager.createTask(jobId); taskManager.createTask(jobId);
String fileId = "file-id"; String fileId = "file-id";
String originalFileName = "test.pdf"; String originalFileName = "test.pdf";
String contentType = "application/pdf"; String contentType = MediaType.APPLICATION_PDF_VALUE;
long fileSize = 1024L; long fileSize = 1024L;
// Mock the fileStorage.getFileSize() call // Mock the fileStorage.getFileSize() call
@ -185,7 +186,8 @@ class TaskManagerTest {
// 2. Create completed successful job with file // 2. Create completed successful job with file
String successFileJobId = "success-file-job"; String successFileJobId = "success-file-job";
taskManager.createTask(successFileJobId); taskManager.createTask(successFileJobId);
taskManager.setFileResult(successFileJobId, "file-id", "test.pdf", "application/pdf"); taskManager.setFileResult(
successFileJobId, "file-id", "test.pdf", MediaType.APPLICATION_PDF_VALUE);
// 3. Create completed successful job without file // 3. Create completed successful job without file
String successJobId = "success-job"; String successJobId = "success-job";
@ -235,7 +237,7 @@ class TaskManagerTest {
ResultFile.builder() ResultFile.builder()
.fileId("file-id") .fileId("file-id")
.fileName("test.pdf") .fileName("test.pdf")
.contentType("application/pdf") .contentType(MediaType.APPLICATION_PDF_VALUE)
.fileSize(1024L) .fileSize(1024L)
.build(); .build();
ReflectionTestUtils.setField(oldJob, "resultFiles", java.util.List.of(resultFile)); ReflectionTestUtils.setField(oldJob, "resultFiles", java.util.List.of(resultFile));

View File

@ -25,6 +25,7 @@ import org.mockito.Mock;
import org.mockito.MockedStatic; import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -57,7 +58,10 @@ class PDFToFileTest {
// Prepare // Prepare
MultipartFile nonPdfFile = MultipartFile nonPdfFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.txt", "text/plain", "This is not a PDF".getBytes()); "file",
"test.txt",
MediaType.TEXT_PLAIN_VALUE,
"This is not a PDF".getBytes());
// Execute // Execute
ResponseEntity<byte[]> response = pdfToFile.processPdfToMarkdown(nonPdfFile); ResponseEntity<byte[]> response = pdfToFile.processPdfToMarkdown(nonPdfFile);
@ -71,7 +75,10 @@ class PDFToFileTest {
// Prepare // Prepare
MultipartFile nonPdfFile = MultipartFile nonPdfFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.txt", "text/plain", "This is not a PDF".getBytes()); "file",
"test.txt",
MediaType.TEXT_PLAIN_VALUE,
"This is not a PDF".getBytes());
// Execute // Execute
ResponseEntity<byte[]> response = pdfToFile.processPdfToHtml(nonPdfFile); ResponseEntity<byte[]> response = pdfToFile.processPdfToHtml(nonPdfFile);
@ -86,7 +93,10 @@ class PDFToFileTest {
// Prepare // Prepare
MultipartFile nonPdfFile = MultipartFile nonPdfFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.txt", "text/plain", "This is not a PDF".getBytes()); "file",
"test.txt",
MediaType.TEXT_PLAIN_VALUE,
"This is not a PDF".getBytes());
// Execute // Execute
ResponseEntity<byte[]> response = ResponseEntity<byte[]> response =
@ -102,7 +112,10 @@ class PDFToFileTest {
// Prepare // Prepare
MultipartFile pdfFile = MultipartFile pdfFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.pdf", "application/pdf", "Fake PDF content".getBytes()); "file",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes());
// Execute with invalid format // Execute with invalid format
ResponseEntity<byte[]> response = ResponseEntity<byte[]> response =
@ -120,7 +133,10 @@ class PDFToFileTest {
// Create a mock PDF file // Create a mock PDF file
MultipartFile pdfFile = MultipartFile pdfFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.pdf", "application/pdf", "Fake PDF content".getBytes()); "file",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes());
// Create a mock HTML output file // Create a mock HTML output file
Path htmlOutputFile = tempDir.resolve("test.html"); Path htmlOutputFile = tempDir.resolve("test.html");
@ -168,7 +184,7 @@ class PDFToFileTest {
new MockMultipartFile( new MockMultipartFile(
"file", "file",
"multipage.pdf", "multipage.pdf",
"application/pdf", MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes()); "Fake PDF content".getBytes());
// Setup ProcessExecutor mock // Setup ProcessExecutor mock
@ -245,7 +261,10 @@ class PDFToFileTest {
// Create a mock PDF file // Create a mock PDF file
MultipartFile pdfFile = MultipartFile pdfFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.pdf", "application/pdf", "Fake PDF content".getBytes()); "file",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes());
// Setup ProcessExecutor mock // Setup ProcessExecutor mock
mockedStaticProcessExecutor mockedStaticProcessExecutor
@ -324,7 +343,7 @@ class PDFToFileTest {
new MockMultipartFile( new MockMultipartFile(
"file", "file",
"document.pdf", "document.pdf",
"application/pdf", MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes()); "Fake PDF content".getBytes());
// Setup ProcessExecutor mock // Setup ProcessExecutor mock
@ -386,7 +405,7 @@ class PDFToFileTest {
new MockMultipartFile( new MockMultipartFile(
"file", "file",
"document.pdf", "document.pdf",
"application/pdf", MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes()); "Fake PDF content".getBytes());
// Setup ProcessExecutor mock // Setup ProcessExecutor mock
@ -472,7 +491,7 @@ class PDFToFileTest {
new MockMultipartFile( new MockMultipartFile(
"file", "file",
"document.pdf", "document.pdf",
"application/pdf", MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes()); "Fake PDF content".getBytes());
// Setup ProcessExecutor mock // Setup ProcessExecutor mock
@ -531,7 +550,10 @@ class PDFToFileTest {
// Create a mock PDF file with no filename // Create a mock PDF file with no filename
MultipartFile pdfFile = MultipartFile pdfFile =
new MockMultipartFile( new MockMultipartFile(
"file", "", "application/pdf", "Fake PDF content".getBytes()); "file",
"",
MediaType.APPLICATION_PDF_VALUE,
"Fake PDF content".getBytes());
// Setup ProcessExecutor mock // Setup ProcessExecutor mock
mockedStaticProcessExecutor mockedStaticProcessExecutor

View File

@ -48,7 +48,8 @@ public class WebResponseUtilsTest {
try { try {
byte[] fileContent = "Sample file content".getBytes(); byte[] fileContent = "Sample file content".getBytes();
MockMultipartFile file = MockMultipartFile file =
new MockMultipartFile("file", "sample.txt", "text/plain", fileContent); new MockMultipartFile(
"file", "sample.txt", MediaType.TEXT_PLAIN_VALUE, fileContent);
ResponseEntity<byte[]> responseEntity = ResponseEntity<byte[]> responseEntity =
WebResponseUtils.multiPartFileToWebResponse(file); WebResponseUtils.multiPartFileToWebResponse(file);

View File

@ -8,6 +8,7 @@ import java.lang.reflect.Method;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -24,7 +25,10 @@ class CustomColorReplaceStrategyTest {
// Create a mock file // Create a mock file
mockFile = mockFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.pdf", "application/pdf", "test pdf content".getBytes()); "file",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
"test pdf content".getBytes());
// Initialize strategy with custom colors // Initialize strategy with custom colors
strategy = strategy =

View File

@ -24,6 +24,7 @@ import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -38,7 +39,9 @@ class InvertFullColorStrategyTest {
void setUp() throws Exception { void setUp() throws Exception {
// Create a simple PDF document for testing // Create a simple PDF document for testing
byte[] pdfBytes = createSimplePdfWithRectangle(); byte[] pdfBytes = createSimplePdfWithRectangle();
mockPdfFile = new MockMultipartFile("file", "test.pdf", "application/pdf", pdfBytes); mockPdfFile =
new MockMultipartFile(
"file", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
// Create the strategy instance // Create the strategy instance
strategy = new InvertFullColorStrategy(mockPdfFile, ReplaceAndInvert.FULL_INVERSION); strategy = new InvertFullColorStrategy(mockPdfFile, ReplaceAndInvert.FULL_INVERSION);

View File

@ -7,6 +7,7 @@ import java.io.IOException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -35,7 +36,10 @@ class ReplaceAndInvertColorStrategyTest {
// Arrange // Arrange
MultipartFile mockFile = MultipartFile mockFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.pdf", "application/pdf", "test content".getBytes()); "file",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
"test content".getBytes());
ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR; ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR;
// Act // Act
@ -56,7 +60,7 @@ class ReplaceAndInvertColorStrategyTest {
// Arrange // Arrange
byte[] content = "test pdf content".getBytes(); byte[] content = "test pdf content".getBytes();
MultipartFile mockFile = MultipartFile mockFile =
new MockMultipartFile("file", "test.pdf", "application/pdf", content); new MockMultipartFile("file", "test.pdf", MediaType.APPLICATION_PDF_VALUE, content);
ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR; ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR;
ReplaceAndInvertColorStrategy strategy = ReplaceAndInvertColorStrategy strategy =
@ -74,10 +78,16 @@ class ReplaceAndInvertColorStrategyTest {
// Arrange // Arrange
MultipartFile mockFile1 = MultipartFile mockFile1 =
new MockMultipartFile( new MockMultipartFile(
"file1", "test1.pdf", "application/pdf", "content1".getBytes()); "file1",
"test1.pdf",
MediaType.APPLICATION_PDF_VALUE,
"content1".getBytes());
MultipartFile mockFile2 = MultipartFile mockFile2 =
new MockMultipartFile( new MockMultipartFile(
"file2", "test2.pdf", "application/pdf", "content2".getBytes()); "file2",
"test2.pdf",
MediaType.APPLICATION_PDF_VALUE,
"content2".getBytes());
// Act // Act
ReplaceAndInvertColorStrategy strategy = ReplaceAndInvertColorStrategy strategy =

View File

@ -11,6 +11,7 @@ import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.pdmodel.encryption.PDEncryption; import org.apache.pdfbox.pdmodel.encryption.PDEncryption;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -29,7 +30,7 @@ public class AnalysisController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/page-count", consumes = "multipart/form-data") @PostMapping(value = "/page-count", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get PDF page count", summary = "Get PDF page count",
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO") description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
@ -39,7 +40,7 @@ public class AnalysisController {
} }
} }
@PostMapping(value = "/basic-info", consumes = "multipart/form-data") @PostMapping(value = "/basic-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get basic PDF information", summary = "Get basic PDF information",
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO") description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
@ -53,7 +54,7 @@ public class AnalysisController {
} }
} }
@PostMapping(value = "/document-properties", consumes = "multipart/form-data") @PostMapping(value = "/document-properties", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get PDF document properties", summary = "Get PDF document properties",
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO") description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
@ -76,7 +77,7 @@ public class AnalysisController {
} }
} }
@PostMapping(value = "/page-dimensions", consumes = "multipart/form-data") @PostMapping(value = "/page-dimensions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get page dimensions for all pages", summary = "Get page dimensions for all pages",
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO") description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
@ -96,7 +97,7 @@ public class AnalysisController {
} }
} }
@PostMapping(value = "/form-fields", consumes = "multipart/form-data") @PostMapping(value = "/form-fields", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get form field information", summary = "Get form field information",
description = description =
@ -119,7 +120,7 @@ public class AnalysisController {
} }
} }
@PostMapping(value = "/annotation-info", consumes = "multipart/form-data") @PostMapping(value = "/annotation-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get annotation information", summary = "Get annotation information",
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO") description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
@ -143,7 +144,7 @@ public class AnalysisController {
} }
} }
@PostMapping(value = "/font-info", consumes = "multipart/form-data") @PostMapping(value = "/font-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get font information", summary = "Get font information",
description = description =
@ -165,7 +166,7 @@ public class AnalysisController {
} }
} }
@PostMapping(value = "/security-info", consumes = "multipart/form-data") @PostMapping(value = "/security-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Get security information", summary = "Get security information",
description = description =

View File

@ -10,6 +10,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode; import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -33,7 +34,7 @@ public class CropController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/crop", consumes = "multipart/form-data") @PostMapping(value = "/crop", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Crops a PDF document", summary = "Crops a PDF document",
description = description =

View File

@ -46,7 +46,7 @@ public class EditTableOfContentsController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
@PostMapping(value = "/extract-bookmarks", consumes = "multipart/form-data") @PostMapping(value = "/extract-bookmarks", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Extract PDF Bookmarks", summary = "Extract PDF Bookmarks",
description = "Extracts bookmarks/table of contents from a PDF document as JSON.") description = "Extracts bookmarks/table of contents from a PDF document as JSON.")
@ -154,7 +154,7 @@ public class EditTableOfContentsController {
return bookmark; return bookmark;
} }
@PostMapping(value = "/edit-table-of-contents", consumes = "multipart/form-data") @PostMapping(value = "/edit-table-of-contents", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Edit Table of Contents", summary = "Edit Table of Contents",
description = "Add or edit bookmarks/table of contents in a PDF document.") description = "Add or edit bookmarks/table of contents in a PDF document.")

View File

@ -20,6 +20,7 @@ import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlin
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -154,7 +155,7 @@ public class MergeController {
} }
} }
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/merge-pdfs")
@Operation( @Operation(
summary = "Merge multiple PDF files into one", summary = "Merge multiple PDF files into one",
description = description =

View File

@ -11,6 +11,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -36,7 +37,7 @@ public class MultiPageLayoutController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/multi-page-layout", consumes = "multipart/form-data") @PostMapping(value = "/multi-page-layout", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Merge multiple pages of a PDF document into a single page", summary = "Merge multiple pages of a PDF document into a single page",
description = description =

View File

@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -46,7 +47,7 @@ public class PdfImageRemovalController {
* content type and filename. * content type and filename.
* @throws IOException If an error occurs while processing the PDF file. * @throws IOException If an error occurs while processing the PDF file.
*/ */
@PostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-image-pdf")
@Operation( @Operation(
summary = "Remove images from file to reduce the file size.", summary = "Remove images from file to reduce the file size.",
description = description =

View File

@ -39,7 +39,7 @@ public class PdfOverlayController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data") @PostMapping(value = "/overlay-pdfs", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Overlay PDF files in various modes", summary = "Overlay PDF files in various modes",
description = description =

View File

@ -7,6 +7,7 @@ import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -38,7 +39,7 @@ public class RearrangePagesPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-pages")
@Operation( @Operation(
summary = "Remove pages from a PDF file", summary = "Remove pages from a PDF file",
description = description =
@ -237,7 +238,7 @@ public class RearrangePagesPDFController {
} }
} }
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/rearrange-pages")
@Operation( @Operation(
summary = "Rearrange pages in a PDF file", summary = "Rearrange pages in a PDF file",
description = description =

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageTree; import org.apache.pdfbox.pdmodel.PDPageTree;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -31,7 +32,7 @@ public class RotationController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/rotate-pdf")
@Operation( @Operation(
summary = "Rotate a PDF file", summary = "Rotate a PDF file",
description = description =

View File

@ -12,6 +12,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -38,7 +39,7 @@ public class ScalePagesController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data") @PostMapping(value = "/scale-pages", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Change the size of a PDF page/document", summary = "Change the size of a PDF page/document",
description = description =

View File

@ -41,7 +41,7 @@ public class SplitPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/split-pages") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/split-pages")
@Operation( @Operation(
summary = "Split a PDF file into separate documents", summary = "Split a PDF file into separate documents",
description = description =

View File

@ -117,7 +117,7 @@ public class SplitPdfByChaptersController {
return bookmarks; return bookmarks;
} }
@PostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data") @PostMapping(value = "/split-pdf-by-chapters", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Split PDFs by Chapters", summary = "Split PDFs by Chapters",
description = "Splits a PDF into chapters and returns a ZIP file.") description = "Splits a PDF into chapters and returns a ZIP file.")

View File

@ -43,7 +43,7 @@ public class SplitPdfBySectionsController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data") @PostMapping(value = "/split-pdf-by-sections", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Split PDF pages into smaller sections", summary = "Split PDF pages into smaller sections",
description = description =

View File

@ -39,7 +39,7 @@ public class SplitPdfBySizeController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data") @PostMapping(value = "/split-by-size-or-count", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Auto split PDF pages into separate documents based on size or count", summary = "Auto split PDF pages into separate documents based on size or count",
description = description =

View File

@ -10,6 +10,7 @@ import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -33,7 +34,7 @@ public class ToSinglePageController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf-to-single-page")
@Operation( @Operation(
summary = "Convert a multi-page PDF into a single long page PDF", summary = "Convert a multi-page PDF into a single long page PDF",
description = description =

View File

@ -40,7 +40,7 @@ public class ConvertEmlToPDF {
private final TempFileManager tempFileManager; private final TempFileManager tempFileManager;
private final CustomHtmlSanitizer customHtmlSanitizer; private final CustomHtmlSanitizer customHtmlSanitizer;
@PostMapping(consumes = "multipart/form-data", value = "/eml/pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/eml/pdf")
@Operation( @Operation(
summary = "Convert EML to PDF", summary = "Convert EML to PDF",
description = description =

View File

@ -1,5 +1,6 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -36,7 +37,7 @@ public class ConvertHtmlToPDF {
private final CustomHtmlSanitizer customHtmlSanitizer; private final CustomHtmlSanitizer customHtmlSanitizer;
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/html/pdf")
@Operation( @Operation(
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF", summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
description = description =

View File

@ -51,7 +51,7 @@ public class ConvertImgPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/pdf/img") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/img")
@Operation( @Operation(
summary = "Convert PDF to image(s)", summary = "Convert PDF to image(s)",
description = description =
@ -213,7 +213,7 @@ public class ConvertImgPDFController {
} }
} }
@PostMapping(consumes = "multipart/form-data", value = "/img/pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/img/pdf")
@Operation( @Operation(
summary = "Convert images to a PDF file", summary = "Convert images to a PDF file",
description = description =
@ -244,7 +244,7 @@ public class ConvertImgPDFController {
private String getMediaType(String imageFormat) { private String getMediaType(String imageFormat) {
String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat); String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat);
return "null".equals(mimeType) ? "application/octet-stream" : mimeType; return "null".equals(mimeType) ? MediaType.APPLICATION_OCTET_STREAM_VALUE : mimeType;
} }
/** /**

View File

@ -10,6 +10,7 @@ import org.commonmark.node.Node;
import org.commonmark.parser.Parser; import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.AttributeProvider; import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.HtmlRenderer; import org.commonmark.renderer.html.HtmlRenderer;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -45,7 +46,7 @@ public class ConvertMarkdownToPdf {
private final CustomHtmlSanitizer customHtmlSanitizer; private final CustomHtmlSanitizer customHtmlSanitizer;
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/markdown/pdf")
@Operation( @Operation(
summary = "Convert a Markdown file to PDF", summary = "Convert a Markdown file to PDF",
description = description =

View File

@ -12,6 +12,7 @@ import java.util.List;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -171,7 +172,7 @@ public class ConvertOfficeController {
return fileExtension.matches(extensionPattern); return fileExtension.matches(extensionPattern);
} }
@PostMapping(consumes = "multipart/form-data", value = "/file/pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/file/pdf")
@Operation( @Operation(
summary = "Convert a file to a PDF using LibreOffice", summary = "Convert a file to a PDF using LibreOffice",
description = description =

View File

@ -1,5 +1,6 @@
package stirling.software.SPDF.controller.api.converters; package stirling.software.SPDF.controller.api.converters;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -18,7 +19,7 @@ import stirling.software.common.util.PDFToFile;
@RequestMapping("/api/v1/convert") @RequestMapping("/api/v1/convert")
public class ConvertPDFToHtml { public class ConvertPDFToHtml {
@PostMapping(consumes = "multipart/form-data", value = "/pdf/html") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/html")
@Operation( @Operation(
summary = "Convert PDF to HTML", summary = "Convert PDF to HTML",
description = description =

View File

@ -34,7 +34,7 @@ public class ConvertPDFToOffice {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/pdf/presentation") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/presentation")
@Operation( @Operation(
summary = "Convert PDF to Presentation format", summary = "Convert PDF to Presentation format",
description = description =
@ -49,7 +49,7 @@ public class ConvertPDFToOffice {
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import"); return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import");
} }
@PostMapping(consumes = "multipart/form-data", value = "/pdf/text") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/text")
@Operation( @Operation(
summary = "Convert PDF to Text or RTF format", summary = "Convert PDF to Text or RTF format",
description = description =
@ -77,7 +77,7 @@ public class ConvertPDFToOffice {
} }
} }
@PostMapping(consumes = "multipart/form-data", value = "/pdf/word") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/word")
@Operation( @Operation(
summary = "Convert PDF to Word document", summary = "Convert PDF to Word document",
description = description =
@ -91,7 +91,7 @@ public class ConvertPDFToOffice {
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import"); return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
} }
@PostMapping(consumes = "multipart/form-data", value = "/pdf/xml") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/xml")
@Operation( @Operation(
summary = "Convert PDF to XML", summary = "Convert PDF to XML",
description = description =

View File

@ -78,7 +78,7 @@ import stirling.software.common.util.WebResponseUtils;
@Tag(name = "Convert", description = "Convert APIs") @Tag(name = "Convert", description = "Convert APIs")
public class ConvertPDFToPDFA { public class ConvertPDFToPDFA {
@PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/pdfa")
@Operation( @Operation(
summary = "Convert a PDF to a PDF/A", summary = "Convert a PDF to a PDF/A",
description = description =
@ -89,7 +89,7 @@ public class ConvertPDFToPDFA {
String outputFormat = request.getOutputFormat(); String outputFormat = request.getOutputFormat();
// Validate input file type // Validate input file type
if (!"application/pdf".equals(inputFile.getContentType())) { if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
log.error("Invalid input file type: {}", inputFile.getContentType()); log.error("Invalid input file type: {}", inputFile.getContentType());
throw ExceptionUtils.createPdfFileRequiredException(); throw ExceptionUtils.createPdfFileRequiredException();
} }

View File

@ -9,6 +9,7 @@ import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -43,7 +44,7 @@ public class ConvertWebsiteToPDF {
private final RuntimePathConfig runtimePathConfig; private final RuntimePathConfig runtimePathConfig;
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/url/pdf")
@Operation( @Operation(
summary = "Convert a URL to a PDF", summary = "Convert a URL to a PDF",
description = description =

View File

@ -46,7 +46,7 @@ public class ExtractCSVController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data") @PostMapping(value = "/pdf/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Extracts a CSV document from a PDF", summary = "Extracts a CSV document from a PDF",
description = description =

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -37,7 +38,7 @@ public class FilterController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-text") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-contains-text")
@Operation( @Operation(
summary = "Checks if a PDF contains set text, returns true if does", summary = "Checks if a PDF contains set text, returns true if does",
description = "Input:PDF Output:Boolean Type:SISO") description = "Input:PDF Output:Boolean Type:SISO")
@ -55,7 +56,7 @@ public class FilterController {
} }
// TODO // TODO
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-image") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-contains-image")
@Operation( @Operation(
summary = "Checks if a PDF contains an image", summary = "Checks if a PDF contains an image",
description = "Input:PDF Output:Boolean Type:SISO") description = "Input:PDF Output:Boolean Type:SISO")
@ -71,7 +72,7 @@ public class FilterController {
return null; return null;
} }
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-count") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-page-count")
@Operation( @Operation(
summary = "Checks if a PDF is greater, less or equal to a setPageCount", summary = "Checks if a PDF is greater, less or equal to a setPageCount",
description = "Input:PDF Output:Boolean Type:SISO") description = "Input:PDF Output:Boolean Type:SISO")
@ -104,7 +105,7 @@ public class FilterController {
return null; return null;
} }
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-size") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-page-size")
@Operation( @Operation(
summary = "Checks if a PDF is of a certain size", summary = "Checks if a PDF is of a certain size",
description = "Input:PDF Output:Boolean Type:SISO") description = "Input:PDF Output:Boolean Type:SISO")
@ -147,7 +148,7 @@ public class FilterController {
return null; return null;
} }
@PostMapping(consumes = "multipart/form-data", value = "/filter-file-size") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-file-size")
@Operation( @Operation(
summary = "Checks if a PDF is a set file size", summary = "Checks if a PDF is a set file size",
description = "Input:PDF Output:Boolean Type:SISO") description = "Input:PDF Output:Boolean Type:SISO")
@ -180,7 +181,7 @@ public class FilterController {
return null; return null;
} }
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-rotation") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-page-rotation")
@Operation( @Operation(
summary = "Checks if a PDF is of a certain rotation", summary = "Checks if a PDF is of a certain rotation",
description = "Input:PDF Output:Boolean Type:SISO") description = "Input:PDF Output:Boolean Type:SISO")

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -34,7 +35,7 @@ public class AttachmentController {
private final AttachmentServiceInterface pdfAttachmentService; private final AttachmentServiceInterface pdfAttachmentService;
@PostMapping(consumes = "multipart/form-data", value = "/add-attachments") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-attachments")
@Operation( @Operation(
summary = "Add attachments to PDF", summary = "Add attachments to PDF",
description = description =

View File

@ -8,6 +8,7 @@ import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition; import org.apache.pdfbox.text.TextPosition;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -38,7 +39,7 @@ public class AutoRenameController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/auto-rename") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/auto-rename")
@Operation( @Operation(
summary = "Extract header from PDF file", summary = "Extract header from PDF file",
description = description =

View File

@ -102,7 +102,7 @@ public class AutoSplitPdfController {
} }
} }
@PostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data") @PostMapping(value = "/auto-split-pdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Auto split PDF pages into separate documents", summary = "Auto split PDF pages into separate documents",
description = description =

View File

@ -69,7 +69,7 @@ public class BlankPageController {
return whitePixelPercentage >= whitePercent; return whitePixelPercentage >= whitePercent;
} }
@PostMapping(consumes = "multipart/form-data", value = "/remove-blanks") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-blanks")
@Operation( @Operation(
summary = "Remove blank pages from a PDF file", summary = "Remove blank pages from a PDF file",
description = description =

View File

@ -32,6 +32,7 @@ import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.PDXObject; import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -658,7 +659,7 @@ public class CompressController {
}; };
} }
@PostMapping(consumes = "multipart/form-data", value = "/compress-pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/compress-pdf")
@Operation( @Operation(
summary = "Optimize PDF file", summary = "Optimize PDF file",
description = description =

View File

@ -38,7 +38,7 @@ public class DecompressPdfController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/decompress-pdf", consumes = "multipart/form-data") @PostMapping(value = "/decompress-pdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Decompress PDF streams", summary = "Decompress PDF streams",
description = "Fully decompresses all PDF streams including text content") description = "Fully decompresses all PDF streams including text content")

View File

@ -50,7 +50,7 @@ public class ExtractImageScansController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/extract-image-scans") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/extract-image-scans")
@Operation( @Operation(
summary = "Extract image scans from an input file", summary = "Extract image scans from an input file",
description = description =

View File

@ -54,7 +54,7 @@ public class ExtractImagesController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/extract-images") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/extract-images")
@Operation( @Operation(
summary = "Extract images from a PDF file", summary = "Extract images from a PDF file",
description = description =

View File

@ -11,6 +11,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -38,7 +39,7 @@ public class FlattenController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/flatten") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/flatten")
@Operation( @Operation(
summary = "Flatten PDF form fields or full page", summary = "Flatten PDF form fields or full page",
description = description =

View File

@ -10,6 +10,7 @@ import java.util.Map.Entry;
import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -51,7 +52,7 @@ public class MetadataController {
binder.registerCustomEditor(Map.class, "allRequestParams", new StringToMapPropertyEditor()); binder.registerCustomEditor(Map.class, "allRequestParams", new StringToMapPropertyEditor());
} }
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/update-metadata")
@Operation( @Operation(
summary = "Update metadata of a PDF file", summary = "Update metadata of a PDF file",
description = description =

View File

@ -76,7 +76,7 @@ public class OCRController {
.toList(); .toList();
} }
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/ocr-pdf")
@Operation( @Operation(
summary = "Process a PDF file with OCR", summary = "Process a PDF file with OCR",
description = description =

View File

@ -3,6 +3,7 @@ package stirling.software.SPDF.controller.api.misc;
import java.io.IOException; import java.io.IOException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -31,7 +32,7 @@ public class OverlayImageController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/add-image") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-image")
@Operation( @Operation(
summary = "Overlay image onto a PDF file", summary = "Overlay image onto a PDF file",
description = description =

View File

@ -39,7 +39,7 @@ public class PageNumbersController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/add-page-numbers", consumes = "multipart/form-data") @PostMapping(value = "/add-page-numbers", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Add page numbers to a PDF document", summary = "Add page numbers to a PDF document",
description = description =

View File

@ -18,6 +18,7 @@ import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.printing.PDFPageable; import org.apache.pdfbox.printing.PDFPageable;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -37,7 +38,7 @@ import stirling.software.SPDF.model.api.misc.PrintFileRequest;
public class PrintFileController { public class PrintFileController {
// TODO // TODO
// @PostMapping(value = "/print-file", consumes = "multipart/form-data") // @PostMapping(value = "/print-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
// @Operation( // @Operation(
// summary = "Prints PDF/Image file to a set printer", // summary = "Prints PDF/Image file to a set printer",
// description = // description =
@ -69,7 +70,7 @@ public class PrintFileController {
log.info("Selected Printer: " + selectedService.getName()); log.info("Selected Printer: " + selectedService.getName());
if ("application/pdf".equals(contentType)) { if (MediaType.APPLICATION_PDF_VALUE.equals(contentType)) {
PDDocument document = Loader.loadPDF(file.getBytes()); PDDocument document = Loader.loadPDF(file.getBytes());
PrinterJob job = PrinterJob.getPrinterJob(); PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintService(selectedService); job.setPrintService(selectedService);

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -46,7 +47,7 @@ public class RepairController {
return endpointConfiguration.isGroupEnabled("qpdf"); return endpointConfiguration.isGroupEnabled("qpdf");
} }
@PostMapping(consumes = "multipart/form-data", value = "/repair") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/repair")
@Operation( @Operation(
summary = "Repair a PDF file", summary = "Repair a PDF file",
description = description =

View File

@ -27,7 +27,7 @@ public class ReplaceAndInvertColorController {
private final ReplaceAndInvertColorService replaceAndInvertColorService; private final ReplaceAndInvertColorService replaceAndInvertColorService;
@PostMapping(consumes = "multipart/form-data", value = "/replace-invert-pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/replace-invert-pdf")
@Operation( @Operation(
summary = "Replace-Invert Color PDF", summary = "Replace-Invert Color PDF",
description = description =

View File

@ -52,7 +52,7 @@ public class ScannerEffectController {
private static final int MAX_IMAGE_HEIGHT = 8192; private static final int MAX_IMAGE_HEIGHT = 8192;
private static final long MAX_IMAGE_PIXELS = 16_777_216; // 4096x4096 private static final long MAX_IMAGE_PIXELS = 16_777_216; // 4096x4096
@PostMapping(value = "/scanner-effect", consumes = "multipart/form-data") @PostMapping(value = "/scanner-effect", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Apply scanner effect to PDF", summary = "Apply scanner effect to PDF",
description = description =

View File

@ -32,7 +32,7 @@ public class ShowJavascript {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/show-javascript") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/show-javascript")
@Operation( @Operation(
summary = "Grabs all JS from a PDF and returns a single JS file with all code", summary = "Grabs all JS from a PDF and returns a single JS file with all code",
description = "desc. Input:PDF Output:JS Type:SISO") description = "desc. Input:PDF Output:JS Type:SISO")

View File

@ -25,6 +25,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
@ -72,7 +73,7 @@ public class StampController {
}); });
} }
@PostMapping(consumes = "multipart/form-data", value = "/add-stamp") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-stamp")
@Operation( @Operation(
summary = "Add stamp to a PDF file", summary = "Add stamp to a PDF file",
description = description =

View File

@ -10,6 +10,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -37,7 +38,7 @@ public class UnlockPDFFormsController {
this.pdfDocumentFactory = pdfDocumentFactory; this.pdfDocumentFactory = pdfDocumentFactory;
} }
@PostMapping(consumes = "multipart/form-data", value = "/unlock-pdf-forms") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/unlock-pdf-forms")
@Operation( @Operation(
summary = "Remove read-only property from form fields", summary = "Remove read-only property from form fields",
description = description =

View File

@ -188,7 +188,7 @@ public class GetInfoOnPDF {
return false; return false;
} }
@PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/get-info-on-pdf")
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO") @Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException { public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException {
MultipartFile inputFile = request.getFileInput(); MultipartFile inputFile = request.getFileInput();

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission; import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy; import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -32,7 +33,7 @@ public class PasswordController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/remove-password") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-password")
@Operation( @Operation(
summary = "Remove password from a PDF file", summary = "Remove password from a PDF file",
description = description =
@ -58,7 +59,7 @@ public class PasswordController {
} }
} }
@PostMapping(consumes = "multipart/form-data", value = "/add-password") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-password")
@Operation( @Operation(
summary = "Add password to a PDF file", summary = "Add password to a PDF file",
description = description =

View File

@ -34,6 +34,7 @@ import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.graphics.PDXObject; import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
@ -97,7 +98,7 @@ public class RedactController {
List.class, "redactions", new StringToArrayListPropertyEditor()); List.class, "redactions", new StringToArrayListPropertyEditor());
} }
@PostMapping(value = "/redact", consumes = "multipart/form-data") @PostMapping(value = "/redact", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Redact PDF manually", summary = "Redact PDF manually",
description = description =
@ -494,7 +495,7 @@ public class RedactController {
return pageNumbers; return pageNumbers;
} }
@PostMapping(value = "/auto-redact", consumes = "multipart/form-data") @PostMapping(value = "/auto-redact", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation( @Operation(
summary = "Redact PDF automatically", summary = "Redact PDF automatically",
description = description =

View File

@ -7,6 +7,7 @@ import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -32,7 +33,7 @@ public class RemoveCertSignController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/remove-cert-sign") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-cert-sign")
@Operation( @Operation(
summary = "Remove digital signature from PDF", summary = "Remove digital signature from PDF",
description = description =

View File

@ -21,6 +21,7 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -46,7 +47,7 @@ public class SanitizeController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/sanitize-pdf") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/sanitize-pdf")
@Operation( @Operation(
summary = "Sanitize a PDF file", summary = "Sanitize a PDF file",
description = description =

View File

@ -24,6 +24,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
@ -64,7 +65,7 @@ public class WatermarkController {
}); });
} }
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-watermark")
@Operation( @Operation(
summary = "Add watermark to a PDF file", summary = "Add watermark to a PDF file",
description = description =

View File

@ -1,5 +1,6 @@
package stirling.software.SPDF.model.api.converters; package stirling.software.SPDF.model.api.converters;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -18,7 +19,7 @@ import stirling.software.common.util.PDFToFile;
@RequestMapping("/api/v1/convert") @RequestMapping("/api/v1/convert")
public class ConvertPDFToMarkdown { public class ConvertPDFToMarkdown {
@PostMapping(consumes = "multipart/form-data", value = "/pdf/markdown") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/markdown")
@Operation( @Operation(
summary = "Convert PDF to Markdown", summary = "Convert PDF to Markdown",
description = description =

View File

@ -260,7 +260,7 @@ public class JobController {
"fileName", "fileName",
"unknown", "unknown",
"contentType", "contentType",
"application/octet-stream", MediaType.APPLICATION_OCTET_STREAM_VALUE,
"fileSize", "fileSize",
fileSize)); fileSize));
} }
@ -295,7 +295,9 @@ public class JobController {
String fileName = resultFile != null ? resultFile.getFileName() : "download"; String fileName = resultFile != null ? resultFile.getFileName() : "download";
String contentType = String contentType =
resultFile != null ? resultFile.getContentType() : "application/octet-stream"; resultFile != null
? resultFile.getContentType()
: MediaType.APPLICATION_OCTET_STREAM_VALUE;
return ResponseEntity.ok() return ResponseEntity.ok()
.header("Content-Type", contentType) .header("Content-Type", contentType)

View File

@ -24,6 +24,7 @@ import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
@ -56,7 +57,10 @@ class EditTableOfContentsControllerTest {
void setUp() { void setUp() {
mockFile = mockFile =
new MockMultipartFile( new MockMultipartFile(
"file", "test.pdf", "application/pdf", "PDF content".getBytes()); "file",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
"PDF content".getBytes());
mockDocument = mock(PDDocument.class); mockDocument = mock(PDDocument.class);
mockCatalog = mock(PDDocumentCatalog.class); mockCatalog = mock(PDDocumentCatalog.class);
mockPages = mock(PDPageTree.class); mockPages = mock(PDPageTree.class);

View File

@ -23,6 +23,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -49,13 +50,22 @@ class MergeControllerTest {
void setUp() { void setUp() {
mockFile1 = mockFile1 =
new MockMultipartFile( new MockMultipartFile(
"file1", "document1.pdf", "application/pdf", "PDF content 1".getBytes()); "file1",
"document1.pdf",
MediaType.APPLICATION_PDF_VALUE,
"PDF content 1".getBytes());
mockFile2 = mockFile2 =
new MockMultipartFile( new MockMultipartFile(
"file2", "document2.pdf", "application/pdf", "PDF content 2".getBytes()); "file2",
"document2.pdf",
MediaType.APPLICATION_PDF_VALUE,
"PDF content 2".getBytes());
mockFile3 = mockFile3 =
new MockMultipartFile( new MockMultipartFile(
"file3", "chapter3.pdf", "application/pdf", "PDF content 3".getBytes()); "file3",
"chapter3.pdf",
MediaType.APPLICATION_PDF_VALUE,
"PDF content 3".getBytes());
mockDocument = mock(PDDocument.class); mockDocument = mock(PDDocument.class);
mockMergedDocument = mock(PDDocument.class); mockMergedDocument = mock(PDDocument.class);
@ -202,7 +212,10 @@ class MergeControllerTest {
// Given // Given
MockMultipartFile fileWithoutExtension = MockMultipartFile fileWithoutExtension =
new MockMultipartFile( new MockMultipartFile(
"file", "document_no_ext", "application/pdf", "PDF content".getBytes()); "file",
"document_no_ext",
MediaType.APPLICATION_PDF_VALUE,
"PDF content".getBytes());
MultipartFile[] files = {fileWithoutExtension}; MultipartFile[] files = {fileWithoutExtension};
when(mockMergedDocument.getDocumentCatalog()).thenReturn(mockCatalog); when(mockMergedDocument.getDocumentCatalog()).thenReturn(mockCatalog);

View File

@ -17,6 +17,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
@ -34,7 +35,8 @@ public class RotationControllerTest {
public void testRotatePDF() throws IOException { public void testRotatePDF() throws IOException {
// Create a mock file // Create a mock file
MockMultipartFile mockFile = MockMultipartFile mockFile =
new MockMultipartFile("file", "test.pdf", "application/pdf", new byte[] {1, 2, 3}); new MockMultipartFile(
"file", "test.pdf", MediaType.APPLICATION_PDF_VALUE, new byte[] {1, 2, 3});
RotatePDFRequest request = new RotatePDFRequest(); RotatePDFRequest request = new RotatePDFRequest();
request.setFileInput(mockFile); request.setFileInput(mockFile);
request.setAngle(90); request.setAngle(90);
@ -62,7 +64,8 @@ public class RotationControllerTest {
public void testRotatePDFInvalidAngle() throws IOException { public void testRotatePDFInvalidAngle() throws IOException {
// Create a mock file // Create a mock file
MockMultipartFile mockFile = MockMultipartFile mockFile =
new MockMultipartFile("file", "test.pdf", "application/pdf", new byte[] {1, 2, 3}); new MockMultipartFile(
"file", "test.pdf", MediaType.APPLICATION_PDF_VALUE, new byte[] {1, 2, 3});
RotatePDFRequest request = new RotatePDFRequest(); RotatePDFRequest request = new RotatePDFRequest();
request.setFileInput(mockFile); request.setFileInput(mockFile);
request.setAngle(45); // Invalid angle request.setAngle(45); // Invalid angle

View File

@ -16,6 +16,7 @@ import org.mockito.Mock;
import org.mockito.MockedStatic; import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -45,13 +46,22 @@ class AttachmentControllerTest {
void setUp() { void setUp() {
pdfFile = pdfFile =
new MockMultipartFile( new MockMultipartFile(
"fileInput", "test.pdf", "application/pdf", "PDF content".getBytes()); "fileInput",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
"PDF content".getBytes());
attachment1 = attachment1 =
new MockMultipartFile( new MockMultipartFile(
"attachment1", "file1.txt", "text/plain", "File 1 content".getBytes()); "attachment1",
"file1.txt",
MediaType.TEXT_PLAIN_VALUE,
"File 1 content".getBytes());
attachment2 = attachment2 =
new MockMultipartFile( new MockMultipartFile(
"attachment2", "file2.jpg", "image/jpeg", "Image content".getBytes()); "attachment2",
"file2.jpg",
MediaType.IMAGE_JPEG_VALUE,
"Image content".getBytes());
request = new AddAttachmentRequest(); request = new AddAttachmentRequest();
mockDocument = mock(PDDocument.class); mockDocument = mock(PDDocument.class);
modifiedMockDocument = mock(PDDocument.class); modifiedMockDocument = mock(PDDocument.class);

View File

@ -18,6 +18,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -117,7 +118,8 @@ class CertSignControllerTest {
@Test @Test
void testSignPdfWithPfx() throws Exception { void testSignPdfWithPfx() throws Exception {
MockMultipartFile pdfFile = MockMultipartFile pdfFile =
new MockMultipartFile("fileInput", "test.pdf", "application/pdf", pdfBytes); new MockMultipartFile(
"fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
MockMultipartFile pfxFile = MockMultipartFile pfxFile =
new MockMultipartFile("p12File", "test-cert.pfx", "application/x-pkcs12", pfxBytes); new MockMultipartFile("p12File", "test-cert.pfx", "application/x-pkcs12", pfxBytes);
@ -142,7 +144,8 @@ class CertSignControllerTest {
@Test @Test
void testSignPdfWithPkcs12() throws Exception { void testSignPdfWithPkcs12() throws Exception {
MockMultipartFile pdfFile = MockMultipartFile pdfFile =
new MockMultipartFile("fileInput", "test.pdf", "application/pdf", pdfBytes); new MockMultipartFile(
"fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
MockMultipartFile p12File = MockMultipartFile p12File =
new MockMultipartFile("p12File", "test-cert.p12", "application/x-pkcs12", p12Bytes); new MockMultipartFile("p12File", "test-cert.p12", "application/x-pkcs12", p12Bytes);
@ -167,7 +170,8 @@ class CertSignControllerTest {
@Test @Test
void testSignPdfWithJks() throws Exception { void testSignPdfWithJks() throws Exception {
MockMultipartFile pdfFile = MockMultipartFile pdfFile =
new MockMultipartFile("fileInput", "test.pdf", "application/pdf", pdfBytes); new MockMultipartFile(
"fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
MockMultipartFile jksFile = MockMultipartFile jksFile =
new MockMultipartFile( new MockMultipartFile(
"jksFile", "test-cert.jks", "application/octet-stream", jksBytes); "jksFile", "test-cert.jks", "application/octet-stream", jksBytes);
@ -193,7 +197,8 @@ class CertSignControllerTest {
@Test @Test
void testSignPdfWithPem() throws Exception { void testSignPdfWithPem() throws Exception {
MockMultipartFile pdfFile = MockMultipartFile pdfFile =
new MockMultipartFile("fileInput", "test.pdf", "application/pdf", pdfBytes); new MockMultipartFile(
"fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
MockMultipartFile keyFile = MockMultipartFile keyFile =
new MockMultipartFile( new MockMultipartFile(
"privateKeyFile", "test-key.pem", "application/x-pem-file", pemKeyBytes); "privateKeyFile", "test-key.pem", "application/x-pem-file", pemKeyBytes);
@ -223,7 +228,8 @@ class CertSignControllerTest {
@Test @Test
void testSignPdfWithCrt() throws Exception { void testSignPdfWithCrt() throws Exception {
MockMultipartFile pdfFile = MockMultipartFile pdfFile =
new MockMultipartFile("fileInput", "test.pdf", "application/pdf", pdfBytes); new MockMultipartFile(
"fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
MockMultipartFile keyFile = MockMultipartFile keyFile =
new MockMultipartFile( new MockMultipartFile(
"privateKeyFile", "test-key.key", "application/x-pem-file", keyBytes); "privateKeyFile", "test-key.key", "application/x-pem-file", keyBytes);
@ -253,7 +259,8 @@ class CertSignControllerTest {
@Test @Test
void testSignPdfWithCer() throws Exception { void testSignPdfWithCer() throws Exception {
MockMultipartFile pdfFile = MockMultipartFile pdfFile =
new MockMultipartFile("fileInput", "test.pdf", "application/pdf", pdfBytes); new MockMultipartFile(
"fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
MockMultipartFile keyFile = MockMultipartFile keyFile =
new MockMultipartFile( new MockMultipartFile(
"privateKeyFile", "test-key.key", "application/x-pem-file", keyBytes); "privateKeyFile", "test-key.key", "application/x-pem-file", keyBytes);
@ -283,7 +290,8 @@ class CertSignControllerTest {
@Test @Test
void testSignPdfWithDer() throws Exception { void testSignPdfWithDer() throws Exception {
MockMultipartFile pdfFile = MockMultipartFile pdfFile =
new MockMultipartFile("fileInput", "test.pdf", "application/pdf", pdfBytes); new MockMultipartFile(
"fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
MockMultipartFile keyFile = MockMultipartFile keyFile =
new MockMultipartFile( new MockMultipartFile(
"privateKeyFile", "test-key.key", "application/x-pem-file", keyBytes); "privateKeyFile", "test-key.key", "application/x-pem-file", keyBytes);

View File

@ -42,6 +42,7 @@ import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness; import org.mockito.quality.Strictness;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
@ -130,7 +131,10 @@ class RedactControllerTest {
void setUp() throws IOException { void setUp() throws IOException {
mockPdfFile = mockPdfFile =
new MockMultipartFile( new MockMultipartFile(
"fileInput", "test.pdf", "application/pdf", createSimplePdfContent()); "fileInput",
"test.pdf",
MediaType.APPLICATION_PDF_VALUE,
createSimplePdfContent());
// Mock PDF document and related objects // Mock PDF document and related objects
mockDocument = mock(PDDocument.class); mockDocument = mock(PDDocument.class);
@ -632,7 +636,7 @@ class RedactControllerTest {
new MockMultipartFile( new MockMultipartFile(
"fileInput", "fileInput",
"malformed.pdf", "malformed.pdf",
"application/pdf", MediaType.APPLICATION_PDF_VALUE,
"Not a real PDF content".getBytes()); "Not a real PDF content".getBytes());
RedactPdfRequest request = new RedactPdfRequest(); RedactPdfRequest request = new RedactPdfRequest();

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
class AttachmentServiceTest { class AttachmentServiceTest {
@ -54,13 +55,13 @@ class AttachmentServiceTest {
when(attachment1.getInputStream()) when(attachment1.getInputStream())
.thenReturn(new ByteArrayInputStream("PDF content".getBytes())); .thenReturn(new ByteArrayInputStream("PDF content".getBytes()));
when(attachment1.getSize()).thenReturn(15L); when(attachment1.getSize()).thenReturn(15L);
when(attachment1.getContentType()).thenReturn("application/pdf"); when(attachment1.getContentType()).thenReturn(MediaType.APPLICATION_PDF_VALUE);
when(attachment2.getOriginalFilename()).thenReturn("image.jpg"); when(attachment2.getOriginalFilename()).thenReturn("image.jpg");
when(attachment2.getInputStream()) when(attachment2.getInputStream())
.thenReturn(new ByteArrayInputStream("Image content".getBytes())); .thenReturn(new ByteArrayInputStream("Image content".getBytes()));
when(attachment2.getSize()).thenReturn(20L); when(attachment2.getSize()).thenReturn(20L);
when(attachment2.getContentType()).thenReturn("image/jpeg"); when(attachment2.getContentType()).thenReturn(MediaType.IMAGE_JPEG_VALUE);
PDDocument result = attachmentService.addAttachment(document, attachments); PDDocument result = attachmentService.addAttachment(document, attachments);

View File

@ -1,6 +1,7 @@
package stirling.software.common.controller; package stirling.software.common.controller;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import java.util.Map; import java.util.Map;
@ -11,6 +12,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockHttpSession; import org.springframework.mock.web.MockHttpSession;
@ -126,7 +128,7 @@ class JobControllerTest {
String jobId = "test-job-id"; String jobId = "test-job-id";
String fileId = "file-id"; String fileId = "file-id";
String originalFileName = "test.pdf"; String originalFileName = "test.pdf";
String contentType = "application/pdf"; String contentType = MediaType.APPLICATION_PDF_VALUE;
byte[] fileContent = "Test file content".getBytes(); byte[] fileContent = "Test file content".getBytes();
JobResult mockResult = new JobResult(); JobResult mockResult = new JobResult();
@ -206,7 +208,7 @@ class JobControllerTest {
String jobId = "test-job-id"; String jobId = "test-job-id";
String fileId = "file-id"; String fileId = "file-id";
String originalFileName = "test.pdf"; String originalFileName = "test.pdf";
String contentType = "application/pdf"; String contentType = MediaType.APPLICATION_PDF_VALUE;
JobResult mockResult = new JobResult(); JobResult mockResult = new JobResult();
mockResult.setJobId(jobId); mockResult.setJobId(jobId);

View File

@ -13,6 +13,7 @@ import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC; import org.slf4j.MDC;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
@ -112,8 +113,8 @@ public class AuditUtils {
&& req.getContentType() != null) { && req.getContentType() != null) {
String contentType = req.getContentType(); String contentType = req.getContentType();
if (contentType.contains("application/x-www-form-urlencoded") if (contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|| contentType.contains("multipart/form-data")) { || contentType.contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
Map<String, String[]> params = new HashMap<>(req.getParameterMap()); Map<String, String[]> params = new HashMap<>(req.getParameterMap());
// Remove CSRF token from logged parameters // Remove CSRF token from logged parameters

View File

@ -44,7 +44,7 @@ public class DatabaseController {
@Operation( @Operation(
summary = "Import a database backup file", summary = "Import a database backup file",
description = "Uploads and imports a database backup SQL file.") description = "Uploads and imports a database backup SQL file.")
@PostMapping(consumes = "multipart/form-data", value = "import-database") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "import-database")
public String importDatabase( public String importDatabase(
@Parameter(description = "SQL file to import", required = true) @Parameter(description = "SQL file to import", required = true)
@RequestParam("fileInput") @RequestParam("fileInput")

View File

@ -2,6 +2,7 @@ package stirling.software.proprietary.security.controller.api;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.mail.MailSendException; import org.springframework.mail.MailSendException;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@ -42,7 +43,7 @@ public class EmailController {
* attachment. * attachment.
* @return ResponseEntity with success or error message. * @return ResponseEntity with success or error message.
*/ */
@PostMapping(consumes = "multipart/form-data", value = "/send-email") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/send-email")
@Operation( @Operation(
summary = "Send an email with an attachment", summary = "Send an email with an attachment",
description = description =