diff --git a/app/common/build.gradle b/app/common/build.gradle index 3c46a59af..9cd5cee6d 100644 --- a/app/common/build.gradle +++ b/app/common/build.gradle @@ -17,7 +17,7 @@ spotless { dependencies { api 'org.springframework.boot:spring-boot-starter-web' api 'org.springframework.boot:spring-boot-starter-aop' - api 'org.springframework.boot:spring-boot-starter-thymeleaf' + // api 'org.springframework.boot:spring-boot-starter-thymeleaf' // Deprecated - UI moved to React frontend api 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1' api 'com.fathzer:javaluator:3.0.6' api 'com.posthog.java:posthog:1.2.0' diff --git a/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java b/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java index f611f42ca..170261ff8 100644 --- a/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java +++ b/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java @@ -10,7 +10,6 @@ import java.util.Properties; import java.util.function.Predicate; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; @@ -19,9 +18,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.core.env.Environment; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.util.ClassUtils; -import org.thymeleaf.spring6.SpringTemplateEngine; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -51,6 +48,7 @@ public class AppConfig { @Value("${server.port:8080}") private String serverPort; + /* Commented out Thymeleaf template engine bean - to be removed when frontend migration is complete @Bean @ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true") public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) { @@ -58,6 +56,7 @@ public class AppConfig { templateEngine.addTemplateResolver(new FileFallbackTemplateResolver(resourceLoader)); return templateEngine; } + */ @Bean(name = "loginEnabled") public boolean loginEnabled() { diff --git a/app/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java b/app/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java index 320d9aaac..9c5e0a7ae 100644 --- a/app/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java +++ b/app/common/src/main/java/stirling/software/common/configuration/FileFallbackTemplateResolver.java @@ -1,19 +1,8 @@ package stirling.software.common.configuration; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; +/* Commented out entire FileFallbackTemplateResolver class - Thymeleaf dependency removed + * This class will be removed when frontend migration to React is complete -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.thymeleaf.IEngineConfiguration; -import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver; -import org.thymeleaf.templateresource.FileTemplateResource; -import org.thymeleaf.templateresource.ITemplateResource; - -import lombok.extern.slf4j.Slf4j; - -import stirling.software.common.model.InputStreamTemplateResource; @Slf4j public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver { @@ -57,3 +46,4 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe return null; } } +*/ diff --git a/app/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java b/app/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java index 4bc81cafa..3bac16fef 100644 --- a/app/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java +++ b/app/common/src/main/java/stirling/software/common/model/InputStreamTemplateResource.java @@ -1,11 +1,8 @@ package stirling.software.common.model; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; +/* Commented out entire InputStreamTemplateResource class - Thymeleaf dependency removed + * This class will be removed when frontend migration to React is complete -import org.thymeleaf.templateresource.ITemplateResource; public class InputStreamTemplateResource implements ITemplateResource { private InputStream inputStream; @@ -42,3 +39,4 @@ public class InputStreamTemplateResource implements ITemplateResource { return inputStream != null; } } +*/ diff --git a/app/core/src/main/java/stirling/software/SPDF/SPDFApplication.java b/app/core/src/main/java/stirling/software/SPDF/SPDFApplication.java index 2131b4239..81973827c 100644 --- a/app/core/src/main/java/stirling/software/SPDF/SPDFApplication.java +++ b/app/core/src/main/java/stirling/software/SPDF/SPDFApplication.java @@ -10,7 +10,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.core.env.Environment; @@ -23,7 +22,6 @@ import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; -import stirling.software.SPDF.UI.WebBrowser; import stirling.software.common.configuration.AppConfig; import stirling.software.common.configuration.ConfigInitializer; import stirling.software.common.configuration.InstallationPathConfig; @@ -47,21 +45,20 @@ public class SPDFApplication { private final AppConfig appConfig; private final Environment env; private final ApplicationProperties applicationProperties; - private final WebBrowser webBrowser; + + // private final WebBrowser webBrowser; // Removed - desktop UI eliminated public SPDFApplication( - AppConfig appConfig, - Environment env, - ApplicationProperties applicationProperties, - @Autowired(required = false) WebBrowser webBrowser) { + AppConfig appConfig, Environment env, ApplicationProperties applicationProperties) { this.appConfig = appConfig; this.env = env; this.applicationProperties = applicationProperties; - this.webBrowser = webBrowser; + // this.webBrowser = webBrowser; // Removed - desktop UI eliminated } public static void main(String[] args) throws IOException, InterruptedException { SpringApplication app = new SpringApplication(SPDFApplication.class); + app.setLazyInitialization(true); // Optimize startup time Properties props = new Properties(); @@ -151,28 +148,31 @@ public class SPDFApplication { serverPortStatic = serverPort; String url = baseUrl + ":" + getStaticPort() + contextPath; - if (webBrowser != null - && Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) { - webBrowser.initWebUI(url); - } else { - String browserOpenEnv = env.getProperty("BROWSER_OPEN"); - boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv); - if (browserOpen) { - try { - String os = System.getProperty("os.name").toLowerCase(); - Runtime rt = Runtime.getRuntime(); + // Desktop UI initialization removed - webBrowser dependency eliminated + // Keep backwards compatibility for STIRLING_PDF_DESKTOP_UI system property + if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) { + log.info("Desktop UI mode enabled, but WebBrowser functionality has been removed"); + // webBrowser.initWebUI(url); // Removed - desktop UI eliminated + } - if (os.contains("win")) { - // For Windows - SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url); - } else if (os.contains("mac")) { - SystemCommand.runCommand(rt, "open " + url); - } else if (os.contains("nix") || os.contains("nux")) { - SystemCommand.runCommand(rt, "xdg-open " + url); - } - } catch (IOException e) { - log.error("Error opening browser: {}", e.getMessage()); + // Standard browser opening logic + String browserOpenEnv = env.getProperty("BROWSER_OPEN"); + boolean browserOpen = browserOpenEnv != null && "true".equalsIgnoreCase(browserOpenEnv); + if (browserOpen) { + try { + String os = System.getProperty("os.name").toLowerCase(); + Runtime rt = Runtime.getRuntime(); + + if (os.contains("win")) { + // For Windows + SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url); + } else if (os.contains("mac")) { + SystemCommand.runCommand(rt, "open " + url); + } else if (os.contains("nix") || os.contains("nux")) { + SystemCommand.runCommand(rt, "xdg-open " + url); } + } catch (IOException e) { + log.error("Error opening browser: {}", e.getMessage()); } } } @@ -189,9 +189,10 @@ public class SPDFApplication { @PreDestroy public void cleanup() { - if (webBrowser != null) { - webBrowser.cleanup(); - } + // webBrowser cleanup removed - desktop UI eliminated + // if (webBrowser != null) { + // webBrowser.cleanup(); + // } } private static void printStartupLogs() { diff --git a/app/core/src/main/java/stirling/software/SPDF/UI/WebBrowser.java b/app/core/src/main/java/stirling/software/SPDF/UI/WebBrowser.java deleted file mode 100644 index b884888fe..000000000 --- a/app/core/src/main/java/stirling/software/SPDF/UI/WebBrowser.java +++ /dev/null @@ -1,7 +0,0 @@ -package stirling.software.SPDF.UI; - -public interface WebBrowser { - void initWebUI(String url); - - void cleanup(); -} diff --git a/app/core/src/main/java/stirling/software/SPDF/UI/impl/DesktopBrowser.java b/app/core/src/main/java/stirling/software/SPDF/UI/impl/DesktopBrowser.java deleted file mode 100644 index 959e7f354..000000000 --- a/app/core/src/main/java/stirling/software/SPDF/UI/impl/DesktopBrowser.java +++ /dev/null @@ -1,497 +0,0 @@ -package stirling.software.SPDF.UI.impl; - -import java.awt.AWTException; -import java.awt.BorderLayout; -import java.awt.Frame; -import java.awt.Image; -import java.awt.MenuItem; -import java.awt.PopupMenu; -import java.awt.SystemTray; -import java.awt.TrayIcon; -import java.awt.event.WindowEvent; -import java.awt.event.WindowStateListener; -import java.io.File; -import java.io.InputStream; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; - -import javax.imageio.ImageIO; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.Timer; - -import org.cef.CefApp; -import org.cef.CefClient; -import org.cef.CefSettings; -import org.cef.browser.CefBrowser; -import org.cef.callback.CefBeforeDownloadCallback; -import org.cef.callback.CefDownloadItem; -import org.cef.callback.CefDownloadItemCallback; -import org.cef.handler.CefDownloadHandlerAdapter; -import org.cef.handler.CefLoadHandlerAdapter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Component; - -import jakarta.annotation.PreDestroy; - -import lombok.extern.slf4j.Slf4j; - -import me.friwi.jcefmaven.CefAppBuilder; -import me.friwi.jcefmaven.EnumProgress; -import me.friwi.jcefmaven.MavenCefAppHandlerAdapter; -import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler; - -import stirling.software.SPDF.UI.WebBrowser; -import stirling.software.common.configuration.InstallationPathConfig; -import stirling.software.common.util.UIScaling; - -@Component -@Slf4j -@ConditionalOnProperty( - name = "STIRLING_PDF_DESKTOP_UI", - havingValue = "true", - matchIfMissing = false) -public class DesktopBrowser implements WebBrowser { - private static CefApp cefApp; - private static CefClient client; - private static CefBrowser browser; - private static JFrame frame; - private static LoadingWindow loadingWindow; - private static volatile boolean browserInitialized = false; - private static TrayIcon trayIcon; - private static SystemTray systemTray; - - public DesktopBrowser() { - SwingUtilities.invokeLater( - () -> { - loadingWindow = new LoadingWindow(null, "Initializing..."); - loadingWindow.setVisible(true); - }); - } - - public void initWebUI(String url) { - CompletableFuture.runAsync( - () -> { - try { - CefAppBuilder builder = new CefAppBuilder(); - configureCefSettings(builder); - builder.setProgressHandler(createProgressHandler()); - builder.setInstallDir( - new File(InstallationPathConfig.getClientWebUIPath())); - // Build and initialize CEF - cefApp = builder.build(); - client = cefApp.createClient(); - - // Set up download handler - setupDownloadHandler(); - - // Create browser and frame on EDT - SwingUtilities.invokeAndWait( - () -> { - browser = client.createBrowser(url, false, false); - setupMainFrame(); - setupLoadHandler(); - - // Force initialize UI after 7 seconds if not already done - Timer timeoutTimer = - new Timer( - 2500, - e -> { - log.warn( - "Loading timeout reached. Forcing" - + " UI transition."); - if (!browserInitialized) { - // Force UI initialization - forceInitializeUI(); - } - }); - timeoutTimer.setRepeats(false); - timeoutTimer.start(); - }); - } catch (Exception e) { - log.error("Error initializing JCEF browser: ", e); - cleanup(); - } - }); - } - - private void configureCefSettings(CefAppBuilder builder) { - CefSettings settings = builder.getCefSettings(); - String basePath = InstallationPathConfig.getClientWebUIPath(); - log.info("basePath " + basePath); - settings.cache_path = new File(basePath + "cache").getAbsolutePath(); - settings.root_cache_path = new File(basePath + "root_cache").getAbsolutePath(); - // settings.browser_subprocess_path = new File(basePath + - // "subprocess").getAbsolutePath(); - // settings.resources_dir_path = new File(basePath + "resources").getAbsolutePath(); - // settings.locales_dir_path = new File(basePath + "locales").getAbsolutePath(); - settings.log_file = new File(basePath, "debug.log").getAbsolutePath(); - - settings.persist_session_cookies = true; - settings.windowless_rendering_enabled = false; - settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_INFO; - - builder.setAppHandler( - new MavenCefAppHandlerAdapter() { - @Override - public void stateHasChanged(org.cef.CefApp.CefAppState state) { - log.info("CEF state changed: " + state); - if (state == CefApp.CefAppState.TERMINATED) { - System.exit(0); - } - } - }); - } - - private void setupDownloadHandler() { - client.addDownloadHandler( - new CefDownloadHandlerAdapter() { - @Override - public boolean onBeforeDownload( - CefBrowser browser, - CefDownloadItem downloadItem, - String suggestedName, - CefBeforeDownloadCallback callback) { - callback.Continue("", true); - return true; - } - - @Override - public void onDownloadUpdated( - CefBrowser browser, - CefDownloadItem downloadItem, - CefDownloadItemCallback callback) { - if (downloadItem.isComplete()) { - log.info("Download completed: " + downloadItem.getFullPath()); - } else if (downloadItem.isCanceled()) { - log.info("Download canceled: " + downloadItem.getFullPath()); - } - } - }); - } - - private ConsoleProgressHandler createProgressHandler() { - return new ConsoleProgressHandler() { - @Override - public void handleProgress(EnumProgress state, float percent) { - Objects.requireNonNull(state, "state cannot be null"); - SwingUtilities.invokeLater( - () -> { - if (loadingWindow != null) { - switch (state) { - case LOCATING: - loadingWindow.setStatus("Locating Files..."); - loadingWindow.setProgress(0); - break; - case DOWNLOADING: - if (percent >= 0) { - loadingWindow.setStatus( - String.format( - "Downloading additional files: %.0f%%", - percent)); - loadingWindow.setProgress((int) percent); - } - break; - case EXTRACTING: - loadingWindow.setStatus("Extracting files..."); - loadingWindow.setProgress(60); - break; - case INITIALIZING: - loadingWindow.setStatus("Initializing UI..."); - loadingWindow.setProgress(80); - break; - case INITIALIZED: - loadingWindow.setStatus("Finalising startup..."); - loadingWindow.setProgress(90); - break; - } - } - }); - } - }; - } - - private void setupMainFrame() { - frame = new JFrame("Stirling-PDF"); - frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - frame.setUndecorated(true); - frame.setOpacity(0.0f); - - JPanel contentPane = new JPanel(new BorderLayout()); - contentPane.setDoubleBuffered(true); - contentPane.add(browser.getUIComponent(), BorderLayout.CENTER); - frame.setContentPane(contentPane); - - frame.addWindowListener( - new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent windowEvent) { - cleanup(); - System.exit(0); - } - }); - - frame.setSize(UIScaling.scaleWidth(1280), UIScaling.scaleHeight(800)); - frame.setLocationRelativeTo(null); - - loadIcon(); - } - - private void setupLoadHandler() { - final long initStartTime = System.currentTimeMillis(); - log.info("Setting up load handler at: {}", initStartTime); - - client.addLoadHandler( - new CefLoadHandlerAdapter() { - @Override - public void onLoadingStateChange( - CefBrowser browser, - boolean isLoading, - boolean canGoBack, - boolean canGoForward) { - log.debug( - "Loading state change - isLoading: {}, canGoBack: {}, canGoForward:" - + " {}, browserInitialized: {}, Time elapsed: {}ms", - isLoading, - canGoBack, - canGoForward, - browserInitialized, - System.currentTimeMillis() - initStartTime); - - if (!isLoading && !browserInitialized) { - log.info( - "Browser finished loading, preparing to initialize UI" - + " components"); - browserInitialized = true; - SwingUtilities.invokeLater( - () -> { - try { - if (loadingWindow != null) { - log.info("Starting UI initialization sequence"); - - // Close loading window first - loadingWindow.setVisible(false); - loadingWindow.dispose(); - loadingWindow = null; - log.info("Loading window disposed"); - - // Then setup the main frame - frame.setVisible(false); - frame.dispose(); - frame.setOpacity(1.0f); - frame.setUndecorated(false); - frame.pack(); - frame.setSize( - UIScaling.scaleWidth(1280), - UIScaling.scaleHeight(800)); - frame.setLocationRelativeTo(null); - log.debug("Frame reconfigured"); - - // Show the main frame - frame.setVisible(true); - frame.requestFocus(); - frame.toFront(); - log.info("Main frame displayed and focused"); - - // Focus the browser component - Timer focusTimer = - new Timer( - 100, - e -> { - try { - browser.getUIComponent() - .requestFocus(); - log.info( - "Browser component" - + " focused"); - } catch (Exception ex) { - log.error( - "Error focusing" - + " browser", - ex); - } - }); - focusTimer.setRepeats(false); - focusTimer.start(); - } - } catch (Exception e) { - log.error("Error during UI initialization", e); - // Attempt cleanup on error - if (loadingWindow != null) { - loadingWindow.dispose(); - loadingWindow = null; - } - if (frame != null) { - frame.setVisible(true); - frame.requestFocus(); - } - } - }); - } - } - }); - } - - private void setupTrayIcon(Image icon) { - if (!SystemTray.isSupported()) { - log.warn("System tray is not supported"); - return; - } - - try { - systemTray = SystemTray.getSystemTray(); - - // Create popup menu - PopupMenu popup = new PopupMenu(); - - // Create menu items - MenuItem showItem = new MenuItem("Show"); - showItem.addActionListener( - e -> { - frame.setVisible(true); - frame.setState(Frame.NORMAL); - }); - - MenuItem exitItem = new MenuItem("Exit"); - exitItem.addActionListener( - e -> { - cleanup(); - System.exit(0); - }); - - // Add menu items to popup menu - popup.add(showItem); - popup.addSeparator(); - popup.add(exitItem); - - // Create tray icon - trayIcon = new TrayIcon(icon, "Stirling-PDF", popup); - trayIcon.setImageAutoSize(true); - - // Add double-click behavior - trayIcon.addActionListener( - e -> { - frame.setVisible(true); - frame.setState(Frame.NORMAL); - }); - - // Add tray icon to system tray - systemTray.add(trayIcon); - - // Modify frame behavior to minimize to tray - frame.addWindowStateListener( - new WindowStateListener() { - public void windowStateChanged(WindowEvent e) { - if (e.getNewState() == Frame.ICONIFIED) { - frame.setVisible(false); - } - } - }); - - } catch (AWTException e) { - log.error("Error setting up system tray icon", e); - } - } - - private void loadIcon() { - try { - Image icon = null; - String[] iconPaths = {"/static/favicon.ico"}; - - for (String path : iconPaths) { - if (icon != null) break; - try { - try (InputStream is = getClass().getResourceAsStream(path)) { - if (is != null) { - icon = ImageIO.read(is); - break; - } - } - } catch (Exception e) { - log.debug("Could not load icon from " + path, e); - } - } - - if (icon != null) { - frame.setIconImage(icon); - setupTrayIcon(icon); - } else { - log.warn("Could not load icon from any source"); - } - } catch (Exception e) { - log.error("Error loading icon", e); - } - } - - @PreDestroy - public void cleanup() { - if (browser != null) browser.close(true); - if (client != null) client.dispose(); - if (cefApp != null) cefApp.dispose(); - if (loadingWindow != null) loadingWindow.dispose(); - } - - public static void forceInitializeUI() { - try { - if (loadingWindow != null) { - log.info("Forcing start of UI initialization sequence"); - - // Close loading window first - loadingWindow.setVisible(false); - loadingWindow.dispose(); - loadingWindow = null; - log.info("Loading window disposed"); - - // Then setup the main frame - frame.setVisible(false); - frame.dispose(); - frame.setOpacity(1.0f); - frame.setUndecorated(false); - frame.pack(); - frame.setSize(UIScaling.scaleWidth(1280), UIScaling.scaleHeight(800)); - frame.setLocationRelativeTo(null); - log.debug("Frame reconfigured"); - - // Show the main frame - frame.setVisible(true); - frame.requestFocus(); - frame.toFront(); - log.info("Main frame displayed and focused"); - - // Focus the browser component if available - if (browser != null) { - Timer focusTimer = - new Timer( - 100, - e -> { - try { - browser.getUIComponent().requestFocus(); - log.info("Browser component focused"); - } catch (Exception ex) { - log.error( - "Error focusing browser during force ui" - + " initialization.", - ex); - } - }); - focusTimer.setRepeats(false); - focusTimer.start(); - } - } - } catch (Exception e) { - log.error("Error during Forced UI initialization.", e); - // Attempt cleanup on error - if (loadingWindow != null) { - loadingWindow.dispose(); - loadingWindow = null; - } - if (frame != null) { - frame.setVisible(true); - frame.setOpacity(1.0f); - frame.setUndecorated(false); - frame.requestFocus(); - } - } - } -} diff --git a/app/core/src/main/java/stirling/software/SPDF/UI/impl/LoadingWindow.java b/app/core/src/main/java/stirling/software/SPDF/UI/impl/LoadingWindow.java deleted file mode 100644 index 5c7381fa4..000000000 --- a/app/core/src/main/java/stirling/software/SPDF/UI/impl/LoadingWindow.java +++ /dev/null @@ -1,351 +0,0 @@ -package stirling.software.SPDF.UI.impl; - -import java.awt.*; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import javax.imageio.ImageIO; -import javax.swing.*; - -import io.github.pixee.security.BoundedLineReader; - -import lombok.extern.slf4j.Slf4j; - -import stirling.software.common.util.UIScaling; - -@Slf4j -public class LoadingWindow extends JDialog { - private final JProgressBar progressBar; - private final JLabel statusLabel; - private final JPanel mainPanel; - private final JLabel brandLabel; - private long startTime; - - private Timer stuckTimer; - private long stuckThreshold = 4000; - private long timeAt90Percent = -1; - private volatile Process explorerProcess; - private static final boolean IS_WINDOWS = - System.getProperty("os.name").toLowerCase().contains("win"); - - public LoadingWindow(Frame parent, String initialUrl) { - super(parent, "Initializing Stirling-PDF", true); - startTime = System.currentTimeMillis(); - log.info("Creating LoadingWindow - initialization started at: {}", startTime); - - // Initialize components - mainPanel = new JPanel(); - mainPanel.setBackground(Color.WHITE); - mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 20, 30)); - mainPanel.setLayout(new GridBagLayout()); - GridBagConstraints gbc = new GridBagConstraints(); - - // Configure GridBagConstraints - gbc.gridwidth = GridBagConstraints.REMAINDER; - gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.insets = new Insets(5, 5, 5, 5); - gbc.weightx = 1.0; - gbc.weighty = 0.0; - - // Add icon - try { - try (InputStream is = getClass().getResourceAsStream("/static/favicon.ico")) { - if (is != null) { - Image img = ImageIO.read(is); - if (img != null) { - Image scaledImg = UIScaling.scaleIcon(img, 48, 48); - JLabel iconLabel = new JLabel(new ImageIcon(scaledImg)); - iconLabel.setHorizontalAlignment(SwingConstants.CENTER); - gbc.gridy = 0; - mainPanel.add(iconLabel, gbc); - log.info("Icon loaded and scaled successfully"); - } - } - } - } catch (Exception e) { - log.error("Failed to load icon", e); - } - - // URL Label with explicit size - brandLabel = new JLabel(initialUrl); - brandLabel.setHorizontalAlignment(SwingConstants.CENTER); - brandLabel.setPreferredSize(new Dimension(300, 25)); - brandLabel.setText("Stirling-PDF"); - gbc.gridy = 1; - mainPanel.add(brandLabel, gbc); - - // Status label with explicit size - statusLabel = new JLabel("Initializing..."); - statusLabel.setHorizontalAlignment(SwingConstants.CENTER); - statusLabel.setPreferredSize(new Dimension(300, 25)); - gbc.gridy = 2; - mainPanel.add(statusLabel, gbc); - - // Progress bar with explicit size - progressBar = new JProgressBar(0, 100); - progressBar.setStringPainted(true); - progressBar.setPreferredSize(new Dimension(300, 25)); - gbc.gridy = 3; - mainPanel.add(progressBar, gbc); - - // Set dialog properties - setContentPane(mainPanel); - setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); - setResizable(false); - setUndecorated(false); - - // Set size and position - setSize(UIScaling.scaleWidth(400), UIScaling.scaleHeight(200)); - - setLocationRelativeTo(parent); - setAlwaysOnTop(true); - setProgress(0); - setStatus("Starting..."); - - log.info( - "LoadingWindow initialization completed in {}ms", - System.currentTimeMillis() - startTime); - } - - private void checkAndRefreshExplorer() { - if (!IS_WINDOWS) { - return; - } - if (timeAt90Percent == -1) { - timeAt90Percent = System.currentTimeMillis(); - stuckTimer = - new Timer( - 1000, - e -> { - long currentTime = System.currentTimeMillis(); - if (currentTime - timeAt90Percent > stuckThreshold) { - try { - log.debug( - "Attempting Windows explorer refresh due to 90% stuck state"); - String currentDir = System.getProperty("user.dir"); - - // Store current explorer PIDs before we start new one - Set existingPids = new HashSet<>(); - ProcessBuilder listExplorer = - new ProcessBuilder( - "cmd", - "/c", - "wmic", - "process", - "where", - "name='explorer.exe'", - "get", - "ProcessId", - "/format:csv"); - Process process = listExplorer.start(); - BufferedReader reader = - new BufferedReader( - new InputStreamReader( - process.getInputStream())); - String line; - while ((line = - BoundedLineReader.readLine( - reader, 5_000_000)) - != null) { - if (line.matches(".*\\d+.*")) { // Contains numbers - String[] parts = line.trim().split(","); - if (parts.length >= 2) { - existingPids.add( - parts[parts.length - 1].trim()); - } - } - } - process.waitFor(2, TimeUnit.SECONDS); - - // Start new explorer - ProcessBuilder pb = - new ProcessBuilder( - "cmd", - "/c", - "start", - "/min", - "/b", - "explorer.exe", - currentDir); - pb.redirectErrorStream(true); - explorerProcess = pb.start(); - - // Schedule cleanup - Timer cleanupTimer = - new Timer( - 2000, - cleanup -> { - try { - // Find new explorer processes - ProcessBuilder findNewExplorer = - new ProcessBuilder( - "cmd", - "/c", - "wmic", - "process", - "where", - "name='explorer.exe'", - "get", - "ProcessId", - "/format:csv"); - Process newProcess = - findNewExplorer.start(); - BufferedReader newReader = - new BufferedReader( - new InputStreamReader( - newProcess - .getInputStream())); - String newLine; - while ((newLine = - BoundedLineReader - .readLine( - newReader, - 5_000_000)) - != null) { - if (newLine.matches( - ".*\\d+.*")) { - String[] parts = - newLine.trim() - .split(","); - if (parts.length >= 2) { - String pid = - parts[ - parts.length - - 1] - .trim(); - if (!existingPids - .contains( - pid)) { - log.debug( - "Found new explorer.exe with PID: " - + pid); - ProcessBuilder - killProcess = - new ProcessBuilder( - "taskkill", - "/PID", - pid, - "/F"); - killProcess - .redirectErrorStream( - true); - Process killResult = - killProcess - .start(); - killResult.waitFor( - 2, - TimeUnit - .SECONDS); - log.debug( - "Explorer process terminated: " - + pid); - } - } - } - } - newProcess.waitFor( - 2, TimeUnit.SECONDS); - } catch (Exception ex) { - log.error( - "Error cleaning up Windows explorer process", - ex); - } - }); - cleanupTimer.setRepeats(false); - cleanupTimer.start(); - stuckTimer.stop(); - } catch (Exception ex) { - log.error("Error refreshing Windows explorer", ex); - } - } - }); - stuckTimer.setRepeats(true); - stuckTimer.start(); - } - } - - public void setProgress(final int progress) { - SwingUtilities.invokeLater( - () -> { - try { - int validProgress = Math.min(Math.max(progress, 0), 100); - log.info( - "Setting progress to {}% at {}ms since start", - validProgress, System.currentTimeMillis() - startTime); - - // Log additional details when near 90% - if (validProgress >= 85 && validProgress <= 95) { - log.info( - "Near 90% progress - Current status: {}, Window visible: {}, " - + "Progress bar responding: {}, Memory usage: {}MB", - statusLabel.getText(), - isVisible(), - progressBar.isEnabled(), - Runtime.getRuntime().totalMemory() / (1024 * 1024)); - - // Add thread state logging - Thread currentThread = Thread.currentThread(); - log.info( - "Current thread state - Name: {}, State: {}, Priority: {}", - currentThread.getName(), - currentThread.getState(), - currentThread.getPriority()); - - if (validProgress >= 90 && validProgress < 95) { - checkAndRefreshExplorer(); - } else { - // Reset the timer if we move past 95% - if (validProgress >= 95) { - if (stuckTimer != null) { - stuckTimer.stop(); - } - timeAt90Percent = -1; - } - } - } - - progressBar.setValue(validProgress); - progressBar.setString(validProgress + "%"); - mainPanel.revalidate(); - mainPanel.repaint(); - } catch (Exception e) { - log.error("Error updating progress to " + progress, e); - } - }); - } - - public void setStatus(final String status) { - log.info( - "Status update at {}ms - Setting status to: {}", - System.currentTimeMillis() - startTime, - status); - - SwingUtilities.invokeLater( - () -> { - try { - String validStatus = status != null ? status : ""; - statusLabel.setText(validStatus); - - // Log UI state when status changes - log.info( - "UI State - Window visible: {}, Progress: {}%, Status: {}", - isVisible(), progressBar.getValue(), validStatus); - - mainPanel.revalidate(); - mainPanel.repaint(); - } catch (Exception e) { - log.error("Error updating status to: " + status, e); - } - }); - } - - @Override - public void dispose() { - log.info("LoadingWindow disposing after {}ms", System.currentTimeMillis() - startTime); - super.dispose(); - } -} diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java b/app/core/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java index 34f8a8daa..4a3da8ce4 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/web/ConverterWebController.java @@ -2,7 +2,6 @@ package stirling.software.SPDF.controller.web; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.servlet.ModelAndView; import io.swagger.v3.oas.annotations.Hidden; @@ -14,42 +13,48 @@ import stirling.software.common.util.CheckProgramInstall; @Tag(name = "Convert", description = "Convert APIs") public class ConverterWebController { - @GetMapping("/img-to-pdf") + @Deprecated + // @GetMapping("/img-to-pdf") @Hidden public String convertImgToPdfForm(Model model) { model.addAttribute("currentPage", "img-to-pdf"); return "convert/img-to-pdf"; } - @GetMapping("/html-to-pdf") + @Deprecated + // @GetMapping("/html-to-pdf") @Hidden public String convertHTMLToPdfForm(Model model) { model.addAttribute("currentPage", "html-to-pdf"); return "convert/html-to-pdf"; } - @GetMapping("/markdown-to-pdf") + @Deprecated + // @GetMapping("/markdown-to-pdf") @Hidden public String convertMarkdownToPdfForm(Model model) { model.addAttribute("currentPage", "markdown-to-pdf"); return "convert/markdown-to-pdf"; } - @GetMapping("/pdf-to-markdown") + @Deprecated + // @GetMapping("/pdf-to-markdown") @Hidden public String convertPdfToMarkdownForm(Model model) { model.addAttribute("currentPage", "pdf-to-markdown"); return "convert/pdf-to-markdown"; } - @GetMapping("/url-to-pdf") + @Deprecated + // @GetMapping("/url-to-pdf") @Hidden public String convertURLToPdfForm(Model model) { model.addAttribute("currentPage", "url-to-pdf"); return "convert/url-to-pdf"; } - @GetMapping("/file-to-pdf") + @Deprecated + // @GetMapping("/file-to-pdf") @Hidden public String convertToPdfForm(Model model) { model.addAttribute("currentPage", "file-to-pdf"); @@ -58,7 +63,8 @@ public class ConverterWebController { // PDF TO...... - @GetMapping("/pdf-to-img") + @Deprecated + // @GetMapping("/pdf-to-img") @Hidden public String pdfToimgForm(Model model) { boolean isPython = CheckProgramInstall.isPythonAvailable(); @@ -67,7 +73,8 @@ public class ConverterWebController { return "convert/pdf-to-img"; } - @GetMapping("/pdf-to-html") + @Deprecated + // @GetMapping("/pdf-to-html") @Hidden public ModelAndView pdfToHTML() { ModelAndView modelAndView = new ModelAndView("convert/pdf-to-html"); @@ -75,7 +82,8 @@ public class ConverterWebController { return modelAndView; } - @GetMapping("/pdf-to-presentation") + @Deprecated + // @GetMapping("/pdf-to-presentation") @Hidden public ModelAndView pdfToPresentation() { ModelAndView modelAndView = new ModelAndView("convert/pdf-to-presentation"); @@ -83,7 +91,8 @@ public class ConverterWebController { return modelAndView; } - @GetMapping("/pdf-to-text") + @Deprecated + // @GetMapping("/pdf-to-text") @Hidden public ModelAndView pdfToText() { ModelAndView modelAndView = new ModelAndView("convert/pdf-to-text"); @@ -91,7 +100,8 @@ public class ConverterWebController { return modelAndView; } - @GetMapping("/pdf-to-word") + @Deprecated + // @GetMapping("/pdf-to-word") @Hidden public ModelAndView pdfToWord() { ModelAndView modelAndView = new ModelAndView("convert/pdf-to-word"); @@ -99,7 +109,8 @@ public class ConverterWebController { return modelAndView; } - @GetMapping("/pdf-to-xml") + @Deprecated + // @GetMapping("/pdf-to-xml") @Hidden public ModelAndView pdfToXML() { ModelAndView modelAndView = new ModelAndView("convert/pdf-to-xml"); @@ -107,7 +118,8 @@ public class ConverterWebController { return modelAndView; } - @GetMapping("/pdf-to-csv") + @Deprecated + // @GetMapping("/pdf-to-csv") @Hidden public ModelAndView pdfToCSV() { ModelAndView modelAndView = new ModelAndView("convert/pdf-to-csv"); @@ -115,14 +127,16 @@ public class ConverterWebController { return modelAndView; } - @GetMapping("/pdf-to-pdfa") + @Deprecated + // @GetMapping("/pdf-to-pdfa") @Hidden public String pdfToPdfAForm(Model model) { model.addAttribute("currentPage", "pdf-to-pdfa"); return "convert/pdf-to-pdfa"; } - @GetMapping("/eml-to-pdf") + @Deprecated + // @GetMapping("/eml-to-pdf") @Hidden public String convertEmlToPdfForm(Model model) { model.addAttribute("currentPage", "eml-to-pdf"); diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java b/app/core/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java index 1084e2fe0..3949d5579 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java @@ -14,7 +14,6 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; 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; @@ -53,7 +52,8 @@ public class GeneralWebController { this.runtimePathConfig = runtimePathConfig; } - @GetMapping("/pipeline") + @Deprecated + // @GetMapping("/pipeline") @Hidden public String pipelineForm(Model model) { model.addAttribute("currentPage", "pipeline"); @@ -103,91 +103,104 @@ public class GeneralWebController { return "pipeline"; } - @GetMapping("/merge-pdfs") + @Deprecated + // @GetMapping("/merge-pdfs") @Hidden public String mergePdfForm(Model model) { model.addAttribute("currentPage", "merge-pdfs"); return "merge-pdfs"; } - @GetMapping("/split-pdf-by-sections") + @Deprecated + // @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") + @Deprecated + // @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") + @Deprecated + // @GetMapping("/view-pdf") @Hidden public String ViewPdfForm2(Model model) { model.addAttribute("currentPage", "view-pdf"); return "view-pdf"; } - @GetMapping("/edit-table-of-contents") + @Deprecated + // @GetMapping("/edit-table-of-contents") @Hidden public String editTableOfContents(Model model) { model.addAttribute("currentPage", "edit-table-of-contents"); return "edit-table-of-contents"; } - @GetMapping("/multi-tool") + @Deprecated + // @GetMapping("/multi-tool") @Hidden public String multiToolForm(Model model) { model.addAttribute("currentPage", "multi-tool"); return "multi-tool"; } - @GetMapping("/remove-pages") + @Deprecated + // @GetMapping("/remove-pages") @Hidden public String pageDeleter(Model model) { model.addAttribute("currentPage", "remove-pages"); return "remove-pages"; } - @GetMapping("/pdf-organizer") + @Deprecated + // @GetMapping("/pdf-organizer") @Hidden public String pageOrganizer(Model model) { model.addAttribute("currentPage", "pdf-organizer"); return "pdf-organizer"; } - @GetMapping("/extract-page") + @Deprecated + // @GetMapping("/extract-page") @Hidden public String extractPages(Model model) { model.addAttribute("currentPage", "extract-page"); return "extract-page"; } - @GetMapping("/pdf-to-single-page") + @Deprecated + // @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") + @Deprecated + // @GetMapping("/rotate-pdf") @Hidden public String rotatePdfForm(Model model) { model.addAttribute("currentPage", "rotate-pdf"); return "rotate-pdf"; } - @GetMapping("/split-pdfs") + @Deprecated + // @GetMapping("/split-pdfs") @Hidden public String splitPdfForm(Model model) { model.addAttribute("currentPage", "split-pdfs"); return "split-pdfs"; } - @GetMapping("/sign") + @Deprecated + // @GetMapping("/sign") @Hidden public String signForm(Model model) { String username = ""; @@ -202,28 +215,32 @@ public class GeneralWebController { return "sign"; } - @GetMapping("/multi-page-layout") + @Deprecated + // @GetMapping("/multi-page-layout") @Hidden public String multiPageLayoutForm(Model model) { model.addAttribute("currentPage", "multi-page-layout"); return "multi-page-layout"; } - @GetMapping("/scale-pages") + @Deprecated + // @GetMapping("/scale-pages") @Hidden public String scalePagesFrom(Model model) { model.addAttribute("currentPage", "scale-pages"); return "scale-pages"; } - @GetMapping("/split-by-size-or-count") + @Deprecated + // @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") + @Deprecated + // @GetMapping("/overlay-pdf") @Hidden public String overlayPdf(Model model) { model.addAttribute("currentPage", "overlay-pdf"); @@ -296,21 +313,24 @@ public class GeneralWebController { } } - @GetMapping("/crop") + @Deprecated + // @GetMapping("/crop") @Hidden public String cropForm(Model model) { model.addAttribute("currentPage", "crop"); return "crop"; } - @GetMapping("/auto-split-pdf") + @Deprecated + // @GetMapping("/auto-split-pdf") @Hidden public String autoSPlitPDFForm(Model model) { model.addAttribute("currentPage", "auto-split-pdf"); return "auto-split-pdf"; } - @GetMapping("/remove-image-pdf") + @Deprecated + // @GetMapping("/remove-image-pdf") @Hidden public String removeImagePdfForm(Model model) { model.addAttribute("currentPage", "remove-image-pdf"); diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java b/app/core/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java index 2b36f95af..4d8f07591 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java @@ -32,14 +32,16 @@ public class HomeWebController { private final ApplicationProperties applicationProperties; - @GetMapping("/about") + @Deprecated + // @GetMapping("/about") @Hidden public String gameForm(Model model) { model.addAttribute("currentPage", "about"); return "about"; } - @GetMapping("/licenses") + @Deprecated + // @GetMapping("/licenses") @Hidden public String licensesForm(Model model) { model.addAttribute("currentPage", "licenses"); @@ -56,12 +58,14 @@ public class HomeWebController { return "licenses"; } - @GetMapping("/releases") + @Deprecated + // @GetMapping("/releases") public String getReleaseNotes(Model model) { return "releases"; } - @GetMapping("/") + @Deprecated + // @GetMapping("/") public String home(Model model) { model.addAttribute("currentPage", "home"); String showSurvey = System.getenv("SHOW_SURVEY"); @@ -70,12 +74,14 @@ public class HomeWebController { return "home"; } - @GetMapping("/home") + @Deprecated + // @GetMapping("/home") public String root(Model model) { return "redirect:/"; } - @GetMapping("/home-legacy") + @Deprecated + // @GetMapping("/home-legacy") public String redirectHomeLegacy() { return "redirect:/"; } diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java b/app/core/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java index bc63a4b84..e7eddf3e7 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java @@ -7,7 +7,6 @@ import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.servlet.ModelAndView; import io.swagger.v3.oas.annotations.Hidden; @@ -25,21 +24,24 @@ public class OtherWebController { private final ApplicationProperties applicationProperties; - @GetMapping("/compress-pdf") + @Deprecated + // @GetMapping("/compress-pdf") @Hidden public String compressPdfForm(Model model) { model.addAttribute("currentPage", "compress-pdf"); return "misc/compress-pdf"; } - @GetMapping("/replace-and-invert-color-pdf") + @Deprecated + // @GetMapping("/replace-and-invert-color-pdf") @Hidden public String replaceAndInvertColorPdfForm(Model model) { model.addAttribute("currentPage", "replace-invert-color-pdf"); return "misc/replace-color"; } - @GetMapping("/extract-image-scans") + @Deprecated + // @GetMapping("/extract-image-scans") @Hidden public ModelAndView extractImageScansForm() { ModelAndView modelAndView = new ModelAndView("misc/extract-image-scans"); @@ -49,70 +51,80 @@ public class OtherWebController { return modelAndView; } - @GetMapping("/show-javascript") + @Deprecated + // @GetMapping("/show-javascript") @Hidden public String extractJavascriptForm(Model model) { model.addAttribute("currentPage", "show-javascript"); return "misc/show-javascript"; } - @GetMapping("/stamp") + @Deprecated + // @GetMapping("/stamp") @Hidden public String stampForm(Model model) { model.addAttribute("currentPage", "stamp"); return "misc/stamp"; } - @GetMapping("/add-page-numbers") + @Deprecated + // @GetMapping("/add-page-numbers") @Hidden public String addPageNumbersForm(Model model) { model.addAttribute("currentPage", "add-page-numbers"); return "misc/add-page-numbers"; } - @GetMapping("/scanner-effect") + @Deprecated + //@GetMapping("/scanner-effect") @Hidden public String scannerEffectForm(Model model) { model.addAttribute("currentPage", "scanner-effect"); return "misc/scanner-effect"; } - @GetMapping("/extract-images") + @Deprecated + // @GetMapping("/extract-images") @Hidden public String extractImagesForm(Model model) { model.addAttribute("currentPage", "extract-images"); return "misc/extract-images"; } - @GetMapping("/flatten") + @Deprecated + // @GetMapping("/flatten") @Hidden public String flattenForm(Model model) { model.addAttribute("currentPage", "flatten"); return "misc/flatten"; } - @GetMapping("/change-metadata") + @Deprecated + // @GetMapping("/change-metadata") @Hidden public String addWatermarkForm(Model model) { model.addAttribute("currentPage", "change-metadata"); return "misc/change-metadata"; } - @GetMapping("/unlock-pdf-forms") + @Deprecated + // @GetMapping("/unlock-pdf-forms") @Hidden public String unlockPDFForms(Model model) { model.addAttribute("currentPage", "unlock-pdf-forms"); return "misc/unlock-pdf-forms"; } - @GetMapping("/compare") + @Deprecated + // @GetMapping("/compare") @Hidden public String compareForm(Model model) { model.addAttribute("currentPage", "compare"); return "misc/compare"; } - @GetMapping("/print-file") + @Deprecated + // @GetMapping("/print-file") @Hidden public String printFileForm(Model model) { model.addAttribute("currentPage", "print-file"); @@ -133,7 +145,8 @@ public class OtherWebController { .toList(); } - @GetMapping("/ocr-pdf") + @Deprecated + // @GetMapping("/ocr-pdf") @Hidden public ModelAndView ocrPdfPage() { ModelAndView modelAndView = new ModelAndView("misc/ocr-pdf"); @@ -143,56 +156,64 @@ public class OtherWebController { return modelAndView; } - @GetMapping("/add-image") + @Deprecated + // @GetMapping("/add-image") @Hidden public String overlayImage(Model model) { model.addAttribute("currentPage", "add-image"); return "misc/add-image"; } - @GetMapping("/adjust-contrast") + @Deprecated + // @GetMapping("/adjust-contrast") @Hidden public String contrast(Model model) { model.addAttribute("currentPage", "adjust-contrast"); return "misc/adjust-contrast"; } - @GetMapping("/repair") + @Deprecated + // @GetMapping("/repair") @Hidden public String repairForm(Model model) { model.addAttribute("currentPage", "repair"); return "misc/repair"; } - @GetMapping("/remove-blanks") + @Deprecated + // @GetMapping("/remove-blanks") @Hidden public String removeBlanksForm(Model model) { model.addAttribute("currentPage", "remove-blanks"); return "misc/remove-blanks"; } - @GetMapping("/remove-annotations") + @Deprecated + // @GetMapping("/remove-annotations") @Hidden public String removeAnnotationsForm(Model model) { model.addAttribute("currentPage", "remove-annotations"); return "misc/remove-annotations"; } - @GetMapping("/auto-crop") + @Deprecated + // @GetMapping("/auto-crop") @Hidden public String autoCropForm(Model model) { model.addAttribute("currentPage", "auto-crop"); return "misc/auto-crop"; } - @GetMapping("/auto-rename") + @Deprecated + // @GetMapping("/auto-rename") @Hidden public String autoRenameForm(Model model) { model.addAttribute("currentPage", "auto-rename"); return "misc/auto-rename"; } - @GetMapping("/add-attachments") + @Deprecated + // @GetMapping("/add-attachments") @Hidden public String attachmentsForm(Model model) { model.addAttribute("currentPage", "add-attachments"); diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java b/app/core/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java index eb7245e5a..dd7900840 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/web/SecurityWebController.java @@ -2,7 +2,6 @@ package stirling.software.SPDF.controller.web; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.tags.Tag; @@ -11,76 +10,87 @@ import io.swagger.v3.oas.annotations.tags.Tag; @Tag(name = "Security", description = "Security APIs") public class SecurityWebController { - @GetMapping("/auto-redact") + @Deprecated + // @GetMapping("/auto-redact") @Hidden public String autoRedactForm(Model model) { model.addAttribute("currentPage", "auto-redact"); return "security/auto-redact"; } - @GetMapping("/redact") + @Deprecated + // @GetMapping("/redact") public String redactForm(Model model) { model.addAttribute("currentPage", "redact"); return "security/redact"; } - @GetMapping("/add-password") + @Deprecated + // @GetMapping("/add-password") @Hidden public String addPasswordForm(Model model) { model.addAttribute("currentPage", "add-password"); return "security/add-password"; } - @GetMapping("/change-permissions") + @Deprecated + // @GetMapping("/change-permissions") @Hidden public String permissionsForm(Model model) { model.addAttribute("currentPage", "change-permissions"); return "security/change-permissions"; } - @GetMapping("/remove-password") + @Deprecated + // @GetMapping("/remove-password") @Hidden public String removePasswordForm(Model model) { model.addAttribute("currentPage", "remove-password"); return "security/remove-password"; } - @GetMapping("/add-watermark") + @Deprecated + // @GetMapping("/add-watermark") @Hidden public String addWatermarkForm(Model model) { model.addAttribute("currentPage", "add-watermark"); return "security/add-watermark"; } - @GetMapping("/cert-sign") + @Deprecated + // @GetMapping("/cert-sign") @Hidden public String certSignForm(Model model) { model.addAttribute("currentPage", "cert-sign"); return "security/cert-sign"; } - @GetMapping("/validate-signature") + @Deprecated + // @GetMapping("/validate-signature") @Hidden public String certSignVerifyForm(Model model) { model.addAttribute("currentPage", "validate-signature"); return "security/validate-signature"; } - @GetMapping("/remove-cert-sign") + @Deprecated + // @GetMapping("/remove-cert-sign") @Hidden public String certUnSignForm(Model model) { model.addAttribute("currentPage", "remove-cert-sign"); return "security/remove-cert-sign"; } - @GetMapping("/sanitize-pdf") + @Deprecated + // @GetMapping("/sanitize-pdf") @Hidden public String sanitizeForm(Model model) { model.addAttribute("currentPage", "sanitize-pdf"); return "security/sanitize-pdf"; } - @GetMapping("/get-info-on-pdf") + @Deprecated + // @GetMapping("/get-info-on-pdf") @Hidden public String getInfo(Model model) { model.addAttribute("currentPage", "get-info-on-pdf"); diff --git a/app/core/src/main/java/stirling/software/SPDF/service/SignatureService.java b/app/core/src/main/java/stirling/software/SPDF/service/SignatureService.java index 1d25f409f..16385392e 100644 --- a/app/core/src/main/java/stirling/software/SPDF/service/SignatureService.java +++ b/app/core/src/main/java/stirling/software/SPDF/service/SignatureService.java @@ -9,7 +9,7 @@ import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Service; -import org.thymeleaf.util.StringUtils; +import org.springframework.util.StringUtils; import lombok.extern.slf4j.Slf4j; @@ -40,7 +40,7 @@ public class SignatureService { List signatures = new ArrayList<>(); // Get signatures from user's personal folder - if (!StringUtils.isEmptyOrWhitespace(username)) { + if (StringUtils.hasText(username)) { Path userFolder = Paths.get(SIGNATURE_BASE_PATH, username); if (Files.exists(userFolder)) { try { diff --git a/app/core/src/main/resources/application.properties b/app/core/src/main/resources/application.properties index ea30bf78e..4efadfa9d 100644 --- a/app/core/src/main/resources/application.properties +++ b/app/core/src/main/resources/application.properties @@ -25,7 +25,7 @@ server.servlet.context-path=${SYSTEM_ROOTURIPATH:/} spring.devtools.restart.enabled=true spring.devtools.livereload.enabled=true spring.devtools.restart.exclude=stirling.software.proprietary.security/** -spring.thymeleaf.encoding=UTF-8 +# spring.thymeleaf.encoding=UTF-8 # Disabled - React frontend replaces Thymeleaf spring.web.resources.mime-mappings.webmanifest=application/manifest+json spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000} @@ -35,6 +35,8 @@ spring.datasource.username=sa spring.datasource.password= spring.h2.console.enabled=false spring.jpa.hibernate.ddl-auto=update +spring.jpa.defer-datasource-initialization=true +spring.jpa.show-sql=false server.servlet.session.timeout:30m # Change the default URL path for OpenAPI JSON springdoc.api-docs.path=/v1/api-docs diff --git a/app/proprietary/build.gradle b/app/proprietary/build.gradle index 2a72f8a65..71c0b1d4b 100644 --- a/app/proprietary/build.gradle +++ b/app/proprietary/build.gradle @@ -23,6 +23,8 @@ dependencies { api 'org.springframework:spring-webmvc' api 'org.springframework.session:spring-session-core' api "org.springframework.security:spring-security-core:$springSecuritySamlVersion" + api "org.springframework.security:spring-security-web:$springSecuritySamlVersion" + api "org.springframework.security:spring-security-config:$springSecuritySamlVersion" api "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion" api 'org.springframework.boot:spring-boot-starter-jetty' api 'org.springframework.boot:spring-boot-starter-security' @@ -35,7 +37,7 @@ dependencies { // https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17 implementation 'org.bouncycastle:bcprov-jdk18on:1.81' - implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE' + // implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE' // Removed - UI moved to React frontend api 'io.micrometer:micrometer-registry-prometheus' implementation 'com.unboundid.product.scim2:scim2-sdk-client:4.0.0' runtimeOnly 'com.h2database:h2:2.3.232' // Don't upgrade h2database diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java index 940c0c13f..36a1dd37b 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/DatabaseWebController.java @@ -6,7 +6,6 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; import io.swagger.v3.oas.annotations.tags.Tag; @@ -24,8 +23,9 @@ public class DatabaseWebController { private final DatabaseService databaseService; + @Deprecated @PreAuthorize("hasRole('ROLE_ADMIN')") - @GetMapping("/database") + // @GetMapping("/database") public String database(HttpServletRequest request, Model model, Authentication authentication) { String error = request.getParameter("error"); String confirmed = request.getParameter("infoMessage"); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java index 2dd9b3478..279e140ab 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/web/TeamWebController.java @@ -8,7 +8,6 @@ import java.util.Map; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -35,7 +34,8 @@ public class TeamWebController { private final SessionRepository sessionRepository; private final UserRepository userRepository; - @GetMapping + @Deprecated + // @GetMapping @PreAuthorize("hasRole('ROLE_ADMIN')") public String listTeams(HttpServletRequest request, Model model) { // Get teams with user counts using a DTO projection @@ -86,7 +86,8 @@ public class TeamWebController { return "accounts/teams"; } - @GetMapping("/{id}") + @Deprecated + // @GetMapping("/{id}") @PreAuthorize("hasRole('ROLE_ADMIN')") public String viewTeamDetails( HttpServletRequest request, @PathVariable("id") Long id, Model model) {