# Description of Changes This pull request includes several changes primarily focused on improving configuration management, removing deprecated methods, and updating paths for external dependencies. The most important changes are summarized below: ### Configuration Management Improvements: * Added a new `RuntimePathConfig` class to manage dynamic paths for operations and pipeline configurations (`src/main/java/stirling/software/SPDF/config/RuntimePathConfig.java`). * Removed the `bookAndHtmlFormatsInstalled` bean and its associated logic from `AppConfig` and `EndpointConfiguration` (`src/main/java/stirling/software/SPDF/config/AppConfig.java`, `src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java`). [[1]](diffhunk://#diff-4d774ec79aa55750c0a4739bee971b68877078b73654e863fd40ee924347e143L130-L138) [[2]](diffhunk://#diff-750f31f6ecbd64b025567108a33775cad339e835a04360affff82a09410b697dL12-L35) [[3]](diffhunk://#diff-750f31f6ecbd64b025567108a33775cad339e835a04360affff82a09410b697dL275-L280) ### External Dependency Path Updates: * Updated paths for `weasyprint` and `unoconvert` in `ExternalAppDepConfig` to use values from `RuntimePathConfig` (`src/main/java/stirling/software/SPDF/config/ExternalAppDepConfig.java`). [[1]](diffhunk://#diff-c47af298c07c2622aa98b038b78822c56bdb002de71081e102d344794e7832a6R12-L33) [[2]](diffhunk://#diff-c47af298c07c2622aa98b038b78822c56bdb002de71081e102d344794e7832a6L104-R115) ### Minor Adjustments: * Corrected a typo from "Unoconv" to "Unoconvert" in `EndpointConfiguration` (`src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java`). --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.
345 lines
12 KiB
Java
345 lines
12 KiB
Java
package stirling.software.SPDF.controller.web;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
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.Collectors;
|
|
import java.util.stream.Stream;
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.core.io.Resource;
|
|
import org.springframework.core.io.ResourceLoader;
|
|
import org.springframework.core.io.support.ResourcePatternUtils;
|
|
import org.springframework.stereotype.Controller;
|
|
import org.springframework.ui.Model;
|
|
import org.springframework.web.bind.annotation.GetMapping;
|
|
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
import io.swagger.v3.oas.annotations.Hidden;
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
|
import stirling.software.SPDF.config.RuntimePathConfig;
|
|
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
|
import stirling.software.SPDF.model.SignatureFile;
|
|
import stirling.software.SPDF.service.SignatureService;
|
|
|
|
@Controller
|
|
@Tag(name = "General", description = "General APIs")
|
|
@Slf4j
|
|
public class GeneralWebController {
|
|
|
|
private final SignatureService signatureService;
|
|
private final UserServiceInterface userService;
|
|
private final ResourceLoader resourceLoader;
|
|
private final RuntimePathConfig runtimePathConfig;
|
|
|
|
public GeneralWebController(
|
|
SignatureService signatureService,
|
|
@Autowired(required = false) UserServiceInterface userService,
|
|
ResourceLoader resourceLoader,
|
|
RuntimePathConfig runtimePathConfig) {
|
|
this.signatureService = signatureService;
|
|
this.userService = userService;
|
|
this.resourceLoader = resourceLoader;
|
|
this.runtimePathConfig = runtimePathConfig;
|
|
}
|
|
|
|
@GetMapping("/pipeline")
|
|
@Hidden
|
|
public String pipelineForm(Model model) {
|
|
model.addAttribute("currentPage", "pipeline");
|
|
List<String> pipelineConfigs = new ArrayList<>();
|
|
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
|
|
if (new 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"))
|
|
.collect(Collectors.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("exception", e);
|
|
}
|
|
}
|
|
if (pipelineConfigsWithNames.size() == 0) {
|
|
Map<String, String> configWithName = new HashMap<>();
|
|
configWithName.put("json", "");
|
|
configWithName.put("name", "No preloaded configs found");
|
|
pipelineConfigsWithNames.add(configWithName);
|
|
}
|
|
model.addAttribute("pipelineConfigsWithNames", pipelineConfigsWithNames);
|
|
model.addAttribute("pipelineConfigs", pipelineConfigs);
|
|
return "pipeline";
|
|
}
|
|
|
|
@GetMapping("/merge-pdfs")
|
|
@Hidden
|
|
public String mergePdfForm(Model model) {
|
|
model.addAttribute("currentPage", "merge-pdfs");
|
|
return "merge-pdfs";
|
|
}
|
|
|
|
@GetMapping("/split-pdf-by-sections")
|
|
@Hidden
|
|
public String splitPdfBySections(Model model) {
|
|
model.addAttribute("currentPage", "split-pdf-by-sections");
|
|
return "split-pdf-by-sections";
|
|
}
|
|
|
|
@GetMapping("/split-pdf-by-chapters")
|
|
@Hidden
|
|
public String splitPdfByChapters(Model model) {
|
|
model.addAttribute("currentPage", "split-pdf-by-chapters");
|
|
return "split-pdf-by-chapters";
|
|
}
|
|
|
|
@GetMapping("/view-pdf")
|
|
@Hidden
|
|
public String ViewPdfForm2(Model model) {
|
|
model.addAttribute("currentPage", "view-pdf");
|
|
return "view-pdf";
|
|
}
|
|
|
|
@GetMapping("/multi-tool")
|
|
@Hidden
|
|
public String multiToolForm(Model model) {
|
|
model.addAttribute("currentPage", "multi-tool");
|
|
return "multi-tool";
|
|
}
|
|
|
|
@GetMapping("/remove-pages")
|
|
@Hidden
|
|
public String pageDeleter(Model model) {
|
|
model.addAttribute("currentPage", "remove-pages");
|
|
return "remove-pages";
|
|
}
|
|
|
|
@GetMapping("/pdf-organizer")
|
|
@Hidden
|
|
public String pageOrganizer(Model model) {
|
|
model.addAttribute("currentPage", "pdf-organizer");
|
|
return "pdf-organizer";
|
|
}
|
|
|
|
@GetMapping("/extract-page")
|
|
@Hidden
|
|
public String extractPages(Model model) {
|
|
model.addAttribute("currentPage", "extract-page");
|
|
return "extract-page";
|
|
}
|
|
|
|
@GetMapping("/pdf-to-single-page")
|
|
@Hidden
|
|
public String pdfToSinglePage(Model model) {
|
|
model.addAttribute("currentPage", "pdf-to-single-page");
|
|
return "pdf-to-single-page";
|
|
}
|
|
|
|
@GetMapping("/rotate-pdf")
|
|
@Hidden
|
|
public String rotatePdfForm(Model model) {
|
|
model.addAttribute("currentPage", "rotate-pdf");
|
|
return "rotate-pdf";
|
|
}
|
|
|
|
@GetMapping("/split-pdfs")
|
|
@Hidden
|
|
public String splitPdfForm(Model model) {
|
|
model.addAttribute("currentPage", "split-pdfs");
|
|
return "split-pdfs";
|
|
}
|
|
|
|
@GetMapping("/sign")
|
|
@Hidden
|
|
public String signForm(Model model) {
|
|
String username = "";
|
|
if (userService != null) {
|
|
username = userService.getCurrentUsername();
|
|
}
|
|
// Get signatures from both personal and ALL_USERS folders
|
|
List<SignatureFile> signatures = signatureService.getAvailableSignatures(username);
|
|
model.addAttribute("currentPage", "sign");
|
|
model.addAttribute("fonts", getFontNames());
|
|
model.addAttribute("signatures", signatures);
|
|
return "sign";
|
|
}
|
|
|
|
@GetMapping("/multi-page-layout")
|
|
@Hidden
|
|
public String multiPageLayoutForm(Model model) {
|
|
model.addAttribute("currentPage", "multi-page-layout");
|
|
return "multi-page-layout";
|
|
}
|
|
|
|
@GetMapping("/scale-pages")
|
|
@Hidden
|
|
public String scalePagesFrom(Model model) {
|
|
model.addAttribute("currentPage", "scale-pages");
|
|
return "scale-pages";
|
|
}
|
|
|
|
@GetMapping("/split-by-size-or-count")
|
|
@Hidden
|
|
public String splitBySizeOrCount(Model model) {
|
|
model.addAttribute("currentPage", "split-by-size-or-count");
|
|
return "split-by-size-or-count";
|
|
}
|
|
|
|
@GetMapping("/overlay-pdf")
|
|
@Hidden
|
|
public String overlayPdf(Model model) {
|
|
model.addAttribute("currentPage", "overlay-pdf");
|
|
return "overlay-pdf";
|
|
}
|
|
|
|
private List<FontResource> getFontNames() {
|
|
List<FontResource> fontNames = new ArrayList<>();
|
|
// Extract font names from classpath
|
|
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
|
|
// Extract font names from external directory
|
|
fontNames.addAll(
|
|
getFontNamesFromLocation(
|
|
"file:" + InstallationPathConfig.getStaticPath() + "fonts/*"));
|
|
return fontNames;
|
|
}
|
|
|
|
private List<FontResource> getFontNamesFromLocation(String locationPattern) {
|
|
try {
|
|
Resource[] resources =
|
|
ResourcePatternUtils.getResourcePatternResolver(resourceLoader)
|
|
.getResources(locationPattern);
|
|
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 new RuntimeException("Error processing filename", e);
|
|
}
|
|
})
|
|
.filter(Objects::nonNull)
|
|
.collect(Collectors.toList());
|
|
} catch (Exception e) {
|
|
throw new RuntimeException("Failed to read font directory from " + locationPattern, e);
|
|
}
|
|
}
|
|
|
|
public 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:
|
|
// or throw an exception if an unexpected extension is encountered
|
|
return "";
|
|
}
|
|
}
|
|
|
|
@GetMapping("/crop")
|
|
@Hidden
|
|
public String cropForm(Model model) {
|
|
model.addAttribute("currentPage", "crop");
|
|
return "crop";
|
|
}
|
|
|
|
@GetMapping("/auto-split-pdf")
|
|
@Hidden
|
|
public String autoSPlitPDFForm(Model model) {
|
|
model.addAttribute("currentPage", "auto-split-pdf");
|
|
return "auto-split-pdf";
|
|
}
|
|
|
|
@GetMapping("/remove-image-pdf")
|
|
@Hidden
|
|
public String removeImagePdfForm(Model model) {
|
|
model.addAttribute("currentPage", "remove-image-pdf");
|
|
return "remove-image-pdf";
|
|
}
|
|
|
|
public 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);
|
|
}
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public void setName(String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
public String getExtension() {
|
|
return extension;
|
|
}
|
|
|
|
public void setExtension(String extension) {
|
|
this.extension = extension;
|
|
}
|
|
|
|
public String getType() {
|
|
return type;
|
|
}
|
|
|
|
public void setType(String type) {
|
|
this.type = type;
|
|
}
|
|
}
|
|
}
|