mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2024-09-21 04:10:38 +02:00
Compare commits
37 Commits
17bf6237a2
...
6606850e4a
Author | SHA1 | Date | |
---|---|---|---|
|
6606850e4a | ||
|
7b08d98232 | ||
|
03150c6462 | ||
|
a3bf7baf35 | ||
|
6c09bcf23c | ||
|
e11fa01d10 | ||
|
d60107f48b | ||
|
0b449af9ba | ||
|
4c9c0207ba | ||
|
d36a59442f | ||
|
fd4c75279f | ||
|
fd5f5025ce | ||
|
319ecbcbc1 | ||
|
04b0bcde61 | ||
|
6499b759d9 | ||
|
2081c4872d | ||
|
37c75971f2 | ||
|
7d9edfca6d | ||
|
a40696f16e | ||
|
515b5b1492 | ||
|
e824a3e7bd | ||
|
9fd508fcc7 | ||
|
a0227a4bdd | ||
|
87be41117f | ||
|
3e9123fcd5 | ||
|
7e7c6a3832 | ||
|
cce31ee0f6 | ||
|
746f341d6a | ||
|
f35bf120e9 | ||
|
1fd4ce339f | ||
|
af736ca33a | ||
|
0878dd10b8 | ||
|
948ddb06bc | ||
|
efc07522ab | ||
|
31938b662c | ||
|
eb526a5d0c | ||
|
c4a620e3f5 |
21
README.md
21
README.md
@ -159,7 +159,7 @@ Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR
|
|||||||
|
|
||||||
## Supported Languages
|
## Supported Languages
|
||||||
|
|
||||||
Stirling PDF currently supports 28!
|
Stirling PDF currently supports 32!
|
||||||
|
|
||||||
| Language | Progress |
|
| Language | Progress |
|
||||||
| ------------------------------------------- | -------------------------------------- |
|
| ------------------------------------------- | -------------------------------------- |
|
||||||
@ -167,15 +167,15 @@ Stirling PDF currently supports 28!
|
|||||||
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
|
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
|
||||||
| Arabic (العربية) (ar_AR) | ![40%](https://geps.dev/progress/40) |
|
| Arabic (العربية) (ar_AR) | ![40%](https://geps.dev/progress/40) |
|
||||||
| German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
|
| German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
|
||||||
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) |
|
| French (Français) (fr_FR) | ![93%](https://geps.dev/progress/93) |
|
||||||
| Spanish (Español) (es_ES) | ![95%](https://geps.dev/progress/95) |
|
| Spanish (Español) (es_ES) | ![95%](https://geps.dev/progress/95) |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) | ![95%](https://geps.dev/progress/95) |
|
| Simplified Chinese (简体中文) (zh_CN) | ![95%](https://geps.dev/progress/95) |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) | ![94%](https://geps.dev/progress/94) |
|
| Traditional Chinese (繁體中文) (zh_TW) | ![94%](https://geps.dev/progress/94) |
|
||||||
| Catalan (Català) (ca_CA) | ![49%](https://geps.dev/progress/49) |
|
| Catalan (Català) (ca_CA) | ![49%](https://geps.dev/progress/49) |
|
||||||
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) |
|
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) |
|
||||||
| Swedish (Svenska) (sv_SE) | ![40%](https://geps.dev/progress/40) |
|
| Swedish (Svenska) (sv_SE) | ![40%](https://geps.dev/progress/40) |
|
||||||
| Polish (Polski) (pl_PL) | ![43%](https://geps.dev/progress/43) |
|
| Polish (Polski) (pl_PL) | ![42%](https://geps.dev/progress/42) |
|
||||||
| Romanian (Română) (ro_RO) | ![40%](https://geps.dev/progress/40) |
|
| Romanian (Română) (ro_RO) | ![39%](https://geps.dev/progress/39) |
|
||||||
| Korean (한국어) (ko_KR) | ![87%](https://geps.dev/progress/87) |
|
| Korean (한국어) (ko_KR) | ![87%](https://geps.dev/progress/87) |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) | ![61%](https://geps.dev/progress/61) |
|
| Portuguese Brazilian (Português) (pt_BR) | ![61%](https://geps.dev/progress/61) |
|
||||||
| Russian (Русский) (ru_RU) | ![87%](https://geps.dev/progress/87) |
|
| Russian (Русский) (ru_RU) | ![87%](https://geps.dev/progress/87) |
|
||||||
@ -183,16 +183,17 @@ Stirling PDF currently supports 28!
|
|||||||
| Japanese (日本語) (ja_JP) | ![87%](https://geps.dev/progress/87) |
|
| Japanese (日本語) (ja_JP) | ![87%](https://geps.dev/progress/87) |
|
||||||
| Dutch (Nederlands) (nl_NL) | ![85%](https://geps.dev/progress/85) |
|
| Dutch (Nederlands) (nl_NL) | ![85%](https://geps.dev/progress/85) |
|
||||||
| Greek (Ελληνικά) (el_GR) | ![85%](https://geps.dev/progress/85) |
|
| Greek (Ελληνικά) (el_GR) | ![85%](https://geps.dev/progress/85) |
|
||||||
| Turkish (Türkçe) (tr_TR) | ![98%](https://geps.dev/progress/98) |
|
| Turkish (Türkçe) (tr_TR) | ![97%](https://geps.dev/progress/97) |
|
||||||
| Indonesia (Bahasa Indonesia) (id_ID) | ![79%](https://geps.dev/progress/79) |
|
| Indonesia (Bahasa Indonesia) (id_ID) | ![78%](https://geps.dev/progress/78) |
|
||||||
| Hindi (हिंदी) (hi_IN) | ![79%](https://geps.dev/progress/79) |
|
| Hindi (हिंदी) (hi_IN) | ![79%](https://geps.dev/progress/79) |
|
||||||
| Hungarian (Magyar) (hu_HU) | ![78%](https://geps.dev/progress/78) |
|
| Hungarian (Magyar) (hu_HU) | ![78%](https://geps.dev/progress/78) |
|
||||||
| Bulgarian (Български) (bg_BG) | ![98%](https://geps.dev/progress/98) |
|
| Bulgarian (Български) (bg_BG) | ![98%](https://geps.dev/progress/98) |
|
||||||
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![81%](https://geps.dev/progress/81) |
|
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![80%](https://geps.dev/progress/80) |
|
||||||
| Ukrainian (Українська) (uk_UA) | ![87%](https://geps.dev/progress/87) |
|
| Ukrainian (Українська) (uk_UA) | ![86%](https://geps.dev/progress/86) |
|
||||||
| Slovakian (Slovensky) (sk_SK) | ![96%](https://geps.dev/progress/96) |
|
| Slovakian (Slovensky) (sk_SK) | ![95%](https://geps.dev/progress/95) |
|
||||||
| Czech (Česky) (cs_CZ) | ![94%](https://geps.dev/progress/94) |
|
| Czech (Česky) (cs_CZ) | ![94%](https://geps.dev/progress/94) |
|
||||||
| Croatian (Hrvatski) (hr_HR) | ![94%](https://geps.dev/progress/94) |
|
| Croatian (Hrvatski) (hr_HR) | ![98%](https://geps.dev/progress/98) |
|
||||||
|
| Norwegian (Norsk) (no_NB) | ![98%](https://geps.dev/progress/98) |
|
||||||
|
|
||||||
## Contributing (creating issues, translations, fixing bugs, etc.)
|
## Contributing (creating issues, translations, fixing bugs, etc.)
|
||||||
|
|
||||||
|
12
build.gradle
12
build.gradle
@ -12,7 +12,7 @@ plugins {
|
|||||||
import com.github.jk1.license.render.*
|
import com.github.jk1.license.render.*
|
||||||
|
|
||||||
group = 'stirling.software'
|
group = 'stirling.software'
|
||||||
version = '0.25.1'
|
version = '0.25.2'
|
||||||
|
|
||||||
//17 is lowest but we support and recommend 21
|
//17 is lowest but we support and recommend 21
|
||||||
sourceCompatibility = '17'
|
sourceCompatibility = '17'
|
||||||
@ -171,14 +171,14 @@ dependencies {
|
|||||||
annotationProcessor 'org.projectlombok:lombok:1.18.32'
|
annotationProcessor 'org.projectlombok:lombok:1.18.32'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
dependsOn 'spotlessApply'
|
dependsOn 'spotlessApply'
|
||||||
}
|
}
|
||||||
compileJava {
|
compileJava {
|
||||||
options.compilerArgs << '-parameters'
|
options.compilerArgs << '-parameters'
|
||||||
}
|
}
|
||||||
|
|
||||||
task writeVersion {
|
task writeVersion {
|
||||||
def propsFile = file('src/main/resources/version.properties')
|
def propsFile = file('src/main/resources/version.properties')
|
||||||
def props = new Properties()
|
def props = new Properties()
|
||||||
props.setProperty('version', version)
|
props.setProperty('version', version)
|
||||||
@ -195,8 +195,6 @@ swaggerhubUpload {
|
|||||||
oas '3.0.0' // The version of the OpenAPI Specification you're using
|
oas '3.0.0' // The version of the OpenAPI Specification you're using
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
enabled = false
|
enabled = false
|
||||||
manifest {
|
manifest {
|
||||||
@ -210,6 +208,6 @@ tasks.named('test') {
|
|||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
task printVersion {
|
task printVersion {
|
||||||
println project.version
|
println project.version
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
appVersion: 0.25.1
|
appVersion: 0.25.2
|
||||||
description: locally hosted web application that allows you to perform various operations
|
description: locally hosted web application that allows you to perform various operations
|
||||||
on PDF files
|
on PDF files
|
||||||
home: https://github.com/Stirling-Tools/Stirling-PDF
|
home: https://github.com/Stirling-Tools/Stirling-PDF
|
||||||
|
@ -13,7 +13,7 @@ services:
|
|||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 16
|
retries: 16
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- /stirling/latest/config:/configs:rw
|
||||||
|
@ -13,7 +13,7 @@ services:
|
|||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 16
|
retries: 16
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- /stirling/latest/config:/configs:rw
|
||||||
|
@ -13,7 +13,7 @@ services:
|
|||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 16
|
retries: 16
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- /stirling/latest/config:/configs:rw
|
||||||
|
@ -13,7 +13,7 @@ services:
|
|||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 16
|
retries: 16
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/config:/configs:rw
|
- /stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- /stirling/latest/logs:/logs:rw
|
||||||
|
@ -13,7 +13,7 @@ services:
|
|||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 16
|
retries: 16
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- /stirling/latest/config:/configs:rw
|
||||||
|
@ -15,7 +15,10 @@ ignore = [
|
|||||||
|
|
||||||
[cs_CZ]
|
[cs_CZ]
|
||||||
ignore = [
|
ignore = [
|
||||||
|
'info',
|
||||||
'language.direction',
|
'language.direction',
|
||||||
|
'pipeline.header',
|
||||||
|
'text',
|
||||||
]
|
]
|
||||||
|
|
||||||
[de_DE]
|
[de_DE]
|
||||||
@ -65,6 +68,16 @@ ignore = [
|
|||||||
'language.direction',
|
'language.direction',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[hr_HR]
|
||||||
|
ignore = [
|
||||||
|
'font',
|
||||||
|
'home.pipeline.title',
|
||||||
|
'info',
|
||||||
|
'language.direction',
|
||||||
|
'pdfOrganiser.tags',
|
||||||
|
'showJS.tags',
|
||||||
|
]
|
||||||
|
|
||||||
[hu_HU]
|
[hu_HU]
|
||||||
ignore = [
|
ignore = [
|
||||||
'language.direction',
|
'language.direction',
|
||||||
@ -103,6 +116,11 @@ ignore = [
|
|||||||
'language.direction',
|
'language.direction',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[no_NB]
|
||||||
|
ignore = [
|
||||||
|
'language.direction',
|
||||||
|
]
|
||||||
|
|
||||||
[pl_PL]
|
[pl_PL]
|
||||||
ignore = [
|
ignore = [
|
||||||
'language.direction',
|
'language.direction',
|
||||||
|
@ -6,11 +6,15 @@ import java.net.Socket;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import io.github.pixee.security.SystemCommand;
|
import io.github.pixee.security.SystemCommand;
|
||||||
|
|
||||||
public class LibreOfficeListener {
|
public class LibreOfficeListener {
|
||||||
|
|
||||||
private static final long ACTIVITY_TIMEOUT = 20 * 60 * 1000; // 20 minutes
|
private static final Logger logger = LoggerFactory.getLogger(LibreOfficeListener.class);
|
||||||
|
private static final long ACTIVITY_TIMEOUT = 20L * 60 * 1000; // 20 minutes
|
||||||
|
|
||||||
private static final LibreOfficeListener INSTANCE = new LibreOfficeListener();
|
private static final LibreOfficeListener INSTANCE = new LibreOfficeListener();
|
||||||
private static final int LISTENER_PORT = 2002;
|
private static final int LISTENER_PORT = 2002;
|
||||||
@ -27,14 +31,12 @@ public class LibreOfficeListener {
|
|||||||
private LibreOfficeListener() {}
|
private LibreOfficeListener() {}
|
||||||
|
|
||||||
private boolean isListenerRunning() {
|
private boolean isListenerRunning() {
|
||||||
try {
|
System.out.println("waiting for listener to start");
|
||||||
System.out.println("waiting for listener to start");
|
try (Socket socket = new Socket()) {
|
||||||
Socket socket = new Socket();
|
|
||||||
socket.connect(
|
socket.connect(
|
||||||
new InetSocketAddress("localhost", 2002), 1000); // Timeout after 1 second
|
new InetSocketAddress("localhost", 2002), 1000); // Timeout after 1 second
|
||||||
socket.close();
|
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,6 +65,7 @@ public class LibreOfficeListener {
|
|||||||
try {
|
try {
|
||||||
Thread.sleep(5000); // Check for inactivity every 5 seconds
|
Thread.sleep(5000); // Check for inactivity every 5 seconds
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,8 +83,8 @@ public class LibreOfficeListener {
|
|||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
Thread.currentThread().interrupt();
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
} // Check every 1 second
|
} // Check every 1 second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import java.nio.file.Paths;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
@ -24,6 +26,8 @@ import stirling.software.SPDF.model.ApplicationProperties;
|
|||||||
@Lazy
|
@Lazy
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AppConfig.class);
|
||||||
|
|
||||||
@Autowired ApplicationProperties applicationProperties;
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -56,7 +60,7 @@ public class AppConfig {
|
|||||||
props.load(resource.getInputStream());
|
props.load(resource.getInputStream());
|
||||||
return props.getProperty("version");
|
return props.getProperty("version");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
return "0.0.0";
|
return "0.0.0";
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
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.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContextInitializer;
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
@ -47,61 +44,49 @@ public class ConfigInitializer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Load the template content from classpath
|
// Path templatePath =
|
||||||
List<String> templateLines;
|
// Paths.get(
|
||||||
try (InputStream in =
|
// getClass()
|
||||||
getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
|
// .getClassLoader()
|
||||||
if (in == null) {
|
// .getResource("settings.yml.template")
|
||||||
throw new FileNotFoundException(
|
// .toURI());
|
||||||
"Resource file not found: settings.yml.template");
|
// Path userPath = Paths.get("configs", "settings.yml");
|
||||||
}
|
//
|
||||||
templateLines = new ArrayList<>();
|
// List<String> templateLines = Files.readAllLines(templatePath);
|
||||||
try (var reader = new InputStreamReader(in)) {
|
// List<String> userLines =
|
||||||
try (var bufferedReader = new BufferedReader(reader)) {
|
// Files.exists(userPath) ? Files.readAllLines(userPath) : new
|
||||||
String line;
|
// ArrayList<>();
|
||||||
while ((line = bufferedReader.readLine()) != null) {
|
//
|
||||||
templateLines.add(line);
|
// List<String> resultLines = new ArrayList<>();
|
||||||
}
|
// int position = 0;
|
||||||
}
|
// for (String templateLine : templateLines) {
|
||||||
}
|
// // Check if the line is a comment
|
||||||
}
|
// if (templateLine.trim().startsWith("#")) {
|
||||||
|
// String entry = templateLine.trim().substring(1).trim();
|
||||||
// Read the user settings file if it exists
|
// if (!entry.isEmpty()) {
|
||||||
Path userPath = Paths.get("configs", "settings.yml");
|
// // Check if this comment has been uncommented in userLines
|
||||||
List<String> userLines =
|
// String key = entry.split(":")[0].trim();
|
||||||
Files.exists(userPath) ? Files.readAllLines(userPath) : new ArrayList<>();
|
// addLine(resultLines, userLines, templateLine, key, position);
|
||||||
|
// } else {
|
||||||
List<String> resultLines = new ArrayList<>();
|
// resultLines.add(templateLine);
|
||||||
int position = 0;
|
// }
|
||||||
for (String templateLine : templateLines) {
|
// }
|
||||||
// Check if the line is a comment
|
// // Check if the line is a key-value pair
|
||||||
if (templateLine.trim().startsWith("#")) {
|
// else if (templateLine.contains(":")) {
|
||||||
String entry = templateLine.trim().substring(1).trim();
|
// String key = templateLine.split(":")[0].trim();
|
||||||
if (!entry.isEmpty()) {
|
// addLine(resultLines, userLines, templateLine, key, position);
|
||||||
// Check if this comment has been uncommented in userLines
|
// }
|
||||||
String key = entry.split(":")[0].trim();
|
// // Handle empty lines
|
||||||
addLine(resultLines, userLines, templateLine, key, position);
|
// else if (templateLine.trim().length() == 0) {
|
||||||
} else {
|
// resultLines.add("");
|
||||||
resultLines.add(templateLine);
|
// }
|
||||||
}
|
// position++;
|
||||||
}
|
// }
|
||||||
// Check if the line is a key-value pair
|
//
|
||||||
else if (templateLine.contains(":")) {
|
// // Write the result to the user settings file
|
||||||
String key = templateLine.split(":")[0].trim();
|
// Files.write(userPath, resultLines);
|
||||||
addLine(resultLines, userLines, templateLine, key, position);
|
|
||||||
}
|
|
||||||
// Handle empty lines
|
|
||||||
else if (templateLine.trim().length() == 0) {
|
|
||||||
resultLines.add("");
|
|
||||||
}
|
|
||||||
position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the result to the user settings file
|
|
||||||
Files.write(userPath, resultLines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the custom settings file exists
|
|
||||||
Path customSettingsPath = Paths.get("configs", "custom_settings.yml");
|
Path customSettingsPath = Paths.get("configs", "custom_settings.yml");
|
||||||
if (!Files.exists(customSettingsPath)) {
|
if (!Files.exists(customSettingsPath)) {
|
||||||
Files.createFile(customSettingsPath);
|
Files.createFile(customSettingsPath);
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.thymeleaf.IEngineConfiguration;
|
import org.thymeleaf.IEngineConfiguration;
|
||||||
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
|
import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver;
|
||||||
import org.thymeleaf.templateresource.ClassLoaderTemplateResource;
|
|
||||||
import org.thymeleaf.templateresource.FileTemplateResource;
|
import org.thymeleaf.templateresource.FileTemplateResource;
|
||||||
import org.thymeleaf.templateresource.ITemplateResource;
|
import org.thymeleaf.templateresource.ITemplateResource;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.InputStreamTemplateResource;
|
||||||
|
|
||||||
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
|
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
|
||||||
|
|
||||||
private final ResourceLoader resourceLoader;
|
private final ResourceLoader resourceLoader;
|
||||||
@ -40,9 +42,13 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ClassLoaderTemplateResource(
|
InputStream inputStream =
|
||||||
Thread.currentThread().getContextClassLoader(),
|
Thread.currentThread()
|
||||||
"classpath:/templates/" + resourceName,
|
.getContextClassLoader()
|
||||||
characterEncoding);
|
.getResourceAsStream("templates/" + resourceName);
|
||||||
|
if (inputStream != null) {
|
||||||
|
return new InputStreamTemplateResource(inputStream, "UTF-8");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ public class MetricsFilter extends OncePerRequestFilter {
|
|||||||
|| uri.startsWith("/v1/api-docs")
|
|| uri.startsWith("/v1/api-docs")
|
||||||
|| uri.endsWith("robots.txt")
|
|| uri.endsWith("robots.txt")
|
||||||
|| uri.startsWith("/images")
|
|| uri.startsWith("/images")
|
||||||
|| uri.startsWith("/images")
|
|
||||||
|| uri.endsWith(".png")
|
|| uri.endsWith(".png")
|
||||||
|| uri.endsWith(".ico")
|
|| uri.endsWith(".ico")
|
||||||
|| uri.endsWith(".css")
|
|| uri.endsWith(".css")
|
||||||
|
@ -49,10 +49,12 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
|
|||||||
}
|
}
|
||||||
|
|
||||||
String username = request.getParameter("username");
|
String username = request.getParameter("username");
|
||||||
if (username != null && !isDemoUser(username)) {
|
Optional<User> optUser = userService.findByUsernameIgnoreCase(username);
|
||||||
|
|
||||||
|
if (username != null && optUser.isPresent() && !isDemoUser(optUser)) {
|
||||||
logger.info(
|
logger.info(
|
||||||
"Remaining attempts for user {}: {}",
|
"Remaining attempts for user {}: {}",
|
||||||
username,
|
optUser.get().getUsername(),
|
||||||
loginAttemptService.getRemainingAttempts(username));
|
loginAttemptService.getRemainingAttempts(username));
|
||||||
loginAttemptService.loginFailed(username);
|
loginAttemptService.loginFailed(username);
|
||||||
if (loginAttemptService.isBlocked(username)
|
if (loginAttemptService.isBlocked(username)
|
||||||
@ -70,8 +72,7 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
|
|||||||
super.onAuthenticationFailure(request, response, exception);
|
super.onAuthenticationFailure(request, response, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDemoUser(String username) {
|
private boolean isDemoUser(Optional<User> user) {
|
||||||
Optional<User> user = userService.findByUsernameIgnoreCase(username);
|
|
||||||
return user.isPresent()
|
return user.isPresent()
|
||||||
&& user.get().getAuthorities().stream()
|
&& user.get().getAuthorities().stream()
|
||||||
.anyMatch(authority -> "ROLE_DEMO_USER".equals(authority.getAuthority()));
|
.anyMatch(authority -> "ROLE_DEMO_USER".equals(authority.getAuthority()));
|
||||||
|
@ -33,7 +33,6 @@ public class LoginAttemptService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void loginSucceeded(String key) {
|
public void loginSucceeded(String key) {
|
||||||
logger.info(key + " " + attemptsCache.mappingCount());
|
|
||||||
if (key == null || key.trim().isEmpty()) {
|
if (key == null || key.trim().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,7 @@ public class SecurityConfiguration {
|
|||||||
GoogleProvider google = client.getGoogle();
|
GoogleProvider google = client.getGoogle();
|
||||||
return google != null && google.isSettingsValid()
|
return google != null && google.isSettingsValid()
|
||||||
? Optional.of(
|
? Optional.of(
|
||||||
ClientRegistration.withRegistrationId("google")
|
ClientRegistration.withRegistrationId(google.getName())
|
||||||
.clientId(google.getClientId())
|
.clientId(google.getClientId())
|
||||||
.clientSecret(google.getClientSecret())
|
.clientSecret(google.getClientSecret())
|
||||||
.scope(google.getScopes())
|
.scope(google.getScopes())
|
||||||
@ -246,8 +246,8 @@ public class SecurityConfiguration {
|
|||||||
.tokenUri(google.getTokenuri())
|
.tokenUri(google.getTokenuri())
|
||||||
.userInfoUri(google.getUserinfouri())
|
.userInfoUri(google.getUserinfouri())
|
||||||
.userNameAttributeName(google.getUseAsUsername())
|
.userNameAttributeName(google.getUseAsUsername())
|
||||||
.clientName("Google")
|
.clientName(google.getClientName())
|
||||||
.redirectUri("{baseUrl}/login/oauth2/code/google")
|
.redirectUri("{baseUrl}/login/oauth2/code/" + google.getName())
|
||||||
.authorizationGrantType(
|
.authorizationGrantType(
|
||||||
org.springframework.security.oauth2.core
|
org.springframework.security.oauth2.core
|
||||||
.AuthorizationGrantType.AUTHORIZATION_CODE)
|
.AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
@ -269,12 +269,12 @@ public class SecurityConfiguration {
|
|||||||
return keycloak != null && keycloak.isSettingsValid()
|
return keycloak != null && keycloak.isSettingsValid()
|
||||||
? Optional.of(
|
? Optional.of(
|
||||||
ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())
|
ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())
|
||||||
.registrationId("keycloak")
|
.registrationId(keycloak.getName())
|
||||||
.clientId(keycloak.getClientId())
|
.clientId(keycloak.getClientId())
|
||||||
.clientSecret(keycloak.getClientSecret())
|
.clientSecret(keycloak.getClientSecret())
|
||||||
.scope(keycloak.getScopes())
|
.scope(keycloak.getScopes())
|
||||||
.userNameAttributeName(keycloak.getUseAsUsername())
|
.userNameAttributeName(keycloak.getUseAsUsername())
|
||||||
.clientName("Keycloak")
|
.clientName(keycloak.getClientName())
|
||||||
.build())
|
.build())
|
||||||
: Optional.empty();
|
: Optional.empty();
|
||||||
}
|
}
|
||||||
@ -291,7 +291,7 @@ public class SecurityConfiguration {
|
|||||||
GithubProvider github = client.getGithub();
|
GithubProvider github = client.getGithub();
|
||||||
return github != null && github.isSettingsValid()
|
return github != null && github.isSettingsValid()
|
||||||
? Optional.of(
|
? Optional.of(
|
||||||
ClientRegistration.withRegistrationId("github")
|
ClientRegistration.withRegistrationId(github.getName())
|
||||||
.clientId(github.getClientId())
|
.clientId(github.getClientId())
|
||||||
.clientSecret(github.getClientSecret())
|
.clientSecret(github.getClientSecret())
|
||||||
.scope(github.getScopes())
|
.scope(github.getScopes())
|
||||||
@ -299,8 +299,8 @@ public class SecurityConfiguration {
|
|||||||
.tokenUri(github.getTokenuri())
|
.tokenUri(github.getTokenuri())
|
||||||
.userInfoUri(github.getUserinfouri())
|
.userInfoUri(github.getUserinfouri())
|
||||||
.userNameAttributeName(github.getUseAsUsername())
|
.userNameAttributeName(github.getUseAsUsername())
|
||||||
.clientName("GitHub")
|
.clientName(github.getClientName())
|
||||||
.redirectUri("{baseUrl}/login/oauth2/code/github")
|
.redirectUri("{baseUrl}/login/oauth2/code/" + github.getName())
|
||||||
.authorizationGrantType(
|
.authorizationGrantType(
|
||||||
org.springframework.security.oauth2.core
|
org.springframework.security.oauth2.core
|
||||||
.AuthorizationGrantType.AUTHORIZATION_CODE)
|
.AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
|
@ -52,7 +52,7 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
|
|||||||
issuer = provider.getIssuer();
|
issuer = provider.getIssuer();
|
||||||
clientId = provider.getClientId();
|
clientId = provider.getClientId();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -60,13 +60,13 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
|
|||||||
issuer = oauth.getIssuer();
|
issuer = oauth.getIssuer();
|
||||||
clientId = oauth.getClientId();
|
clientId = oauth.getClientId();
|
||||||
}
|
}
|
||||||
|
String errorMessage = "";
|
||||||
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
||||||
param = "erroroauth=oauth2AuthenticationErrorWeb";
|
param = "erroroauth=oauth2AuthenticationErrorWeb";
|
||||||
} else if (request.getParameter("error") != null) {
|
} else if ((errorMessage = request.getParameter("error")) != null) {
|
||||||
param = "error=" + request.getParameter("error");
|
param = "error=" + sanitizeInput(errorMessage);
|
||||||
} else if (request.getParameter("erroroauth") != null) {
|
} else if ((errorMessage = request.getParameter("erroroauth")) != null) {
|
||||||
param = "erroroauth=" + request.getParameter("erroroauth");
|
param = "erroroauth=" + sanitizeInput(errorMessage);
|
||||||
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
|
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
|
||||||
param = "error=oauth2AutoCreateDisabled";
|
param = "error=oauth2AutoCreateDisabled";
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
|
|||||||
logger.info("Session invalidated: " + sessionId);
|
logger.info("Session invalidated: " + sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (registrationId) {
|
switch (registrationId.toLowerCase()) {
|
||||||
case "keycloak":
|
case "keycloak":
|
||||||
// Add Keycloak specific logout URL if needed
|
// Add Keycloak specific logout URL if needed
|
||||||
String logoutUrl =
|
String logoutUrl =
|
||||||
@ -115,4 +115,8 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String sanitizeInput(String input) {
|
||||||
|
return input.replaceAll("[^a-zA-Z0-9 ]", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
|||||||
import stirling.software.SPDF.config.security.LoginAttemptService;
|
import stirling.software.SPDF.config.security.LoginAttemptService;
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
|
|
||||||
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
|
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
|
||||||
@ -41,11 +43,27 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
||||||
String usernameAttribute =
|
OAUTH2 oauth2 = applicationProperties.getSecurity().getOAUTH2();
|
||||||
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername();
|
String usernameAttribute = oauth2.getUseAsUsername();
|
||||||
|
if (usernameAttribute == null || usernameAttribute.trim().isEmpty()) {
|
||||||
|
Client client = oauth2.getClient();
|
||||||
|
if (client != null && client.getKeycloak() != null) {
|
||||||
|
usernameAttribute = client.getKeycloak().getUseAsUsername();
|
||||||
|
} else {
|
||||||
|
usernameAttribute = "email";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OidcUser user = delegate.loadUser(userRequest);
|
OidcUser user = delegate.loadUser(userRequest);
|
||||||
String username = user.getUserInfo().getClaimAsString(usernameAttribute);
|
String username = user.getUserInfo().getClaimAsString(usernameAttribute);
|
||||||
|
|
||||||
|
// Check if the username claim is null or empty
|
||||||
|
if (username == null || username.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Claim '" + usernameAttribute + "' cannot be null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
Optional<User> duser = userService.findByUsernameIgnoreCase(username);
|
Optional<User> duser = userService.findByUsernameIgnoreCase(username);
|
||||||
if (duser.isPresent()) {
|
if (duser.isPresent()) {
|
||||||
if (loginAttemptService.isBlocked(username)) {
|
if (loginAttemptService.isBlocked(username)) {
|
||||||
@ -56,13 +74,14 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
|
|||||||
throw new IllegalArgumentException("Password must not be null");
|
throw new IllegalArgumentException("Password must not be null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a new OidcUser with adjusted attributes
|
// Return a new OidcUser with adjusted attributes
|
||||||
return new DefaultOidcUser(
|
return new DefaultOidcUser(
|
||||||
user.getAuthorities(),
|
user.getAuthorities(),
|
||||||
userRequest.getIdToken(),
|
userRequest.getIdToken(),
|
||||||
user.getUserInfo(),
|
user.getUserInfo(),
|
||||||
usernameAttribute);
|
usernameAttribute);
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
logger.error("Error loading OIDC user: {}", e.getMessage());
|
logger.error("Error loading OIDC user: {}", e.getMessage());
|
||||||
throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e);
|
throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -18,6 +18,8 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
|||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
import org.apache.pdfbox.util.Matrix;
|
import org.apache.pdfbox.util.Matrix;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
@ -38,6 +40,9 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class SplitPdfBySectionsController {
|
public class SplitPdfBySectionsController {
|
||||||
|
|
||||||
|
private static final Logger logger =
|
||||||
|
LoggerFactory.getLogger(SplitPdfBySectionsController.class);
|
||||||
|
|
||||||
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
|
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Split PDF pages into smaller sections",
|
summary = "Split PDF pages into smaller sections",
|
||||||
@ -92,7 +97,7 @@ public class SplitPdfBySectionsController {
|
|||||||
if (sectionNum == horiz * verti) pageNum++;
|
if (sectionNum == horiz * verti) pageNum++;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
} finally {
|
} finally {
|
||||||
data = Files.readAllBytes(zipFile);
|
data = Files.readAllBytes(zipFile);
|
||||||
Files.deleteIfExists(zipFile);
|
Files.deleteIfExists(zipFile);
|
||||||
|
@ -10,6 +10,8 @@ import java.util.zip.ZipOutputStream;
|
|||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
@ -31,6 +33,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class SplitPdfBySizeController {
|
public class SplitPdfBySizeController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(SplitPdfBySizeController.class);
|
||||||
|
|
||||||
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
|
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Auto split PDF pages into separate documents based on size or count",
|
summary = "Auto split PDF pages into separate documents based on size or count",
|
||||||
@ -66,7 +70,7 @@ public class SplitPdfBySizeController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
} finally {
|
} finally {
|
||||||
data = Files.readAllBytes(zipFile);
|
data = Files.readAllBytes(zipFile);
|
||||||
Files.deleteIfExists(zipFile);
|
Files.deleteIfExists(zipFile);
|
||||||
|
@ -66,46 +66,46 @@ public class UserController {
|
|||||||
RedirectAttributes redirectAttributes) {
|
RedirectAttributes redirectAttributes) {
|
||||||
|
|
||||||
if (!userService.isUsernameValid(newUsername)) {
|
if (!userService.isUsernameValid(newUsername)) {
|
||||||
return new RedirectView("/account?messageType=invalidUsername");
|
return new RedirectView("/account?messageType=invalidUsername", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (principal == null) {
|
if (principal == null) {
|
||||||
return new RedirectView("/account?messageType=notAuthenticated");
|
return new RedirectView("/account?messageType=notAuthenticated", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The username MUST be unique when renaming
|
// The username MUST be unique when renaming
|
||||||
Optional<User> userOpt = userService.findByUsername(principal.getName());
|
Optional<User> userOpt = userService.findByUsername(principal.getName());
|
||||||
|
|
||||||
if (userOpt == null || userOpt.isEmpty()) {
|
if (userOpt == null || userOpt.isEmpty()) {
|
||||||
return new RedirectView("/account?messageType=userNotFound");
|
return new RedirectView("/account?messageType=userNotFound", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
|
|
||||||
if (user.getUsername().equals(newUsername)) {
|
if (user.getUsername().equals(newUsername)) {
|
||||||
return new RedirectView("/account?messageType=usernameExists");
|
return new RedirectView("/account?messageType=usernameExists", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userService.isPasswordCorrect(user, currentPassword)) {
|
if (!userService.isPasswordCorrect(user, currentPassword)) {
|
||||||
return new RedirectView("/account?messageType=incorrectPassword");
|
return new RedirectView("/account?messageType=incorrectPassword", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.getUsername().equals(newUsername) && userService.usernameExists(newUsername)) {
|
if (!user.getUsername().equals(newUsername) && userService.usernameExists(newUsername)) {
|
||||||
return new RedirectView("/account?messageType=usernameExists");
|
return new RedirectView("/account?messageType=usernameExists", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newUsername != null && newUsername.length() > 0) {
|
if (newUsername != null && newUsername.length() > 0) {
|
||||||
try {
|
try {
|
||||||
userService.changeUsername(user, newUsername);
|
userService.changeUsername(user, newUsername);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
return new RedirectView("/account?messageType=invalidUsername");
|
return new RedirectView("/account?messageType=invalidUsername", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout using Spring's utility
|
// Logout using Spring's utility
|
||||||
new SecurityContextLogoutHandler().logout(request, response, null);
|
new SecurityContextLogoutHandler().logout(request, response, null);
|
||||||
|
|
||||||
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED);
|
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
||||||
@ -118,19 +118,19 @@ public class UserController {
|
|||||||
HttpServletResponse response,
|
HttpServletResponse response,
|
||||||
RedirectAttributes redirectAttributes) {
|
RedirectAttributes redirectAttributes) {
|
||||||
if (principal == null) {
|
if (principal == null) {
|
||||||
return new RedirectView("/change-creds?messageType=notAuthenticated");
|
return new RedirectView("/change-creds?messageType=notAuthenticated", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName());
|
Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName());
|
||||||
|
|
||||||
if (userOpt == null || userOpt.isEmpty()) {
|
if (userOpt == null || userOpt.isEmpty()) {
|
||||||
return new RedirectView("/change-creds?messageType=userNotFound");
|
return new RedirectView("/change-creds?messageType=userNotFound", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
|
|
||||||
if (!userService.isPasswordCorrect(user, currentPassword)) {
|
if (!userService.isPasswordCorrect(user, currentPassword)) {
|
||||||
return new RedirectView("/change-creds?messageType=incorrectPassword");
|
return new RedirectView("/change-creds?messageType=incorrectPassword", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
userService.changePassword(user, newPassword);
|
userService.changePassword(user, newPassword);
|
||||||
@ -138,7 +138,7 @@ public class UserController {
|
|||||||
// Logout using Spring's utility
|
// Logout using Spring's utility
|
||||||
new SecurityContextLogoutHandler().logout(request, response, null);
|
new SecurityContextLogoutHandler().logout(request, response, null);
|
||||||
|
|
||||||
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED);
|
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
||||||
@ -151,19 +151,19 @@ public class UserController {
|
|||||||
HttpServletResponse response,
|
HttpServletResponse response,
|
||||||
RedirectAttributes redirectAttributes) {
|
RedirectAttributes redirectAttributes) {
|
||||||
if (principal == null) {
|
if (principal == null) {
|
||||||
return new RedirectView("/account?messageType=notAuthenticated");
|
return new RedirectView("/account?messageType=notAuthenticated", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName());
|
Optional<User> userOpt = userService.findByUsernameIgnoreCase(principal.getName());
|
||||||
|
|
||||||
if (userOpt == null || userOpt.isEmpty()) {
|
if (userOpt == null || userOpt.isEmpty()) {
|
||||||
return new RedirectView("/account?messageType=userNotFound");
|
return new RedirectView("/account?messageType=userNotFound", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
|
|
||||||
if (!userService.isPasswordCorrect(user, currentPassword)) {
|
if (!userService.isPasswordCorrect(user, currentPassword)) {
|
||||||
return new RedirectView("/account?messageType=incorrectPassword");
|
return new RedirectView("/account?messageType=incorrectPassword", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
userService.changePassword(user, newPassword);
|
userService.changePassword(user, newPassword);
|
||||||
@ -171,7 +171,7 @@ public class UserController {
|
|||||||
// Logout using Spring's utility
|
// Logout using Spring's utility
|
||||||
new SecurityContextLogoutHandler().logout(request, response, null);
|
new SecurityContextLogoutHandler().logout(request, response, null);
|
||||||
|
|
||||||
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED);
|
return new RedirectView(LOGIN_MESSAGETYPE_CREDSUPDATED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
@PreAuthorize("!hasAuthority('ROLE_DEMO_USER')")
|
||||||
@ -204,7 +204,7 @@ public class UserController {
|
|||||||
boolean forceChange) {
|
boolean forceChange) {
|
||||||
|
|
||||||
if (!userService.isUsernameValid(username)) {
|
if (!userService.isUsernameValid(username)) {
|
||||||
return new RedirectView("/addUsers?messageType=invalidUsername");
|
return new RedirectView("/addUsers?messageType=invalidUsername", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
|
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
|
||||||
@ -212,26 +212,27 @@ public class UserController {
|
|||||||
if (userOpt.isPresent()) {
|
if (userOpt.isPresent()) {
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
if (user != null && user.getUsername().equalsIgnoreCase(username)) {
|
if (user != null && user.getUsername().equalsIgnoreCase(username)) {
|
||||||
return new RedirectView("/addUsers?messageType=usernameExists");
|
return new RedirectView("/addUsers?messageType=usernameExists", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (userService.usernameExistsIgnoreCase(username)) {
|
if (userService.usernameExistsIgnoreCase(username)) {
|
||||||
return new RedirectView("/addUsers?messageType=usernameExists");
|
return new RedirectView("/addUsers?messageType=usernameExists", true);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Validate the role
|
// Validate the role
|
||||||
Role roleEnum = Role.fromString(role);
|
Role roleEnum = Role.fromString(role);
|
||||||
if (roleEnum == Role.INTERNAL_API_USER) {
|
if (roleEnum == Role.INTERNAL_API_USER) {
|
||||||
// If the role is INTERNAL_API_USER, reject the request
|
// If the role is INTERNAL_API_USER, reject the request
|
||||||
return new RedirectView("/addUsers?messageType=invalidRole");
|
return new RedirectView("/addUsers?messageType=invalidRole", true);
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
// If the role ID is not valid, redirect with an error message
|
// If the role ID is not valid, redirect with an error message
|
||||||
return new RedirectView("/addUsers?messageType=invalidRole");
|
return new RedirectView("/addUsers?messageType=invalidRole", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
userService.saveUser(username, password, role, forceChange);
|
userService.saveUser(username, password, role, forceChange);
|
||||||
return new RedirectView("/addUsers"); // Redirect to account page after adding the user
|
return new RedirectView(
|
||||||
|
"/addUsers", true); // Redirect to account page after adding the user
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
@ -244,33 +245,34 @@ public class UserController {
|
|||||||
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
|
Optional<User> userOpt = userService.findByUsernameIgnoreCase(username);
|
||||||
|
|
||||||
if (!userOpt.isPresent()) {
|
if (!userOpt.isPresent()) {
|
||||||
return new RedirectView("/addUsers?messageType=userNotFound");
|
return new RedirectView("/addUsers?messageType=userNotFound", true);
|
||||||
}
|
}
|
||||||
if (!userService.usernameExistsIgnoreCase(username)) {
|
if (!userService.usernameExistsIgnoreCase(username)) {
|
||||||
return new RedirectView("/addUsers?messageType=userNotFound");
|
return new RedirectView("/addUsers?messageType=userNotFound", true);
|
||||||
}
|
}
|
||||||
// Get the currently authenticated username
|
// Get the currently authenticated username
|
||||||
String currentUsername = authentication.getName();
|
String currentUsername = authentication.getName();
|
||||||
|
|
||||||
// Check if the provided username matches the current session's username
|
// Check if the provided username matches the current session's username
|
||||||
if (currentUsername.equalsIgnoreCase(username)) {
|
if (currentUsername.equalsIgnoreCase(username)) {
|
||||||
return new RedirectView("/addUsers?messageType=downgradeCurrentUser");
|
return new RedirectView("/addUsers?messageType=downgradeCurrentUser", true);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Validate the role
|
// Validate the role
|
||||||
Role roleEnum = Role.fromString(role);
|
Role roleEnum = Role.fromString(role);
|
||||||
if (roleEnum == Role.INTERNAL_API_USER) {
|
if (roleEnum == Role.INTERNAL_API_USER) {
|
||||||
// If the role is INTERNAL_API_USER, reject the request
|
// If the role is INTERNAL_API_USER, reject the request
|
||||||
return new RedirectView("/addUsers?messageType=invalidRole");
|
return new RedirectView("/addUsers?messageType=invalidRole", true);
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
// If the role ID is not valid, redirect with an error message
|
// If the role ID is not valid, redirect with an error message
|
||||||
return new RedirectView("/addUsers?messageType=invalidRole");
|
return new RedirectView("/addUsers?messageType=invalidRole", true);
|
||||||
}
|
}
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
|
|
||||||
userService.changeRole(user, role);
|
userService.changeRole(user, role);
|
||||||
return new RedirectView("/addUsers"); // Redirect to account page after adding the user
|
return new RedirectView(
|
||||||
|
"/addUsers", true); // Redirect to account page after adding the user
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
@ -279,7 +281,7 @@ public class UserController {
|
|||||||
@PathVariable(name = "username") String username, Authentication authentication) {
|
@PathVariable(name = "username") String username, Authentication authentication) {
|
||||||
|
|
||||||
if (!userService.usernameExistsIgnoreCase(username)) {
|
if (!userService.usernameExistsIgnoreCase(username)) {
|
||||||
return new RedirectView("/addUsers?messageType=deleteUsernameExists");
|
return new RedirectView("/addUsers?messageType=deleteUsernameExists", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the currently authenticated username
|
// Get the currently authenticated username
|
||||||
@ -287,11 +289,11 @@ public class UserController {
|
|||||||
|
|
||||||
// Check if the provided username matches the current session's username
|
// Check if the provided username matches the current session's username
|
||||||
if (currentUsername.equalsIgnoreCase(username)) {
|
if (currentUsername.equalsIgnoreCase(username)) {
|
||||||
return new RedirectView("/addUsers?messageType=deleteCurrentUser");
|
return new RedirectView("/addUsers?messageType=deleteCurrentUser", true);
|
||||||
}
|
}
|
||||||
invalidateUserSessions(username);
|
invalidateUserSessions(username);
|
||||||
userService.deleteUser(username);
|
userService.deleteUser(username);
|
||||||
return new RedirectView("/addUsers");
|
return new RedirectView("/addUsers", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired private SessionRegistry sessionRegistry;
|
@Autowired private SessionRegistry sessionRegistry;
|
||||||
|
@ -15,6 +15,8 @@ import java.util.zip.ZipOutputStream;
|
|||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
@ -43,6 +45,7 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class AutoSplitPdfController {
|
public class AutoSplitPdfController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AutoSplitPdfController.class);
|
||||||
private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF";
|
private static final String QR_CONTENT = "https://github.com/Stirling-Tools/Stirling-PDF";
|
||||||
private static final String QR_CONTENT_OLD = "https://github.com/Frooodle/Stirling-PDF";
|
private static final String QR_CONTENT_OLD = "https://github.com/Frooodle/Stirling-PDF";
|
||||||
|
|
||||||
@ -115,7 +118,7 @@ public class AutoSplitPdfController {
|
|||||||
zipOut.closeEntry();
|
zipOut.closeEntry();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
} finally {
|
} finally {
|
||||||
data = Files.readAllBytes(zipFile);
|
data = Files.readAllBytes(zipFile);
|
||||||
Files.deleteIfExists(zipFile);
|
Files.deleteIfExists(zipFile);
|
||||||
|
@ -106,7 +106,7 @@ public class BlankPageController {
|
|||||||
.replaceFirst("[.][^.]+$", "")
|
.replaceFirst("[.][^.]+$", "")
|
||||||
+ "_blanksRemoved.pdf");
|
+ "_blanksRemoved.pdf");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
} finally {
|
} finally {
|
||||||
if (document != null) document.close();
|
if (document != null) document.close();
|
||||||
|
@ -110,8 +110,8 @@ public class FakeScanControllerWIP {
|
|||||||
private BufferedImage rotate(BufferedImage image, double rotation) {
|
private BufferedImage rotate(BufferedImage image, double rotation) {
|
||||||
|
|
||||||
double rotationRequired = Math.toRadians(rotation);
|
double rotationRequired = Math.toRadians(rotation);
|
||||||
double locationX = image.getWidth() / 2;
|
double locationX = (double) image.getWidth() / 2;
|
||||||
double locationY = image.getHeight() / 2;
|
double locationY = (double) image.getHeight() / 2;
|
||||||
AffineTransform tx =
|
AffineTransform tx =
|
||||||
AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
|
AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
|
||||||
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC);
|
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC);
|
||||||
@ -127,8 +127,8 @@ public class FakeScanControllerWIP {
|
|||||||
|
|
||||||
for (int i = -radius; i <= radius; i++) {
|
for (int i = -radius; i <= radius; i++) {
|
||||||
for (int j = -radius; j <= radius; j++) {
|
for (int j = -radius; j <= radius; j++) {
|
||||||
double xDistance = i * i;
|
double xDistance = (double) i * i;
|
||||||
double yDistance = j * j;
|
double yDistance = (double) j * j;
|
||||||
double g = Math.exp(-(xDistance + yDistance) / (2 * sigma * sigma));
|
double g = Math.exp(-(xDistance + yDistance) / (2 * sigma * sigma));
|
||||||
data[(i + radius) * size + j + radius] = (float) g;
|
data[(i + radius) * size + j + radius] = (float) g;
|
||||||
sum += g;
|
sum += g;
|
||||||
@ -137,7 +137,7 @@ public class FakeScanControllerWIP {
|
|||||||
|
|
||||||
// Normalize the kernel
|
// Normalize the kernel
|
||||||
for (int i = 0; i < data.length; i++) {
|
for (int i = 0; i < data.length; i++) {
|
||||||
data[i] /= sum;
|
if (sum != 0) data[i] /= sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel kernel = new Kernel(size, size, data);
|
Kernel kernel = new Kernel(size, size, data);
|
||||||
@ -166,7 +166,7 @@ public class FakeScanControllerWIP {
|
|||||||
0,
|
0,
|
||||||
new Color(0, 0, 0, 1f),
|
new Color(0, 0, 0, 1f),
|
||||||
0,
|
0,
|
||||||
featherRadius * 2,
|
featherRadius * 2f,
|
||||||
new Color(0, 0, 0, 0f)));
|
new Color(0, 0, 0, 0f)));
|
||||||
g2.fillRect(0, 0, width, featherRadius);
|
g2.fillRect(0, 0, width, featherRadius);
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ public class FakeScanControllerWIP {
|
|||||||
g2.setPaint(
|
g2.setPaint(
|
||||||
new GradientPaint(
|
new GradientPaint(
|
||||||
0,
|
0,
|
||||||
height - featherRadius * 2,
|
height - featherRadius * 2f,
|
||||||
new Color(0, 0, 0, 0f),
|
new Color(0, 0, 0, 0f),
|
||||||
0,
|
0,
|
||||||
height,
|
height,
|
||||||
@ -187,7 +187,7 @@ public class FakeScanControllerWIP {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
new Color(0, 0, 0, 1f),
|
new Color(0, 0, 0, 1f),
|
||||||
featherRadius * 2,
|
featherRadius * 2f,
|
||||||
0,
|
0,
|
||||||
new Color(0, 0, 0, 0f)));
|
new Color(0, 0, 0, 0f)));
|
||||||
g2.fillRect(0, 0, featherRadius, height);
|
g2.fillRect(0, 0, featherRadius, height);
|
||||||
@ -195,7 +195,7 @@ public class FakeScanControllerWIP {
|
|||||||
// Right edge
|
// Right edge
|
||||||
g2.setPaint(
|
g2.setPaint(
|
||||||
new GradientPaint(
|
new GradientPaint(
|
||||||
width - featherRadius * 2,
|
width - featherRadius * 2f,
|
||||||
0,
|
0,
|
||||||
new Color(0, 0, 0, 0f),
|
new Color(0, 0, 0, 0f),
|
||||||
width,
|
width,
|
||||||
@ -244,7 +244,7 @@ public class FakeScanControllerWIP {
|
|||||||
int y2 = y1 + random.nextInt(20) - 10;
|
int y2 = y1 + random.nextInt(20) - 10;
|
||||||
Path2D.Double hair = new Path2D.Double();
|
Path2D.Double hair = new Path2D.Double();
|
||||||
hair.moveTo(x1, y1);
|
hair.moveTo(x1, y1);
|
||||||
hair.curveTo(x1, y1, (x1 + x2) / 2, (y1 + y2) / 2, x2, y2);
|
hair.curveTo(x1, y1, (double) (x1 + x2) / 2, (double) (y1 + y2) / 2, x2, y2);
|
||||||
g2d.draw(hair);
|
g2d.draw(hair);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
import org.apache.pdfbox.rendering.ImageType;
|
import org.apache.pdfbox.rendering.ImageType;
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -33,6 +35,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class FlattenController {
|
public class FlattenController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(FlattenController.class);
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/flatten")
|
@PostMapping(consumes = "multipart/form-data", value = "/flatten")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Flatten PDF form fields or full page",
|
summary = "Flatten PDF form fields or full page",
|
||||||
@ -73,7 +77,7 @@ public class FlattenController {
|
|||||||
contentStream.drawImage(pdImage, 0, 0, pageWidth, pageHeight);
|
contentStream.drawImage(pdImage, 0, 0, pageWidth, pageHeight);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PdfUtils.setMetadataToPdf(newDocument, metadata);
|
PdfUtils.setMetadataToPdf(newDocument, metadata);
|
||||||
|
@ -11,6 +11,8 @@ import org.apache.pdfbox.Loader;
|
|||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -30,6 +32,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||||
public class MetadataController {
|
public class MetadataController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MetadataController.class);
|
||||||
|
|
||||||
private String checkUndefined(String entry) {
|
private String checkUndefined(String entry) {
|
||||||
// Check if the string is "undefined"
|
// Check if the string is "undefined"
|
||||||
if ("undefined".equals(entry)) {
|
if ("undefined".equals(entry)) {
|
||||||
@ -136,7 +140,7 @@ public class MetadataController {
|
|||||||
creationDateCal.setTime(
|
creationDateCal.setTime(
|
||||||
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(creationDate));
|
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(creationDate));
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
info.setCreationDate(creationDateCal);
|
info.setCreationDate(creationDateCal);
|
||||||
} else {
|
} else {
|
||||||
@ -148,7 +152,7 @@ public class MetadataController {
|
|||||||
modificationDateCal.setTime(
|
modificationDateCal.setTime(
|
||||||
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(modificationDate));
|
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(modificationDate));
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
info.setModificationDate(modificationDateCal);
|
info.setModificationDate(modificationDateCal);
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,7 +148,7 @@ public class CertSignController {
|
|||||||
doc.addSignature(signature, instance);
|
doc.addSignature(signature, instance);
|
||||||
doc.saveIncremental(output);
|
doc.saveIncremental(output);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ import org.apache.xmpbox.XMPMetadata;
|
|||||||
import org.apache.xmpbox.xml.DomXmpParser;
|
import org.apache.xmpbox.xml.DomXmpParser;
|
||||||
import org.apache.xmpbox.xml.XmpParsingException;
|
import org.apache.xmpbox.xml.XmpParsingException;
|
||||||
import org.apache.xmpbox.xml.XmpSerializer;
|
import org.apache.xmpbox.xml.XmpSerializer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
@ -79,6 +81,8 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Security", description = "Security APIs")
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
public class GetInfoOnPDF {
|
public class GetInfoOnPDF {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GetInfoOnPDF.class);
|
||||||
|
|
||||||
static ObjectMapper objectMapper = new ObjectMapper();
|
static ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
|
@PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
|
||||||
@ -220,7 +224,7 @@ public class GetInfoOnPDF {
|
|||||||
javascriptArray.add(jsNode);
|
javascriptArray.add(jsNode);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,7 +257,7 @@ public class GetInfoOnPDF {
|
|||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isPdfACompliant = checkForStandard(pdfBoxDoc, "PDF/A");
|
boolean isPdfACompliant = checkForStandard(pdfBoxDoc, "PDF/A");
|
||||||
@ -305,7 +309,7 @@ public class GetInfoOnPDF {
|
|||||||
new XmpSerializer().serialize(xmpMeta, os, true);
|
new XmpSerializer().serialize(xmpMeta, os, true);
|
||||||
xmpString = new String(os.toByteArray(), StandardCharsets.UTF_8);
|
xmpString = new String(os.toByteArray(), StandardCharsets.UTF_8);
|
||||||
} catch (XmpParsingException | IOException e) {
|
} catch (XmpParsingException | IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +597,7 @@ public class GetInfoOnPDF {
|
|||||||
MediaType.APPLICATION_JSON);
|
MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -691,7 +695,7 @@ public class GetInfoOnPDF {
|
|||||||
Exception
|
Exception
|
||||||
e) { // Catching general exception for brevity, ideally you'd catch specific
|
e) { // Catching general exception for brevity, ideally you'd catch specific
|
||||||
// exceptions.
|
// exceptions.
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -117,7 +117,6 @@ public class PDFTableStripper extends PDFTextStripper {
|
|||||||
/**
|
/**
|
||||||
* Instantiate a new PDFTableStripper object.
|
* Instantiate a new PDFTableStripper object.
|
||||||
*
|
*
|
||||||
* @param document
|
|
||||||
* @throws IOException If there is an error loading the properties.
|
* @throws IOException If there is an error loading the properties.
|
||||||
*/
|
*/
|
||||||
public PDFTableStripper() throws IOException {
|
public PDFTableStripper() throws IOException {
|
||||||
|
@ -52,23 +52,23 @@ public class AccountWebController {
|
|||||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
||||||
if (oauth != null) {
|
if (oauth != null) {
|
||||||
if (oauth.isSettingsValid()) {
|
if (oauth.isSettingsValid()) {
|
||||||
providerList.put("oidc", "OpenID Connect");
|
providerList.put("oidc", oauth.getProvider());
|
||||||
}
|
}
|
||||||
Client client = oauth.getClient();
|
Client client = oauth.getClient();
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
GoogleProvider google = client.getGoogle();
|
GoogleProvider google = client.getGoogle();
|
||||||
if (google.isSettingsValid()) {
|
if (google.isSettingsValid()) {
|
||||||
providerList.put("google", "Google");
|
providerList.put(google.getName(), google.getClientName());
|
||||||
}
|
}
|
||||||
|
|
||||||
GithubProvider github = client.getGithub();
|
GithubProvider github = client.getGithub();
|
||||||
if (github.isSettingsValid()) {
|
if (github.isSettingsValid()) {
|
||||||
providerList.put("github", "Github");
|
providerList.put(github.getName(), github.getClientName());
|
||||||
}
|
}
|
||||||
|
|
||||||
KeycloakProvider keycloak = client.getKeycloak();
|
KeycloakProvider keycloak = client.getKeycloak();
|
||||||
if (keycloak.isSettingsValid()) {
|
if (keycloak.isSettingsValid()) {
|
||||||
providerList.put("keycloak", "Keycloak");
|
providerList.put(keycloak.getName(), keycloak.getClientName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,8 +262,7 @@ public class AccountWebController {
|
|||||||
userRepository.findByUsernameIgnoreCase(
|
userRepository.findByUsernameIgnoreCase(
|
||||||
username); // Assuming findByUsername method exists
|
username); // Assuming findByUsername method exists
|
||||||
if (!user.isPresent()) {
|
if (!user.isPresent()) {
|
||||||
// Handle error appropriately
|
return "redirect:/error";
|
||||||
return "redirect:/error"; // Example redirection in case of error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert settings map to JSON string
|
// Convert settings map to JSON string
|
||||||
@ -273,8 +272,8 @@ public class AccountWebController {
|
|||||||
settingsJson = objectMapper.writeValueAsString(user.get().getSettings());
|
settingsJson = objectMapper.writeValueAsString(user.get().getSettings());
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
// Handle JSON conversion error
|
// Handle JSON conversion error
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
return "redirect:/error"; // Example redirection in case of error
|
return "redirect:/error";
|
||||||
}
|
}
|
||||||
|
|
||||||
String messageType = request.getParameter("messageType");
|
String messageType = request.getParameter("messageType");
|
||||||
|
@ -15,6 +15,8 @@ import java.util.Objects;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
@ -33,6 +35,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
@Tag(name = "General", description = "General APIs")
|
@Tag(name = "General", description = "General APIs")
|
||||||
public class GeneralWebController {
|
public class GeneralWebController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GeneralWebController.class);
|
||||||
|
|
||||||
@GetMapping("/pipeline")
|
@GetMapping("/pipeline")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String pipelineForm(Model model) {
|
public String pipelineForm(Model model) {
|
||||||
@ -74,7 +78,7 @@ public class GeneralWebController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pipelineConfigsWithNames.size() == 0) {
|
if (pipelineConfigsWithNames.size() == 0) {
|
||||||
|
@ -6,6 +6,8 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@ -26,6 +28,8 @@ import stirling.software.SPDF.model.Dependency;
|
|||||||
@Controller
|
@Controller
|
||||||
public class HomeWebController {
|
public class HomeWebController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(HomeWebController.class);
|
||||||
|
|
||||||
@GetMapping("/about")
|
@GetMapping("/about")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String gameForm(Model model) {
|
public String gameForm(Model model) {
|
||||||
@ -46,7 +50,7 @@ public class HomeWebController {
|
|||||||
mapper.readValue(json, new TypeReference<Map<String, List<Dependency>>>() {});
|
mapper.readValue(json, new TypeReference<Map<String, List<Dependency>>>() {});
|
||||||
model.addAttribute("dependencies", data.get("dependencies"));
|
model.addAttribute("dependencies", data.get("dependencies"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
return "licenses";
|
return "licenses";
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ public class ApplicationProperties {
|
|||||||
private KeycloakProvider keycloak = new KeycloakProvider();
|
private KeycloakProvider keycloak = new KeycloakProvider();
|
||||||
|
|
||||||
public Provider get(String registrationId) throws Exception {
|
public Provider get(String registrationId) throws Exception {
|
||||||
switch (registrationId) {
|
switch (registrationId.toLowerCase()) {
|
||||||
case "google":
|
case "google":
|
||||||
return getGoogle();
|
return getGoogle();
|
||||||
case "github":
|
case "github":
|
||||||
@ -455,6 +455,7 @@ public class ApplicationProperties {
|
|||||||
@Override
|
@Override
|
||||||
public Collection<String> getScopes() {
|
public Collection<String> getScopes() {
|
||||||
if (scopes == null || scopes.isEmpty()) {
|
if (scopes == null || scopes.isEmpty()) {
|
||||||
|
scopes = new ArrayList<>();
|
||||||
scopes.add("https://www.googleapis.com/auth/userinfo.email");
|
scopes.add("https://www.googleapis.com/auth/userinfo.email");
|
||||||
scopes.add("https://www.googleapis.com/auth/userinfo.profile");
|
scopes.add("https://www.googleapis.com/auth/userinfo.profile");
|
||||||
}
|
}
|
||||||
@ -495,6 +496,11 @@ public class ApplicationProperties {
|
|||||||
return "google";
|
return "google";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClientName() {
|
||||||
|
return "Google";
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSettingsValid() {
|
public boolean isSettingsValid() {
|
||||||
return super.isValid(this.getClientId(), "clientId")
|
return super.isValid(this.getClientId(), "clientId")
|
||||||
&& super.isValid(this.getClientSecret(), "clientSecret")
|
&& super.isValid(this.getClientSecret(), "clientSecret")
|
||||||
@ -555,6 +561,7 @@ public class ApplicationProperties {
|
|||||||
|
|
||||||
public Collection<String> getScopes() {
|
public Collection<String> getScopes() {
|
||||||
if (scopes == null || scopes.isEmpty()) {
|
if (scopes == null || scopes.isEmpty()) {
|
||||||
|
scopes = new ArrayList<>();
|
||||||
scopes.add("read:user");
|
scopes.add("read:user");
|
||||||
}
|
}
|
||||||
return scopes;
|
return scopes;
|
||||||
@ -594,6 +601,11 @@ public class ApplicationProperties {
|
|||||||
return "github";
|
return "github";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClientName() {
|
||||||
|
return "GitHub";
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSettingsValid() {
|
public boolean isSettingsValid() {
|
||||||
return super.isValid(this.getClientId(), "clientId")
|
return super.isValid(this.getClientId(), "clientId")
|
||||||
&& super.isValid(this.getClientSecret(), "clientSecret")
|
&& super.isValid(this.getClientSecret(), "clientSecret")
|
||||||
@ -642,7 +654,7 @@ public class ApplicationProperties {
|
|||||||
@Override
|
@Override
|
||||||
public Collection<String> getScopes() {
|
public Collection<String> getScopes() {
|
||||||
if (scopes == null || scopes.isEmpty()) {
|
if (scopes == null || scopes.isEmpty()) {
|
||||||
scopes.add("openid");
|
scopes = new ArrayList<>();
|
||||||
scopes.add("profile");
|
scopes.add("profile");
|
||||||
scopes.add("email");
|
scopes.add("email");
|
||||||
}
|
}
|
||||||
@ -684,6 +696,11 @@ public class ApplicationProperties {
|
|||||||
return "keycloak";
|
return "keycloak";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClientName() {
|
||||||
|
return "Keycloak";
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSettingsValid() {
|
public boolean isSettingsValid() {
|
||||||
return isValid(this.getIssuer(), "issuer")
|
return isValid(this.getIssuer(), "issuer")
|
||||||
&& isValid(this.getClientId(), "clientId")
|
&& isValid(this.getClientId(), "clientId")
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
|
||||||
|
import org.thymeleaf.templateresource.ITemplateResource;
|
||||||
|
|
||||||
|
public class InputStreamTemplateResource implements ITemplateResource {
|
||||||
|
private InputStream inputStream;
|
||||||
|
private String characterEncoding;
|
||||||
|
|
||||||
|
public InputStreamTemplateResource(InputStream inputStream, String characterEncoding) {
|
||||||
|
this.inputStream = inputStream;
|
||||||
|
this.characterEncoding = characterEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Reader reader() throws IOException {
|
||||||
|
return new InputStreamReader(inputStream, characterEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ITemplateResource relative(String relativeLocation) {
|
||||||
|
// Implement logic for relative resources, if needed
|
||||||
|
throw new UnsupportedOperationException("Relative resources not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "InputStream resource [Stream]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBaseName() {
|
||||||
|
return "streamResource";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -4,11 +4,16 @@ import java.util.Collection;
|
|||||||
|
|
||||||
public class Provider implements ProviderInterface {
|
public class Provider implements ProviderInterface {
|
||||||
private String name;
|
private String name;
|
||||||
|
private String clientName;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getClientName() {
|
||||||
|
return clientName;
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean isValid(String value, String name) {
|
protected boolean isValid(String value, String name) {
|
||||||
if (value != null && !value.trim().isEmpty()) {
|
if (value != null && !value.trim().isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -5,6 +5,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Hidden;
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
@ -19,6 +21,8 @@ import stirling.software.SPDF.utils.GeneralUtils;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class PDFWithPageNums extends PDFFile {
|
public class PDFWithPageNums extends PDFFile {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PDFWithPageNums.class);
|
||||||
|
|
||||||
@Schema(
|
@Schema(
|
||||||
description =
|
description =
|
||||||
"The pages to select, Supports ranges (e.g., '1,3,5-9'), or 'all' or functions in the format 'an+b' where 'a' is the multiplier of the page number 'n', and 'b' is a constant (e.g., '2n+1', '3n', '6n-5')\"")
|
"The pages to select, Supports ranges (e.g., '1,3,5-9'), or 'all' or functions in the format 'an+b' where 'a' is the multiplier of the page number 'n', and 'b' is a constant (e.g., '2n+1', '3n', '6n-5')\"")
|
||||||
@ -31,7 +35,7 @@ public class PDFWithPageNums extends PDFFile {
|
|||||||
pageCount = Loader.loadPDF(getFileInput().getBytes()).getNumberOfPages();
|
pageCount = Loader.loadPDF(getFileInput().getBytes()).getNumberOfPages();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
|
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ public class FileToPdf {
|
|||||||
command.add("--paper-size");
|
command.add("--paper-size");
|
||||||
command.add("a4");
|
command.add("a4");
|
||||||
|
|
||||||
if (request.getZoom() != 1.0) {
|
if (request != null && request.getZoom() != 1.0) {
|
||||||
// Create a temporary CSS file
|
// Create a temporary CSS file
|
||||||
File tempCssFile = Files.createTempFile("customStyle", ".css").toFile();
|
File tempCssFile = Files.createTempFile("customStyle", ".css").toFile();
|
||||||
try (FileWriter writer = new FileWriter(tempCssFile)) {
|
try (FileWriter writer = new FileWriter(tempCssFile)) {
|
||||||
|
@ -14,6 +14,8 @@ import java.nio.file.attribute.BasicFileAttributes;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.fathzer.soft.javaluator.DoubleEvaluator;
|
import com.fathzer.soft.javaluator.DoubleEvaluator;
|
||||||
@ -23,6 +25,8 @@ import io.github.pixee.security.Urls;
|
|||||||
|
|
||||||
public class GeneralUtils {
|
public class GeneralUtils {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GeneralUtils.class);
|
||||||
|
|
||||||
public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
|
public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
|
||||||
File tempFile = Files.createTempFile("temp", null).toFile();
|
File tempFile = Files.createTempFile("temp", null).toFile();
|
||||||
try (FileOutputStream os = new FileOutputStream(tempFile)) {
|
try (FileOutputStream os = new FileOutputStream(tempFile)) {
|
||||||
@ -234,7 +238,7 @@ public class GeneralUtils {
|
|||||||
try {
|
try {
|
||||||
Files.createDirectories(folder);
|
Files.createDirectories(folder);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import java.util.zip.ZipOutputStream;
|
|||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@ -24,6 +26,7 @@ import io.github.pixee.security.Filenames;
|
|||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
|
|
||||||
public class PDFToFile {
|
public class PDFToFile {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PDFToFile.class);
|
||||||
|
|
||||||
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
|
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
@ -67,18 +70,20 @@ public class PDFToFile {
|
|||||||
// Return output files in a ZIP archive
|
// Return output files in a ZIP archive
|
||||||
fileName = pdfBaseName + "ToHtml.zip";
|
fileName = pdfBaseName + "ToHtml.zip";
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);
|
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
|
||||||
|
for (File outputFile : outputFiles) {
|
||||||
for (File outputFile : outputFiles) {
|
ZipEntry entry = new ZipEntry(outputFile.getName());
|
||||||
ZipEntry entry = new ZipEntry(outputFile.getName());
|
zipOutputStream.putNextEntry(entry);
|
||||||
zipOutputStream.putNextEntry(entry);
|
try (FileInputStream fis = new FileInputStream(outputFile)) {
|
||||||
FileInputStream fis = new FileInputStream(outputFile);
|
IOUtils.copy(fis, zipOutputStream);
|
||||||
IOUtils.copy(fis, zipOutputStream);
|
} catch (IOException e) {
|
||||||
fis.close();
|
logger.error("Exception writing zip entry", e);
|
||||||
zipOutputStream.closeEntry();
|
}
|
||||||
|
zipOutputStream.closeEntry();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Exception writing zip", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
zipOutputStream.close();
|
|
||||||
fileBytes = byteArrayOutputStream.toByteArray();
|
fileBytes = byteArrayOutputStream.toByteArray();
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
@ -160,18 +165,22 @@ public class PDFToFile {
|
|||||||
// Return output files in a ZIP archive
|
// Return output files in a ZIP archive
|
||||||
fileName = pdfBaseName + "To" + outputFormat + ".zip";
|
fileName = pdfBaseName + "To" + outputFormat + ".zip";
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);
|
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
|
||||||
|
for (File outputFile : outputFiles) {
|
||||||
|
ZipEntry entry = new ZipEntry(outputFile.getName());
|
||||||
|
zipOutputStream.putNextEntry(entry);
|
||||||
|
try (FileInputStream fis = new FileInputStream(outputFile)) {
|
||||||
|
IOUtils.copy(fis, zipOutputStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Exception writing zip entry", e);
|
||||||
|
}
|
||||||
|
|
||||||
for (File outputFile : outputFiles) {
|
zipOutputStream.closeEntry();
|
||||||
ZipEntry entry = new ZipEntry(outputFile.getName());
|
}
|
||||||
zipOutputStream.putNextEntry(entry);
|
} catch (IOException e) {
|
||||||
FileInputStream fis = new FileInputStream(outputFile);
|
logger.error("Exception writing zip", e);
|
||||||
IOUtils.copy(fis, zipOutputStream);
|
|
||||||
fis.close();
|
|
||||||
zipOutputStream.closeEntry();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zipOutputStream.close();
|
|
||||||
fileBytes = byteArrayOutputStream.toByteArray();
|
fileBytes = byteArrayOutputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ public class ProcessExecutor {
|
|||||||
logger.warn(
|
logger.warn(
|
||||||
"Error reader thread was interrupted due to timeout.");
|
"Error reader thread was interrupted due to timeout.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ public class ProcessExecutor {
|
|||||||
logger.warn(
|
logger.warn(
|
||||||
"Error reader thread was interrupted due to timeout.");
|
"Error reader thread was interrupted due to timeout.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ bored=Nudíte se při čekání?
|
|||||||
alphabet=Abeceda
|
alphabet=Abeceda
|
||||||
downloadPdf=Stáhnout PDF
|
downloadPdf=Stáhnout PDF
|
||||||
text=Text
|
text=Text
|
||||||
font=Font
|
font=Písmo
|
||||||
selectFillter=-- Vyberte --
|
selectFillter=-- Vyberte --
|
||||||
pageNum=Číslo stránky
|
pageNum=Číslo stránky
|
||||||
sizes.small=Malé
|
sizes.small=Malé
|
||||||
|
@ -71,7 +71,7 @@ visitGithub=GitHub-Repository besuchen
|
|||||||
donate=Spenden
|
donate=Spenden
|
||||||
color=Farbe
|
color=Farbe
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Die Info
|
info=Informationen
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -660,10 +660,10 @@ certSign.submit=PDF signieren
|
|||||||
|
|
||||||
|
|
||||||
#removeCertSign
|
#removeCertSign
|
||||||
removeCertSign.title=Remove Certificate Signature
|
removeCertSign.title=Zertifikatsignatur entfernen
|
||||||
removeCertSign.header=Remove the digital certificate from the PDF
|
removeCertSign.header=Digitales Zertifikat aus dem PDF entfernen
|
||||||
removeCertSign.selectPDF=Select a PDF file:
|
removeCertSign.selectPDF=PDF-Datei auswählen:
|
||||||
removeCertSign.submit=Remove Signature
|
removeCertSign.submit=Signatur entfernen
|
||||||
|
|
||||||
|
|
||||||
#removeBlanks
|
#removeBlanks
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
###########
|
###########
|
||||||
# Generic #
|
# Generic #
|
||||||
###########
|
###########
|
||||||
# the direction that the language is written (ltr=left to right, rtl = right to left)
|
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=Odaberi PDF(ove)
|
pdfPrompt=Odaberi PDF(ove)
|
||||||
@ -331,9 +331,10 @@ compare.tags=razlikovati,kontrast,izmjene,analiza
|
|||||||
home.certSign.title=Potpišite s certifikatom
|
home.certSign.title=Potpišite s certifikatom
|
||||||
home.certSign.desc=Potpisuje PDF s certifikatom/ključem (PEM/P12)
|
home.certSign.desc=Potpisuje PDF s certifikatom/ključem (PEM/P12)
|
||||||
certSign.tags=autentifikacija,PEM,P12,zvanično,šifriranje
|
certSign.tags=autentifikacija,PEM,P12,zvanično,šifriranje
|
||||||
# home.removeCertSign.title=Remove Certificate Sign
|
|
||||||
# home.removeCertSign.desc=Remove certificate signature from PDF
|
home.removeCertSign.title=Remove Certificate Sign
|
||||||
# removeCertSign.tags=authenticate,PEM,P12,official,decrypt
|
home.removeCertSign.desc=Remove certificate signature from PDF
|
||||||
|
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
|
||||||
|
|
||||||
home.pageLayout.title=Izgled s više stranica
|
home.pageLayout.title=Izgled s više stranica
|
||||||
home.pageLayout.desc=Spojite više stranica PDF dokumenta u jednu stranicu
|
home.pageLayout.desc=Spojite više stranica PDF dokumenta u jednu stranicu
|
||||||
@ -656,10 +657,13 @@ certSign.reason=Razlog
|
|||||||
certSign.location=Mjesto
|
certSign.location=Mjesto
|
||||||
certSign.name=Ime
|
certSign.name=Ime
|
||||||
certSign.submit=Potpiši PDF
|
certSign.submit=Potpiši PDF
|
||||||
# removeCertSign.title=Remove Certificate Signature
|
|
||||||
# removeCertSign.header=Remove the digital certificate from the PDF
|
|
||||||
# removeCertSign.selectPDF=Select a PDF file:
|
#removeCertSign
|
||||||
# removeCertSign.submit=Remove Signature
|
removeCertSign.title=Remove Certificate Signature
|
||||||
|
removeCertSign.header=Remove the digital certificate from the PDF
|
||||||
|
removeCertSign.selectPDF=Select a PDF file:
|
||||||
|
removeCertSign.submit=Remove Signature
|
||||||
|
|
||||||
|
|
||||||
#removeBlanks
|
#removeBlanks
|
||||||
|
1093
src/main/resources/messages_no_NB.properties
Normal file
1093
src/main/resources/messages_no_NB.properties
Normal file
File diff suppressed because it is too large
Load Diff
7
src/main/resources/static/images/flags/no.svg
Normal file
7
src/main/resources/static/images/flags/no.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-no" viewBox="0 0 640 480">
|
||||||
|
<path fill="#ed2939" d="M0 0h640v480H0z"/>
|
||||||
|
<path fill="#fff" d="M180 0h120v480H180z"/>
|
||||||
|
<path fill="#fff" d="M0 180h640v120H0z"/>
|
||||||
|
<path fill="#002664" d="M210 0h60v480h-60z"/>
|
||||||
|
<path fill="#002664" d="M0 210h640v60H0z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 318 B |
@ -34,7 +34,7 @@
|
|||||||
<td th:text="#{${user.roleName}}"></td>
|
<td th:text="#{${user.roleName}}"></td>
|
||||||
<td>
|
<td>
|
||||||
<form th:if="${user.username != currentUsername}" th:action="@{'/api/v1/user/admin/deleteUser/' + ${user.username}}" method="post">
|
<form th:if="${user.username != currentUsername}" th:action="@{'/api/v1/user/admin/deleteUser/' + ${user.username}}" method="post">
|
||||||
<button type="submit" th:text="#{delete}">Delete</button>
|
<button class="btn btn-danger" type="submit" th:text="#{delete}">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
<td th:text="${user.authenticationType}"></td>
|
<td th:text="${user.authenticationType}"></td>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<span th:text="#{${addMessage}}">Default message if not found</span>
|
<span th:text="#{${addMessage}}">Default message if not found</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-outline-info" data-toggle="tooltip" data-placement="auto" th:title="#{adminUserSettings.usernameInfo}" th:text="#{help}">Help</button>
|
<button class="btn btn-outline-info" data-toggle="tooltip" data-placement="auto" th:title="#{adminUserSettings.usernameInfo}" th:text="#{help}">Help</button>
|
||||||
<form id="formsaveuser" action="/api/v1/user/admin/saveUser" method="post">
|
<form id="formsaveuser" th:action="@{/api/v1/user/admin/saveUser}" method="post">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="username" th:text="#{username}">Username</label>
|
<label for="username" th:text="#{username}">Username</label>
|
||||||
<input type="text" class="form-control" name="username" id="username" th:title="#{adminUserSettings.usernameInfo}" required>
|
<input type="text" class="form-control" name="username" id="username" th:title="#{adminUserSettings.usernameInfo}" required>
|
||||||
@ -78,7 +78,7 @@
|
|||||||
<div th:if="${changeMessage}" class="alert alert-danger">
|
<div th:if="${changeMessage}" class="alert alert-danger">
|
||||||
<span th:text="#{${changeMessage}}">Default message if not found</span>
|
<span th:text="#{${changeMessage}}">Default message if not found</span>
|
||||||
</div>
|
</div>
|
||||||
<form action="/api/v1/user/admin/changeRole" method="post">
|
<form th:action="@{/api/v1/user/admin/changeRole}" method="post">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="username" th:text="#{username}">Username</label>
|
<label for="username" th:text="#{username}">Username</label>
|
||||||
<select name="username" class="form-control" required>
|
<select name="username" class="form-control" required>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<span class="material-symbols-rounded tool-header-icon organize">crop</span>
|
<span class="material-symbols-rounded tool-header-icon organize">crop</span>
|
||||||
<span class="tool-header-text" th:text="#{crop.header}"></span>
|
<span class="tool-header-text" th:text="#{crop.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form id="cropForm" action="/api/v1/general/crop" method="post" enctype="multipart/form-data">
|
<form id="cropForm" th:action="@{/api/v1/general/crop}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<input id="x" type="hidden" name="x">
|
<input id="x" type="hidden" name="x">
|
||||||
<input id="y" type="hidden" name="y">
|
<input id="y" type="hidden" name="y">
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" class="btn btn-primary" target="_blank" th:text="#{error.github}"></a>
|
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" class="btn btn-primary" target="_blank" th:text="#{error.github}"></a>
|
||||||
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a>
|
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a>
|
||||||
</div>
|
</div>
|
||||||
<a href="/" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a>
|
<a th:href="@{/}" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,4 +30,5 @@
|
|||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="uk_UA"> <img src="images/flags/ua.svg" alt="icon" width="20" height="15"> Українська</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="uk_UA"> <img src="images/flags/ua.svg" alt="icon" width="20" height="15"> Українська</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="cs_CZ"> <img src="images/flags/cz.svg" alt="icon" width="20" height="15"> Česky</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="cs_CZ"> <img src="images/flags/cz.svg" alt="icon" width="20" height="15"> Česky</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="hr_HR"> <img src="images/flags/hr.svg" alt="icon" width="20" height="15"> Hrvatski</a>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="hr_HR"> <img src="images/flags/hr.svg" alt="icon" width="20" height="15"> Hrvatski</a>
|
||||||
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="no_NB"> <img src="images/flags/no.svg" alt="icon" width="20" height="15"> Norsk</a>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<script src="js/githubVersion.js"></script>
|
<script src="js/githubVersion.js"></script>
|
||||||
<nav class="navbar navbar-expand-lg">
|
<nav class="navbar navbar-expand-lg">
|
||||||
<div class="container ">
|
<div class="container ">
|
||||||
<a class="navbar-brand" href="/" style="display: flex;">
|
<a class="navbar-brand" th:href="@{/}" style="display: flex;">
|
||||||
<img class="main-icon" src="favicon.svg" alt="icon">
|
<img class="main-icon" src="favicon.svg" alt="icon">
|
||||||
<span class="icon-text" th:text="${@navBarText}"></span>
|
<span class="icon-text" th:text="${@navBarText}"></span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/flatten}" id="pdfForm" class="mb-3">
|
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/flatten}" id="pdfForm" class="mb-3">
|
||||||
<div class="custom-file">
|
<div class="custom-file">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check ms-3">
|
<div class="form-check ms-3">
|
||||||
<input type="checkbox" id="flattenOnlyForms" name="flattenOnlyForms">
|
<input type="checkbox" id="flattenOnlyForms" name="flattenOnlyForms">
|
||||||
@ -35,4 +35,4 @@
|
|||||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -298,7 +298,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||||||
<input type="number" id="pageNumber" class="toolbarField" title="Page" value="1" min="1" tabindex="15" data-l10n-id="pdfjs-page-input" autocomplete="off">
|
<input type="number" id="pageNumber" class="toolbarField" title="Page" value="1" min="1" tabindex="15" data-l10n-id="pdfjs-page-input" autocomplete="off">
|
||||||
</span>
|
</span>
|
||||||
<span id="numPages" class="toolbarLabel"></span>
|
<span id="numPages" class="toolbarLabel"></span>
|
||||||
<a class="navbar-brand hiddenMediumView" href="/" tabindex="16" >
|
<a class="navbar-brand hiddenMediumView" th:href="@{/}" tabindex="16" >
|
||||||
<img class="main-icon" src="favicon.svg" alt="icon" style="max-height: 1.6rem; width: auto;">
|
<img class="main-icon" src="favicon.svg" alt="icon" style="max-height: 1.6rem; width: auto;">
|
||||||
<span class="icon-text" style="color: #ffffff;" th:text="${@appName}">Stirling PDF</span>
|
<span class="icon-text" style="color: #ffffff;" th:text="${@appName}">Stirling PDF</span>
|
||||||
</a>
|
</a>
|
||||||
@ -308,7 +308,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||||||
<button id="editorHighlight" class="toolbarButton" hidden="true" disabled="disabled" title="Highlight" role="radio" aria-checked="false" aria-controls="editorHighlightParamsToolbar" tabindex="31" data-l10n-id="pdfjs-editor-highlight-button">
|
<button id="editorHighlight" class="toolbarButton" hidden="true" disabled="disabled" title="Highlight" role="radio" aria-checked="false" aria-controls="editorHighlightParamsToolbar" tabindex="31" data-l10n-id="pdfjs-editor-highlight-button">
|
||||||
<span data-l10n-id="pdfjs-editor-highlight-button-label">Highlight</span>
|
<span data-l10n-id="pdfjs-editor-highlight-button-label">Highlight</span>
|
||||||
</button>
|
</button>
|
||||||
<a id="backToHome" class="toolbarButton hiddenMediumView" title="Back to Main Page" role="radio" aria-checked="false" tabindex="32" href="/">
|
<a id="backToHome" class="toolbarButton hiddenMediumView" title="Back to Main Page" role="radio" aria-checked="false" tabindex="32" th:href="@{/}">
|
||||||
<span data-l10n-id="pdfjs-open-file-button-label">Back to Main Page</span>
|
<span data-l10n-id="pdfjs-open-file-button-label">Back to Main Page</span>
|
||||||
</a>
|
</a>
|
||||||
<button id="openFile" class="toolbarButton hiddenMediumView" title="Open File" role="radio" aria-checked="false" tabindex="33" data-l10n-id="pdfjs-open-file-button">
|
<button id="openFile" class="toolbarButton hiddenMediumView" title="Open File" role="radio" aria-checked="false" tabindex="33" data-l10n-id="pdfjs-open-file-button">
|
||||||
|
Loading…
Reference in New Issue
Block a user