pipeline fixes
This commit is contained in:
parent
3912f42128
commit
2fa68be36b
9 changed files with 139 additions and 57 deletions
|
@ -96,7 +96,7 @@ public class ConvertImgPDFController {
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert images to a PDF file",
|
summary = "Convert images to a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images. Input:Image Output:PDF Type:SISO?")
|
"This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images. Input:Image Output:PDF Type:MISO")
|
||||||
public ResponseEntity<byte[]> convertToPdf(@ModelAttribute ConvertToPdfRequest request)
|
public ResponseEntity<byte[]> convertToPdf(@ModelAttribute ConvertToPdfRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MultipartFile[] file = request.getFileInput();
|
MultipartFile[] file = request.getFileInput();
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class ConvertMarkdownToPdf {
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a Markdown file to PDF",
|
summary = "Convert a Markdown file to PDF",
|
||||||
description =
|
description =
|
||||||
"This endpoint takes a Markdown file input, converts it to HTML, and then to PDF format.")
|
"This endpoint takes a Markdown file input, converts it to HTML, and then to PDF format. Input:MARKDOWN Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> markdownToPdf(@ModelAttribute GeneralFile request)
|
public ResponseEntity<byte[]> markdownToPdf(@ModelAttribute GeneralFile request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile fileInput = request.getFileInput();
|
MultipartFile fileInput = request.getFileInput();
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class OverlayImageController {
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Overlay image onto a PDF file",
|
summary = "Overlay image onto a PDF file",
|
||||||
description =
|
description =
|
||||||
"This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified. Input:PDF/IMAGE Output:PDF Type:MF-SISO")
|
"This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified. Input:PDF/IMAGE Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> overlayImage(@ModelAttribute OverlayImageRequest request) {
|
public ResponseEntity<byte[]> overlayImage(@ModelAttribute OverlayImageRequest request) {
|
||||||
MultipartFile pdfFile = request.getFileInput();
|
MultipartFile pdfFile = request.getFileInput();
|
||||||
MultipartFile imageFile = request.getImageFile();
|
MultipartFile imageFile = request.getImageFile();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package stirling.software.SPDF.controller.api.pipeline;
|
package stirling.software.SPDF.controller.api.pipeline;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -22,7 +23,7 @@ import jakarta.servlet.ServletContext;
|
||||||
import stirling.software.SPDF.SPdfApplication;
|
import stirling.software.SPDF.SPdfApplication;
|
||||||
import stirling.software.SPDF.model.ApiEndpoint;
|
import stirling.software.SPDF.model.ApiEndpoint;
|
||||||
import stirling.software.SPDF.model.Role;
|
import stirling.software.SPDF.model.Role;
|
||||||
|
import java.util.List;
|
||||||
@Service
|
@Service
|
||||||
public class ApiDocService {
|
public class ApiDocService {
|
||||||
|
|
||||||
|
@ -38,6 +39,48 @@ public class ApiDocService {
|
||||||
|
|
||||||
return "http://localhost:" + port + contextPath + "/v1/api-docs";
|
return "http://localhost:" + port + contextPath + "/v1/api-docs";
|
||||||
}
|
}
|
||||||
|
Map<String, List<String>> outputToFileTypes = new HashMap<>();
|
||||||
|
|
||||||
|
public List getExtensionTypes(boolean output, String operationName) {
|
||||||
|
if(outputToFileTypes.size() == 0) {
|
||||||
|
outputToFileTypes.put("PDF", Arrays.asList("pdf"));
|
||||||
|
outputToFileTypes.put("IMAGE", Arrays.asList("png", "jpg", "jpeg", "gif", "webp", "bmp", "tif", "tiff", "svg", "psd", "ai", "eps"));
|
||||||
|
outputToFileTypes.put("ZIP", Arrays.asList("zip", "rar", "7z", "tar", "gz", "bz2", "xz", "lz", "lzma", "z"));
|
||||||
|
outputToFileTypes.put("WORD", Arrays.asList("doc", "docx", "odt", "rtf"));
|
||||||
|
outputToFileTypes.put("CSV", Arrays.asList("csv"));
|
||||||
|
outputToFileTypes.put("JS", Arrays.asList("js", "jsx"));
|
||||||
|
outputToFileTypes.put("HTML", Arrays.asList("html", "htm", "xhtml"));
|
||||||
|
outputToFileTypes.put("JSON", Arrays.asList("json"));
|
||||||
|
outputToFileTypes.put("TXT", Arrays.asList("txt", "text", "md", "markdown"));
|
||||||
|
outputToFileTypes.put("PPT", Arrays.asList("ppt", "pptx", "odp"));
|
||||||
|
outputToFileTypes.put("XML", Arrays.asList("xml", "xsd", "xsl"));
|
||||||
|
outputToFileTypes.put("BOOK", Arrays.asList("epub", "mobi", "azw3", "fb2", "txt", "docx")); // As noted before, "Boolean" isn't a file type but a value type.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiDocsJsonRootNode == null || apiDocumentation.size() == 0) {
|
||||||
|
loadApiDocumentation();
|
||||||
|
}
|
||||||
|
if (!apiDocumentation.containsKey(operationName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiEndpoint endpoint = apiDocumentation.get(operationName);
|
||||||
|
String description = endpoint.getDescription();
|
||||||
|
Pattern pattern = null;
|
||||||
|
if(output) {
|
||||||
|
pattern = Pattern.compile("Output:(\\w+)");
|
||||||
|
} else {
|
||||||
|
pattern = Pattern.compile("Input:(\\w+)");
|
||||||
|
}
|
||||||
|
Matcher matcher = pattern.matcher(description);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String type = matcher.group(1).toUpperCase();
|
||||||
|
if(outputToFileTypes.containsKey(type)) {
|
||||||
|
return outputToFileTypes.get(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private UserServiceInterface userService;
|
private UserServiceInterface userService;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -82,15 +83,13 @@ public class PipelineProcessor {
|
||||||
operation,
|
operation,
|
||||||
isMultiInputOperation);
|
isMultiInputOperation);
|
||||||
Map<String, Object> parameters = pipelineOperation.getParameters();
|
Map<String, Object> parameters = pipelineOperation.getParameters();
|
||||||
String inputFileExtension = "";
|
List<String> inputFileTypes = apiDocService.getExtensionTypes(false, operation);
|
||||||
|
if(inputFileTypes == null) {
|
||||||
|
inputFileTypes = new ArrayList<String>(Arrays.asList("ALL"));
|
||||||
|
}
|
||||||
|
//List outputFileTypes = apiDocService.getExtensionTypes(true, operation);
|
||||||
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// if (operationNode.has("inputFileType")) {
|
|
||||||
// inputFileExtension = operationNode.get("inputFileType").asText();
|
|
||||||
// } else {
|
|
||||||
inputFileExtension = ".pdf";
|
|
||||||
// }
|
|
||||||
final String finalInputFileExtension = inputFileExtension;
|
|
||||||
|
|
||||||
String url = getBaseUrl() + operation;
|
String url = getBaseUrl() + operation;
|
||||||
|
|
||||||
|
@ -98,7 +97,8 @@ public class PipelineProcessor {
|
||||||
if (!isMultiInputOperation) {
|
if (!isMultiInputOperation) {
|
||||||
for (Resource file : outputFiles) {
|
for (Resource file : outputFiles) {
|
||||||
boolean hasInputFileType = false;
|
boolean hasInputFileType = false;
|
||||||
if (file.getFilename().endsWith(inputFileExtension)) {
|
for (String extension : inputFileTypes) {
|
||||||
|
if (extension.equals("ALL") || file.getFilename().endsWith(extension)) {
|
||||||
hasInputFileType = true;
|
hasInputFileType = true;
|
||||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||||
body.add("fileInput", file);
|
body.add("fileInput", file);
|
||||||
|
@ -123,13 +123,14 @@ public class PipelineProcessor {
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
processOutputFiles(operation, file.getFilename(), response, newOutputFiles);
|
processOutputFiles(operation, response, newOutputFiles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasInputFileType) {
|
if (!hasInputFileType) {
|
||||||
logPrintStream.println(
|
logPrintStream.println(
|
||||||
"No files with extension "
|
"No files with extension "
|
||||||
+ inputFileExtension
|
+ String.join(", ", inputFileTypes)
|
||||||
+ " found for operation "
|
+ " found for operation "
|
||||||
+ operation);
|
+ operation);
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
|
@ -138,13 +139,16 @@ public class PipelineProcessor {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Filter and collect all files that match the inputFileExtension
|
// Filter and collect all files that match the inputFileExtension
|
||||||
List<Resource> matchingFiles =
|
List<Resource> matchingFiles;
|
||||||
|
if (inputFileTypes.contains("ALL")) {
|
||||||
|
matchingFiles = new ArrayList<>(outputFiles);
|
||||||
|
} else {
|
||||||
|
final List<String> finalinputFileTypes = inputFileTypes;
|
||||||
|
matchingFiles =
|
||||||
outputFiles.stream()
|
outputFiles.stream()
|
||||||
.filter(
|
.filter(file -> finalinputFileTypes.stream().anyMatch(file.getFilename()::endsWith))
|
||||||
file ->
|
|
||||||
file.getFilename()
|
|
||||||
.endsWith(finalInputFileExtension))
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there are matching files
|
// Check if there are matching files
|
||||||
if (!matchingFiles.isEmpty()) {
|
if (!matchingFiles.isEmpty()) {
|
||||||
|
@ -166,7 +170,6 @@ public class PipelineProcessor {
|
||||||
if (response.getStatusCode().equals(HttpStatus.OK)) {
|
if (response.getStatusCode().equals(HttpStatus.OK)) {
|
||||||
processOutputFiles(
|
processOutputFiles(
|
||||||
operation,
|
operation,
|
||||||
matchingFiles.get(0).getFilename(),
|
|
||||||
response,
|
response,
|
||||||
newOutputFiles);
|
newOutputFiles);
|
||||||
} else {
|
} else {
|
||||||
|
@ -178,7 +181,7 @@ public class PipelineProcessor {
|
||||||
} else {
|
} else {
|
||||||
logPrintStream.println(
|
logPrintStream.println(
|
||||||
"No files with extension "
|
"No files with extension "
|
||||||
+ inputFileExtension
|
+ String.join(", ", inputFileTypes)
|
||||||
+ " found for multi-input operation "
|
+ " found for multi-input operation "
|
||||||
+ operation);
|
+ operation);
|
||||||
hasErrors = true;
|
hasErrors = true;
|
||||||
|
@ -211,9 +214,29 @@ public class PipelineProcessor {
|
||||||
return restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
return restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String removeTrailingNaming(String filename) {
|
||||||
|
// Splitting filename into name and extension
|
||||||
|
int dotIndex = filename.lastIndexOf(".");
|
||||||
|
if (dotIndex == -1) {
|
||||||
|
// No extension found
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
String name = filename.substring(0, dotIndex);
|
||||||
|
String extension = filename.substring(dotIndex);
|
||||||
|
|
||||||
|
// Finding the last underscore
|
||||||
|
int underscoreIndex = name.lastIndexOf("_");
|
||||||
|
if (underscoreIndex == -1) {
|
||||||
|
// No underscore found
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removing the last part and reattaching the extension
|
||||||
|
return name.substring(0, underscoreIndex) + extension;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Resource> processOutputFiles(
|
private List<Resource> processOutputFiles(
|
||||||
String operation,
|
String operation,
|
||||||
String fileName,
|
|
||||||
ResponseEntity<byte[]> response,
|
ResponseEntity<byte[]> response,
|
||||||
List<Resource> newOutputFiles)
|
List<Resource> newOutputFiles)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -227,7 +250,7 @@ public class PipelineProcessor {
|
||||||
newFilename = extractFilename(response);
|
newFilename = extractFilename(response);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, keep the original filename.
|
// Otherwise, keep the original filename.
|
||||||
newFilename = fileName;
|
newFilename = removeTrailingNaming(extractFilename(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the response body is a zip file
|
// Check if the response body is a zip file
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class CertSignController {
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Sign PDF with a Digital Certificate",
|
summary = "Sign PDF with a Digital Certificate",
|
||||||
description =
|
description =
|
||||||
"This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:MF-SISO")
|
"This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request)
|
public ResponseEntity<byte[]> signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
MultipartFile pdf = request.getFileInput();
|
MultipartFile pdf = request.getFileInput();
|
||||||
|
|
|
@ -36,6 +36,10 @@ public class FileToPdf {
|
||||||
} else {
|
} else {
|
||||||
command.add("wkhtmltopdf");
|
command.add("wkhtmltopdf");
|
||||||
command.add("--enable-local-file-access");
|
command.add("--enable-local-file-access");
|
||||||
|
command.add("--load-error-handling");
|
||||||
|
command.add("ignore");
|
||||||
|
command.add("--load-media-error-handling");
|
||||||
|
command.add("ignore");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
|
@ -130,7 +134,6 @@ public class FileToPdf {
|
||||||
command.add("ebook-convert");
|
command.add("ebook-convert");
|
||||||
command.add(tempInputFile.toString());
|
command.add(tempInputFile.toString());
|
||||||
command.add(tempOutputFile.toString());
|
command.add(tempOutputFile.toString());
|
||||||
|
|
||||||
ProcessExecutorResult returnCode =
|
ProcessExecutorResult returnCode =
|
||||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.CALIBRE)
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.CALIBRE)
|
||||||
.runCommandWithOutputHandling(command);
|
.runCommandWithOutputHandling(command);
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
setLanguageForDropdown('.lang_dropdown-item');
|
setLanguageForDropdown('.lang_dropdown-item');
|
||||||
const defaultLocale = document.documentElement.lang || 'en_GB';
|
|
||||||
|
// Detect the browser's preferred language
|
||||||
|
let browserLang = navigator.language || navigator.userLanguage;
|
||||||
|
// Convert to a format consistent with your language codes (e.g., en-GB, fr-FR)
|
||||||
|
browserLang = browserLang.replace('-', '_');
|
||||||
|
|
||||||
|
// Check if the dropdown contains the browser's language
|
||||||
|
const dropdownLangExists = document.querySelector(`.lang_dropdown-item[data-language-code="${browserLang}"]`);
|
||||||
|
|
||||||
|
// Set the default language to browser's language or 'en_GB' if not found in the dropdown
|
||||||
|
const defaultLocale = dropdownLangExists ? browserLang : 'en_GB';
|
||||||
const storedLocale = localStorage.getItem('languageCode') || defaultLocale;
|
const storedLocale = localStorage.getItem('languageCode') || defaultLocale;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const dropdownItems = document.querySelectorAll('.lang_dropdown-item');
|
const dropdownItems = document.querySelectorAll('.lang_dropdown-item');
|
||||||
|
|
||||||
for (let i = 0; i < dropdownItems.length; i++) {
|
for (let i = 0; i < dropdownItems.length; i++) {
|
||||||
|
|
Loading…
Reference in a new issue