Compare commits
16 Commits
multipleFi
...
v0.28.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d75e4f1318 | ||
|
|
4088132597 | ||
|
|
7b9d419267 | ||
|
|
9b710b489e | ||
|
|
e2ff418c89 | ||
|
|
be006f08a6 | ||
|
|
b007c805bf | ||
|
|
24be10eed4 | ||
|
|
0854a1d26e | ||
|
|
33c7bb7e13 | ||
|
|
cdf31622e2 | ||
|
|
c7e5987342 | ||
|
|
d3ef335c24 | ||
|
|
b23784f598 | ||
|
|
90cbcde029 | ||
|
|
382edc01f8 |
2
.github/ISSUE_TEMPLATE/1-bug.yml
vendored
2
.github/ISSUE_TEMPLATE/1-bug.yml
vendored
@@ -22,8 +22,6 @@ body:
|
|||||||
- Docker ultra lite
|
- Docker ultra lite
|
||||||
- Docker fat
|
- Docker fat
|
||||||
- Local Installation
|
- Local Installation
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: problem
|
id: problem
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ The Current list of settings is
|
|||||||
security:
|
security:
|
||||||
enableLogin: false # set to 'true' to enable login
|
enableLogin: false # set to 'true' to enable login
|
||||||
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
|
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
|
||||||
loginAttemptCount: 5 # lock user account after 5 tries
|
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
|
||||||
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
||||||
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
|
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
|
||||||
initialLogin:
|
initialLogin:
|
||||||
|
|||||||
60
build.gradle
60
build.gradle
@@ -7,6 +7,7 @@ plugins {
|
|||||||
id "edu.sc.seis.launch4j" version "3.0.6"
|
id "edu.sc.seis.launch4j" version "3.0.6"
|
||||||
id "com.diffplug.spotless" version "6.25.0"
|
id "com.diffplug.spotless" version "6.25.0"
|
||||||
id "com.github.jk1.dependency-license-report" version "2.9"
|
id "com.github.jk1.dependency-license-report" version "2.9"
|
||||||
|
//id "nebula.lint" version "19.0.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
import com.github.jk1.license.render.*
|
import com.github.jk1.license.render.*
|
||||||
@@ -21,7 +22,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "stirling.software"
|
group = "stirling.software"
|
||||||
version = "0.28.2"
|
version = "0.28.3"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
// 17 is lowest but we support and recommend 21
|
// 17 is lowest but we support and recommend 21
|
||||||
@@ -100,14 +101,20 @@ spotless {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//gradleLint {
|
||||||
|
// rules=['unused-dependency']
|
||||||
|
// }
|
||||||
tasks.wrapper {
|
tasks.wrapper {
|
||||||
gradleVersion = "8.7"
|
gradleVersion = "8.7"
|
||||||
}
|
}
|
||||||
|
//tasks.withType(JavaCompile) {
|
||||||
|
// options.compilerArgs << "-Xlint:deprecation"
|
||||||
|
//}
|
||||||
|
configurations.all {
|
||||||
|
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
||||||
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
//security updates
|
//security updates
|
||||||
implementation "ch.qos.logback:logback-classic:$logbackVersion"
|
|
||||||
implementation "ch.qos.logback:logback-core:$logbackVersion"
|
|
||||||
implementation "org.springframework:spring-webmvc:6.1.9"
|
implementation "org.springframework:spring-webmvc:6.1.9"
|
||||||
|
|
||||||
implementation("io.github.pixee:java-security-toolkit:1.2.0")
|
implementation("io.github.pixee:java-security-toolkit:1.2.0")
|
||||||
@@ -116,21 +123,19 @@ dependencies {
|
|||||||
implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4'
|
implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4'
|
||||||
|
|
||||||
// Exclude Tomcat and include Jetty
|
// Exclude Tomcat and include Jetty
|
||||||
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion") {
|
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
||||||
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
|
|
||||||
}
|
|
||||||
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
|
||||||
|
|
||||||
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
||||||
|
|
||||||
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
|
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
|
||||||
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
|
||||||
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE"
|
runtimeOnly "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
||||||
|
|
||||||
//2.2.x requires rebuild of DB file.. need migration path
|
//2.2.x requires rebuild of DB file.. need migration path
|
||||||
implementation "com.h2database:h2:2.1.214"
|
runtimeOnly "com.h2database:h2:2.1.214"
|
||||||
// implementation "com.h2database:h2:2.2.224"
|
// implementation "com.h2database:h2:2.2.224"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,28 +143,27 @@ dependencies {
|
|||||||
|
|
||||||
// Batik
|
// Batik
|
||||||
implementation "org.apache.xmlgraphics:batik-all:1.17"
|
implementation "org.apache.xmlgraphics:batik-all:1.17"
|
||||||
|
|
||||||
// TwelveMonkeys
|
// TwelveMonkeys
|
||||||
implementation "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion"
|
runtimeOnly "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion"
|
||||||
implementation "com.twelvemonkeys.imageio:imageio-bmp:$imageioVersion"
|
runtimeOnly "com.twelvemonkeys.imageio:imageio-bmp:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-hdr:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-hdr:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-icns:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-icns:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-iff:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-iff:$imageioVersion"
|
||||||
implementation "com.twelvemonkeys.imageio:imageio-jpeg:$imageioVersion"
|
runtimeOnly "com.twelvemonkeys.imageio:imageio-jpeg:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-psd:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-psd:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-sgi:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-sgi:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-tga:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-tga:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-thumbsdb:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-thumbsdb:$imageioVersion"
|
||||||
implementation "com.twelvemonkeys.imageio:imageio-tiff:$imageioVersion"
|
runtimeOnly "com.twelvemonkeys.imageio:imageio-tiff:$imageioVersion"
|
||||||
implementation "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
|
runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
|
||||||
// implementation "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
|
// runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
|
||||||
|
|
||||||
implementation "commons-io:commons-io:2.16.1"
|
implementation "commons-io:commons-io:2.16.1"
|
||||||
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
|
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
|
||||||
|
|
||||||
//general PDF
|
//general PDF
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/com.opencsv/opencsv
|
// https://mvnrepository.com/artifact/com.opencsv/opencsv
|
||||||
@@ -196,7 +200,7 @@ dependencies {
|
|||||||
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
||||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
||||||
|
|
||||||
testImplementation 'org.mockito:mockito-inline:5.2.0'
|
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
appVersion: 0.28.2
|
appVersion: 0.28.3
|
||||||
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
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public class SPdfApplication {
|
|||||||
public static void main(String[] args) throws IOException, InterruptedException {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
|
|
||||||
SpringApplication app = new SpringApplication(SPdfApplication.class);
|
SpringApplication app = new SpringApplication(SPdfApplication.class);
|
||||||
|
app.setAdditionalProfiles("default");
|
||||||
app.addInitializers(new ConfigInitializer());
|
app.addInitializers(new ConfigInitializer());
|
||||||
Map<String, String> propertyFiles = new HashMap<>();
|
Map<String, String> propertyFiles = new HashMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -126,13 +126,12 @@ public class AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "directoryFilter")
|
@Bean(name = "directoryFilter")
|
||||||
public Predicate<Path> processPDFOnlyFilter() {
|
public Predicate<Path> processOnlyFiles() {
|
||||||
return path -> {
|
return path -> {
|
||||||
if (Files.isDirectory(path)) {
|
if (Files.isDirectory(path)) {
|
||||||
return !path.toString().contains("processing");
|
return !path.toString().contains("processing");
|
||||||
} else {
|
} else {
|
||||||
String fileName = path.getFileName().toString();
|
return true;
|
||||||
return fileName.endsWith(".pdf");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,21 +7,28 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.AttemptCounter;
|
import stirling.software.SPDF.model.AttemptCounter;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class LoginAttemptService {
|
public class LoginAttemptService {
|
||||||
|
|
||||||
@Autowired ApplicationProperties applicationProperties;
|
@Autowired private ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
private int MAX_ATTEMPT;
|
private int MAX_ATTEMPT;
|
||||||
private long ATTEMPT_INCREMENT_TIME;
|
private long ATTEMPT_INCREMENT_TIME;
|
||||||
private ConcurrentHashMap<String, AttemptCounter> attemptsCache;
|
private ConcurrentHashMap<String, AttemptCounter> attemptsCache;
|
||||||
|
private boolean isBlockedEnabled = true;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
MAX_ATTEMPT = applicationProperties.getSecurity().getLoginAttemptCount();
|
MAX_ATTEMPT = applicationProperties.getSecurity().getLoginAttemptCount();
|
||||||
|
if (MAX_ATTEMPT == -1) {
|
||||||
|
isBlockedEnabled = false;
|
||||||
|
log.info("Login attempt tracking is disabled.");
|
||||||
|
}
|
||||||
ATTEMPT_INCREMENT_TIME =
|
ATTEMPT_INCREMENT_TIME =
|
||||||
TimeUnit.MINUTES.toMillis(
|
TimeUnit.MINUTES.toMillis(
|
||||||
applicationProperties.getSecurity().getLoginResetTimeMinutes());
|
applicationProperties.getSecurity().getLoginResetTimeMinutes());
|
||||||
@@ -29,14 +36,16 @@ public class LoginAttemptService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void loginSucceeded(String key) {
|
public void loginSucceeded(String key) {
|
||||||
if (key == null || key.trim().isEmpty()) {
|
if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
attemptsCache.remove(key.toLowerCase());
|
attemptsCache.remove(key.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loginFailed(String key) {
|
public void loginFailed(String key) {
|
||||||
if (key == null || key.trim().isEmpty()) return;
|
if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
||||||
if (attemptCounter == null) {
|
if (attemptCounter == null) {
|
||||||
@@ -51,7 +60,9 @@ public class LoginAttemptService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBlocked(String key) {
|
public boolean isBlocked(String key) {
|
||||||
if (key == null || key.trim().isEmpty()) return false;
|
if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
||||||
if (attemptCounter == null) {
|
if (attemptCounter == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -61,7 +72,9 @@ public class LoginAttemptService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getRemainingAttempts(String key) {
|
public int getRemainingAttempts(String key) {
|
||||||
if (key == null || key.trim().isEmpty()) return MAX_ATTEMPT;
|
if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
|
||||||
|
return Integer.MAX_VALUE; // Arbitrarily high number if tracking is disabled
|
||||||
|
}
|
||||||
|
|
||||||
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
|
||||||
if (attemptCounter == null) {
|
if (attemptCounter == null) {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
@@ -150,8 +149,7 @@ public class SecurityConfiguration {
|
|||||||
})
|
})
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated())
|
.authenticated());
|
||||||
.authenticationProvider(authenticationProvider());
|
|
||||||
|
|
||||||
// Handle OAUTH2 Logins
|
// Handle OAUTH2 Logins
|
||||||
if (applicationProperties.getSecurity().getOAUTH2() != null
|
if (applicationProperties.getSecurity().getOAUTH2() != null
|
||||||
@@ -379,14 +377,6 @@ public class SecurityConfiguration {
|
|||||||
return new IPRateLimitingFilter(maxRequestsPerIp, maxRequestsPerIp);
|
return new IPRateLimitingFilter(maxRequestsPerIp, maxRequestsPerIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public DaoAuthenticationProvider authenticationProvider() {
|
|
||||||
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
|
|
||||||
authProvider.setUserDetailsService(userDetailsService);
|
|
||||||
authProvider.setPasswordEncoder(passwordEncoder());
|
|
||||||
return authProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PersistentTokenRepository persistentTokenRepository() {
|
public PersistentTokenRepository persistentTokenRepository() {
|
||||||
return new JPATokenRepositoryImpl();
|
return new JPATokenRepositoryImpl();
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
try {
|
try {
|
||||||
// Use API key to authenticate. This requires you to have an authentication
|
// Use API key to authenticate. This requires you to have an authentication
|
||||||
// provider for API keys.
|
// provider for API keys.
|
||||||
Optional<User> user = userService.loadUserByApiKey(apiKey);
|
Optional<User> user = userService.getUserByApiKey(apiKey);
|
||||||
if (!user.isPresent()) {
|
if (!user.isPresent()) {
|
||||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
response.getWriter().write("Invalid API Key.");
|
response.getWriter().write("Invalid API Key.");
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
package stirling.software.SPDF.config.security;
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
@@ -21,8 +13,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import stirling.software.SPDF.config.DatabaseBackupInterface;
|
import stirling.software.SPDF.config.DatabaseBackupInterface;
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||||
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
||||||
@@ -33,6 +23,10 @@ import stirling.software.SPDF.model.User;
|
|||||||
import stirling.software.SPDF.repository.AuthorityRepository;
|
import stirling.software.SPDF.repository.AuthorityRepository;
|
||||||
import stirling.software.SPDF.repository.UserRepository;
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserService implements UserServiceInterface {
|
public class UserService implements UserServiceInterface {
|
||||||
|
|
||||||
@@ -222,7 +216,7 @@ public class UserService implements UserServiceInterface {
|
|||||||
|
|
||||||
public void updateUserSettings(String username, Map<String, String> updates)
|
public void updateUserSettings(String username, Map<String, String> updates)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Optional<User> userOpt = findByUsernameIgnoreCase(username);
|
Optional<User> userOpt = findByUsernameIgnoreCaseWithSettings(username);
|
||||||
if (userOpt.isPresent()) {
|
if (userOpt.isPresent()) {
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
Map<String, String> settingsMap = user.getSettings();
|
Map<String, String> settingsMap = user.getSettings();
|
||||||
@@ -247,6 +241,10 @@ public class UserService implements UserServiceInterface {
|
|||||||
return userRepository.findByUsernameIgnoreCase(username);
|
return userRepository.findByUsernameIgnoreCase(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<User> findByUsernameIgnoreCaseWithSettings(String username) {
|
||||||
|
return userRepository.findByUsernameIgnoreCaseWithSettings(username);
|
||||||
|
}
|
||||||
|
|
||||||
public Authority findRole(User user) {
|
public Authority findRole(User user) {
|
||||||
return authorityRepository.findByUserId(user.getId());
|
return authorityRepository.findByUserId(user.getId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class AutoRenameController {
|
|||||||
private static final Logger logger = LoggerFactory.getLogger(AutoRenameController.class);
|
private static final Logger logger = LoggerFactory.getLogger(AutoRenameController.class);
|
||||||
|
|
||||||
private static final float TITLE_FONT_SIZE_THRESHOLD = 20.0f;
|
private static final float TITLE_FONT_SIZE_THRESHOLD = 20.0f;
|
||||||
private static final int LINE_LIMIT = 11;
|
private static final int LINE_LIMIT = 200;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/auto-rename")
|
@PostMapping(consumes = "multipart/form-data", value = "/auto-rename")
|
||||||
@Operation(
|
@Operation(
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class ApiDocService {
|
|||||||
|
|
||||||
Map<String, List<String>> outputToFileTypes = new HashMap<>();
|
Map<String, List<String>> outputToFileTypes = new HashMap<>();
|
||||||
|
|
||||||
public List getExtensionTypes(boolean output, String operationName) {
|
public List<String> getExtensionTypes(boolean output, String operationName) {
|
||||||
if (outputToFileTypes.size() == 0) {
|
if (outputToFileTypes.size() == 0) {
|
||||||
outputToFileTypes.put("PDF", Arrays.asList("pdf"));
|
outputToFileTypes.put("PDF", Arrays.asList("pdf"));
|
||||||
outputToFileTypes.put(
|
outputToFileTypes.put(
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
package stirling.software.SPDF.controller.web;
|
package stirling.software.SPDF.controller.web;
|
||||||
|
|
||||||
import java.time.Instant;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import java.time.temporal.ChronoUnit;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import java.util.Date;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import java.util.HashMap;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.Iterator;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@@ -18,27 +13,20 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
|||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.*;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
|
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
|
||||||
import stirling.software.SPDF.model.Authority;
|
|
||||||
import stirling.software.SPDF.model.Role;
|
|
||||||
import stirling.software.SPDF.model.SessionEntity;
|
|
||||||
import stirling.software.SPDF.model.User;
|
|
||||||
import stirling.software.SPDF.model.provider.GithubProvider;
|
import stirling.software.SPDF.model.provider.GithubProvider;
|
||||||
import stirling.software.SPDF.model.provider.GoogleProvider;
|
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||||
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
||||||
import stirling.software.SPDF.repository.UserRepository;
|
import stirling.software.SPDF.repository.UserRepository;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Tag(name = "Account Security", description = "Account Security APIs")
|
@Tag(name = "Account Security", description = "Account Security APIs")
|
||||||
@@ -361,7 +349,7 @@ public class AccountWebController {
|
|||||||
if (username != null) {
|
if (username != null) {
|
||||||
// Fetch user details from the database
|
// Fetch user details from the database
|
||||||
Optional<User> user =
|
Optional<User> user =
|
||||||
userRepository.findByUsernameIgnoreCase(
|
userRepository.findByUsernameIgnoreCaseWithSettings(
|
||||||
username); // Assuming findByUsername method exists
|
username); // Assuming findByUsername method exists
|
||||||
if (!user.isPresent()) {
|
if (!user.isPresent()) {
|
||||||
return "redirect:/error";
|
return "redirect:/error";
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package stirling.software.SPDF.model;
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -7,21 +9,6 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
|
||||||
import jakarta.persistence.CollectionTable;
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.ElementCollection;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.FetchType;
|
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.GenerationType;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.JoinColumn;
|
|
||||||
import jakarta.persistence.Lob;
|
|
||||||
import jakarta.persistence.MapKeyColumn;
|
|
||||||
import jakarta.persistence.OneToMany;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "users")
|
@Table(name = "users")
|
||||||
public class User implements Serializable {
|
public class User implements Serializable {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import lombok.EqualsAndHashCode;
|
|||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
public class UrlToPdfRequest {
|
public class UrlToPdfRequest {
|
||||||
|
|
||||||
@Schema(description = "The input URL to be converted to a PDF file", required = true)
|
@Schema(
|
||||||
|
description = "The input URL to be converted to a PDF file",
|
||||||
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String urlInput;
|
private String urlInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFWithPageNums;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class ContainsTextRequest extends PDFWithPageNums {
|
public class ContainsTextRequest extends PDFWithPageNums {
|
||||||
|
|
||||||
@Schema(description = "The text to check for", required = true)
|
@Schema(description = "The text to check for", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String text;
|
private String text;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFComparison;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class FileSizeRequest extends PDFComparison {
|
public class FileSizeRequest extends PDFComparison {
|
||||||
|
|
||||||
@Schema(description = "File Size", required = true)
|
@Schema(description = "File Size", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String fileSize;
|
private String fileSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFComparison;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class PageRotationRequest extends PDFComparison {
|
public class PageRotationRequest extends PDFComparison {
|
||||||
|
|
||||||
@Schema(description = "Rotation in degrees", required = true)
|
@Schema(description = "Rotation in degrees", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private int rotation;
|
private int rotation;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ import stirling.software.SPDF.model.api.PDFComparison;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class PageSizeRequest extends PDFComparison {
|
public class PageSizeRequest extends PDFComparison {
|
||||||
|
|
||||||
@Schema(description = "Standard Page Size", required = true)
|
@Schema(description = "Standard Page Size", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String standardPageSize;
|
private String standardPageSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ public class OverlayPdfsRequest extends PDFFile {
|
|||||||
@Schema(
|
@Schema(
|
||||||
description =
|
description =
|
||||||
"The mode of overlaying: 'SequentialOverlay' for sequential application, 'InterleavedOverlay' for round-robin application, 'FixedRepeatOverlay' for fixed repetition based on provided counts",
|
"The mode of overlaying: 'SequentialOverlay' for sequential application, 'InterleavedOverlay' for round-robin application, 'FixedRepeatOverlay' for fixed repetition based on provided counts",
|
||||||
required = true)
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String overlayMode;
|
private String overlayMode;
|
||||||
|
|
||||||
@Schema(
|
@Schema(
|
||||||
description =
|
description =
|
||||||
"An array of integers specifying the number of times each corresponding overlay file should be applied in the 'FixedRepeatOverlay' mode. This should match the length of the overlayFiles array.",
|
"An array of integers specifying the number of times each corresponding overlay file should be applied in the 'FixedRepeatOverlay' mode. This should match the length of the overlayFiles array.",
|
||||||
required = false)
|
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||||
private int[] counts;
|
private int[] counts;
|
||||||
|
|
||||||
@Schema(description = "Overlay position 0 is Foregound, 1 is Background")
|
@Schema(description = "Overlay position 0 is Foregound, 1 is Background")
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ public class SplitPdfBySizeOrCountRequest extends PDFFile {
|
|||||||
@Schema(
|
@Schema(
|
||||||
description =
|
description =
|
||||||
"Determines the type of split: 0 for size, 1 for page count, 2 for document count",
|
"Determines the type of split: 0 for size, 1 for page count, 2 for document count",
|
||||||
required = false,
|
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
|
||||||
defaultValue = "0")
|
defaultValue = "0")
|
||||||
private int splitType;
|
private int splitType;
|
||||||
|
|
||||||
@Schema(
|
@Schema(
|
||||||
description =
|
description =
|
||||||
"Value for split: size in MB (e.g., '10MB') or number of pages (e.g., '5')",
|
"Value for split: size in MB (e.g., '10MB') or number of pages (e.g., '5')",
|
||||||
required = false,
|
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
|
||||||
defaultValue = "10MB")
|
defaultValue = "10MB")
|
||||||
private String splitValue;
|
private String splitValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class AddStampRequest extends PDFWithPageNums {
|
|||||||
@Schema(
|
@Schema(
|
||||||
description = "The stamp type (text or image)",
|
description = "The stamp type (text or image)",
|
||||||
allowableValues = {"text", "image"},
|
allowableValues = {"text", "image"},
|
||||||
required = true)
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String stampType;
|
private String stampType;
|
||||||
|
|
||||||
@Schema(description = "The stamp text")
|
@Schema(description = "The stamp text")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class AutoSplitPdfRequest extends PDFFile {
|
|||||||
@Schema(
|
@Schema(
|
||||||
description =
|
description =
|
||||||
"Flag indicating if the duplex mode is active, where the page after the divider also gets removed.",
|
"Flag indicating if the duplex mode is active, where the page after the divider also gets removed.",
|
||||||
required = false,
|
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
|
||||||
defaultValue = "false")
|
defaultValue = "false")
|
||||||
private boolean duplexMode;
|
private boolean duplexMode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class ExtractHeaderRequest extends PDFFile {
|
|||||||
@Schema(
|
@Schema(
|
||||||
description =
|
description =
|
||||||
"Flag indicating whether to use the first text as a fallback if no suitable title is found. Defaults to false.",
|
"Flag indicating whether to use the first text as a fallback if no suitable title is found. Defaults to false.",
|
||||||
required = false,
|
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
|
||||||
defaultValue = "false")
|
defaultValue = "false")
|
||||||
private boolean useFirstTextAsFallback;
|
private boolean useFirstTextAsFallback;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import lombok.EqualsAndHashCode;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
public class ExtractImageScansRequest {
|
public class ExtractImageScansRequest {
|
||||||
@Schema(description = "The input file containing image scans", required = true)
|
@Schema(
|
||||||
|
description = "The input file containing image scans",
|
||||||
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private MultipartFile fileInput;
|
private MultipartFile fileInput;
|
||||||
|
|
||||||
@Schema(
|
@Schema(
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class PrintFileRequest extends PDFFile {
|
public class PrintFileRequest extends PDFFile {
|
||||||
|
|
||||||
@Schema(description = "Name of printer to match against", required = true)
|
@Schema(
|
||||||
|
description = "Name of printer to match against",
|
||||||
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String printerName;
|
private String printerName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class AddWatermarkRequest extends PDFFile {
|
|||||||
@Schema(
|
@Schema(
|
||||||
description = "The watermark type (text or image)",
|
description = "The watermark type (text or image)",
|
||||||
allowableValues = {"text", "image"},
|
allowableValues = {"text", "image"},
|
||||||
required = true)
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String watermarkType;
|
private String watermarkType;
|
||||||
|
|
||||||
@Schema(description = "The watermark text")
|
@Schema(description = "The watermark text")
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class PDFPasswordRequest extends PDFFile {
|
public class PDFPasswordRequest extends PDFFile {
|
||||||
|
|
||||||
@Schema(description = "The password of the PDF file", required = true)
|
@Schema(
|
||||||
|
description = "The password of the PDF file",
|
||||||
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String password;
|
private String password;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class RedactPdfRequest extends PDFFile {
|
public class RedactPdfRequest extends PDFFile {
|
||||||
|
|
||||||
@Schema(description = "List of text to redact from the PDF", type = "string", required = true)
|
@Schema(
|
||||||
|
description = "List of text to redact from the PDF",
|
||||||
|
type = "string",
|
||||||
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String listOfText;
|
private String listOfText;
|
||||||
|
|
||||||
@Schema(description = "Whether to use regex for the listOfText", defaultValue = "false")
|
@Schema(description = "Whether to use regex for the listOfText", defaultValue = "false")
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
package stirling.software.SPDF.repository;
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface UserRepository extends JpaRepository<User, Long> {
|
public interface UserRepository extends JpaRepository<User, Long> {
|
||||||
Optional<User> findByUsernameIgnoreCase(String username);
|
Optional<User> findByUsernameIgnoreCase(String username);
|
||||||
|
|
||||||
|
@Query("FROM User u LEFT JOIN FETCH u.settings where upper(u.username) = upper(:username)")
|
||||||
|
Optional<User> findByUsernameIgnoreCaseWithSettings(String username);
|
||||||
|
|
||||||
Optional<User> findByUsername(String username);
|
Optional<User> findByUsername(String username);
|
||||||
|
|
||||||
Optional<User> findByApiKey(String apiKey);
|
Optional<User> findByApiKey(String apiKey);
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -13,8 +16,6 @@ import java.nio.file.SimpleFileVisitor;
|
|||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.net.URL;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -73,12 +74,11 @@ public class GeneralUtils {
|
|||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isURLReachable(String urlStr) {
|
public static boolean isURLReachable(String urlStr) {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(urlStr);
|
URL url = URI.create(urlStr).toURL();
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
connection.setRequestMethod("HEAD");
|
connection.setRequestMethod("HEAD");
|
||||||
int responseCode = connection.getResponseCode();
|
int responseCode = connection.getResponseCode();
|
||||||
@@ -112,16 +112,19 @@ public class GeneralUtils {
|
|||||||
sizeStr = sizeStr.replace(",", ".").replace(" ", "");
|
sizeStr = sizeStr.replace(",", ".").replace(" ", "");
|
||||||
try {
|
try {
|
||||||
if (sizeStr.endsWith("KB")) {
|
if (sizeStr.endsWith("KB")) {
|
||||||
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024);
|
return (long)
|
||||||
|
(Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2)) * 1024);
|
||||||
} else if (sizeStr.endsWith("MB")) {
|
} else if (sizeStr.endsWith("MB")) {
|
||||||
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2))
|
return (long)
|
||||||
* 1024
|
(Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2))
|
||||||
* 1024);
|
* 1024
|
||||||
|
* 1024);
|
||||||
} else if (sizeStr.endsWith("GB")) {
|
} else if (sizeStr.endsWith("GB")) {
|
||||||
return (long) (Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2))
|
return (long)
|
||||||
* 1024
|
(Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 2))
|
||||||
* 1024
|
* 1024
|
||||||
* 1024);
|
* 1024
|
||||||
|
* 1024);
|
||||||
} else if (sizeStr.endsWith("B")) {
|
} else if (sizeStr.endsWith("B")) {
|
||||||
return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1));
|
return Long.parseLong(sizeStr.substring(0, sizeStr.length() - 1));
|
||||||
} else {
|
} else {
|
||||||
@@ -191,8 +194,7 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
// Check if the result is null or not within bounds
|
// Check if the result is null or not within bounds
|
||||||
if (result == null || result <= 0 || result.intValue() > maxValue) {
|
if (result == null || result <= 0 || result.intValue() > maxValue) {
|
||||||
if (n != 0)
|
if (n != 0) break;
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
results.add(result.intValue());
|
results.add(result.intValue());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
multipart.enabled=true
|
multipart.enabled=true
|
||||||
|
|
||||||
|
logging.level.org.springframework=WARN
|
||||||
|
logging.level.org.hibernate=WARN
|
||||||
|
logging.level.org.eclipse.jetty=WARN
|
||||||
|
logging.level.com.zaxxer.hikari=WARN
|
||||||
|
|
||||||
|
spring.jpa.open-in-view=false
|
||||||
|
|
||||||
server.forward-headers-strategy=NATIVE
|
server.forward-headers-strategy=NATIVE
|
||||||
|
|
||||||
@@ -24,10 +30,8 @@ spring.devtools.livereload.enabled=true
|
|||||||
|
|
||||||
spring.thymeleaf.encoding=UTF-8
|
spring.thymeleaf.encoding=UTF-8
|
||||||
|
|
||||||
server.connection-timeout=${SYSTEM_CONNECTIONTIMEOUTMINUTES:20m}
|
|
||||||
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
|
|
||||||
|
|
||||||
spring.resources.static-locations=file:customFiles/static/
|
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
|
||||||
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
|
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
|
||||||
#spring.thymeleaf.cache=false
|
#spring.thymeleaf.cache=false
|
||||||
|
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=تغيير البيانات الوصفية
|
home.changeMetadata.title=تغيير البيانات الوصفية
|
||||||
home.changeMetadata.desc=تغيير / إزالة / إضافة بيانات أولية من مستند PDF
|
home.changeMetadata.desc=تغيير / إزالة / إضافة بيانات أولية من مستند PDF
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=تحويل الملف إلى PDF
|
home.fileToPDF.title=تحويل الملف إلى PDF
|
||||||
home.fileToPDF.desc=تحويل أي ملف تقريبا إلى PDF (DOCX وPNG وXLS وPPT وTXT والمزيد)
|
home.fileToPDF.desc=تحويل أي ملف تقريبا إلى PDF (DOCX وPNG وXLS وPPT وTXT والمزيد)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Canvia Metadades
|
home.changeMetadata.title=Canvia Metadades
|
||||||
home.changeMetadata.desc=Canvia/Treu/Afegeix matadades al document PDF.
|
home.changeMetadata.desc=Canvia/Treu/Afegeix matadades al document PDF.
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Converteix arxiu a PDF
|
home.fileToPDF.title=Converteix arxiu a PDF
|
||||||
home.fileToPDF.desc=Converteix qualsevol arxiu a PDF (DOCX, PNG, XLS, PPT, TXT i més)
|
home.fileToPDF.desc=Converteix qualsevol arxiu a PDF (DOCX, PNG, XLS, PPT, TXT i més)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=rozmáčknout,malý,drobný
|
|||||||
|
|
||||||
home.changeMetadata.title=Změnit Metadata
|
home.changeMetadata.title=Změnit Metadata
|
||||||
home.changeMetadata.desc=Změnit/Odebrat/Přidat metadata z PDF dokumentu
|
home.changeMetadata.desc=Změnit/Odebrat/Přidat metadata z PDF dokumentu
|
||||||
changeMetadata.tags==Název,autor,datum,tvorba,čas,vydavatel,výrobce,statistiky
|
changeMetadata.tags=Název,autor,datum,tvorba,čas,vydavatel,výrobce,statistiky
|
||||||
|
|
||||||
home.fileToPDF.title=Převést soubor do PDF
|
home.fileToPDF.title=Převést soubor do PDF
|
||||||
home.fileToPDF.desc=Převést téměř jakýkoli soubor do PDF (DOCX, PNG, XLS, PPT, TXT a více)
|
home.fileToPDF.desc=Převést téměř jakýkoli soubor do PDF (DOCX, PNG, XLS, PPT, TXT a více)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Change Metadata
|
home.changeMetadata.title=Change Metadata
|
||||||
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Convert file to PDF
|
home.fileToPDF.title=Convert file to PDF
|
||||||
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# 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=PDF auswählen
|
pdfPrompwt=PDF auswählen
|
||||||
multiPdfPrompt=PDFs auswählen(2+)
|
multiPdfPrompt=PDFs auswählen(2+)
|
||||||
multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin)
|
multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin)
|
||||||
imgPrompt=Wählen Sie ein Bild
|
imgPrompt=Wählen Sie ein Bild
|
||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=komprimieren,verkleinern,minimieren
|
|||||||
|
|
||||||
home.changeMetadata.title=Metadaten ändern
|
home.changeMetadata.title=Metadaten ändern
|
||||||
home.changeMetadata.desc=Ändern/Entfernen/Hinzufügen von Metadaten aus einem PDF-Dokument
|
home.changeMetadata.desc=Ändern/Entfernen/Hinzufügen von Metadaten aus einem PDF-Dokument
|
||||||
changeMetadata.tags==titel,autor,datum,erstellung,uhrzeit,herausgeber,produzent,statistiken
|
changeMetadata.tags=titel,autor,datum,erstellung,uhrzeit,herausgeber,produzent,statistiken
|
||||||
|
|
||||||
home.fileToPDF.title=Datei in PDF konvertieren
|
home.fileToPDF.title=Datei in PDF konvertieren
|
||||||
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Αλλαγή Μεταδεδομένων
|
home.changeMetadata.title=Αλλαγή Μεταδεδομένων
|
||||||
home.changeMetadata.desc=Αλλαγή/Κατάργηση/Προσθήκη μεταδεδομένων από ένα έγγραφο PDF.
|
home.changeMetadata.desc=Αλλαγή/Κατάργηση/Προσθήκη μεταδεδομένων από ένα έγγραφο PDF.
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Μετατροπή ενός αρχείου σε PDF
|
home.fileToPDF.title=Μετατροπή ενός αρχείου σε PDF
|
||||||
home.fileToPDF.desc=Μετατροπή σχεδόν οποιουδήποτε αρχείου σε PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
home.fileToPDF.desc=Μετατροπή σχεδόν οποιουδήποτε αρχείου σε PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Change Metadata
|
home.changeMetadata.title=Change Metadata
|
||||||
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Convert file to PDF
|
home.fileToPDF.title=Convert file to PDF
|
||||||
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Change Metadata
|
home.changeMetadata.title=Change Metadata
|
||||||
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Convert file to PDF
|
home.fileToPDF.title=Convert file to PDF
|
||||||
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Aldatu metadatuak
|
home.changeMetadata.title=Aldatu metadatuak
|
||||||
home.changeMetadata.desc=Aldatu/Ezabatu/Gehitu metadatuak PDF dokumentuari
|
home.changeMetadata.desc=Aldatu/Ezabatu/Gehitu metadatuak PDF dokumentuari
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Fitxategia PDF bihurtu
|
home.fileToPDF.title=Fitxategia PDF bihurtu
|
||||||
home.fileToPDF.desc=PDF bihurtu ia edozein fitxategi (DOCX, PNG, XLS, PPT, TXT eta gehiago)
|
home.fileToPDF.desc=PDF bihurtu ia edozein fitxategi (DOCX, PNG, XLS, PPT, TXT eta gehiago)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish, beag, beag bídeach
|
|||||||
|
|
||||||
home.changeMetadata.title=Athraigh Meiteashonraí
|
home.changeMetadata.title=Athraigh Meiteashonraí
|
||||||
home.changeMetadata.desc=Athraigh/Bain/Cuir meiteashonraí ó dhoiciméad PDF
|
home.changeMetadata.desc=Athraigh/Bain/Cuir meiteashonraí ó dhoiciméad PDF
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Comhad a thiontú go PDF
|
home.fileToPDF.title=Comhad a thiontú go PDF
|
||||||
home.fileToPDF.desc=Tiontaigh beagnach aon chomhad go PDF (DOCX, PNG, XLS, PPT, TXT agus go leor eile)
|
home.fileToPDF.desc=Tiontaigh beagnach aon chomhad go PDF (DOCX, PNG, XLS, PPT, TXT agus go leor eile)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish, kecil, kecil
|
|||||||
|
|
||||||
home.changeMetadata.title=Ubah Metadata
|
home.changeMetadata.title=Ubah Metadata
|
||||||
home.changeMetadata.desc=Mengubah/Menghapus/Menambahkan metadata dari dokumen PDF
|
home.changeMetadata.desc=Mengubah/Menghapus/Menambahkan metadata dari dokumen PDF
|
||||||
changeMetadata.tags==Judul,penulis,tanggal,pembuatan,waktu,penerbit,produser,statistik
|
changeMetadata.tags=Judul,penulis,tanggal,pembuatan,waktu,penerbit,produser,statistik
|
||||||
|
|
||||||
home.fileToPDF.title=Mengonversi berkas ke PDF
|
home.fileToPDF.title=Mengonversi berkas ke PDF
|
||||||
home.fileToPDF.desc=Mengonversi hampir semua berkas ke PDF (DOCX, PNG, XLS, PPT, TXT dan lain-lain)
|
home.fileToPDF.desc=Mengonversi hampir semua berkas ke PDF (DOCX, PNG, XLS, PPT, TXT dan lain-lain)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ confirmPasswordErrorMessage=La nuova password e la conferma della nuova password
|
|||||||
deleteCurrentUserMessage=Impossibile eliminare l'utente attualmente connesso.
|
deleteCurrentUserMessage=Impossibile eliminare l'utente attualmente connesso.
|
||||||
deleteUsernameExistsMessage=Il nome utente non esiste e non può essere eliminato.
|
deleteUsernameExistsMessage=Il nome utente non esiste e non può essere eliminato.
|
||||||
downgradeCurrentUserMessage=Impossibile declassare il ruolo dell'utente corrente
|
downgradeCurrentUserMessage=Impossibile declassare il ruolo dell'utente corrente
|
||||||
disabledCurrentUserMessage=The current user cannot be disabled
|
disabledCurrentUserMessage=L'utente corrente non può essere disabilitato
|
||||||
downgradeCurrentUserLongMessage=Impossibile declassare il ruolo dell'utente corrente. Pertanto, l'utente corrente non verrà visualizzato.
|
downgradeCurrentUserLongMessage=Impossibile declassare il ruolo dell'utente corrente. Pertanto, l'utente corrente non verrà visualizzato.
|
||||||
userAlreadyExistsOAuthMessage=L'utente esiste già come utente OAuth2.
|
userAlreadyExistsOAuthMessage=L'utente esiste già come utente OAuth2.
|
||||||
userAlreadyExistsWebMessage=L'utente esiste già come utente web.
|
userAlreadyExistsWebMessage=L'utente esiste già come utente web.
|
||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=comprimere,piccolo,minuscolo
|
|||||||
|
|
||||||
home.changeMetadata.title=Modifica Proprietà
|
home.changeMetadata.title=Modifica Proprietà
|
||||||
home.changeMetadata.desc=Modifica/Aggiungi/Rimuovi le proprietà di un documento PDF.
|
home.changeMetadata.desc=Modifica/Aggiungi/Rimuovi le proprietà di un documento PDF.
|
||||||
changeMetadata.tags==Titolo,autore,data,creazione,ora,editore,produttore,statistiche
|
changeMetadata.tags=Titolo,autore,data,creazione,ora,editore,produttore,statistiche
|
||||||
|
|
||||||
home.fileToPDF.title=Converti file in PDF
|
home.fileToPDF.title=Converti file in PDF
|
||||||
home.fileToPDF.desc=Converti quasi ogni file in PDF (DOCX, PNG, XLS, PPT, TXT e altro)
|
home.fileToPDF.desc=Converti quasi ogni file in PDF (DOCX, PNG, XLS, PPT, TXT e altro)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=メタデータの変更
|
home.changeMetadata.title=メタデータの変更
|
||||||
home.changeMetadata.desc=PDFのメタデータを変更/削除/追加します。
|
home.changeMetadata.desc=PDFのメタデータを変更/削除/追加します。
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=ファイルをPDFに変換
|
home.fileToPDF.title=ファイルをPDFに変換
|
||||||
home.fileToPDF.desc=ほぼすべてのファイルをPDFに変換します。 (DOCX, PNG, XLS, PPT, TXTなど)
|
home.fileToPDF.desc=ほぼすべてのファイルをPDFに変換します。 (DOCX, PNG, XLS, PPT, TXTなど)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=메타데이터 변경
|
home.changeMetadata.title=메타데이터 변경
|
||||||
home.changeMetadata.desc=PDF 문서의 메타데이터를 수정/제거/추가합니다.
|
home.changeMetadata.desc=PDF 문서의 메타데이터를 수정/제거/추가합니다.
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=파일을 PDF로 변환
|
home.fileToPDF.title=파일을 PDF로 변환
|
||||||
home.fileToPDF.desc=거의 모든 파일을 PDF로 변환합니다(DOCX, PNG, XLS, PPT, TXT 등)
|
home.fileToPDF.desc=거의 모든 파일을 PDF로 변환합니다(DOCX, PNG, XLS, PPT, TXT 등)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Schimbă Metadatele
|
home.changeMetadata.title=Schimbă Metadatele
|
||||||
home.changeMetadata.desc=Schimbă/Elimină/Adaugă metadate într-un document PDF.
|
home.changeMetadata.desc=Schimbă/Elimină/Adaugă metadate într-un document PDF.
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Convertește fișierul în PDF
|
home.fileToPDF.title=Convertește fișierul în PDF
|
||||||
home.fileToPDF.desc=Convertește aproape orice fișier în format PDF (DOCX, PNG, XLS, PPT, TXT și altele).
|
home.fileToPDF.desc=Convertește aproape orice fișier în format PDF (DOCX, PNG, XLS, PPT, TXT și altele).
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Изменить метаданные
|
home.changeMetadata.title=Изменить метаданные
|
||||||
home.changeMetadata.desc=Изменить/удалить/добавить метаданные из документа PDF
|
home.changeMetadata.desc=Изменить/удалить/добавить метаданные из документа PDF
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Конвертировать файл в PDF
|
home.fileToPDF.title=Конвертировать файл в PDF
|
||||||
home.fileToPDF.desc=Конвертируйте практически любой файл в PDF (DOCX, PNG, XLS, PPT, TXT и другие)
|
home.fileToPDF.desc=Конвертируйте практически любой файл в PDF (DOCX, PNG, XLS, PPT, TXT и другие)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=squish,small,tiny
|
|||||||
|
|
||||||
home.changeMetadata.title=Ändra metadata
|
home.changeMetadata.title=Ändra metadata
|
||||||
home.changeMetadata.desc=Ändra/ta bort/lägg till metadata från ett PDF-dokument
|
home.changeMetadata.desc=Ändra/ta bort/lägg till metadata från ett PDF-dokument
|
||||||
changeMetadata.tags==Title,author,date,creation,time,publisher,producer,stats
|
changeMetadata.tags=Title,author,date,creation,time,publisher,producer,stats
|
||||||
|
|
||||||
home.fileToPDF.title=Konvertera fil till PDF
|
home.fileToPDF.title=Konvertera fil till PDF
|
||||||
home.fileToPDF.desc=Konvertera nästan vilken fil som helst till PDF (DOCX, PNG, XLS, PPT, TXT och mer)
|
home.fileToPDF.desc=Konvertera nästan vilken fil som helst till PDF (DOCX, PNG, XLS, PPT, TXT och mer)
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ compressPdfs.tags=壓縮,小,微小
|
|||||||
|
|
||||||
home.changeMetadata.title=變更中繼資料
|
home.changeMetadata.title=變更中繼資料
|
||||||
home.changeMetadata.desc=從 PDF 檔案中變更/移除/新增中繼資料
|
home.changeMetadata.desc=從 PDF 檔案中變更/移除/新增中繼資料
|
||||||
changeMetadata.tags==標題,作者,日期,建立,時間,出版商,製作人,統計
|
changeMetadata.tags=標題,作者,日期,建立,時間,出版商,製作人,統計
|
||||||
|
|
||||||
home.fileToPDF.title=檔案轉 PDF
|
home.fileToPDF.title=檔案轉 PDF
|
||||||
home.fileToPDF.desc=將幾乎所有格式轉換為 PDF(DOCX、PNG、XLS、PPT、TXT 等等)
|
home.fileToPDF.desc=將幾乎所有格式轉換為 PDF(DOCX、PNG、XLS、PPT、TXT 等等)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
security:
|
security:
|
||||||
enableLogin: false # set to 'true' to enable login
|
enableLogin: false # set to 'true' to enable login
|
||||||
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
|
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
|
||||||
loginAttemptCount: 5 # lock user account after 5 tries
|
loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
|
||||||
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
|
||||||
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
|
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
|
||||||
initialLogin:
|
initialLogin:
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "ch.qos.logback:logback-classic",
|
"moduleName": "ch.qos.logback:logback-classic",
|
||||||
"moduleUrl": "http://www.qos.ch",
|
"moduleUrl": "http://www.qos.ch",
|
||||||
"moduleVersion": "1.5.7",
|
"moduleVersion": "1.5.6",
|
||||||
"moduleLicense": "GNU Lesser General Public License",
|
"moduleLicense": "GNU Lesser General Public License",
|
||||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "ch.qos.logback:logback-core",
|
"moduleName": "ch.qos.logback:logback-core",
|
||||||
"moduleUrl": "http://www.qos.ch",
|
"moduleUrl": "http://www.qos.ch",
|
||||||
"moduleVersion": "1.5.7",
|
"moduleVersion": "1.5.6",
|
||||||
"moduleLicense": "GNU Lesser General Public License",
|
"moduleLicense": "GNU Lesser General Public License",
|
||||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||||
},
|
},
|
||||||
|
|||||||
Binary file not shown.
@@ -37,7 +37,7 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (remoteCall === true) {
|
if (remoteCall === true) {
|
||||||
if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
|
if (override === "multi" || (!multipleInputsForSingleRequest && files.length > 1 && override !== "single")) {
|
||||||
await submitMultiPdfForm(url, files);
|
await submitMultiPdfForm(url, files);
|
||||||
} else {
|
} else {
|
||||||
await handleSingleDownload(url, formData);
|
await handleSingleDownload(url, formData);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-split-pdf'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-split-pdf'}">
|
||||||
<p th:text="#{autoSplitPDF.formPrompt}"></p>
|
<p th:text="#{autoSplitPDF.formPrompt}"></p>
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}">
|
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check ms-3">
|
<div class="form-check ms-3">
|
||||||
<input type="checkbox" name="duplexMode" id="duplexMode">
|
<input type="checkbox" name="duplexMode" id="duplexMode">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2 th:text="#{BookToPDF.header}"></h2>
|
<h2 th:text="#{BookToPDF.header}"></h2>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/book/pdf'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/book/pdf'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false)}"></div>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{BookToPDF.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{BookToPDF.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<p class="mt-3" th:text="#{BookToPDF.credit}"></p>
|
<p class="mt-3" th:text="#{BookToPDF.credit}"></p>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p th:text="#{processTimeWarning}"></p>
|
<p th:text="#{processTimeWarning}"></p>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/file/pdf'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/file/pdf'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false)}"></div>
|
||||||
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
|
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
|
||||||
aria-expanded="false" aria-controls="info" th:text="#{fileToPDF.supportedFileTypesInfo}"></a>
|
aria-expanded="false" aria-controls="info" th:text="#{fileToPDF.supportedFileTypesInfo}"></a>
|
||||||
<div class="collapse" id="info">
|
<div class="collapse" id="info">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{HTMLToPDF.header}"></span>
|
<span class="tool-header-text" th:text="#{HTMLToPDF.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/html/pdf'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/html/pdf'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='text/html,application/zip' )}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label>
|
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label>
|
||||||
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1">
|
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{imageToPDF.header}"></span>
|
<span class="tool-header-text" th:text="#{imageToPDF.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/img/pdf'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/img/pdf'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='image/*', inputText=#{imgPrompt})}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label>
|
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label>
|
||||||
<select class="form-control" id="fitOption" name="fitOption">
|
<select class="form-control" id="fitOption" name="fitOption">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span>
|
<span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/markdown/pdf'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/markdown/pdf'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/markdown')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='text/markdown')}"></div>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<p class="mt-3" th:text="#{MarkdownToPDF.help}"></p>
|
<p class="mt-3" th:text="#{MarkdownToPDF.help}"></p>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2 th:text="#{PDFToBook.header}"></h2>
|
<h2 th:text="#{PDFToBook.header}"></h2>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/book'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/book'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{PDFToBook.selectText.1}"></label>
|
<label th:text="#{PDFToBook.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form id="PDFToCSVForm" th:action="@{'/api/v1/convert/pdf/csv'}" method="post" enctype="multipart/form-data">
|
<form id="PDFToCSVForm" th:action="@{'/api/v1/convert/pdf/csv'}" method="post" enctype="multipart/form-data">
|
||||||
<input id="pageId" type="hidden" name="pageId">
|
<input id="pageId" type="hidden" name="pageId">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{PDFToCSV.submit}"></button>
|
<button type="submit" class="btn btn-primary" th:text="#{PDFToCSV.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
|
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{PDFToHTML.header}"></span>
|
<span class="tool-header-text" th:text="#{PDFToHTML.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/html'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/html'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToHTML.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -18,8 +18,9 @@
|
|||||||
<span class="tool-header-text" th:text="#{pdfToImage.header}"></span>
|
<span class="tool-header-text" th:text="#{pdfToImage.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<p th:text="#{processTimeWarning}"></p>
|
<p th:text="#{processTimeWarning}"></p>
|
||||||
|
<p th:if="${!isPython}" th:text="#{pdfToImage.info}">Python is not installed. Required for WebP conversion.</p>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/img'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/img'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{pdfToImage.selectText}"></label>
|
<label th:text="#{pdfToImage.selectText}"></label>
|
||||||
<select class="form-control" name="imageFormat">
|
<select class="form-control" name="imageFormat">
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
<option value="gif">GIF</option>
|
<option value="gif">GIF</option>
|
||||||
<option value="tiff">TIFF</option>
|
<option value="tiff">TIFF</option>
|
||||||
<option value="bmp">BMP</option>
|
<option value="bmp">BMP</option>
|
||||||
<option value="webp">WEPB</option>
|
<option th:if="${isPython}" value="webp">WEPB</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p th:text="#{pdfToPDFA.tip}"></p>
|
<p th:text="#{pdfToPDFA.tip}"></p>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/pdfa'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/pdfa'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="outputFormat" th:text="#{pdfToPDFA.outputFormat}"></label>
|
<label for="outputFormat" th:text="#{pdfToPDFA.outputFormat}"></label>
|
||||||
<select class="form-control" name="outputFormat" id="outputFormat">
|
<select class="form-control" name="outputFormat" id="outputFormat">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{PDFToPresentation.header}"></span>
|
<span class="tool-header-text" th:text="#{PDFToPresentation.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/presentation'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/presentation'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{PDFToPresentation.selectText.1}"></label>
|
<label th:text="#{PDFToPresentation.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{PDFToText.header}"></span>
|
<span class="tool-header-text" th:text="#{PDFToText.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/text'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/text'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{PDFToText.selectText.1}"></label>
|
<label th:text="#{PDFToText.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{PDFToWord.header}"></span>
|
<span class="tool-header-text" th:text="#{PDFToWord.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/word'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/word'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{PDFToWord.selectText.1}"></label>
|
<label th:text="#{PDFToWord.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{PDFToXML.header}"></span>
|
<span class="tool-header-text" th:text="#{PDFToXML.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/xml'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/xml'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToXML.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToXML.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<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" th: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', multipleInputsForSingleRequest=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">
|
||||||
<input id="width" type="hidden" name="width">
|
<input id="width" type="hidden" name="width">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{pageExtracter.header}"></span>
|
<span class="tool-header-text" th:text="#{pageExtracter.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data">
|
<form th:action="@{'/api/v1/general/rearrange-pages'}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<input type="hidden" id="customMode" name="customMode" value="">
|
<input type="hidden" id="customMode" name="customMode" value="">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||||
|
|||||||
@@ -144,17 +144,18 @@
|
|||||||
</dialog>
|
</dialog>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false">
|
<th:block th:fragment="fileSelector(name, multipleInputsForSingleRequest)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, disableMultipleFiles=${disableMultipleFiles} ?: false, notRequired=${notRequired} ?: false">
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
|
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
|
||||||
const multiple = /*[[${multiple}]]*/ false;
|
const multipleInputsForSingleRequest = /*[[${multipleInputsForSingleRequest}]]*/ false;
|
||||||
|
const disableMultipleFiles = /*[[${disableMultipleFiles}]]*/ false;
|
||||||
const remoteCall = /*[[${remoteCall}]]*/ true;
|
const remoteCall = /*[[${remoteCall}]]*/ true;
|
||||||
</script>
|
</script>
|
||||||
<script th:src="@{'/js/downloader.js'}"></script>
|
<script th:src="@{'/js/downloader.js'}"></script>
|
||||||
|
|
||||||
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" th:attr="multiple=${multiple}" th:required="${notRequired} ? null : 'required'">
|
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" th:attr="multiple=${!disableMultipleFiles}" th:required="${notRequired} ? null : 'required'">
|
||||||
</div>
|
</div>
|
||||||
<div class="selected-files"></div>
|
<div class="selected-files"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<form action="api/v1/general/merge-pdfs" method="post" enctype="multipart/form-data">
|
<form action="api/v1/general/merge-pdfs" method="post" enctype="multipart/form-data">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{multiPdfDropPrompt}" for="fileInput-input"></label>
|
<label th:text="#{multiPdfDropPrompt}" for="fileInput-input"></label>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=true, accept='application/pdf')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<input type="checkbox" name="removeCertSign" id="removeCertSign">
|
<input type="checkbox" name="removeCertSign" id="removeCertSign">
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- pdf selector -->
|
<!-- pdf selector -->
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<script>
|
<script>
|
||||||
let originalFileName = '';
|
let originalFileName = '';
|
||||||
document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => {
|
document.querySelector('input[name=pdf-upload]').addEventListener('change', async (event) => {
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
<div class="tab-group show-on-file-selected">
|
<div class="tab-group show-on-file-selected">
|
||||||
<div class="tab-container" th:title="#{addImage.upload}">
|
<div class="tab-container" th:title="#{addImage.upload}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='image-upload', multiple=true, accept='image/*', inputText=#{imgPrompt})}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='image-upload', multipleInputsForSingleRequest=true, accept='image/*', inputText=#{imgPrompt})}"></div>
|
||||||
<script>
|
<script>
|
||||||
const imageUpload = document.querySelector('input[name=image-upload]');
|
const imageUpload = document.querySelector('input[name=image-upload]');
|
||||||
imageUpload.addEventListener('change', e => {
|
imageUpload.addEventListener('change', e => {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{addPageNumbers.header}"></span>
|
<span class="tool-header-text" th:text="#{addPageNumbers.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/add-page-numbers'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/add-page-numbers'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="customMargin" th:text="#{addPageNumbers.selectText.2}"></label>
|
<label for="customMargin" th:text="#{addPageNumbers.selectText.2}"></label>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{adjustContrast.header}"></span>
|
<span class="tool-header-text" th:text="#{adjustContrast.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<canvas id="contrast-pdf-canvas"></canvas>
|
<canvas id="contrast-pdf-canvas"></canvas>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{autoCrop.header}"></span>
|
<span class="tool-header-text" th:text="#{autoCrop.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-crop'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-crop'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{autoCrop.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{autoCrop.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{auto-rename.header}"></span>
|
<span class="tool-header-text" th:text="#{auto-rename.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-rename'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-rename'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{auto-rename.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{auto-rename.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{changeMetadata.header}"></span>
|
<span class="tool-header-text" th:text="#{changeMetadata.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" id="form1" enctype="multipart/form-data" th:action="@{'/api/v1/misc/update-metadata'}">
|
<form method="post" id="form1" enctype="multipart/form-data" th:action="@{'/api/v1/misc/update-metadata'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p>
|
<p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p>
|
||||||
<div class="form-check mb-3-inline ms-3">
|
<div class="form-check mb-3-inline ms-3">
|
||||||
<input type="checkbox" id="deleteAll" name="deleteAll">
|
<input type="checkbox" id="deleteAll" name="deleteAll">
|
||||||
|
|||||||
@@ -51,8 +51,8 @@
|
|||||||
<span class="material-symbols-rounded tool-header-icon other">compare</span>
|
<span class="material-symbols-rounded tool-header-icon other">compare</span>
|
||||||
<span class="tool-header-text" th:text="#{compare.header}"></span>
|
<span class="tool-header-text" th:text="#{compare.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form action="#" th:action="@{'/api/v1/misc/compress-pdf'}" method="post" enctype="multipart/form-data">
|
<form action="#" th:action="@{'/api/v1/misc/compress-pdf'}" method="post" enctype="multipart/form-data">
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}">
|
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||||
</div>
|
</div>
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<p th:if="${!isPython}" th:text="#{ScannerImageSplit.info}" class="alert alert-success text-center">Python is not installed. It is required to run.</p>
|
<p th:if="${!isPython}" th:text="#{ScannerImageSplit.info}" class="alert alert-success text-center">Python is not installed. It is required to run.</p>
|
||||||
|
|
||||||
<form th:if="${isPython}" id="multiPdfForm" th:action="@{'/api/v1/misc/extract-image-scans'}" method="post" enctype="multipart/form-data">
|
<form th:if="${isPython}" id="multiPdfForm" th:action="@{'/api/v1/misc/extract-image-scans'}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='image/*, application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="angleThreshold" th:text="#{ScannerImageSplit.selectText.1}"></label>
|
<label for="angleThreshold" th:text="#{ScannerImageSplit.selectText.1}"></label>
|
||||||
<input type="number" class="form-control" id="angleThreshold" name="angle_threshold" value="10">
|
<input type="number" class="form-control" id="angleThreshold" name="angle_threshold" value="10">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{extractImages.header}"></span>
|
<span class="tool-header-text" th:text="#{extractImages.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form id="multiPdfForm" th:action="@{'/api/v1/misc/extract-images'}" method="post" enctype="multipart/form-data">
|
<form id="multiPdfForm" th:action="@{'/api/v1/misc/extract-images'}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{extractImages.selectText}"></label>
|
<label th:text="#{extractImages.selectText}"></label>
|
||||||
<select class="form-control" name="format">
|
<select class="form-control" name="format">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2 th:text="#{fakeScan.header}"></h2>
|
<h2 th:text="#{fakeScan.header}"></h2>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/fake-scan'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/fake-scan'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fakeScan.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fakeScan.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -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')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=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">
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{ocr.header}"></span>
|
<span class="tool-header-text" th:text="#{ocr.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form th:if="${#lists.size(languages) > 0}" action="#" th:action="@{'/api/v1/misc/ocr-pdf'}" method="post" enctype="multipart/form-data" class="mb-3">
|
<form th:if="${#lists.size(languages) > 0}" action="#" th:action="@{'/api/v1/misc/ocr-pdf'}" method="post" enctype="multipart/form-data" class="mb-3">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
|
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2 th:text="#{printFile.header}"></h2>
|
<h2 th:text="#{printFile.header}"></h2>
|
||||||
<form action="#" th:action="@{'/api/v1/misc/print-file'}" method="post" enctype="multipart/form-data">
|
<form action="#" th:action="@{'/api/v1/misc/print-file'}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf,image/*')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf,image/*')}"></div>
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 th:text="#{printFile.selectText.1}">Select Printer</h4> <!-- Assuming the message code printFile.selectText.3 corresponds to "Select Printer" -->
|
<h4 th:text="#{printFile.selectText.1}">Select Printer</h4> <!-- Assuming the message code printFile.selectText.3 corresponds to "Select Printer" -->
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form id="pdfForm" class="mb-3">
|
<form 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', multipleInputsForSingleRequest=false, accept='application/pdf', remoteCall='false')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeAnnotations.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeAnnotations.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{removeBlanks.header}"></span>
|
<span class="tool-header-text" th:text="#{removeBlanks.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form id="multiPdfForm" th:action="@{'/api/v1/misc/remove-blanks'}" method="post" enctype="multipart/form-data">
|
<form id="multiPdfForm" th:action="@{'/api/v1/misc/remove-blanks'}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="threshold" th:text="#{removeBlanks.threshold}"></label>
|
<label for="threshold" th:text="#{removeBlanks.threshold}"></label>
|
||||||
<input type="number" class="form-control" id="threshold" name="threshold" value="10">
|
<input type="number" class="form-control" id="threshold" name="threshold" value="10">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{repair.header}"></span>
|
<span class="tool-header-text" th:text="#{repair.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form id="multiPdfForm" th:action="@{'/api/v1/misc/repair'}" method="post" enctype="multipart/form-data">
|
<form id="multiPdfForm" th:action="@{'/api/v1/misc/repair'}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{repair.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{repair.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{showJS.header}"></span>
|
<span class="tool-header-text" th:text="#{showJS.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{'/show-javascript'}">
|
<form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{'/show-javascript'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, remoteCall='false', accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, remoteCall='false', accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{showJS.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{showJS.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{AddStampRequest.header}"></span>
|
<span class="tool-header-text" th:text="#{AddStampRequest.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/add-stamp'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/add-stamp'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<br>
|
<br>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pageOrder" th:text="#{pageSelectionPrompt}"></label>
|
<label for="pageOrder" th:text="#{pageSelectionPrompt}"></label>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{pageLayout.header}"></span>
|
<span class="tool-header-text" th:text="#{pageLayout.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form id="multiPdfForm" th:action="@{'/api/v1/general/multi-page-layout'}" method="post" enctype="multipart/form-data">
|
<form id="multiPdfForm" th:action="@{'/api/v1/general/multi-page-layout'}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pagesPerSheet" th:text="#{pageLayout.pagesPerSheet}"></label>
|
<label for="pagesPerSheet" th:text="#{pageLayout.pagesPerSheet}"></label>
|
||||||
<select class="form-control" id="pagesPerSheet" name="pagesPerSheet">
|
<select class="form-control" id="pagesPerSheet" name="pagesPerSheet">
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
<span class="tool-header-text" th:text="#{overlay-pdfs.header}"></span>
|
<span class="tool-header-text" th:text="#{overlay-pdfs.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form id="overlayForm" method="post" enctype="multipart/form-data" th:action="@{'/api/v1/general/overlay-pdfs'}">
|
<form id="overlayForm" method="post" enctype="multipart/form-data" th:action="@{'/api/v1/general/overlay-pdfs'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='overlayFiles', multiple=true, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='overlayFiles', multipleInputsForSingleRequest=true, accept='application/pdf')}"></div>
|
||||||
|
|
||||||
<label for="overlayMode" th:text="#{overlay-pdfs.mode.label}">Overlay Mode</label>
|
<label for="overlayMode" th:text="#{overlay-pdfs.mode.label}">Overlay Mode</label>
|
||||||
<select id="overlayMode" name="overlayMode" class="form-control">
|
<select id="overlayMode" name="overlayMode" class="form-control">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data">
|
<form th:action="@{'/api/v1/general/rearrange-pages'}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="customMode" th:text="#{pdfOrganiser.mode}">Mode</label>
|
<label for="customMode" th:text="#{pdfOrganiser.mode}">Mode</label>
|
||||||
<select class="form-control" id="customMode" name="customMode">
|
<select class="form-control" id="customMode" name="customMode">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{pdfToSinglePage.header}"></span>
|
<span class="tool-header-text" th:text="#{pdfToSinglePage.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/general/pdf-to-single-page'}">
|
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/general/pdf-to-single-page'}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToSinglePage.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToSinglePage.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="element-margin">
|
<div class="element-margin">
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true)}"
|
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=true)}"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="element-margin">
|
<div class="element-margin">
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{removeImage.header}"></span>
|
<span class="tool-header-text" th:text="#{removeImage.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form action="api/v1/general/remove-image-pdf" method="post" enctype="multipart/form-data">
|
<form action="api/v1/general/remove-image-pdf" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeImage.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeImage.submit}"></button>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form th:action="@{'/api/v1/general/remove-pages'}" method="post" enctype="multipart/form-data">
|
<form th:action="@{'/api/v1/general/remove-pages'}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="fileInput" th:text="#{pageRemover.pagesToDelete}"></label>
|
<label for="fileInput" th:text="#{pageRemover.pagesToDelete}"></label>
|
||||||
<input type="text" class="form-control" id="fileInput" name="pageNumbers" th:placeholder="#{pageRemover.placeholder}" required>
|
<input type="text" class="form-control" id="fileInput" name="pageNumbers" th:placeholder="#{pageRemover.placeholder}" required>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form action="#" th:action="@{'/api/v1/general/rotate-pdf'}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
|
<form action="#" th:action="@{'/api/v1/general/rotate-pdf'}" th:object="${rotateForm}" 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', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<input type="hidden" id="angleInput" name="angle" value="0">
|
<input type="hidden" id="angleInput" name="angle" value="0">
|
||||||
|
|
||||||
<div id="editSection" style="display: none">
|
<div id="editSection" style="display: none">
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user