Merge remote-tracking branch 'origin/V2' into mainClone

This commit is contained in:
Anthony Stirling
2025-08-10 17:48:44 +01:00
360 changed files with 167841 additions and 559 deletions
@@ -45,6 +45,7 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) {
Map<String, String> allowedParameters = new HashMap<>();
// Keep only the allowed parameters
@@ -10,6 +10,7 @@ import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import lombok.RequiredArgsConstructor;
@@ -50,17 +51,26 @@ public class OpenApiConfig {
.url("https://www.stirlingpdf.com")
.email("[email protected]"))
.description(DEFAULT_DESCRIPTION);
OpenAPI openAPI = new OpenAPI().info(info);
// Add server configuration from environment variable
String swaggerServerUrl = System.getenv("SWAGGER_SERVER_URL");
if (swaggerServerUrl != null && !swaggerServerUrl.trim().isEmpty()) {
Server server = new Server().url(swaggerServerUrl).description("API Server");
openAPI.addServersItem(server);
}
if (!applicationProperties.getSecurity().getEnableLogin()) {
return new OpenAPI().components(new Components()).info(info);
return openAPI.components(new Components());
} else {
SecurityScheme apiKeyScheme =
new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("X-API-KEY");
return new OpenAPI()
return openAPI
.components(new Components().addSecuritySchemes("apiKey", apiKeyScheme))
.info(info)
.addSecurityItem(new SecurityRequirement().addList("apiKey"));
}
}
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.util.*;
@@ -29,7 +31,7 @@ public class AnalysisController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/page-count", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/page-count", consumes = "multipart/form-data")
@Operation(
summary = "Get PDF page count",
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
@@ -39,7 +41,7 @@ public class AnalysisController {
}
}
@PostMapping(value = "/basic-info", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/basic-info", consumes = "multipart/form-data")
@Operation(
summary = "Get basic PDF information",
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
@@ -53,7 +55,7 @@ public class AnalysisController {
}
}
@PostMapping(value = "/document-properties", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/document-properties", consumes = "multipart/form-data")
@Operation(
summary = "Get PDF document properties",
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
@@ -76,7 +78,7 @@ public class AnalysisController {
}
}
@PostMapping(value = "/page-dimensions", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/page-dimensions", consumes = "multipart/form-data")
@Operation(
summary = "Get page dimensions for all pages",
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
@@ -96,7 +98,7 @@ public class AnalysisController {
}
}
@PostMapping(value = "/form-fields", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/form-fields", consumes = "multipart/form-data")
@Operation(
summary = "Get form field information",
description =
@@ -119,7 +121,7 @@ public class AnalysisController {
}
}
@PostMapping(value = "/annotation-info", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/annotation-info", consumes = "multipart/form-data")
@Operation(
summary = "Get annotation information",
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
@@ -143,7 +145,7 @@ public class AnalysisController {
}
}
@PostMapping(value = "/font-info", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/font-info", consumes = "multipart/form-data")
@Operation(
summary = "Get font information",
description =
@@ -165,7 +167,7 @@ public class AnalysisController {
}
}
@PostMapping(value = "/security-info", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/security-info", consumes = "multipart/form-data")
@Operation(
summary = "Get security information",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -33,7 +35,7 @@ public class CropController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/crop", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/crop", consumes = "multipart/form-data")
@Operation(
summary = "Crops a PDF document",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
@@ -44,7 +46,7 @@ public class EditTableOfContentsController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
private final ObjectMapper objectMapper;
@PostMapping(value = "/extract-bookmarks", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/extract-bookmarks", consumes = "multipart/form-data")
@Operation(
summary = "Extract PDF Bookmarks",
description = "Extracts bookmarks/table of contents from a PDF document as JSON.")
@@ -152,7 +154,7 @@ public class EditTableOfContentsController {
return bookmark;
}
@PostMapping(value = "/edit-table-of-contents", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/edit-table-of-contents", consumes = "multipart/form-data")
@Operation(
summary = "Edit Table of Contents",
description = "Add or edit bookmarks/table of contents in a PDF document.")
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -154,7 +156,7 @@ public class MergeController {
}
}
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
@Operation(
summary = "Merge multiple PDF files into one",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -36,7 +38,7 @@ public class MultiPageLayoutController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
@Operation(
summary = "Merge multiple pages of a PDF document into a single page",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -46,7 +48,7 @@ public class PdfImageRemovalController {
* content type and filename.
* @throws IOException If an error occurs while processing the PDF file.
*/
@PostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf")
@Operation(
summary = "Remove images from file to reduce the file size.",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -39,7 +41,7 @@ public class PdfOverlayController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data")
@Operation(
summary = "Overlay PDF files in various modes",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -38,7 +40,7 @@ public class RearrangePagesPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@Operation(
summary = "Remove pages from a PDF file",
description =
@@ -237,7 +239,7 @@ public class RearrangePagesPDFController {
}
}
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
@Operation(
summary = "Rearrange pages in a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -31,7 +33,7 @@ public class RotationController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
@Operation(
summary = "Rotate a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
@@ -38,7 +40,7 @@ public class ScalePagesController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/scale-pages", consumes = "multipart/form-data")
@Operation(
summary = "Change the size of a PDF page/document",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.util.Map;
@@ -31,7 +33,7 @@ public class SettingsController {
private final ApplicationProperties applicationProperties;
private final EndpointConfiguration endpointConfiguration;
@PostMapping("/update-enable-analytics")
@AutoJobPostMapping("/update-enable-analytics")
@Hidden
public ResponseEntity<String> updateApiKey(@RequestBody Boolean enabled) throws IOException {
if (applicationProperties.getSystem().getEnableAnalytics() != null) {
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
@@ -41,7 +43,7 @@ public class SplitPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/split-pages")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/split-pages")
@Operation(
summary = "Split a PDF file into separate documents",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -117,7 +119,7 @@ public class SplitPdfByChaptersController {
return bookmarks;
}
@PostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data")
@Operation(
summary = "Split PDFs by Chapters",
description = "Splits a PDF into chapters and returns a ZIP file.")
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
@@ -43,7 +45,7 @@ public class SplitPdfBySectionsController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
@Operation(
summary = "Split PDF pages into smaller sections",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
@@ -39,7 +41,7 @@ public class SplitPdfBySizeController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
@Operation(
summary = "Auto split PDF pages into separate documents based on size or count",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.geom.AffineTransform;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -33,7 +35,7 @@ public class ToSinglePageController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
@Operation(
summary = "Convert a multi-page PDF into a single long page PDF",
description =
@@ -0,0 +1,301 @@
package stirling.software.SPDF.controller.api;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.Dependency;
import stirling.software.SPDF.model.SignatureFile;
import stirling.software.SPDF.service.SignatureService;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.UserServiceInterface;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.GeneralUtils;
@Slf4j
@RestController
@RequestMapping("/api/v1/ui-data")
@Tag(name = "UI Data", description = "APIs for React UI data")
public class UIDataController {
private final ApplicationProperties applicationProperties;
private final SignatureService signatureService;
private final UserServiceInterface userService;
private final ResourceLoader resourceLoader;
private final RuntimePathConfig runtimePathConfig;
public UIDataController(
ApplicationProperties applicationProperties,
SignatureService signatureService,
@Autowired(required = false) UserServiceInterface userService,
ResourceLoader resourceLoader,
RuntimePathConfig runtimePathConfig) {
this.applicationProperties = applicationProperties;
this.signatureService = signatureService;
this.userService = userService;
this.resourceLoader = resourceLoader;
this.runtimePathConfig = runtimePathConfig;
}
@GetMapping("/home")
@Operation(summary = "Get home page data")
public ResponseEntity<HomeData> getHomeData() {
String showSurvey = System.getenv("SHOW_SURVEY");
boolean showSurveyValue = showSurvey == null || "true".equalsIgnoreCase(showSurvey);
HomeData data = new HomeData();
data.setShowSurveyFromDocker(showSurveyValue);
return ResponseEntity.ok(data);
}
@GetMapping("/licenses")
@Operation(summary = "Get third-party licenses data")
public ResponseEntity<LicensesData> getLicensesData() {
LicensesData data = new LicensesData();
Resource resource = new ClassPathResource("static/3rdPartyLicenses.json");
try {
InputStream is = resource.getInputStream();
String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
Map<String, List<Dependency>> licenseData =
mapper.readValue(json, new TypeReference<>() {});
data.setDependencies(licenseData.get("dependencies"));
} catch (IOException e) {
log.error("Failed to load licenses data", e);
data.setDependencies(Collections.emptyList());
}
return ResponseEntity.ok(data);
}
@GetMapping("/pipeline")
@Operation(summary = "Get pipeline configuration data")
public ResponseEntity<PipelineData> getPipelineData() {
PipelineData data = new PipelineData();
List<String> pipelineConfigs = new ArrayList<>();
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
if (new java.io.File(runtimePathConfig.getPipelineDefaultWebUiConfigs()).exists()) {
try (Stream<Path> paths =
Files.walk(Paths.get(runtimePathConfig.getPipelineDefaultWebUiConfigs()))) {
List<Path> jsonFiles =
paths.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".json"))
.toList();
for (Path jsonFile : jsonFiles) {
String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
pipelineConfigs.add(content);
}
for (String config : pipelineConfigs) {
Map<String, Object> jsonContent =
new ObjectMapper()
.readValue(config, new TypeReference<Map<String, Object>>() {});
String name = (String) jsonContent.get("name");
if (name == null || name.length() < 1) {
String filename =
jsonFiles
.get(pipelineConfigs.indexOf(config))
.getFileName()
.toString();
name = filename.substring(0, filename.lastIndexOf('.'));
}
Map<String, String> configWithName = new HashMap<>();
configWithName.put("json", config);
configWithName.put("name", name);
pipelineConfigsWithNames.add(configWithName);
}
} catch (IOException e) {
log.error("Failed to load pipeline configs", e);
}
}
if (pipelineConfigsWithNames.isEmpty()) {
Map<String, String> configWithName = new HashMap<>();
configWithName.put("json", "");
configWithName.put("name", "No preloaded configs found");
pipelineConfigsWithNames.add(configWithName);
}
data.setPipelineConfigsWithNames(pipelineConfigsWithNames);
data.setPipelineConfigs(pipelineConfigs);
return ResponseEntity.ok(data);
}
@GetMapping("/sign")
@Operation(summary = "Get signature form data")
public ResponseEntity<SignData> getSignData() {
String username = "";
if (userService != null) {
username = userService.getCurrentUsername();
}
List<SignatureFile> signatures = signatureService.getAvailableSignatures(username);
List<FontResource> fonts = getFontNames();
SignData data = new SignData();
data.setSignatures(signatures);
data.setFonts(fonts);
return ResponseEntity.ok(data);
}
@GetMapping("/ocr-pdf")
@Operation(summary = "Get OCR PDF data")
public ResponseEntity<OcrData> getOcrPdfData() {
List<String> languages = getAvailableTesseractLanguages();
OcrData data = new OcrData();
data.setLanguages(languages);
return ResponseEntity.ok(data);
}
private List<String> getAvailableTesseractLanguages() {
String tessdataDir = applicationProperties.getSystem().getTessdataDir();
java.io.File[] files = new java.io.File(tessdataDir).listFiles();
if (files == null) {
return Collections.emptyList();
}
return Arrays.stream(files)
.filter(file -> file.getName().endsWith(".traineddata"))
.map(file -> file.getName().replace(".traineddata", ""))
.filter(lang -> !"osd".equalsIgnoreCase(lang))
.sorted()
.toList();
}
private List<FontResource> getFontNames() {
List<FontResource> fontNames = new ArrayList<>();
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
fontNames.addAll(
getFontNamesFromLocation(
"file:"
+ InstallationPathConfig.getStaticPath()
+ "fonts"
+ java.io.File.separator
+ "*"));
return fontNames;
}
private List<FontResource> getFontNamesFromLocation(String locationPattern) {
try {
Resource[] resources =
GeneralUtils.getResourcesFromLocationPattern(locationPattern, resourceLoader);
return Arrays.stream(resources)
.map(
resource -> {
try {
String filename = resource.getFilename();
if (filename != null) {
int lastDotIndex = filename.lastIndexOf('.');
if (lastDotIndex != -1) {
String name = filename.substring(0, lastDotIndex);
String extension = filename.substring(lastDotIndex + 1);
return new FontResource(name, extension);
}
}
return null;
} catch (Exception e) {
throw ExceptionUtils.createRuntimeException(
"error.fontLoadingFailed",
"Error processing font file",
e);
}
})
.filter(Objects::nonNull)
.toList();
} catch (Exception e) {
throw ExceptionUtils.createRuntimeException(
"error.fontDirectoryReadFailed", "Failed to read font directory", e);
}
}
// Data classes
@Data
public static class HomeData {
private boolean showSurveyFromDocker;
}
@Data
public static class LicensesData {
private List<Dependency> dependencies;
}
@Data
public static class PipelineData {
private List<Map<String, String>> pipelineConfigsWithNames;
private List<String> pipelineConfigs;
}
@Data
public static class SignData {
private List<SignatureFile> signatures;
private List<FontResource> fonts;
}
@Data
public static class OcrData {
private List<String> languages;
}
@Data
public static class FontResource {
private String name;
private String extension;
private String type;
public FontResource(String name, String extension) {
this.name = name;
this.extension = extension;
this.type = getFormatFromExtension(extension);
}
private static String getFormatFromExtension(String extension) {
switch (extension) {
case "ttf":
return "truetype";
case "woff":
return "woff";
case "woff2":
return "woff2";
case "eot":
return "embedded-opentype";
case "svg":
return "svg";
default:
return "";
}
}
}
}
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -40,7 +42,7 @@ public class ConvertEmlToPDF {
private final TempFileManager tempFileManager;
private final CustomHtmlSanitizer customHtmlSanitizer;
@PostMapping(consumes = "multipart/form-data", value = "/eml/pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/eml/pdf")
@Operation(
summary = "Convert EML to PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -36,7 +38,8 @@ public class ConvertHtmlToPDF {
private final CustomHtmlSanitizer customHtmlSanitizer;
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@Operation(
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -51,7 +53,7 @@ public class ConvertImgPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/pdf/img")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/img")
@Operation(
summary = "Convert PDF to image(s)",
description =
@@ -211,7 +213,7 @@ public class ConvertImgPDFController {
}
}
@PostMapping(consumes = "multipart/form-data", value = "/img/pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/img/pdf")
@Operation(
summary = "Convert images to a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.util.List;
import java.util.Map;
@@ -45,7 +47,8 @@ public class ConvertMarkdownToPdf {
private final CustomHtmlSanitizer customHtmlSanitizer;
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@Operation(
summary = "Convert a Markdown file to PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -97,7 +99,7 @@ public class ConvertOfficeController {
return fileExtension.matches(extensionPattern);
}
@PostMapping(consumes = "multipart/form-data", value = "/file/pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/file/pdf")
@Operation(
summary = "Convert a file to a PDF using LibreOffice",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -18,7 +20,7 @@ import stirling.software.common.util.PDFToFile;
@RequestMapping("/api/v1/convert")
public class ConvertPDFToHtml {
@PostMapping(consumes = "multipart/form-data", value = "/pdf/html")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/html")
@Operation(
summary = "Convert PDF to HTML",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -34,7 +36,7 @@ public class ConvertPDFToOffice {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/pdf/presentation")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/presentation")
@Operation(
summary = "Convert PDF to Presentation format",
description =
@@ -49,7 +51,7 @@ public class ConvertPDFToOffice {
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import");
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf/text")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/text")
@Operation(
summary = "Convert PDF to Text or RTF format",
description =
@@ -77,7 +79,7 @@ public class ConvertPDFToOffice {
}
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf/word")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/word")
@Operation(
summary = "Convert PDF to Word document",
description =
@@ -91,7 +93,7 @@ public class ConvertPDFToOffice {
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf/xml")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/xml")
@Operation(
summary = "Convert PDF to XML",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -78,7 +80,7 @@ import stirling.software.common.util.WebResponseUtils;
@Tag(name = "Convert", description = "Convert APIs")
public class ConvertPDFToPDFA {
@PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@Operation(
summary = "Convert a PDF to a PDF/A",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -40,7 +42,7 @@ public class ConvertWebsiteToPDF {
private final RuntimePathConfig runtimePathConfig;
private final ApplicationProperties applicationProperties;
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@Operation(
summary = "Convert a URL to a PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
@@ -46,7 +48,7 @@ public class ExtractCSVController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
@Operation(
summary = "Extracts a CSV document from a PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.filters;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -37,7 +39,7 @@ public class FilterController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-text")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-contains-text")
@Operation(
summary = "Checks if a PDF contains set text, returns true if does",
description = "Input:PDF Output:Boolean Type:SISO")
@@ -55,7 +57,7 @@ public class FilterController {
}
// TODO
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-image")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-contains-image")
@Operation(
summary = "Checks if a PDF contains an image",
description = "Input:PDF Output:Boolean Type:SISO")
@@ -71,7 +73,7 @@ public class FilterController {
return null;
}
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-count")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-page-count")
@Operation(
summary = "Checks if a PDF is greater, less or equal to a setPageCount",
description = "Input:PDF Output:Boolean Type:SISO")
@@ -104,7 +106,7 @@ public class FilterController {
return null;
}
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-size")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-page-size")
@Operation(
summary = "Checks if a PDF is of a certain size",
description = "Input:PDF Output:Boolean Type:SISO")
@@ -147,7 +149,7 @@ public class FilterController {
return null;
}
@PostMapping(consumes = "multipart/form-data", value = "/filter-file-size")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-file-size")
@Operation(
summary = "Checks if a PDF is a set file size",
description = "Input:PDF Output:Boolean Type:SISO")
@@ -180,7 +182,7 @@ public class FilterController {
return null;
}
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-rotation")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-page-rotation")
@Operation(
summary = "Checks if a PDF is of a certain rotation",
description = "Input:PDF Output:Boolean Type:SISO")
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.util.List;
@@ -34,7 +36,7 @@ public class AttachmentController {
private final AttachmentServiceInterface pdfAttachmentService;
@PostMapping(consumes = "multipart/form-data", value = "/add-attachments")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-attachments")
@Operation(
summary = "Add attachments to PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
@@ -38,7 +40,7 @@ public class AutoRenameController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/auto-rename")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/auto-rename")
@Operation(
summary = "Extract header from PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
@@ -102,7 +104,7 @@ public class AutoSplitPdfController {
}
}
@PostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
@Operation(
summary = "Auto split PDF pages into separate documents",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -69,7 +71,7 @@ public class BlankPageController {
return whitePixelPercentage >= whitePercent;
}
@PostMapping(consumes = "multipart/form-data", value = "/remove-blanks")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-blanks")
@Operation(
summary = "Remove blank pages from a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
@@ -658,7 +660,7 @@ public class CompressController {
};
}
@PostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
@Operation(
summary = "Optimize PDF file",
description =
@@ -0,0 +1,129 @@
package stirling.software.SPDF.controller.api.misc;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.ApplicationContext;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.common.configuration.AppConfig;
import stirling.software.common.model.ApplicationProperties;
@RestController
@Tag(name = "Config", description = "Configuration APIs")
@RequestMapping("/api/v1/config")
@RequiredArgsConstructor
@Hidden
public class ConfigController {
private final ApplicationProperties applicationProperties;
private final ApplicationContext applicationContext;
private final EndpointConfiguration endpointConfiguration;
@GetMapping("/app-config")
public ResponseEntity<Map<String, Object>> getAppConfig() {
Map<String, Object> configData = new HashMap<>();
try {
// Get AppConfig bean
AppConfig appConfig = applicationContext.getBean(AppConfig.class);
// Extract key configuration values from AppConfig
configData.put("baseUrl", appConfig.getBaseUrl());
configData.put("contextPath", appConfig.getContextPath());
configData.put("serverPort", appConfig.getServerPort());
// Extract values from ApplicationProperties
configData.put("appName", applicationProperties.getUi().getAppName());
configData.put("appNameNavbar", applicationProperties.getUi().getAppNameNavbar());
configData.put("homeDescription", applicationProperties.getUi().getHomeDescription());
configData.put("languages", applicationProperties.getUi().getLanguages());
// Security settings
configData.put("enableLogin", applicationProperties.getSecurity().getEnableLogin());
// System settings
configData.put(
"enableAlphaFunctionality",
applicationProperties.getSystem().getEnableAlphaFunctionality());
configData.put(
"enableAnalytics", applicationProperties.getSystem().getEnableAnalytics());
// Premium/Enterprise settings
configData.put("premiumEnabled", applicationProperties.getPremium().isEnabled());
// Legal settings
configData.put(
"termsAndConditions", applicationProperties.getLegal().getTermsAndConditions());
configData.put("privacyPolicy", applicationProperties.getLegal().getPrivacyPolicy());
configData.put("cookiePolicy", applicationProperties.getLegal().getCookiePolicy());
configData.put("impressum", applicationProperties.getLegal().getImpressum());
configData.put(
"accessibilityStatement",
applicationProperties.getLegal().getAccessibilityStatement());
// Try to get EEAppConfig values if available
try {
if (applicationContext.containsBean("runningProOrHigher")) {
configData.put(
"runningProOrHigher",
applicationContext.getBean("runningProOrHigher", Boolean.class));
}
if (applicationContext.containsBean("runningEE")) {
configData.put(
"runningEE", applicationContext.getBean("runningEE", Boolean.class));
}
if (applicationContext.containsBean("license")) {
configData.put("license", applicationContext.getBean("license", String.class));
}
if (applicationContext.containsBean("GoogleDriveEnabled")) {
configData.put(
"GoogleDriveEnabled",
applicationContext.getBean("GoogleDriveEnabled", Boolean.class));
}
if (applicationContext.containsBean("SSOAutoLogin")) {
configData.put(
"SSOAutoLogin",
applicationContext.getBean("SSOAutoLogin", Boolean.class));
}
} catch (Exception e) {
// EE features not available, continue without them
}
return ResponseEntity.ok(configData);
} catch (Exception e) {
// Return basic config if there are any issues
configData.put("error", "Unable to retrieve full configuration");
return ResponseEntity.ok(configData);
}
}
@GetMapping("/endpoint-enabled")
public ResponseEntity<Boolean> isEndpointEnabled(@RequestParam(name = "endpoint") String endpoint) {
boolean enabled = endpointConfiguration.isEndpointEnabled(endpoint);
return ResponseEntity.ok(enabled);
}
@GetMapping("/endpoints-enabled")
public ResponseEntity<Map<String, Boolean>> areEndpointsEnabled(
@RequestParam(name = "endpoints") String endpoints) {
Map<String, Boolean> result = new HashMap<>();
String[] endpointArray = endpoints.split(",");
for (String endpoint : endpointArray) {
String trimmedEndpoint = endpoint.trim();
result.put(trimmedEndpoint, endpointConfiguration.isEndpointEnabled(trimmedEndpoint));
}
return ResponseEntity.ok(result);
}
}
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -38,7 +40,7 @@ public class DecompressPdfController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/decompress-pdf", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/decompress-pdf", consumes = "multipart/form-data")
@Operation(
summary = "Decompress PDF streams",
description = "Fully decompresses all PDF streams including text content")
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -50,7 +52,7 @@ public class ExtractImageScansController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/extract-image-scans")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/extract-image-scans")
@Operation(
summary = "Extract image scans from an input file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
@@ -54,7 +56,7 @@ public class ExtractImagesController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/extract-images")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/extract-images")
@Operation(
summary = "Extract images from a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.image.BufferedImage;
import java.io.IOException;
@@ -38,7 +40,7 @@ public class FlattenController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/flatten")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/flatten")
@Operation(
summary = "Flatten PDF form fields or full page",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -51,7 +53,7 @@ public class MetadataController {
binder.registerCustomEditor(Map.class, "allRequestParams", new StringToMapPropertyEditor());
}
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/update-metadata")
@Operation(
summary = "Update metadata of a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
@@ -76,7 +78,7 @@ public class OCRController {
.toList();
}
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
@Operation(
summary = "Process a PDF file with OCR",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import org.springframework.http.HttpStatus;
@@ -31,7 +33,7 @@ public class OverlayImageController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/add-image")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-image")
@Operation(
summary = "Overlay image onto a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
@@ -37,7 +39,7 @@ public class PageNumbersController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(value = "/add-page-numbers", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/add-page-numbers", consumes = "multipart/form-data")
@Operation(
summary = "Add page numbers to a PDF document",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
@@ -37,7 +39,7 @@ import stirling.software.SPDF.model.api.misc.PrintFileRequest;
public class PrintFileController {
// TODO
// @PostMapping(value = "/print-file", consumes = "multipart/form-data")
// @AutoJobPostMapping(value = "/print-file", consumes = "multipart/form-data")
// @Operation(
// summary = "Prints PDF/Image file to a set printer",
// description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -46,7 +48,7 @@ public class RepairController {
return endpointConfiguration.isGroupEnabled("qpdf");
}
@PostMapping(consumes = "multipart/form-data", value = "/repair")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/repair")
@Operation(
summary = "Repair a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import org.springframework.core.io.InputStreamResource;
@@ -27,7 +29,7 @@ public class ReplaceAndInvertColorController {
private final ReplaceAndInvertColorService replaceAndInvertColorService;
@PostMapping(consumes = "multipart/form-data", value = "/replace-invert-pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/replace-invert-pdf")
@Operation(
summary = "Replace-Invert Color PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
@@ -52,7 +54,7 @@ public class ScannerEffectController {
private static final int MAX_IMAGE_HEIGHT = 8192;
private static final long MAX_IMAGE_PIXELS = 16_777_216; // 4096x4096
@PostMapping(value = "/scanner-effect", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/scanner-effect", consumes = "multipart/form-data")
@Operation(
summary = "Apply scanner effect to PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@@ -32,7 +34,7 @@ public class ShowJavascript {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/show-javascript")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/show-javascript")
@Operation(
summary = "Grabs all JS from a PDF and returns a single JS file with all code",
description = "desc. Input:PDF Output:JS Type:SISO")
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
@@ -52,7 +54,7 @@ public class StampController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
private final TempFileManager tempFileManager;
@PostMapping(consumes = "multipart/form-data", value = "/add-stamp")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-stamp")
@Operation(
summary = "Add stamp to a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.misc;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
@@ -37,7 +39,7 @@ public class UnlockPDFFormsController {
this.pdfDocumentFactory = pdfDocumentFactory;
}
@PostMapping(consumes = "multipart/form-data", value = "/unlock-pdf-forms")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/unlock-pdf-forms")
@Operation(
summary = "Remove read-only property from form fields",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.pipeline;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
@@ -46,7 +48,7 @@ public class PipelineController {
private final PostHogService postHogService;
@PostMapping(value = "/handleData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@AutoJobPostMapping(value = "/handleData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<byte[]> handleData(@ModelAttribute HandleDataRequest request)
throws JsonMappingException, JsonProcessingException {
MultipartFile[] files = request.getFileInput();
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.beans.PropertyEditorSupport;
import java.io.*;
@@ -138,7 +140,7 @@ public class CertSignController {
}
}
@PostMapping(
@AutoJobPostMapping(
consumes = {
MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_FORM_URLENCODED_VALUE
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -188,7 +190,7 @@ public class GetInfoOnPDF {
return false;
}
@PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException {
MultipartFile inputFile = request.getFileInput();
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -32,7 +34,7 @@ public class PasswordController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/remove-password")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-password")
@Operation(
summary = "Remove password from a PDF file",
description =
@@ -58,7 +60,7 @@ public class PasswordController {
}
}
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-password")
@Operation(
summary = "Add password to a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -56,7 +58,7 @@ public class RedactController {
List.class, "redactions", new StringToArrayListPropertyEditor());
}
@PostMapping(value = "/redact", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/redact", consumes = "multipart/form-data")
@Operation(
summary = "Redacts areas and pages in a PDF document",
description =
@@ -190,7 +192,7 @@ public class RedactController {
return pageNumbers;
}
@PostMapping(value = "/auto-redact", consumes = "multipart/form-data")
@AutoJobPostMapping(value = "/auto-redact", consumes = "multipart/form-data")
@Operation(
summary = "Redacts listOfText in a PDF document",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -32,7 +34,7 @@ public class RemoveCertSignController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/remove-cert-sign")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-cert-sign")
@Operation(
summary = "Remove digital signature from PDF",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.io.IOException;
import org.apache.pdfbox.cos.COSDictionary;
@@ -46,7 +48,7 @@ public class SanitizeController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@PostMapping(consumes = "multipart/form-data", value = "/sanitize-pdf")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/sanitize-pdf")
@Operation(
summary = "Sanitize a PDF file",
description =
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.beans.PropertyEditorSupport;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -69,7 +71,7 @@ public class ValidateSignatureController {
description =
"Validates the digital signatures in a PDF file against default or custom"
+ " certificates. Input:PDF Output:JSON Type:SISO")
@PostMapping(value = "/validate-signature", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@AutoJobPostMapping(value = "/validate-signature", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
@ModelAttribute SignatureValidationRequest request) throws IOException {
List<SignatureValidationResult> results = new ArrayList<>();
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.security;
import stirling.software.common.annotations.AutoJobPostMapping;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyEditorSupport;
@@ -64,7 +66,7 @@ public class WatermarkController {
});
}
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-watermark")
@Operation(
summary = "Add watermark to a PDF file",
description =
@@ -0,0 +1,18 @@
package stirling.software.SPDF.controller.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ReactRoutingController {
@GetMapping("/{path:^(?!api|static|robots\\.txt|favicon\\.ico)[^\\.]*$}")
public String forwardRootPaths() {
return "forward:/index.html";
}
@GetMapping("/{path:^(?!api|static)[^\\.]*}/{subpath:^(?!.*\\.).*$}")
public String forwardNestedPaths() {
return "forward:/index.html";
}
}
@@ -1,5 +1,7 @@
package stirling.software.SPDF.model.api.converters;
import stirling.software.common.annotations.AutoJobPostMapping;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@@ -18,7 +20,7 @@ import stirling.software.common.util.PDFToFile;
@RequestMapping("/api/v1/convert")
public class ConvertPDFToMarkdown {
@PostMapping(consumes = "multipart/form-data", value = "/pdf/markdown")
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/markdown")
@Operation(
summary = "Convert PDF to Markdown",
description =