Merge pull request #1201 from Ludy87/add_functions_oauth2

extends the functionality of oauth in Stirling PDF
This commit is contained in:
Anthony Stirling 2024-05-18 23:30:37 +01:00 committed by GitHub
commit 6fc9a2032a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 1552 additions and 762 deletions

View file

@ -15,7 +15,14 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
private static final List<String> ALLOWED_PARAMS = private static final List<String> ALLOWED_PARAMS =
Arrays.asList( Arrays.asList(
"lang", "endpoint", "endpoints", "logout", "error", "file", "messageType"); "lang",
"endpoint",
"endpoints",
"logout",
"error",
"erroroauth",
"file",
"messageType");
@Override @Override
public boolean preHandle( public boolean preHandle(

View file

@ -3,27 +3,31 @@ package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import java.util.Optional; import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Autowired private final LoginAttemptService loginAttemptService; private LoginAttemptService loginAttemptService;
@Autowired private final UserService userService; // Inject the UserService private UserService userService;
private static final Logger logger =
LoggerFactory.getLogger(CustomAuthenticationFailureHandler.class);
public CustomAuthenticationFailureHandler( public CustomAuthenticationFailureHandler(
LoginAttemptService loginAttemptService, UserService userService) { final LoginAttemptService loginAttemptService, UserService userService) {
this.loginAttemptService = loginAttemptService; this.loginAttemptService = loginAttemptService;
this.userService = userService; this.userService = userService;
} }
@ -34,22 +38,33 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
HttpServletResponse response, HttpServletResponse response,
AuthenticationException exception) AuthenticationException exception)
throws IOException, ServletException { throws IOException, ServletException {
String ip = request.getRemoteAddr(); String ip = request.getRemoteAddr();
logger.error("Failed login attempt from IP: " + ip); logger.error("Failed login attempt from IP: {}", ip);
if (exception.getClass().isAssignableFrom(InternalAuthenticationServiceException.class)
|| "Password must not be null".equalsIgnoreCase(exception.getMessage())) {
response.sendRedirect("/login?error=oauth2AuthenticationError");
return;
}
String username = request.getParameter("username"); String username = request.getParameter("username");
if (!isDemoUser(username)) { if (username != null && !isDemoUser(username)) {
if (loginAttemptService.loginAttemptCheck(username)) { logger.info(
setDefaultFailureUrl("/login?error=locked"); "Remaining attempts for user {}: {}",
username,
} else { loginAttemptService.getRemainingAttempts(username));
if (exception.getClass().isAssignableFrom(LockedException.class)) { loginAttemptService.loginFailed(username);
setDefaultFailureUrl("/login?error=locked"); if (loginAttemptService.isBlocked(username)
|| exception.getClass().isAssignableFrom(LockedException.class)) {
response.sendRedirect("/login?error=locked");
return;
} }
} }
} if (exception.getClass().isAssignableFrom(BadCredentialsException.class)
if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) { || exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) {
setDefaultFailureUrl("/login?error=badcredentials"); response.sendRedirect("/login?error=badcredentials");
return;
} }
super.onAuthenticationFailure(request, response, exception); super.onAuthenticationFailure(request, response, exception);

View file

@ -2,11 +2,9 @@ package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -14,25 +12,30 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.utils.RequestUriUtils; import stirling.software.SPDF.utils.RequestUriUtils;
@Component
public class CustomAuthenticationSuccessHandler public class CustomAuthenticationSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler { extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired private LoginAttemptService loginAttemptService; private LoginAttemptService loginAttemptService;
public CustomAuthenticationSuccessHandler(LoginAttemptService loginAttemptService) {
this.loginAttemptService = loginAttemptService;
}
@Override @Override
public void onAuthenticationSuccess( public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication) HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws ServletException, IOException { throws ServletException, IOException {
String username = request.getParameter("username");
loginAttemptService.loginSucceeded(username); String userName = request.getParameter("username");
loginAttemptService.loginSucceeded(userName);
// Get the saved request // Get the saved request
HttpSession session = request.getSession(false); HttpSession session = request.getSession(false);
SavedRequest savedRequest = SavedRequest savedRequest =
session != null (session != null)
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST") ? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
: null; : null;
if (savedRequest != null if (savedRequest != null
&& !RequestUriUtils.isStaticResource(savedRequest.getRedirectUrl())) { && !RequestUriUtils.isStaticResource(savedRequest.getRedirectUrl())) {
// Redirect to the original destination // Redirect to the original destination

View file

@ -2,10 +2,9 @@ package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import org.springframework.context.annotation.Bean; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
@ -14,10 +13,8 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler { public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@Bean
public SessionRegistry sessionRegistry() { @Autowired SessionRegistry sessionRegistry;
return new SessionRegistryImpl();
}
@Override @Override
public void onLogoutSuccess( public void onLogoutSuccess(
@ -26,14 +23,11 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
HttpSession session = request.getSession(false); HttpSession session = request.getSession(false);
if (session != null) { if (session != null) {
String sessionId = session.getId(); String sessionId = session.getId();
sessionRegistry().removeSessionInformation(sessionId); sessionRegistry.removeSessionInformation(sessionId);
session.invalidate();
logger.debug("Session invalidated: " + sessionId);
} }
if (request.getParameter("oauth2AutoCreateDisabled") != null) {
response.sendRedirect(
request.getContextPath() + "/login?error=oauth2AutoCreateDisabled");
} else {
response.sendRedirect(request.getContextPath() + "/login?logout=true"); response.sendRedirect(request.getContextPath() + "/login?logout=true");
} }
}
} }

View file

@ -39,6 +39,10 @@ public class CustomUserDetailsService implements UserDetailsService {
"Your account has been locked due to too many failed login attempts."); "Your account has been locked due to too many failed login attempts.");
} }
if (!user.hasPassword()) {
throw new IllegalArgumentException("Password must not be null");
}
return new org.springframework.security.core.userdetails.User( return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getUsername(),
user.getPassword(), user.getPassword(),

View file

@ -7,6 +7,8 @@ import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -19,32 +21,16 @@ public class InitialSecuritySetup {
@Autowired private UserService userService; @Autowired private UserService userService;
@Autowired ApplicationProperties applicationProperties; @Autowired private ApplicationProperties applicationProperties;
private static final Logger logger = LoggerFactory.getLogger(InitialSecuritySetup.class);
@PostConstruct @PostConstruct
public void init() { public void init() {
if (!userService.hasUsers()) { if (!userService.hasUsers()) {
initializeAdminUser();
String initialUsername =
applicationProperties.getSecurity().getInitialLogin().getUsername();
String initialPassword =
applicationProperties.getSecurity().getInitialLogin().getPassword();
if (initialUsername != null && initialPassword != null) {
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
} else {
initialUsername = "admin";
initialPassword = "stirling";
userService.saveUser(
initialUsername, initialPassword, Role.ADMIN.getRoleId(), true);
}
}
if (!userService.usernameExistsIgnoreCase(Role.INTERNAL_API_USER.getRoleId())) {
userService.saveUser(
Role.INTERNAL_API_USER.getRoleId(),
UUID.randomUUID().toString(),
Role.INTERNAL_API_USER.getRoleId());
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
} }
initializeInternalApiUser();
} }
@PostConstruct @PostConstruct
@ -56,6 +42,51 @@ public class InitialSecuritySetup {
} }
} }
private void initializeAdminUser() {
String initialUsername =
applicationProperties.getSecurity().getInitialLogin().getUsername();
String initialPassword =
applicationProperties.getSecurity().getInitialLogin().getPassword();
if (initialUsername != null
&& !initialUsername.isEmpty()
&& initialPassword != null
&& !initialPassword.isEmpty()
&& !userService.findByUsernameIgnoreCase(initialUsername).isPresent()) {
try {
if (userService.isUsernameValid(initialUsername)) {
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
logger.info("Admin user created: " + initialUsername);
}
} catch (IllegalArgumentException e) {
logger.error("Failed to initialize security setup", e);
System.exit(1);
}
} else {
createDefaultAdminUser();
}
}
private void createDefaultAdminUser() {
String defaultUsername = "admin";
String defaultPassword = "stirling";
if (!userService.findByUsernameIgnoreCase(defaultUsername).isPresent()) {
userService.saveUser(defaultUsername, defaultPassword, Role.ADMIN.getRoleId(), true);
logger.info("Default admin user created: " + defaultUsername);
}
}
private void initializeInternalApiUser() {
if (!userService.usernameExistsIgnoreCase(Role.INTERNAL_API_USER.getRoleId())) {
userService.saveUser(
Role.INTERNAL_API_USER.getRoleId(),
UUID.randomUUID().toString(),
Role.INTERNAL_API_USER.getRoleId());
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
logger.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
}
}
private void saveKeyToConfig(String key) throws IOException { private void saveKeyToConfig(String key) throws IOException {
Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml
List<String> lines = Files.readAllLines(path); List<String> lines = Files.readAllLines(path);

View file

@ -3,6 +3,8 @@ package stirling.software.SPDF.config.security;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -15,44 +17,62 @@ public class LoginAttemptService {
@Autowired ApplicationProperties applicationProperties; @Autowired ApplicationProperties applicationProperties;
private int MAX_ATTEMPTS; private static final Logger logger = LoggerFactory.getLogger(LoginAttemptService.class);
private int MAX_ATTEMPT;
private long ATTEMPT_INCREMENT_TIME; private long ATTEMPT_INCREMENT_TIME;
private ConcurrentHashMap<String, AttemptCounter> attemptsCache;
@PostConstruct @PostConstruct
public void init() { public void init() {
MAX_ATTEMPTS = applicationProperties.getSecurity().getLoginAttemptCount(); MAX_ATTEMPT = applicationProperties.getSecurity().getLoginAttemptCount();
ATTEMPT_INCREMENT_TIME = ATTEMPT_INCREMENT_TIME =
TimeUnit.MINUTES.toMillis( TimeUnit.MINUTES.toMillis(
applicationProperties.getSecurity().getLoginResetTimeMinutes()); applicationProperties.getSecurity().getLoginResetTimeMinutes());
attemptsCache = new ConcurrentHashMap<>();
} }
private final ConcurrentHashMap<String, AttemptCounter> attemptsCache =
new ConcurrentHashMap<>();
public void loginSucceeded(String key) { public void loginSucceeded(String key) {
attemptsCache.remove(key); logger.info(key + " " + attemptsCache.mappingCount());
if (key == null || key.trim().isEmpty()) {
return;
}
attemptsCache.remove(key.toLowerCase());
} }
public boolean loginAttemptCheck(String key) { public void loginFailed(String key) {
attemptsCache.compute( if (key == null || key.trim().isEmpty()) return;
key,
(k, attemptCounter) -> { AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
if (attemptCounter == null if (attemptCounter == null) {
|| attemptCounter.shouldReset(ATTEMPT_INCREMENT_TIME)) { attemptCounter = new AttemptCounter();
return new AttemptCounter(); attemptsCache.put(key.toLowerCase(), attemptCounter);
} else { } else {
attemptCounter.increment(); if (attemptCounter.shouldReset(ATTEMPT_INCREMENT_TIME)) {
return attemptCounter; attemptCounter.reset();
}
attemptCounter.increment();
} }
});
return attemptsCache.get(key).getAttemptCount() >= MAX_ATTEMPTS;
} }
public boolean isBlocked(String key) { public boolean isBlocked(String key) {
AttemptCounter attemptCounter = attemptsCache.get(key); if (key == null || key.trim().isEmpty()) return false;
if (attemptCounter != null) { AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
return attemptCounter.getAttemptCount() >= MAX_ATTEMPTS; if (attemptCounter == null) {
}
return false; return false;
} }
return attemptCounter.getAttemptCount() >= MAX_ATTEMPT;
}
public int getRemainingAttempts(String key) {
if (key == null || key.trim().isEmpty()) return MAX_ATTEMPT;
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
if (attemptCounter == null) {
return MAX_ATTEMPT;
}
return MAX_ATTEMPT - attemptCounter.getAttemptCount();
}
} }

View file

@ -1,6 +1,5 @@
package stirling.software.SPDF.config.security; package stirling.software.SPDF.config.security;
import java.io.IOException;
import java.util.*; import java.util.*;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -14,33 +13,30 @@ import org.springframework.security.config.annotation.method.configuration.Enabl
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;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ClientRegistrations; import org.springframework.security.oauth2.client.registration.ClientRegistrations;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.savedrequest.NullRequestCache; import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import jakarta.servlet.ServletException; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
import jakarta.servlet.http.HttpServletRequest; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
import jakarta.servlet.http.HttpServletResponse; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2LogoutSuccessHandler;
import jakarta.servlet.http.HttpSession; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.JPATokenRepositoryImpl; import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
@ -49,7 +45,7 @@ import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
@EnableMethodSecurity @EnableMethodSecurity
public class SecurityConfiguration { public class SecurityConfiguration {
@Autowired private UserDetailsService userDetailsService; @Autowired private CustomUserDetailsService userDetailsService;
@Bean @Bean
public PasswordEncoder passwordEncoder() { public PasswordEncoder passwordEncoder() {
@ -98,7 +94,8 @@ public class SecurityConfiguration {
formLogin formLogin
.loginPage("/login") .loginPage("/login")
.successHandler( .successHandler(
new CustomAuthenticationSuccessHandler()) new CustomAuthenticationSuccessHandler(
loginAttemptService))
.defaultSuccessUrl("/") .defaultSuccessUrl("/")
.failureHandler( .failureHandler(
new CustomAuthenticationFailureHandler( new CustomAuthenticationFailureHandler(
@ -111,18 +108,7 @@ public class SecurityConfiguration {
new AntPathRequestMatcher("/logout")) new AntPathRequestMatcher("/logout"))
.logoutSuccessHandler(new CustomLogoutSuccessHandler()) .logoutSuccessHandler(new CustomLogoutSuccessHandler())
.invalidateHttpSession(true) // Invalidate session .invalidateHttpSession(true) // Invalidate session
.deleteCookies("JSESSIONID", "remember-me") .deleteCookies("JSESSIONID", "remember-me"))
.addLogoutHandler(
(request, response, authentication) -> {
HttpSession session =
request.getSession(false);
if (session != null) {
String sessionId = session.getId();
sessionRegistry()
.removeSessionInformation(
sessionId);
}
}))
.rememberMe( .rememberMe(
rememberMeConfigurer -> rememberMeConfigurer ->
rememberMeConfigurer // Use the configurator directly rememberMeConfigurer // Use the configurator directly
@ -161,7 +147,6 @@ public class SecurityConfiguration {
.permitAll() .permitAll()
.anyRequest() .anyRequest()
.authenticated()) .authenticated())
.userDetailsService(userDetailsService)
.authenticationProvider(authenticationProvider()); .authenticationProvider(authenticationProvider());
// Handle OAUTH2 Logins // Handle OAUTH2 Logins
@ -176,35 +161,29 @@ public class SecurityConfiguration {
is set as true, else login fails with an error message advising the same. is set as true, else login fails with an error message advising the same.
*/ */
.successHandler( .successHandler(
new AuthenticationSuccessHandler() { new CustomOAuth2AuthenticationSuccessHandler(
@Override loginAttemptService,
public void onAuthenticationSuccess( applicationProperties,
HttpServletRequest request, userService))
HttpServletResponse response, .failureHandler(
Authentication authentication) new CustomOAuth2AuthenticationFailureHandler())
throws ServletException, IOException {
OAuth2User oauthUser =
(OAuth2User)
authentication
.getPrincipal();
if (userService.processOAuth2PostLogin(
oauthUser.getAttribute("email"),
applicationProperties
.getSecurity()
.getOAUTH2()
.getAutoCreateUser())) {
response.sendRedirect("/");
} else {
response.sendRedirect(
"/logout?oauth2AutoCreateDisabled=true");
}
}
})
// Add existing Authorities from the database // Add existing Authorities from the database
.userInfoEndpoint( .userInfoEndpoint(
userInfoEndpoint -> userInfoEndpoint ->
userInfoEndpoint.userAuthoritiesMapper( userInfoEndpoint
userAuthoritiesMapper()))); .oidcUserService(
new CustomOAuth2UserService(
applicationProperties,
userService,
loginAttemptService))
.userAuthoritiesMapper(
userAuthoritiesMapper())))
.logout(
logout ->
logout.logoutSuccessHandler(
new CustomOAuth2LogoutSuccessHandler(
this.applicationProperties,
sessionRegistry())));
} }
} else { } else {
http.csrf(csrf -> csrf.disable()) http.csrf(csrf -> csrf.disable())
@ -225,13 +204,13 @@ public class SecurityConfiguration {
} }
private ClientRegistration oidcClientRegistration() { private ClientRegistration oidcClientRegistration() {
return ClientRegistrations.fromOidcIssuerLocation( OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
applicationProperties.getSecurity().getOAUTH2().getIssuer()) return ClientRegistrations.fromIssuerLocation(oauth.getIssuer())
.registrationId("oidc") .registrationId("oidc")
.clientId(applicationProperties.getSecurity().getOAUTH2().getClientId()) .clientId(oauth.getClientId())
.clientSecret(applicationProperties.getSecurity().getOAUTH2().getClientSecret()) .clientSecret(oauth.getClientSecret())
.scope("openid", "profile", "email") .scope(oauth.getScopes())
.userNameAttributeName("email") .userNameAttributeName(oauth.getUseAsUsername())
.clientName("OIDC") .clientName("OIDC")
.build(); .build();
} }
@ -256,9 +235,14 @@ public class SecurityConfiguration {
// Add Authorities from database for existing user, if user is present. // Add Authorities from database for existing user, if user is present.
if (authority instanceof OAuth2UserAuthority oauth2Auth) { if (authority instanceof OAuth2UserAuthority oauth2Auth) {
String useAsUsername =
applicationProperties
.getSecurity()
.getOAUTH2()
.getUseAsUsername();
Optional<User> userOpt = Optional<User> userOpt =
userService.findByUsernameIgnoreCase( userService.findByUsernameIgnoreCase(
(String) oauth2Auth.getAttributes().get("email")); (String) oauth2Auth.getAttributes().get(useAsUsername));
if (userOpt.isPresent()) { if (userOpt.isPresent()) {
User user = userOpt.get(); User user = userOpt.get();
if (user != null) { if (user != null) {

View file

@ -8,6 +8,8 @@ import java.util.UUID;
import java.util.stream.Collectors; 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.i18n.LocaleContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
@ -18,6 +20,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.model.Authority; import stirling.software.SPDF.model.Authority;
import stirling.software.SPDF.model.Role; import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
@ -33,19 +36,19 @@ public class UserService implements UserServiceInterface {
@Autowired private PasswordEncoder passwordEncoder; @Autowired private PasswordEncoder passwordEncoder;
@Autowired private MessageSource messageSource;
// Handle OAUTH2 login and user auto creation. // Handle OAUTH2 login and user auto creation.
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) { public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) {
Optional<User> existUser = userRepository.findByUsernameIgnoreCase(username); if (!isUsernameValid(username)) {
if (existUser.isPresent()) { return false;
}
Optional<User> existingUser = userRepository.findByUsernameIgnoreCase(username);
if (existingUser.isPresent()) {
return true; return true;
} }
if (autoCreateUser) { if (autoCreateUser) {
User user = new User(); saveUser(username, AuthenticationType.OAUTH2);
user.setUsername(username);
user.setEnabled(true);
user.setFirstLogin(false);
user.addAuthority(new Authority(Role.USER.getRoleId(), user));
userRepository.save(user);
return true; return true;
} }
return false; return false;
@ -111,9 +114,8 @@ public class UserService implements UserServiceInterface {
} }
public UserDetails loadUserByApiKey(String apiKey) { public UserDetails loadUserByApiKey(String apiKey) {
User userOptional = userRepository.findByApiKey(apiKey); User user = userRepository.findByApiKey(apiKey);
if (userOptional != null) { if (user != null) {
User user = userOptional;
// Convert your User entity to a UserDetails object with authorities // Convert your User entity to a UserDetails object with authorities
return new org.springframework.security.core.userdetails.User( return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getUsername(),
@ -125,35 +127,53 @@ public class UserService implements UserServiceInterface {
public boolean validateApiKeyForUser(String username, String apiKey) { public boolean validateApiKeyForUser(String username, String apiKey) {
Optional<User> userOpt = userRepository.findByUsernameIgnoreCase(username); Optional<User> userOpt = userRepository.findByUsernameIgnoreCase(username);
return userOpt.isPresent() && userOpt.get().getApiKey().equals(apiKey); return userOpt.isPresent() && apiKey.equals(userOpt.get().getApiKey());
} }
public void saveUser(String username, String password) { public void saveUser(String username, AuthenticationType authenticationType)
throws IllegalArgumentException {
if (!isUsernameValid(username)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
User user = new User();
user.setUsername(username);
user.setEnabled(true);
user.setFirstLogin(false);
user.addAuthority(new Authority(Role.USER.getRoleId(), user));
user.setAuthenticationType(authenticationType);
userRepository.save(user);
}
public void saveUser(String username, String password) throws IllegalArgumentException {
if (!isUsernameValid(username)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
User user = new User(); User user = new User();
user.setUsername(username); user.setUsername(username);
user.setPassword(passwordEncoder.encode(password)); user.setPassword(passwordEncoder.encode(password));
user.setEnabled(true); user.setEnabled(true);
user.setAuthenticationType(AuthenticationType.WEB);
userRepository.save(user); userRepository.save(user);
} }
public void saveUser(String username, String password, String role, boolean firstLogin) { public void saveUser(String username, String password, String role, boolean firstLogin)
throws IllegalArgumentException {
if (!isUsernameValid(username)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
User user = new User(); User user = new User();
user.setUsername(username); user.setUsername(username);
user.setPassword(passwordEncoder.encode(password)); user.setPassword(passwordEncoder.encode(password));
user.addAuthority(new Authority(role, user)); user.addAuthority(new Authority(role, user));
user.setEnabled(true); user.setEnabled(true);
user.setAuthenticationType(AuthenticationType.WEB);
user.setFirstLogin(firstLogin); user.setFirstLogin(firstLogin);
userRepository.save(user); userRepository.save(user);
} }
public void saveUser(String username, String password, String role) { public void saveUser(String username, String password, String role)
User user = new User(); throws IllegalArgumentException {
user.setUsername(username); saveUser(username, password, role, false);
user.setPassword(passwordEncoder.encode(password));
user.addAuthority(new Authority(role, user));
user.setEnabled(true);
user.setFirstLogin(false);
userRepository.save(user);
} }
public void deleteUser(String username) { public void deleteUser(String username) {
@ -187,7 +207,7 @@ public class UserService implements UserServiceInterface {
Map<String, String> settingsMap = user.getSettings(); Map<String, String> settingsMap = user.getSettings();
if (settingsMap == null) { if (settingsMap == null) {
settingsMap = new HashMap<String, String>(); settingsMap = new HashMap<>();
} }
settingsMap.clear(); settingsMap.clear();
settingsMap.putAll(updates); settingsMap.putAll(updates);
@ -209,7 +229,10 @@ public class UserService implements UserServiceInterface {
return authorityRepository.findByUserId(user.getId()); return authorityRepository.findByUserId(user.getId());
} }
public void changeUsername(User user, String newUsername) { public void changeUsername(User user, String newUsername) throws IllegalArgumentException {
if (!isUsernameValid(newUsername)) {
throw new IllegalArgumentException(getInvalidUsernameMessage());
}
user.setUsername(newUsername); user.setUsername(newUsername);
userRepository.save(user); userRepository.save(user);
} }
@ -235,6 +258,30 @@ public class UserService implements UserServiceInterface {
} }
public boolean isUsernameValid(String username) { public boolean isUsernameValid(String username) {
return username.matches("[a-zA-Z0-9]+"); // Checks whether the simple username is formatted correctly
boolean isValidSimpleUsername =
username.matches("^[a-zA-Z0-9][a-zA-Z0-9@._+-]*[a-zA-Z0-9]$");
// Checks whether the email address is formatted correctly
boolean isValidEmail =
username.matches(
"^(?=.{1,64}@)[A-Za-z0-9]+(\\.[A-Za-z0-9_+.-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$");
return isValidSimpleUsername || isValidEmail;
}
private String getInvalidUsernameMessage() {
return messageSource.getMessage(
"invalidUsernameMessage", null, LocaleContextHolder.getLocale());
}
public boolean hasPassword(String username) {
Optional<User> user = userRepository.findByUsernameIgnoreCase(username);
return user.isPresent() && user.get().hasPassword();
}
public boolean isAuthenticationTypeByUsername(
String username, AuthenticationType authenticationType) {
Optional<User> user = userRepository.findByUsernameIgnoreCase(username);
return user.isPresent()
&& authenticationType.name().equalsIgnoreCase(user.get().getAuthenticationType());
} }
} }

View file

@ -0,0 +1,49 @@
package stirling.software.SPDF.config.security.oauth2;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class CustomOAuth2AuthenticationFailureHandler
extends SimpleUrlAuthenticationFailureHandler {
private static final Logger logger =
LoggerFactory.getLogger(CustomOAuth2AuthenticationFailureHandler.class);
@Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException {
if (exception instanceof OAuth2AuthenticationException) {
OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
String errorCode = error.getErrorCode();
if (error.getErrorCode().equals("Password must not be null")) {
errorCode = "userAlreadyExistsWeb";
}
logger.error("OAuth2 Authentication error: " + errorCode);
getRedirectStrategy()
.sendRedirect(request, response, "/logout?erroroauth=" + errorCode);
return;
} else if (exception instanceof LockedException) {
logger.error("Account locked: ", exception);
getRedirectStrategy().sendRedirect(request, response, "/logout?error=locked");
} else {
logger.error("Unhandled authentication exception", exception);
super.onAuthenticationFailure(request, response, exception);
}
}
}

View file

@ -0,0 +1,93 @@
package stirling.software.SPDF.config.security.oauth2;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.utils.RequestUriUtils;
public class CustomOAuth2AuthenticationSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler {
private LoginAttemptService loginAttemptService;
private static final Logger logger =
LoggerFactory.getLogger(CustomOAuth2AuthenticationSuccessHandler.class);
private ApplicationProperties applicationProperties;
private UserService userService;
public CustomOAuth2AuthenticationSuccessHandler(
final LoginAttemptService loginAttemptService,
ApplicationProperties applicationProperties,
UserService userService) {
this.applicationProperties = applicationProperties;
this.userService = userService;
this.loginAttemptService = loginAttemptService;
}
@Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
// Get the saved request
HttpSession session = request.getSession(false);
SavedRequest savedRequest =
(session != null)
? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")
: null;
if (savedRequest != null
&& !RequestUriUtils.isStaticResource(savedRequest.getRedirectUrl())) {
// Redirect to the original destination
super.onAuthenticationSuccess(request, response, authentication);
} else {
OAuth2User oauthUser = (OAuth2User) authentication.getPrincipal();
OAUTH2 oAuth = applicationProperties.getSecurity().getOAUTH2();
String username = oauthUser.getName();
if (loginAttemptService.isBlocked(username)) {
if (session != null) {
session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
}
throw new LockedException(
"Your account has been locked due to too many failed login attempts.");
}
if (userService.usernameExistsIgnoreCase(username)
&& userService.hasPassword(username)
&& !userService.isAuthenticationTypeByUsername(
username, AuthenticationType.OAUTH2)
&& oAuth.getAutoCreateUser()) {
response.sendRedirect(
request.getContextPath() + "/logout?oauth2AuthenticationErrorWeb=true");
return;
} else {
try {
userService.processOAuth2PostLogin(username, oAuth.getAutoCreateUser());
response.sendRedirect("/");
return;
} catch (IllegalArgumentException e) {
response.sendRedirect("/logout?invalidUsername=true");
return;
}
}
}
}
}

View file

@ -0,0 +1,86 @@
package stirling.software.SPDF.config.security.oauth2;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
private static final Logger logger =
LoggerFactory.getLogger(CustomOAuth2LogoutSuccessHandler.class);
private final SessionRegistry sessionRegistry;
private final ApplicationProperties applicationProperties;
public CustomOAuth2LogoutSuccessHandler(
ApplicationProperties applicationProperties, SessionRegistry sessionRegistry) {
this.sessionRegistry = sessionRegistry;
this.applicationProperties = applicationProperties;
}
@Override
public void onLogoutSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
String param = "logout=true";
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
String provider = oauth.getProvider() != null ? oauth.getProvider() : "";
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
param = "erroroauth=oauth2AuthenticationErrorWeb";
} else if (request.getParameter("error") != null) {
param = "error=" + request.getParameter("error");
} else if (request.getParameter("erroroauth") != null) {
param = "erroroauth=" + request.getParameter("erroroauth");
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
param = "error=oauth2AutoCreateDisabled";
}
HttpSession session = request.getSession(false);
if (session != null) {
String sessionId = session.getId();
sessionRegistry.removeSessionInformation(sessionId);
session.invalidate();
logger.debug("Session invalidated: " + sessionId);
}
switch (provider) {
case "keycloak":
String logoutUrl =
oauth.getIssuer()
+ "/protocol/openid-connect/logout"
+ "?client_id="
+ oauth.getClientId()
+ "&post_logout_redirect_uri="
+ response.encodeRedirectURL(
request.getScheme()
+ "://"
+ request.getHeader("host")
+ "/login?"
+ param);
logger.debug("Redirecting to Keycloak logout URL: " + logoutUrl);
response.sendRedirect(logoutUrl);
break;
case "google":
// Add Google specific logout URL if needed
default:
String redirectUrl = request.getContextPath() + "/login?" + param;
logger.debug("Redirecting to default logout URL: " + redirectUrl);
response.sendRedirect(redirectUrl);
break;
}
}
}

View file

@ -0,0 +1,73 @@
package stirling.software.SPDF.config.security.oauth2;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.User;
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
private final OidcUserService delegate = new OidcUserService();
private UserService userService;
private LoginAttemptService loginAttemptService;
private ApplicationProperties applicationProperties;
private static final Logger logger = LoggerFactory.getLogger(CustomOAuth2UserService.class);
public CustomOAuth2UserService(
ApplicationProperties applicationProperties,
UserService userService,
LoginAttemptService loginAttemptService) {
this.applicationProperties = applicationProperties;
this.userService = userService;
this.loginAttemptService = loginAttemptService;
}
@Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
String usernameAttribute =
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername();
try {
OidcUser user = delegate.loadUser(userRequest);
String username = user.getUserInfo().getClaimAsString(usernameAttribute);
Optional<User> duser = userService.findByUsernameIgnoreCase(username);
if (duser.isPresent()) {
if (loginAttemptService.isBlocked(username)) {
throw new LockedException(
"Your account has been locked due to too many failed login attempts.");
}
if (userService.hasPassword(username)) {
throw new IllegalArgumentException("Password must not be null");
}
}
// Return a new OidcUser with adjusted attributes
return new DefaultOidcUser(
user.getAuthorities(),
userRequest.getIdToken(),
user.getUserInfo(),
usernameAttribute);
} catch (java.lang.IllegalArgumentException e) {
logger.error("Error loading OIDC user: {}", e.getMessage());
throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e);
} catch (Exception e) {
logger.error("Unexpected error loading OIDC user", e);
throw new OAuth2AuthenticationException("Unexpected error during authentication");
}
}
}

View file

@ -0,0 +1,57 @@
package stirling.software.SPDF.config.security.oauth2;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import stirling.software.SPDF.model.ApplicationProperties;
public class CustomOAuthUserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
private static final Logger logger = LoggerFactory.getLogger(CustomOAuthUserService.class);
private final OidcUserService delegate = new OidcUserService();
private ApplicationProperties applicationProperties;
public CustomOAuthUserService(ApplicationProperties applicationProperties) {
this.applicationProperties = applicationProperties;
}
@Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
String usernameAttribute =
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername();
try {
OidcUser user = delegate.loadUser(userRequest);
Map<String, Object> attributes = new HashMap<>(user.getAttributes());
// Ensure the preferred username attribute is present
if (!attributes.containsKey(usernameAttribute)) {
attributes.put(usernameAttribute, attributes.getOrDefault("email", ""));
usernameAttribute = "email";
logger.info("Adjusted username attribute to use email");
}
// Return a new OidcUser with adjusted attributes
return new DefaultOidcUser(
user.getAuthorities(),
userRequest.getIdToken(),
user.getUserInfo(),
usernameAttribute);
} catch (java.lang.IllegalArgumentException e) {
throw new OAuth2AuthenticationException(
new OAuth2Error(e.getMessage()), e.getMessage(), e);
}
}
}

View file

@ -47,8 +47,11 @@ public class UserController {
model.addAttribute("error", "Username already exists"); model.addAttribute("error", "Username already exists");
return "register"; return "register";
} }
try {
userService.saveUser(requestModel.getUsername(), requestModel.getPassword()); userService.saveUser(requestModel.getUsername(), requestModel.getPassword());
} catch (IllegalArgumentException e) {
return "redirect:/login?messageType=invalidUsername";
}
return "redirect:/login?registered=true"; return "redirect:/login?registered=true";
} }
@ -92,7 +95,11 @@ public class UserController {
} }
if (newUsername != null && newUsername.length() > 0) { if (newUsername != null && newUsername.length() > 0) {
try {
userService.changeUsername(user, newUsername); userService.changeUsername(user, newUsername);
} catch (IllegalArgumentException e) {
return new RedirectView("/account?messageType=invalidUsername");
}
} }
// Logout using Spring's utility // Logout using Spring's utility

View file

@ -43,9 +43,52 @@ public class AccountWebController {
model.addAttribute("currentPage", "login"); model.addAttribute("currentPage", "login");
if (request.getParameter("error") != null) { String error = request.getParameter("error");
if (error != null) {
model.addAttribute("error", request.getParameter("error")); switch (error) {
case "badcredentials":
error = "login.invalid";
break;
case "locked":
error = "login.locked";
break;
case "oauth2AuthenticationError":
error = "userAlreadyExistsOAuthMessage";
break;
default:
break;
}
model.addAttribute("error", error);
}
String erroroauth = request.getParameter("erroroauth");
if (erroroauth != null) {
switch (erroroauth) {
case "oauth2AutoCreateDisabled":
erroroauth = "login.oauth2AutoCreateDisabled";
break;
case "invalidUsername":
erroroauth = "login.invalid";
break;
case "userAlreadyExistsWeb":
erroroauth = "userAlreadyExistsWebMessage";
break;
case "oauth2AuthenticationErrorWeb":
erroroauth = "login.oauth2InvalidUserType";
break;
case "invalid_token_response":
erroroauth = "login.oauth2InvalidTokenResponse";
default:
break;
}
model.addAttribute("erroroauth", erroroauth);
}
if (request.getParameter("messageType") != null) {
model.addAttribute("messageType", "changedCredsMessage");
} }
if (request.getParameter("logout") != null) { if (request.getParameter("logout") != null) {
@ -60,7 +103,8 @@ public class AccountWebController {
@PreAuthorize("hasRole('ROLE_ADMIN')") @PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/addUsers") @GetMapping("/addUsers")
public String showAddUserForm(Model model, Authentication authentication) { public String showAddUserForm(
HttpServletRequest request, Model model, Authentication authentication) {
List<User> allUsers = userRepository.findAll(); List<User> allUsers = userRepository.findAll();
Iterator<User> iterator = allUsers.iterator(); Iterator<User> iterator = allUsers.iterator();
Map<String, String> roleDetails = Role.getAllRoleDetails(); Map<String, String> roleDetails = Role.getAllRoleDetails();
@ -78,6 +122,52 @@ public class AccountWebController {
} }
} }
String messageType = request.getParameter("messageType");
String deleteMessage = null;
if (messageType != null) {
switch (messageType) {
case "deleteCurrentUser":
deleteMessage = "deleteCurrentUserMessage";
break;
case "deleteUsernameExists":
deleteMessage = "deleteUsernameExistsMessage";
break;
default:
break;
}
model.addAttribute("deleteMessage", deleteMessage);
String addMessage = null;
switch (messageType) {
case "usernameExists":
addMessage = "usernameExistsMessage";
break;
case "invalidUsername":
addMessage = "invalidUsernameMessage";
break;
default:
break;
}
model.addAttribute("addMessage", addMessage);
}
String changeMessage = null;
if (messageType != null) {
switch (messageType) {
case "userNotFound":
changeMessage = "userNotFoundMessage";
break;
case "downgradeCurrentUser":
changeMessage = "downgradeCurrentUserMessage";
break;
default:
break;
}
model.addAttribute("changeMessage", changeMessage);
}
model.addAttribute("users", allUsers); model.addAttribute("users", allUsers);
model.addAttribute("currentUsername", authentication.getName()); model.addAttribute("currentUsername", authentication.getName());
model.addAttribute("roleDetails", roleDetails); model.addAttribute("roleDetails", roleDetails);
@ -109,8 +199,9 @@ public class AccountWebController {
OAuth2User userDetails = (OAuth2User) principal; OAuth2User userDetails = (OAuth2User) principal;
// Retrieve username and other attributes // Retrieve username and other attributes
username = userDetails.getAttribute("email"); username =
userDetails.getAttribute(
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername());
// Add oAuth2 Login attributes to the model // Add oAuth2 Login attributes to the model
model.addAttribute("oAuth2Login", true); model.addAttribute("oAuth2Login", true);
} }
@ -135,6 +226,30 @@ public class AccountWebController {
return "redirect:/error"; // Example redirection in case of error return "redirect:/error"; // Example redirection in case of error
} }
String messageType = request.getParameter("messageType");
if (messageType != null) {
switch (messageType) {
case "notAuthenticated":
messageType = "notAuthenticatedMessage";
break;
case "userNotFound":
messageType = "userNotFoundMessage";
break;
case "incorrectPassword":
messageType = "incorrectPasswordMessage";
break;
case "usernameExists":
messageType = "usernameExistsMessage";
break;
case "invalidUsername":
messageType = "invalidUsernameMessage";
break;
default:
break;
}
model.addAttribute("messageType", messageType);
}
// Add attributes to the model // Add attributes to the model
model.addAttribute("username", username); model.addAttribute("username", username);
model.addAttribute("role", user.get().getRolesAsString()); model.addAttribute("role", user.get().getRolesAsString());
@ -173,6 +288,28 @@ public class AccountWebController {
// Handle error appropriately // Handle error appropriately
return "redirect:/error"; // Example redirection in case of error return "redirect:/error"; // Example redirection in case of error
} }
String messageType = request.getParameter("messageType");
if (messageType != null) {
switch (messageType) {
case "notAuthenticated":
messageType = "notAuthenticatedMessage";
break;
case "userNotFound":
messageType = "userNotFoundMessage";
break;
case "incorrectPassword":
messageType = "incorrectPasswordMessage";
break;
case "usernameExists":
messageType = "usernameExistsMessage";
break;
default:
break;
}
model.addAttribute("messageType", messageType);
}
// Add attributes to the model // Add attributes to the model
model.addAttribute("username", username); model.addAttribute("username", username);
} }

View file

@ -1,6 +1,10 @@
package stirling.software.SPDF.model; package stirling.software.SPDF.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -221,6 +225,10 @@ public class ApplicationProperties {
private String clientId; private String clientId;
private String clientSecret; private String clientSecret;
private boolean autoCreateUser; private boolean autoCreateUser;
private String useAsUsername;
private String provider;
private Collection<String> scopes = new ArrayList<String>();
public boolean getEnabled() { public boolean getEnabled() {
return enabled; return enabled;
@ -262,6 +270,37 @@ public class ApplicationProperties {
this.autoCreateUser = autoCreateUser; this.autoCreateUser = autoCreateUser;
} }
public String getUseAsUsername() {
if (useAsUsername != null && useAsUsername.trim().length() > 0) {
return useAsUsername;
}
return "email";
}
public void setUseAsUsername(String useAsUsername) {
this.useAsUsername = useAsUsername;
}
public String getProvider() {
return provider;
}
public void setProvider(String provider) {
this.provider = provider;
}
public Collection<String> getScopes() {
return scopes;
}
public void setScopes(String scpoes) {
List<String> scopesList =
Arrays.stream(scpoes.split(","))
.map(String::trim)
.collect(Collectors.toList());
this.scopes.addAll(scopesList);
}
@Override @Override
public String toString() { public String toString() {
return "OAUTH2 [enabled=" return "OAUTH2 [enabled="
@ -274,6 +313,12 @@ public class ApplicationProperties {
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL") + (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL")
+ ", autoCreateUser=" + ", autoCreateUser="
+ autoCreateUser + autoCreateUser
+ ", useAsUsername="
+ useAsUsername
+ ", provider"
+ provider
+ ", scopes="
+ scopes
+ "]"; + "]";
} }
} }

View file

@ -5,7 +5,7 @@ public class AttemptCounter {
private long lastAttemptTime; private long lastAttemptTime;
public AttemptCounter() { public AttemptCounter() {
this.attemptCount = 1; this.attemptCount = 0;
this.lastAttemptTime = System.currentTimeMillis(); this.lastAttemptTime = System.currentTimeMillis();
} }
@ -18,11 +18,16 @@ public class AttemptCounter {
return attemptCount; return attemptCount;
} }
public long getlastAttemptTime() { public long getLastAttemptTime() {
return lastAttemptTime; return lastAttemptTime;
} }
public boolean shouldReset(long ATTEMPT_INCREMENT_TIME) { public boolean shouldReset(long attemptIncrementTime) {
return System.currentTimeMillis() - lastAttemptTime > ATTEMPT_INCREMENT_TIME; return System.currentTimeMillis() - lastAttemptTime > attemptIncrementTime;
}
public void reset() {
this.attemptCount = 0;
this.lastAttemptTime = System.currentTimeMillis();
} }
} }

View file

@ -0,0 +1,6 @@
package stirling.software.SPDF.model;
public enum AuthenticationType {
WEB,
OAUTH2
}

View file

@ -47,6 +47,9 @@ public class User {
@Column(name = "roleName") @Column(name = "roleName")
private String roleName; private String roleName;
@Column(name = "authenticationtype")
private String authenticationType;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user") @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user")
private Set<Authority> authorities = new HashSet<>(); private Set<Authority> authorities = new HashSet<>();
@ -116,6 +119,14 @@ public class User {
this.enabled = enabled; this.enabled = enabled;
} }
public void setAuthenticationType(AuthenticationType authenticationType) {
this.authenticationType = authenticationType.toString().toLowerCase();
}
public String getAuthenticationType() {
return authenticationType;
}
public Set<Authority> getAuthorities() { public Set<Authority> getAuthorities() {
return authorities; return authorities;
} }
@ -137,4 +148,8 @@ public class User {
.map(Authority::getAuthority) .map(Authority::getAuthority)
.collect(Collectors.joining(", ")); .collect(Collectors.joining(", "));
} }
public boolean hasPassword() {
return this.password != null && !this.password.isEmpty();
}
} }

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=لا يمكن خفض دور المستخدم الحالي downgradeCurrentUserMessage=لا يمكن خفض دور المستخدم الحالي
downgradeCurrentUserLongMessage=لا يمكن تخفيض دور المستخدم الحالي. وبالتالي، لن يظهر المستخدم الحالي. downgradeCurrentUserLongMessage=لا يمكن تخفيض دور المستخدم الحالي. وبالتالي، لن يظهر المستخدم الحالي.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -72,6 +74,7 @@ sponsor=Sponsor
info=Info info=Info
############### ###############
# Pipeline # # Pipeline #
############### ###############
@ -170,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -182,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=تغيير دور المستخدم adminUserSettings.changeUserRole=تغيير دور المستخدم
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -1056,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Потребителят не е автентикира
userNotFoundMessage=Потребителят не е намерен userNotFoundMessage=Потребителят не е намерен
incorrectPasswordMessage=Текущата парола е неправилна. incorrectPasswordMessage=Текущата парола е неправилна.
usernameExistsMessage=Новият потребител вече съществува. usernameExistsMessage=Новият потребител вече съществува.
invalidUsernameMessage=Невалидно потребителско име, потребителското име трябва да съдържа само букви и цифри. invalidUsernameMessage=Невалидно потребителско име, потребителското име може да съдържа само букви, цифри и следните специални знаци @._+- или трябва да е валиден имейл адрес.
deleteCurrentUserMessage=Не може да се изтрие вписания в момента потребител. deleteCurrentUserMessage=Не може да се изтрие вписания в момента потребител.
deleteUsernameExistsMessage=Потребителското име не съществува и не може да бъде изтрито. deleteUsernameExistsMessage=Потребителското име не съществува и не може да бъде изтрито.
downgradeCurrentUserMessage=Не може да се понижи ролята на текущия потребител downgradeCurrentUserMessage=Не може да се понижи ролята на текущия потребител
downgradeCurrentUserLongMessage=Не може да се понижи ролята на текущия потребител. Следователно текущият потребител няма да бъде показан. downgradeCurrentUserLongMessage=Не може да се понижи ролята на текущия потребител. Следователно текущият потребител няма да бъде показан.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Грешка error=Грешка
oops=Опаа! oops=Опаа!
help=Помощ help=Помощ
@ -73,7 +75,6 @@ info=Info
############### ###############
# Pipeline # # Pipeline #
############### ###############
@ -172,7 +173,7 @@ adminUserSettings.header=Настройки за администраторск
adminUserSettings.admin=Администратор adminUserSettings.admin=Администратор
adminUserSettings.user=Потребител adminUserSettings.user=Потребител
adminUserSettings.addUser=Добавяне на нов потребител adminUserSettings.addUser=Добавяне на нов потребител
adminUserSettings.usernameInfo=Потребителското име трябва да съдържа само букви и цифри, без интервали или специални знаци. adminUserSettings.usernameInfo=Потребителското име може да съдържа само букви, цифри и следните специални символи @._+- или трябва да е валиден имейл адрес.
adminUserSettings.roles=Роли adminUserSettings.roles=Роли
adminUserSettings.role=Роля adminUserSettings.role=Роля
adminUserSettings.actions=Действия adminUserSettings.actions=Действия
@ -184,6 +185,7 @@ adminUserSettings.internalApiUser=Вътрешен API потребител
adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане adminUserSettings.forceChange=Принудете потребителя да промени потребителското име/парола при влизане
adminUserSettings.submit=Съхранете потребителя adminUserSettings.submit=Съхранете потребителя
adminUserSettings.changeUserRole=Промяна на ролята на потребителя adminUserSettings.changeUserRole=Промяна на ролята на потребителя
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -805,7 +807,6 @@ multiTool.title=PDF Мулти инструмент
multiTool.header=PDF Мулти инструмент multiTool.header=PDF Мулти инструмент
multiTool.uploadPrompts=File Name multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Преглед на PDF viewPdf.title=Преглед на PDF
viewPdf.header=Преглед на PDF viewPdf.header=Преглед на PDF
@ -1059,7 +1060,7 @@ licenses.version=Версия
licenses.license=Лиценз licenses.license=Лиценз
# error #error
error.sorry=Извинете за проблема! error.sorry=Извинете за проблема!
error.needHelp=Нуждаете се от помощ / Открихте проблем? error.needHelp=Нуждаете се от помощ / Открихте проблем?
error.contactTip=Ако все още имате проблеми, не се колебайте да се свържете с нас за помощ. Можете да изпратите запитване на нашата страница в GitHub или да се свържете с нас чрез Discord: error.contactTip=Ако все още имате проблеми, не се колебайте да се свържете с нас за помощ. Можете да изпратите запитване на нашата страница в GitHub или да се свържете с нас чрез Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=No es pot reduir la funció de l'usuari actual downgradeCurrentUserMessage=No es pot reduir la funció de l'usuari actual
downgradeCurrentUserLongMessage=No es pot baixar la funció de l'usuari actual. Per tant, no es mostrarà l'usuari actual. downgradeCurrentUserLongMessage=No es pot baixar la funció de l'usuari actual. Per tant, no es mostrarà l'usuari actual.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Usuari Admin Opcions Control
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Usuari adminUserSettings.user=Usuari
adminUserSettings.addUser=Afegir Usuari adminUserSettings.addUser=Afegir Usuari
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Rols adminUserSettings.roles=Rols
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Accions adminUserSettings.actions=Accions
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Desar Usuari adminUserSettings.submit=Desar Usuari
adminUserSettings.changeUserRole=Canvia el rol de l'usuari adminUserSettings.changeUserRole=Canvia el rol de l'usuari
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=PDF Multi Tool multiTool.title=PDF Multi Tool
multiTool.header=PDF Multi Tool multiTool.header=PDF Multi Tool
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Benutzer nicht authentifiziert.
userNotFoundMessage=Benutzer nicht gefunden. userNotFoundMessage=Benutzer nicht gefunden.
incorrectPasswordMessage=Das Passwort ist falsch. incorrectPasswordMessage=Das Passwort ist falsch.
usernameExistsMessage=Neuer Benutzername existiert bereits. usernameExistsMessage=Neuer Benutzername existiert bereits.
invalidUsernameMessage=Ungültiger Benutzername. Der Benutzername darf nur Buchstaben und Zahlen enthalten. invalidUsernameMessage=Ungültiger Benutzername. Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein.
deleteCurrentUserMessage=Der aktuell angemeldete Benutzer kann nicht gelöscht werden. deleteCurrentUserMessage=Der aktuell angemeldete Benutzer kann nicht gelöscht werden.
deleteUsernameExistsMessage=Der Benutzername existiert nicht und kann nicht gelöscht werden. deleteUsernameExistsMessage=Der Benutzername existiert nicht und kann nicht gelöscht werden.
downgradeCurrentUserMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden downgradeCurrentUserMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden
downgradeCurrentUserLongMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden. Daher wird der aktuelle Benutzer nicht angezeigt. downgradeCurrentUserLongMessage=Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden. Daher wird der aktuelle Benutzer nicht angezeigt.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Fehler error=Fehler
oops=Hoppla! oops=Hoppla!
help=Hilfe help=Hilfe
@ -171,7 +173,7 @@ adminUserSettings.header=Administrator-Benutzerkontrolle
adminUserSettings.admin=Administrator adminUserSettings.admin=Administrator
adminUserSettings.user=Benutzer adminUserSettings.user=Benutzer
adminUserSettings.addUser=Neuen Benutzer hinzufügen adminUserSettings.addUser=Neuen Benutzer hinzufügen
adminUserSettings.usernameInfo=Der Benutzername darf nur Buchstaben und Zahlen enthalten, keine Leerzeichen oder Sonderzeichen. adminUserSettings.usernameInfo=Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein.
adminUserSettings.roles=Rollen adminUserSettings.roles=Rollen
adminUserSettings.role=Rolle adminUserSettings.role=Rolle
adminUserSettings.actions=Aktion adminUserSettings.actions=Aktion
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Interner API-Benutzer
adminUserSettings.forceChange=Benutzer dazu zwingen, Benutzernamen/Passwort bei der Anmeldung zu ändern adminUserSettings.forceChange=Benutzer dazu zwingen, Benutzernamen/Passwort bei der Anmeldung zu ändern
adminUserSettings.submit=Benutzer speichern adminUserSettings.submit=Benutzer speichern
adminUserSettings.changeUserRole=Benutzerrolle ändern adminUserSettings.changeUserRole=Benutzerrolle ändern
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(z.B. 1,3,2 oder 4-8,2,10-12 oder 2n-1)
#multiTool #multiTool
multiTool.title=PDF-Multitool multiTool.title=PDF-Multitool
multiTool.header=PDF-Multitool multiTool.header=PDF-Multitool
multiTool.uploadPrompts=Bitte PDF hochladen multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=PDF anzeigen viewPdf.title=PDF anzeigen
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=Lizenz licenses.license=Lizenz
# error #error
error.sorry=Entschuldigung für das Problem! error.sorry=Entschuldigung für das Problem!
error.needHelp=Brauchst du Hilfe / Ein Problem gefunden? error.needHelp=Brauchst du Hilfe / Ein Problem gefunden?
error.contactTip=Wenn du weiterhin Probleme hast, zögere nicht, uns um Hilfe zu bitten. Du kannst ein Ticket auf unserer GitHub-Seite einreichen oder uns über Discord kontaktieren: error.contactTip=Wenn du weiterhin Probleme hast, zögere nicht, uns um Hilfe zu bitten. Du kannst ein Ticket auf unserer GitHub-Seite einreichen oder uns über Discord kontaktieren:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Ο χρήστης δεν έχει αυθεντικοπο
userNotFoundMessage=Ο χρήστης δεν βρέθηκε. userNotFoundMessage=Ο χρήστης δεν βρέθηκε.
incorrectPasswordMessage=Ο τρέχων κωδικός πρόσβασης είναι λανθασμένος. incorrectPasswordMessage=Ο τρέχων κωδικός πρόσβασης είναι λανθασμένος.
usernameExistsMessage=Το νέο όνομα χρήστη υπάρχει ήδη. usernameExistsMessage=Το νέο όνομα χρήστη υπάρχει ήδη.
invalidUsernameMessage=Μη έγκυρο όνομα χρήστη, το όνομα χρήστη πρέπει να περιέχει μόνο αλφαβητικούς χαρακτήρες και αριθμούς. invalidUsernameMessage=Μη έγκυρο όνομα χρήστη, όνομα χρήστη μπορεί να περιέχει μόνο γράμματα, αριθμούς και τους ακόλουθους ειδικούς χαρακτήρες @._+- ή πρέπει να είναι έγκυρη διεύθυνση email.
deleteCurrentUserMessage=Δεν είναι δυνατή η διαγραφή του τρέχοντος συνδεδεμένου χρήστη. deleteCurrentUserMessage=Δεν είναι δυνατή η διαγραφή του τρέχοντος συνδεδεμένου χρήστη.
deleteUsernameExistsMessage=Το όνομα χρήστη δεν υπάρχει και δεν μπορεί να διαγραφεί. deleteUsernameExistsMessage=Το όνομα χρήστη δεν υπάρχει και δεν μπορεί να διαγραφεί.
downgradeCurrentUserMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη downgradeCurrentUserMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη
downgradeCurrentUserLongMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη. Ως εκ τούτου, ο τρέχων χρήστης δεν θα εμφανίζεται. downgradeCurrentUserLongMessage=Δεν είναι δυνατή η υποβάθμιση του ρόλου του τρέχοντος χρήστη. Ως εκ τούτου, ο τρέχων χρήστης δεν θα εμφανίζεται.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Σφάλμα error=Σφάλμα
oops=Ωχ! oops=Ωχ!
help=Βοήθεια help=Βοήθεια
@ -171,7 +173,7 @@ adminUserSettings.header=Ρυθμίσεις ελέγχου Διαχειριστ
adminUserSettings.admin=Διαχειριστής adminUserSettings.admin=Διαχειριστής
adminUserSettings.user=Χρήστης adminUserSettings.user=Χρήστης
adminUserSettings.addUser=Προσθήκη νέου Χρήστη adminUserSettings.addUser=Προσθήκη νέου Χρήστη
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Ρόλοι adminUserSettings.roles=Ρόλοι
adminUserSettings.role=Ρόλος adminUserSettings.role=Ρόλος
adminUserSettings.actions=Ενέργειες adminUserSettings.actions=Ενέργειες
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Εσωτερικός API χρήστης
adminUserSettings.forceChange=Αναγκάστε τον χρήστη να αλλάξει το όνομα χρήστη/κωδικό πρόσβασης κατά τη σύνδεση adminUserSettings.forceChange=Αναγκάστε τον χρήστη να αλλάξει το όνομα χρήστη/κωδικό πρόσβασης κατά τη σύνδεση
adminUserSettings.submit=Αποθήκευση Χρήστη adminUserSettings.submit=Αποθήκευση Χρήστη
adminUserSettings.changeUserRole=Αλλαγή ρόλου χρήστη adminUserSettings.changeUserRole=Αλλαγή ρόλου χρήστη
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(π.χ. 1,3,2 ή 4-8,2,10-12 ή 2n-1)
#multiTool #multiTool
multiTool.title=PDF Πολυεργαλείο multiTool.title=PDF Πολυεργαλείο
multiTool.header=PDF Πολυεργαλείο multiTool.header=PDF Πολυεργαλείο
multiTool.uploadPrompts=Ανεβάστε το PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Προβολή PDF viewPdf.title=Προβολή PDF
@ -1057,7 +1060,7 @@ licenses.version=Εκδοχή
licenses.license=Άδεια licenses.license=Άδεια
# error #error
error.sorry=Συγγνώμη για το ζήτημα! error.sorry=Συγγνώμη για το ζήτημα!
error.needHelp=Χρειάζεστε βοήθεια / Βρήκατε πρόβλημα; error.needHelp=Χρειάζεστε βοήθεια / Βρήκατε πρόβλημα;
error.contactTip=Εάν εξακολουθείτε να αντιμετωπίζετε προβλήματα, μη διστάσετε να επικοινωνήσετε μαζί μας για βοήθεια. Μπορείτε να υποβάλετε ένα ticket στη σελίδα μας στο GitHub ή να επικοινωνήσετε μαζί μας μέσω του Discord: error.contactTip=Εάν εξακολουθείτε να αντιμετωπίζετε προβλήματα, μη διστάσετε να επικοινωνήσετε μαζί μας για βοήθεια. Μπορείτε να υποβάλετε ένα ticket στη σελίδα μας στο GitHub ή να επικοινωνήσετε μαζί μας μέσω του Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Cannot downgrade current user's role downgradeCurrentUserMessage=Cannot downgrade current user's role
downgradeCurrentUserLongMessage=Cannot downgrade current user's role. Hence, current user will not be shown. downgradeCurrentUserLongMessage=Cannot downgrade current user's role. Hence, current user will not be shown.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Change User's Role adminUserSettings.changeUserRole=Change User's Role
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Cannot downgrade current user's role downgradeCurrentUserMessage=Cannot downgrade current user's role
downgradeCurrentUserLongMessage=Cannot downgrade current user's role. Hence, current user will not be shown. downgradeCurrentUserLongMessage=Cannot downgrade current user's role. Hence, current user will not be shown.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -72,6 +74,7 @@ sponsor=Sponsor
info=Info info=Info
############### ###############
# Pipeline # # Pipeline #
############### ###############
@ -170,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -182,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Change User's Role adminUserSettings.changeUserRole=Change User's Role
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -1056,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Usuario no autentificado.
userNotFoundMessage=Usuario no encontrado. userNotFoundMessage=Usuario no encontrado.
incorrectPasswordMessage=La contraseña actual no es correcta. incorrectPasswordMessage=La contraseña actual no es correcta.
usernameExistsMessage=El nuevo nombre de usuario está en uso. usernameExistsMessage=El nuevo nombre de usuario está en uso.
invalidUsernameMessage=Nombre de usuario no válido, El nombre de ususario debe contener únicamente números y caracteres alfabéticos. invalidUsernameMessage=Nombre de usuario no válido, el nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida.
deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actualmente en uso. deleteCurrentUserMessage=No puede eliminar el usuario que tiene la sesión actualmente en uso.
deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse. deleteUsernameExistsMessage=El usuario no existe y no puede eliminarse.
downgradeCurrentUserMessage=No se puede degradar el rol del usuario actual downgradeCurrentUserMessage=No se puede degradar el rol del usuario actual
downgradeCurrentUserLongMessage=No se puede degradar el rol del usuario actual. Por lo tanto, el usuario actual no se mostrará. downgradeCurrentUserLongMessage=No se puede degradar el rol del usuario actual. Por lo tanto, el usuario actual no se mostrará.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Ups! oops=Ups!
help=Help help=Help
@ -73,9 +75,6 @@ info=Info
############### ###############
# Pipeline # # Pipeline #
############### ###############
@ -174,7 +173,7 @@ adminUserSettings.header=Configuración de control de usuario administrador
adminUserSettings.admin=Administrador adminUserSettings.admin=Administrador
adminUserSettings.user=Usuario adminUserSettings.user=Usuario
adminUserSettings.addUser=Añadir Nuevo Usuario adminUserSettings.addUser=Añadir Nuevo Usuario
adminUserSettings.usernameInfo=El nombrede usuario debe contener únicamente letras y números, no espacios ni caracteres especiales. adminUserSettings.usernameInfo=El nombre de usuario solo puede contener letras, números y los siguientes caracteres especiales @._+- o debe ser una dirección de correo electrónico válida.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Acciones adminUserSettings.actions=Acciones
@ -186,6 +185,7 @@ adminUserSettings.internalApiUser=Usuario interno de API
adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso adminUserSettings.forceChange=Forzar usuario a cambiar usuario/contraseña en el acceso
adminUserSettings.submit=Guardar Usuario adminUserSettings.submit=Guardar Usuario
adminUserSettings.changeUserRole=Cambiar rol de usuario adminUserSettings.changeUserRole=Cambiar rol de usuario
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -805,7 +805,7 @@ pdfOrganiser.placeholder=(por ej., 1,3,2 o 4-8,2,10-12 o 2n-1)
#multiTool #multiTool
multiTool.title=Multi-herramienta PDF multiTool.title=Multi-herramienta PDF
multiTool.header=Multi-herramienta PDF multiTool.header=Multi-herramienta PDF
multiTool.uploadPrompts=Por favor, cargue PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Ver PDF viewPdf.title=Ver PDF
@ -1060,7 +1060,7 @@ licenses.version=Versión
licenses.license=Licencia licenses.license=Licencia
# error #error
error.sorry=¡Perdón por el fallo! error.sorry=¡Perdón por el fallo!
error.needHelp=Necesita ayuda / Encontró un fallo? error.needHelp=Necesita ayuda / Encontró un fallo?
error.contactTip=Si sigue experimentando errores, no dude en contactarnos para solicitar soporte. Puede enviarnos un ticket en la página de GitHub o contactarnos mediante Discord: error.contactTip=Si sigue experimentando errores, no dude en contactarnos para solicitar soporte. Puede enviarnos un ticket en la página de GitHub o contactarnos mediante Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Ezin da uneko erabiltzailearen rola jaitsi downgradeCurrentUserMessage=Ezin da uneko erabiltzailearen rola jaitsi
downgradeCurrentUserLongMessage=Ezin da uneko erabiltzailearen rola jaitsi. Beraz, oraingo erabiltzailea ez da erakutsiko. downgradeCurrentUserLongMessage=Ezin da uneko erabiltzailearen rola jaitsi. Beraz, oraingo erabiltzailea ez da erakutsiko.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Admin Erabiltzailearen Ezarpenen Kontrolak
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Erabiltzaile adminUserSettings.user=Erabiltzaile
adminUserSettings.addUser=Erabiltzaile berria adminUserSettings.addUser=Erabiltzaile berria
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Rolak adminUserSettings.roles=Rolak
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Ekintzak adminUserSettings.actions=Ekintzak
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Gorde Erabiltzailea adminUserSettings.submit=Gorde Erabiltzailea
adminUserSettings.changeUserRole=Erabiltzailearen rola aldatu adminUserSettings.changeUserRole=Erabiltzailearen rola aldatu
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=PDF erabilera anitzeko tresna multiTool.title=PDF erabilera anitzeko tresna
multiTool.header=PDF erabilera anitzeko tresna multiTool.header=PDF erabilera anitzeko tresna
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Utilisateur non authentifié.
userNotFoundMessage=Utilisateur non trouvé. userNotFoundMessage=Utilisateur non trouvé.
incorrectPasswordMessage=Le mot de passe actuel est incorrect. incorrectPasswordMessage=Le mot de passe actuel est incorrect.
usernameExistsMessage=Le nouveau nom dutilisateur existe déjà. usernameExistsMessage=Le nouveau nom dutilisateur existe déjà.
invalidUsernameMessage=Nom dutilisateur invalide, le nom dutilisateur ne peut contenir que des chiffres et des lettres. invalidUsernameMessage=Nom dutilisateur invalide, le nom dutilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
deleteCurrentUserMessage=Impossible de supprimer lutilisateur actuellement connecté. deleteCurrentUserMessage=Impossible de supprimer lutilisateur actuellement connecté.
deleteUsernameExistsMessage=Le nom dutilisateur nexiste pas et ne peut pas être supprimé. deleteUsernameExistsMessage=Le nom dutilisateur nexiste pas et ne peut pas être supprimé.
downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel downgradeCurrentUserMessage=Impossible de rétrograder le rôle de l'utilisateur actuel
downgradeCurrentUserLongMessage=Impossible de rétrograder le rôle de l'utilisateur actuel. Par conséquent, l'utilisateur actuel ne sera pas affiché. downgradeCurrentUserLongMessage=Impossible de rétrograder le rôle de l'utilisateur actuel. Par conséquent, l'utilisateur actuel ne sera pas affiché.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Erreur error=Erreur
oops=Oups ! oops=Oups !
help=Aide help=Aide
@ -72,6 +74,7 @@ sponsor=Sponsor
info=Info info=Info
############### ###############
# Pipeline # # Pipeline #
############### ###############
@ -170,7 +173,7 @@ adminUserSettings.header=Administration des paramètres des utilisateurs
adminUserSettings.admin=Administateur adminUserSettings.admin=Administateur
adminUserSettings.user=Utilisateur adminUserSettings.user=Utilisateur
adminUserSettings.addUser=Ajouter un utilisateur adminUserSettings.addUser=Ajouter un utilisateur
adminUserSettings.usernameInfo=Le nom dutilisateur ne doit contenir que des lettres et des chiffres, sans espaces ni caractères spéciaux. adminUserSettings.usernameInfo=Le nom d'utilisateur ne peut contenir que des lettres, des chiffres et les caractères spéciaux suivants @._+- ou doit être une adresse e-mail valide.
adminUserSettings.roles=Rôles adminUserSettings.roles=Rôles
adminUserSettings.role=Rôle adminUserSettings.role=Rôle
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -182,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Forcer lutilisateur à changer son nom dutilisateur/mot de passe lors de la connexion adminUserSettings.forceChange=Forcer lutilisateur à changer son nom dutilisateur/mot de passe lors de la connexion
adminUserSettings.submit=Ajouter adminUserSettings.submit=Ajouter
adminUserSettings.changeUserRole=Changer le rôle de l'utilisateur adminUserSettings.changeUserRole=Changer le rôle de l'utilisateur
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -801,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=Outil multifonction PDF multiTool.title=Outil multifonction PDF
multiTool.header=Outil multifonction PDF multiTool.header=Outil multifonction PDF
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Visualiser un PDF viewPdf.title=Visualiser un PDF
@ -1056,7 +1060,7 @@ licenses.version=Version
licenses.license=Licence licenses.license=Licence
# error #error
error.sorry=Désolé pour ce problème ! error.sorry=Désolé pour ce problème !
error.needHelp=Besoin daide / Vous avez trouvé un problème ? error.needHelp=Besoin daide / Vous avez trouvé un problème ?
error.contactTip=Si vous avez encore des problèmes, nhésitez pas à nous contacter pour obtenir de laide. Vous pouvez soumettre un ticket sur notre page GitHub ou nous contacter via Discord : error.contactTip=Si vous avez encore des problèmes, nhésitez pas à nous contacter pour obtenir de laide. Vous pouvez soumettre un ticket sur notre page GitHub ou nous contacter via Discord :

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=उपयोगकर्ता प्रमाणित
userNotFoundMessage=उपयोगकर्ता नहीं मिला। userNotFoundMessage=उपयोगकर्ता नहीं मिला।
incorrectPasswordMessage=वर्तमान पासवर्ड गलत है। incorrectPasswordMessage=वर्तमान पासवर्ड गलत है।
usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है। usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है।
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता downgradeCurrentUserMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता
downgradeCurrentUserLongMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता। इसलिए, वर्तमान उपयोगकर्ता को नहीं दिखाया जाएगा। downgradeCurrentUserLongMessage=मौजूदा यूज़र की भूमिका को डाउनग्रेड नहीं किया जा सकता। इसलिए, वर्तमान उपयोगकर्ता को नहीं दिखाया जाएगा।
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=व्यवस्थापक उपयोगकर्
adminUserSettings.admin=व्यवस्थापक adminUserSettings.admin=व्यवस्थापक
adminUserSettings.user=उपयोगकर्ता adminUserSettings.user=उपयोगकर्ता
adminUserSettings.addUser=नया उपयोगकर्ता जोड़ें adminUserSettings.addUser=नया उपयोगकर्ता जोड़ें
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=रोल्स adminUserSettings.roles=रोल्स
adminUserSettings.role=रोल adminUserSettings.role=रोल
adminUserSettings.actions=क्रियाएँ adminUserSettings.actions=क्रियाएँ
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=उपयोगकर्ता को लॉगिन पर उपयोगकर्ता नाम/पासवर्ड बदलने के लिए मजबूर करें adminUserSettings.forceChange=उपयोगकर्ता को लॉगिन पर उपयोगकर्ता नाम/पासवर्ड बदलने के लिए मजबूर करें
adminUserSettings.submit=उपयोगकर्ता को सहेजें adminUserSettings.submit=उपयोगकर्ता को सहेजें
adminUserSettings.changeUserRole=यूज़र की भूमिका बदलें adminUserSettings.changeUserRole=यूज़र की भूमिका बदलें
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=पीडीएफ मल्टी टूल multiTool.title=पीडीएफ मल्टी टूल
multiTool.header=पीडीएफ मल्टी टूल multiTool.header=पीडीएफ मल्टी टूल
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=पीडीएफ देखें viewPdf.title=पीडीएफ देखें
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Felhasználó nincs hitelesítve.
userNotFoundMessage=A felhasználó nem található. userNotFoundMessage=A felhasználó nem található.
incorrectPasswordMessage=A jelenlegi jelszó helytelen. incorrectPasswordMessage=A jelenlegi jelszó helytelen.
usernameExistsMessage=Az új felhasználónév már létezik. usernameExistsMessage=Az új felhasználónév már létezik.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=A jelenlegi felhasználó szerepkörét nem lehet visszaminősíteni downgradeCurrentUserMessage=A jelenlegi felhasználó szerepkörét nem lehet visszaminősíteni
downgradeCurrentUserLongMessage=Az aktuális felhasználó szerepkörét nem lehet visszaminősíteni. Ezért az aktuális felhasználó nem jelenik meg. downgradeCurrentUserLongMessage=Az aktuális felhasználó szerepkörét nem lehet visszaminősíteni. Ezért az aktuális felhasználó nem jelenik meg.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Adminisztrátori Felhasználói Vezérlési Beállítá
adminUserSettings.admin=Adminisztrátor adminUserSettings.admin=Adminisztrátor
adminUserSettings.user=Felhasználó adminUserSettings.user=Felhasználó
adminUserSettings.addUser=Új felhasználó hozzáadása adminUserSettings.addUser=Új felhasználó hozzáadása
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Szerepek adminUserSettings.roles=Szerepek
adminUserSettings.role=Szerep adminUserSettings.role=Szerep
adminUserSettings.actions=Műveletek adminUserSettings.actions=Műveletek
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Kényszerítse a felhasználót a felhasználónév/jelszó megváltoztatására bejelentkezéskor adminUserSettings.forceChange=Kényszerítse a felhasználót a felhasználónév/jelszó megváltoztatására bejelentkezéskor
adminUserSettings.submit=Felhasználó mentése adminUserSettings.submit=Felhasználó mentése
adminUserSettings.changeUserRole=Felhasználó szerepkörének módosítása adminUserSettings.changeUserRole=Felhasználó szerepkörének módosítása
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=PDF többfunkciós eszköz multiTool.title=PDF többfunkciós eszköz
multiTool.header=PDF többfunkciós eszköz multiTool.header=PDF többfunkciós eszköz
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=PDF megtekintése viewPdf.title=PDF megtekintése
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Pengguna tidak ter-autentikasi.
userNotFoundMessage=Pengguna tidak ditemukan. userNotFoundMessage=Pengguna tidak ditemukan.
incorrectPasswordMessage=Kata sandi saat ini salah. incorrectPasswordMessage=Kata sandi saat ini salah.
usernameExistsMessage=Nama pengguna baru sudah ada. usernameExistsMessage=Nama pengguna baru sudah ada.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Tidak dapat menurunkan peran pengguna saat ini downgradeCurrentUserMessage=Tidak dapat menurunkan peran pengguna saat ini
downgradeCurrentUserLongMessage=Tidak dapat menurunkan peran pengguna saat ini. Oleh karena itu, pengguna saat ini tidak akan ditampilkan. downgradeCurrentUserLongMessage=Tidak dapat menurunkan peran pengguna saat ini. Oleh karena itu, pengguna saat ini tidak akan ditampilkan.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Pengaturan Kontrol Admin
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=Pengguna adminUserSettings.user=Pengguna
adminUserSettings.addUser=Tambahkan Pengguna Baru adminUserSettings.addUser=Tambahkan Pengguna Baru
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Peran adminUserSettings.roles=Peran
adminUserSettings.role=Peran adminUserSettings.role=Peran
adminUserSettings.actions=Tindakan adminUserSettings.actions=Tindakan
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Memaksa pengguna untuk mengubah nama pengguna/kata sandi saat masuk adminUserSettings.forceChange=Memaksa pengguna untuk mengubah nama pengguna/kata sandi saat masuk
adminUserSettings.submit=Simpan Pengguna adminUserSettings.submit=Simpan Pengguna
adminUserSettings.changeUserRole=Ubah Peran Pengguna adminUserSettings.changeUserRole=Ubah Peran Pengguna
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=Alat Multi PDF multiTool.title=Alat Multi PDF
multiTool.header=Alat Multi PDF multiTool.header=Alat Multi PDF
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Lihat PDF viewPdf.title=Lihat PDF
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Utente non autenticato.
userNotFoundMessage=Utente non trovato. userNotFoundMessage=Utente non trovato.
incorrectPasswordMessage=La password attuale non è corretta. incorrectPasswordMessage=La password attuale non è corretta.
usernameExistsMessage=Il nuovo nome utente esiste già. usernameExistsMessage=Il nuovo nome utente esiste già.
invalidUsernameMessage=Nome utente non valido, il nome utente deve contenere solo caratteri alfabetici e numeri. invalidUsernameMessage=Nome utente non valido, il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- o deve essere un indirizzo email valido.
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
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=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Errore error=Errore
oops=Oops! oops=Oops!
help=Aiuto help=Aiuto
@ -171,7 +173,7 @@ adminUserSettings.header=Impostazioni di controllo utente amministratore
adminUserSettings.admin=Amministratore adminUserSettings.admin=Amministratore
adminUserSettings.user=Utente adminUserSettings.user=Utente
adminUserSettings.addUser=Aggiungi un nuovo Utente adminUserSettings.addUser=Aggiungi un nuovo Utente
adminUserSettings.usernameInfo=Il nome utente deve contenere solo lettere e numeri, senza spazi o caratteri speciali. adminUserSettings.usernameInfo=Il nome utente può contenere solo lettere, numeri e i seguenti caratteri speciali @._+- oppure deve essere un indirizzo email valido.
adminUserSettings.roles=Ruoli adminUserSettings.roles=Ruoli
adminUserSettings.role=Ruolo adminUserSettings.role=Ruolo
adminUserSettings.actions=Azioni adminUserSettings.actions=Azioni
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=API utente interna
adminUserSettings.forceChange=Forza l'utente a cambiare nome username/password all'accesso adminUserSettings.forceChange=Forza l'utente a cambiare nome username/password all'accesso
adminUserSettings.submit=Salva utente adminUserSettings.submit=Salva utente
adminUserSettings.changeUserRole=Cambia il ruolo dell'utente adminUserSettings.changeUserRole=Cambia il ruolo dell'utente
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(ad es. 1,3,2 o 4-8,2,10-12 o 2n-1)
#multiTool #multiTool
multiTool.title=Multifunzione PDF multiTool.title=Multifunzione PDF
multiTool.header=Multifunzione PDF multiTool.header=Multifunzione PDF
multiTool.uploadPrompts=Caricare il PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Visualizza PDF viewPdf.title=Visualizza PDF
@ -1057,7 +1060,7 @@ licenses.version=Versione
licenses.license=Licenza licenses.license=Licenza
# error #error
error.sorry=Ci scusiamo per il problema! error.sorry=Ci scusiamo per il problema!
error.needHelp=Hai bisogno di aiuto / trovato un problema? error.needHelp=Hai bisogno di aiuto / trovato un problema?
error.contactTip=Se i problemi persistono, non esitare a contattarci per chiedere aiuto. Puoi inviare un ticket sulla nostra pagina GitHub o contattarci tramite Discord: error.contactTip=Se i problemi persistono, non esitare a contattarci per chiedere aiuto. Puoi inviare un ticket sulla nostra pagina GitHub o contattarci tramite Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=ユーザーが認証されていません。
userNotFoundMessage=ユーザーが見つかりません。 userNotFoundMessage=ユーザーが見つかりません。
incorrectPasswordMessage=現在のパスワードが正しくありません。 incorrectPasswordMessage=現在のパスワードが正しくありません。
usernameExistsMessage=新しいユーザー名はすでに存在します。 usernameExistsMessage=新しいユーザー名はすでに存在します。
invalidUsernameMessage=ユーザー名が無効です。ユーザー名にはアルファベットと数字のみを使用してください invalidUsernameMessage=ユーザー名が無効です。ユーザー名には文字、数字、およびそれに続く特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります
deleteCurrentUserMessage=現在ログインしているユーザーは削除できません。 deleteCurrentUserMessage=現在ログインしているユーザーは削除できません。
deleteUsernameExistsMessage=そのユーザー名は存在しないため削除できません。 deleteUsernameExistsMessage=そのユーザー名は存在しないため削除できません。
downgradeCurrentUserMessage=現在のユーザーの役割をダウングレードできません downgradeCurrentUserMessage=現在のユーザーの役割をダウングレードできません
downgradeCurrentUserLongMessage=現在のユーザーの役割をダウングレードできません。したがって、現在のユーザーは表示されません。 downgradeCurrentUserLongMessage=現在のユーザーの役割をダウングレードできません。したがって、現在のユーザーは表示されません。
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=エラー error=エラー
oops=おっと! oops=おっと!
help=ヘルプ help=ヘルプ
@ -171,7 +173,7 @@ adminUserSettings.header=管理者ユーザー制御設定
adminUserSettings.admin=管理者 adminUserSettings.admin=管理者
adminUserSettings.user=ユーザー adminUserSettings.user=ユーザー
adminUserSettings.addUser=新しいユーザを追加 adminUserSettings.addUser=新しいユーザを追加
adminUserSettings.usernameInfo=ユーザー名には文字と数字のみが使用でき、スペースや特殊文字は使用できません adminUserSettings.usernameInfo=ユーザー名には、文字、数字、および次の特殊文字 @._+- のみを含めることができます。または、有効な電子メール アドレスである必要があります
adminUserSettings.roles=役割 adminUserSettings.roles=役割
adminUserSettings.role=役割 adminUserSettings.role=役割
adminUserSettings.actions=アクション adminUserSettings.actions=アクション
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=内部APIユーザー
adminUserSettings.forceChange=ログイン時にユーザー名/パスワードを強制的に変更する adminUserSettings.forceChange=ログイン時にユーザー名/パスワードを強制的に変更する
adminUserSettings.submit=ユーザーの保存 adminUserSettings.submit=ユーザーの保存
adminUserSettings.changeUserRole=ユーザーの役割を変更する adminUserSettings.changeUserRole=ユーザーの役割を変更する
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1)
#multiTool #multiTool
multiTool.title=PDFマルチツール multiTool.title=PDFマルチツール
multiTool.header=PDFマルチツール multiTool.header=PDFマルチツール
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=PDFを表示 viewPdf.title=PDFを表示
@ -1057,7 +1060,7 @@ licenses.version=バージョン
licenses.license=ライセンス licenses.license=ライセンス
# error #error
error.sorry=問題が発生したことをお詫び申し上げます! error.sorry=問題が発生したことをお詫び申し上げます!
error.needHelp=助けが必要/問題が見つかりましたか? error.needHelp=助けが必要/問題が見つかりましたか?
error.contactTip=まだ問題が解決していない場合は、お手数ですが、GitHubページでチケットを提出するか、Discordで私たちに連絡してください error.contactTip=まだ問題が解決していない場合は、お手数ですが、GitHubページでチケットを提出するか、Discordで私たちに連絡してください

View file

@ -54,13 +54,13 @@ notAuthenticatedMessage=사용자가 인증되지 않았습니다.
userNotFoundMessage=사용자를 찾을 수 없습니다. userNotFoundMessage=사용자를 찾을 수 없습니다.
incorrectPasswordMessage=현재 비밀번호가 틀립니다. incorrectPasswordMessage=현재 비밀번호가 틀립니다.
usernameExistsMessage=새 사용자명이 이미 존재합니다. usernameExistsMessage=새 사용자명이 이미 존재합니다.
invalidUsernameMessage=사용자 이름이 잘못되었습니다. 사용자 이름에는 알파벳 문자와 숫자만 포함되어야 합니다. invalidUsernameMessage=잘못된 사용자 이름입니다. 사용자 이름에는 문자, 숫자 및 다음 특수 문자(@._+-)만 포함할 수 있거나 유효한 이메일 주소여야 합니다.
deleteCurrentUserMessage=현재 로그인한 사용자를 삭제할 수 없습니다. deleteCurrentUserMessage=현재 로그인한 사용자를 삭제할 수 없습니다.
deleteUsernameExistsMessage=사용자 이름이 존재하지 않으며 삭제할 수 없습니다. deleteUsernameExistsMessage=사용자 이름이 존재하지 않으며 삭제할 수 없습니다.
info=Info
downgradeCurrentUserMessage=현재 사용자의 역할을 다운그레이드할 수 없습니다 downgradeCurrentUserMessage=현재 사용자의 역할을 다운그레이드할 수 없습니다
downgradeCurrentUserLongMessage=현재 사용자의 역할을 다운그레이드할 수 없습니다. 따라서 현재 사용자는 표시되지 않습니다. downgradeCurrentUserLongMessage=현재 사용자의 역할을 다운그레이드할 수 없습니다. 따라서 현재 사용자는 표시되지 않습니다.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=오류 error=오류
oops=어머나! oops=어머나!
help=도움말 help=도움말
@ -71,6 +71,7 @@ visitGithub=GitHub 저장소 방문하기
donate=기부하기 donate=기부하기
color=색상 color=색상
sponsor=스폰서 sponsor=스폰서
info=Info
@ -172,7 +173,7 @@ adminUserSettings.header=사용자 관리
adminUserSettings.admin=관리자 adminUserSettings.admin=관리자
adminUserSettings.user=사용자 adminUserSettings.user=사용자
adminUserSettings.addUser=새 사용자 추가 adminUserSettings.addUser=새 사용자 추가
adminUserSettings.usernameInfo=사용자 이름은 문자와 숫자만 포함해야 하며 공백이나 특수 문자는 포함할 수 없습니다. adminUserSettings.usernameInfo=사용자 이름은 문자, 숫자, 특수 문자 @._+-만 포함할 수 있으며 유효한 이메일 주소여야 합니다.
adminUserSettings.roles=역할 adminUserSettings.roles=역할
adminUserSettings.role=역할 adminUserSettings.role=역할
adminUserSettings.actions=동작 adminUserSettings.actions=동작
@ -184,6 +185,7 @@ adminUserSettings.internalApiUser=내부 API 사용자
adminUserSettings.forceChange=다음 로그인 때 사용자명과 비밀번호를 변경하도록 강제 adminUserSettings.forceChange=다음 로그인 때 사용자명과 비밀번호를 변경하도록 강제
adminUserSettings.submit=사용자 저장 adminUserSettings.submit=사용자 저장
adminUserSettings.changeUserRole=사용자의 역할 변경 adminUserSettings.changeUserRole=사용자의 역할 변경
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -803,7 +805,7 @@ pdfOrganiser.placeholder=(예: 1,3,2 또는 4-8,2,10-12 또는 2n-1)
#multiTool #multiTool
multiTool.title=PDF 멀티툴 multiTool.title=PDF 멀티툴
multiTool.header=PDF 멀티툴 multiTool.header=PDF 멀티툴
multiTool.uploadPrompts=PDF를 업로드하십시오 multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=PDF 뷰어 viewPdf.title=PDF 뷰어
@ -1058,7 +1060,7 @@ licenses.version=버전
licenses.license=라이센스 licenses.license=라이센스
# error #error
error.sorry=문제를 끼친 점 죄송합니다! error.sorry=문제를 끼친 점 죄송합니다!
error.needHelp=도움이 필요하신가요 / 문제가 있으신가요? error.needHelp=도움이 필요하신가요 / 문제가 있으신가요?
error.contactTip=여전히 문제가 해결되지 않는다면 망설이지 마시고 도움을 요청하십시오. GitHub 페이지에서 티켓을 제출하거나 Discord를 통해 우리에게 연락하실 수 있습니다: error.contactTip=여전히 문제가 해결되지 않는다면 망설이지 마시고 도움을 요청하십시오. GitHub 페이지에서 티켓을 제출하거나 Discord를 통해 우리에게 연락하실 수 있습니다:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Gebruiker niet ingelogd.
userNotFoundMessage=Gebruiker niet gevonden. userNotFoundMessage=Gebruiker niet gevonden.
incorrectPasswordMessage=Huidige wachtwoord is onjuist. incorrectPasswordMessage=Huidige wachtwoord is onjuist.
usernameExistsMessage=Nieuwe gebruikersnaam bestaat al. usernameExistsMessage=Nieuwe gebruikersnaam bestaat al.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Kan de rol van de huidige gebruiker niet downgraden downgradeCurrentUserMessage=Kan de rol van de huidige gebruiker niet downgraden
downgradeCurrentUserLongMessage=Kan de rol van de huidige gebruiker niet downgraden. Huidige gebruiker wordt dus niet weergegeven. downgradeCurrentUserLongMessage=Kan de rol van de huidige gebruiker niet downgraden. Huidige gebruiker wordt dus niet weergegeven.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Beheer gebruikers
adminUserSettings.admin=Beheerder adminUserSettings.admin=Beheerder
adminUserSettings.user=Gebruiker adminUserSettings.user=Gebruiker
adminUserSettings.addUser=Voeg nieuwe gebruiker toe adminUserSettings.addUser=Voeg nieuwe gebruiker toe
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Rollen adminUserSettings.roles=Rollen
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Acties adminUserSettings.actions=Acties
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Forceer gebruiker om gebruikersnaam/wachtwoord te wijzigen bij inloggen adminUserSettings.forceChange=Forceer gebruiker om gebruikersnaam/wachtwoord te wijzigen bij inloggen
adminUserSettings.submit=Gebruiker opslaan adminUserSettings.submit=Gebruiker opslaan
adminUserSettings.changeUserRole=De rol van de gebruiker wijzigen adminUserSettings.changeUserRole=De rol van de gebruiker wijzigen
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=PDF Multitool multiTool.title=PDF Multitool
multiTool.header=PDF Multitool multiTool.header=PDF Multitool
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=PDF bekijken viewPdf.title=PDF bekijken
@ -1057,7 +1060,7 @@ licenses.version=Versie
licenses.license=Licentie licenses.license=Licentie
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Nie można obniżyć roli bieżącego użytkownika downgradeCurrentUserMessage=Nie można obniżyć roli bieżącego użytkownika
downgradeCurrentUserLongMessage=Nie można obniżyć roli bieżącego użytkownika. W związku z tym bieżący użytkownik nie zostanie wyświetlony. downgradeCurrentUserLongMessage=Nie można obniżyć roli bieżącego użytkownika. W związku z tym bieżący użytkownik nie zostanie wyświetlony.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Zmień rolę użytkownika adminUserSettings.changeUserRole=Zmień rolę użytkownika
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=Multi narzędzie PDF multiTool.title=Multi narzędzie PDF
multiTool.header=Multi narzędzie PDF multiTool.header=Multi narzędzie PDF
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Não é possível fazer downgrade da função do usuário atual downgradeCurrentUserMessage=Não é possível fazer downgrade da função do usuário atual
downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do usuário atual. Portanto, o usuário atual não será mostrado. downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do usuário atual. Portanto, o usuário atual não será mostrado.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Alterar Função de Usuário adminUserSettings.changeUserRole=Alterar Função de Usuário
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=Multiferramenta de PDF multiTool.title=Multiferramenta de PDF
multiTool.header=Multiferramenta de PDF multiTool.header=Multiferramenta de PDF
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Utilizador não autenticado.
userNotFoundMessage=Utilizador inexistente. userNotFoundMessage=Utilizador inexistente.
incorrectPasswordMessage=Senha incorreta. incorrectPasswordMessage=Senha incorreta.
usernameExistsMessage=Esse utilizador já existe. usernameExistsMessage=Esse utilizador já existe.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Não é possível fazer downgrade da função do utilizador atual downgradeCurrentUserMessage=Não é possível fazer downgrade da função do utilizador atual
downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do utilizador atual. Portanto, o utilizador atual não será mostrado. downgradeCurrentUserLongMessage=Não é possível fazer downgrade da função do utilizador atual. Portanto, o utilizador atual não será mostrado.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Alterar usuário adminUserSettings.changeUserRole=Alterar usuário
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=Multiferramenta de PDF multiTool.title=Multiferramenta de PDF
multiTool.header=Multiferramenta de PDF multiTool.header=Multiferramenta de PDF
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@ -1057,7 +1060,7 @@ licenses.version=Versão
licenses.license=Licença licenses.license=Licença
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Rolul utilizatorului curent nu poate fi retrogradat downgradeCurrentUserMessage=Rolul utilizatorului curent nu poate fi retrogradat
downgradeCurrentUserLongMessage=Rolul utilizatorului curent nu poate fi retrogradat. Prin urmare, utilizatorul curent nu va fi afișat. downgradeCurrentUserLongMessage=Rolul utilizatorului curent nu poate fi retrogradat. Prin urmare, utilizatorul curent nu va fi afișat.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Schimbați rolul utilizatorului adminUserSettings.changeUserRole=Schimbați rolul utilizatorului
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=Instrument PDF multiplu multiTool.title=Instrument PDF multiplu
multiTool.header=Instrument PDF multiplu multiTool.header=Instrument PDF multiplu
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,12 +54,13 @@ notAuthenticatedMessage=Пользователь не прошел провер
userNotFoundMessage=Пользователь не найден. userNotFoundMessage=Пользователь не найден.
incorrectPasswordMessage=Текущий пароль неверен. incorrectPasswordMessage=Текущий пароль неверен.
usernameExistsMessage=Новое имя пользователя уже существует. usernameExistsMessage=Новое имя пользователя уже существует.
invalidUsernameMessage=Недопустимое имя пользователя, Имя пользователя должно содержать только буквы алфавита и цифры. invalidUsernameMessage=Неверное имя пользователя. Имя пользователя может содержать только буквы, цифры и следующие специальные символы @._+- или должно быть действительным адресом электронной почты.
deleteCurrentUserMessage=Невозможно удалить пользователя, вошедшего в систему. deleteCurrentUserMessage=Невозможно удалить пользователя, вошедшего в систему.
deleteUsernameExistsMessage=Имя пользователя не существует и не может быть удалено. deleteUsernameExistsMessage=Имя пользователя не существует и не может быть удалено.
info=Info
downgradeCurrentUserMessage=Невозможно понизить роль текущего пользователя downgradeCurrentUserMessage=Невозможно понизить роль текущего пользователя
downgradeCurrentUserLongMessage=Невозможно понизить роль текущего пользователя. Следовательно, текущий пользователь не будет отображаться. downgradeCurrentUserLongMessage=Невозможно понизить роль текущего пользователя. Следовательно, текущий пользователь не будет отображаться.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Ошибка error=Ошибка
oops=Ой! oops=Ой!
help=Помощь help=Помощь
@ -70,7 +71,7 @@ visitGithub=Посетить репозиторий на GitHub
donate=Пожертвовать donate=Пожертвовать
color=Цвет color=Цвет
sponsor=Спонсор sponsor=Спонсор
info=Info
@ -172,7 +173,7 @@ adminUserSettings.header=Настройки контроля пользоват
adminUserSettings.admin=Администратор adminUserSettings.admin=Администратор
adminUserSettings.user=Пользователь adminUserSettings.user=Пользователь
adminUserSettings.addUser=Добавить нового пользователя adminUserSettings.addUser=Добавить нового пользователя
adminUserSettings.usernameInfo=Имя пользователя должно содержать только буквы и цифры, без пробелов и специальных символов. adminUserSettings.usernameInfo=Имя пользователя может содержать только буквы, цифры и следующие специальные символы @._+- или должно быть действительным адресом электронной почты.
adminUserSettings.roles=Роли adminUserSettings.roles=Роли
adminUserSettings.role=Роль adminUserSettings.role=Роль
adminUserSettings.actions=Действия adminUserSettings.actions=Действия
@ -184,6 +185,7 @@ adminUserSettings.internalApiUser=Внутренний пользователь
adminUserSettings.forceChange=Просить пользователя изменить пароль при входе в систему adminUserSettings.forceChange=Просить пользователя изменить пароль при входе в систему
adminUserSettings.submit=Сохранить пользователя adminUserSettings.submit=Сохранить пользователя
adminUserSettings.changeUserRole=Изменить роль пользователя adminUserSettings.changeUserRole=Изменить роль пользователя
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -803,7 +805,7 @@ pdfOrganiser.placeholder=(например, 1,3,2 или 4-8,2,10-12 или 2n-1
#multiTool #multiTool
multiTool.title=Мультиинструмент PDF multiTool.title=Мультиинструмент PDF
multiTool.header=Мультиинструмент PDF multiTool.header=Мультиинструмент PDF
multiTool.uploadPrompts=Пожалуйста, загрузите PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Просмотреть PDF viewPdf.title=Просмотреть PDF
@ -1058,7 +1060,7 @@ licenses.version=Версия
licenses.license=Лицензия licenses.license=Лицензия
# error #error
error.sorry=Извините за проблему! error.sorry=Извините за проблему!
error.needHelp=Нужна помощь / Нашли проблему? error.needHelp=Нужна помощь / Нашли проблему?
error.contactTip=Если у вас все еще есть проблемы, не стесняйтесь обращаться к нам за помощью. Вы можете отправить заявку на нашей странице GitHub или связаться с нами через Discord: error.contactTip=Если у вас все еще есть проблемы, не стесняйтесь обращаться к нам за помощью. Вы можете отправить заявку на нашей странице GitHub или связаться с нами через Discord:

View file

@ -59,6 +59,8 @@ deleteCurrentUserMessage=Nie je možné zmazať aktuálne prihláseného použí
deleteUsernameExistsMessage=Používateľské meno neexistuje a nemôže byť zmazané. deleteUsernameExistsMessage=Používateľské meno neexistuje a nemôže byť zmazané.
downgradeCurrentUserMessage=Nie je možné znížiť rolu aktuálneho používateľa downgradeCurrentUserMessage=Nie je možné znížiť rolu aktuálneho používateľa
downgradeCurrentUserLongMessage=Nie je možné znížiť rolu aktuálneho používateľa. Preto, aktuálny používateľ nebude zobrazený. downgradeCurrentUserLongMessage=Nie je možné znížiť rolu aktuálneho používateľa. Preto, aktuálny používateľ nebude zobrazený.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Chyba error=Chyba
oops=Ups! oops=Ups!
help=Pomoc help=Pomoc
@ -69,6 +71,7 @@ visitGithub=Navštíviť GitHub repozitár
donate=Darovať donate=Darovať
color=Farba color=Farba
sponsor=Sponzorovať sponsor=Sponzorovať
info=Info
@ -102,12 +105,18 @@ pipelineOptions.validateButton=Overiť
############# #############
# NAVBAR # # NAVBAR #
############# #############
navbar.convert=Konvertovať navbar.favorite=Favorites
navbar.security=Bezpečnosť
navbar.other=Rôzne
navbar.darkmode=Tmavý režim navbar.darkmode=Tmavý režim
navbar.pageOps=Operácie so stránkami navbar.language=Languages
navbar.settings=Nastavenia navbar.settings=Nastavenia
navbar.allTools=Tools
navbar.multiTool=Multi Tools
navbar.sections.organize=Organize
navbar.sections.convertTo=Convert to PDF
navbar.sections.convertFrom=Convert from PDF
navbar.sections.security=Sign & Security
navbar.sections.advance=Advanced
navbar.sections.edit=View & Edit
############# #############
# SETTINGS # # SETTINGS #
@ -176,6 +185,7 @@ adminUserSettings.internalApiUser=Interný API používateľ
adminUserSettings.forceChange=Donútiť používateľa zmeniť heslo pri prihlásení adminUserSettings.forceChange=Donútiť používateľa zmeniť heslo pri prihlásení
adminUserSettings.submit=Uložiť používateľa adminUserSettings.submit=Uložiť používateľa
adminUserSettings.changeUserRole=Zmeniť rolu používateľa adminUserSettings.changeUserRole=Zmeniť rolu používateľa
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -742,6 +752,7 @@ extractImages.submit=Extrahovať
fileToPDF.title=Súbor do PDF fileToPDF.title=Súbor do PDF
fileToPDF.header=Konvertovať akýkoľvek súbor do PDF fileToPDF.header=Konvertovať akýkoľvek súbor do PDF
fileToPDF.credit=Táto služba používa LibreOffice a Unoconv pre konverziu súborov. fileToPDF.credit=Táto služba používa LibreOffice a Unoconv pre konverziu súborov.
fileToPDF.supportedFileTypesInfo=Supported File types
fileToPDF.supportedFileTypes=Podporované typy súborov by mali zahŕňať nižšie uvedené, avšak pre úplný aktualizovaný zoznam podporovaných formátov, prosím, odkazujte na dokumentáciu LibreOffice fileToPDF.supportedFileTypes=Podporované typy súborov by mali zahŕňať nižšie uvedené, avšak pre úplný aktualizovaný zoznam podporovaných formátov, prosím, odkazujte na dokumentáciu LibreOffice
fileToPDF.submit=Konvertovať do PDF fileToPDF.submit=Konvertovať do PDF
@ -794,7 +805,7 @@ pdfOrganiser.placeholder=(napr. 1,3,2 alebo 4-8,2,10-12 alebo 2n-1)
#multiTool #multiTool
multiTool.title=PDF Multi Nástroj multiTool.title=PDF Multi Nástroj
multiTool.header=PDF Multi Nástroj multiTool.header=PDF Multi Nástroj
multiTool.uploadPrompts=Prosím, nahrajte PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Zobraziť PDF viewPdf.title=Zobraziť PDF
@ -1049,7 +1060,7 @@ licenses.version=Verzia
licenses.license=Licencia licenses.license=Licencia
# error #error
error.sorry=Ospravedlňujeme sa za problém! error.sorry=Ospravedlňujeme sa za problém!
error.needHelp=Potrebujete pomoc / Našli ste problém? error.needHelp=Potrebujete pomoc / Našli ste problém?
error.contactTip=Ak máte stále problémy, neváhajte nás kontaktovať pre pomoc. Môžete podať tiket na našej stránke GitHub alebo nás kontaktovať cez Discord: error.contactTip=Ak máte stále problémy, neváhajte nás kontaktovať pre pomoc. Môžete podať tiket na našej stránke GitHub alebo nás kontaktovať cez Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Korisnik nije autentifikovan.
userNotFoundMessage=Korisnik nije pronađen. userNotFoundMessage=Korisnik nije pronađen.
incorrectPasswordMessage=Trenutna šifra je netačna. incorrectPasswordMessage=Trenutna šifra je netačna.
usernameExistsMessage=Novi korisnik već postoji usernameExistsMessage=Novi korisnik već postoji
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Nije moguće degradirati ulogu trenutnog korisnika downgradeCurrentUserMessage=Nije moguće degradirati ulogu trenutnog korisnika
downgradeCurrentUserLongMessage=Nije moguće unazaditi ulogu trenutnog korisnika. Dakle, trenutni korisnik neće biti prikazan. downgradeCurrentUserLongMessage=Nije moguće unazaditi ulogu trenutnog korisnika. Dakle, trenutni korisnik neće biti prikazan.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Podešavanja kontrole korisnika za administratora
adminUserSettings.admin=Administrator adminUserSettings.admin=Administrator
adminUserSettings.user=Korisnik adminUserSettings.user=Korisnik
adminUserSettings.addUser=Dodaj novog korisnika adminUserSettings.addUser=Dodaj novog korisnika
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Uloge adminUserSettings.roles=Uloge
adminUserSettings.role=Uloga adminUserSettings.role=Uloga
adminUserSettings.actions=Akcije adminUserSettings.actions=Akcije
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Prisili korisnika da promeni korisničko ime/lozinku pri prijavi adminUserSettings.forceChange=Prisili korisnika da promeni korisničko ime/lozinku pri prijavi
adminUserSettings.submit=Sačuvaj korisnika adminUserSettings.submit=Sačuvaj korisnika
adminUserSettings.changeUserRole=Promenite ulogu korisnika adminUserSettings.changeUserRole=Promenite ulogu korisnika
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=PDF Multi Alatka multiTool.title=PDF Multi Alatka
multiTool.header=PDF Multi Alatka multiTool.header=PDF Multi Alatka
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Prikaz viewPdf.title=Prikaz
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=User not authenticated.
userNotFoundMessage=User not found. userNotFoundMessage=User not found.
incorrectPasswordMessage=Current password is incorrect. incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
invalidUsernameMessage=Invalid username, Username must only contain alphabet characters and numbers. invalidUsernameMessage=Invalid username, username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
deleteCurrentUserMessage=Cannot delete currently logged in user. deleteCurrentUserMessage=Cannot delete currently logged in user.
deleteUsernameExistsMessage=The username does not exist and cannot be deleted. deleteUsernameExistsMessage=The username does not exist and cannot be deleted.
downgradeCurrentUserMessage=Kan inte nedgradera nuvarande användares roll downgradeCurrentUserMessage=Kan inte nedgradera nuvarande användares roll
downgradeCurrentUserLongMessage=Kan inte nedgradera nuvarande användares roll. Därför kommer den aktuella användaren inte att visas. downgradeCurrentUserLongMessage=Kan inte nedgradera nuvarande användares roll. Därför kommer den aktuella användaren inte att visas.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Admin User Control Settings
adminUserSettings.admin=Admin adminUserSettings.admin=Admin
adminUserSettings.user=User adminUserSettings.user=User
adminUserSettings.addUser=Add New User adminUserSettings.addUser=Add New User
adminUserSettings.usernameInfo=Username must only contain letters and numbers, no spaces or special characters. adminUserSettings.usernameInfo=Username can only contain letters, numbers and the following special characters @._+- or must be a valid email address.
adminUserSettings.roles=Roles adminUserSettings.roles=Roles
adminUserSettings.role=Role adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Internal API User
adminUserSettings.forceChange=Force user to change password on login adminUserSettings.forceChange=Force user to change password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
adminUserSettings.changeUserRole=Ändra användarens roll adminUserSettings.changeUserRole=Ändra användarens roll
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
#multiTool #multiTool
multiTool.title=PDF-multiverktyg multiTool.title=PDF-multiverktyg
multiTool.header=PDF Multi-verktyg multiTool.header=PDF Multi-verktyg
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=View PDF viewPdf.title=View PDF
@ -1057,7 +1060,7 @@ licenses.version=Version
licenses.license=License licenses.license=License
# error #error
error.sorry=Sorry for the issue! error.sorry=Sorry for the issue!
error.needHelp=Need help / Found an issue? error.needHelp=Need help / Found an issue?
error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord: error.contactTip=If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Kullanıcı doğrulanmadı.
userNotFoundMessage=Kullanıcı bulunamadı. userNotFoundMessage=Kullanıcı bulunamadı.
incorrectPasswordMessage=Mevcut şifre yanlış. incorrectPasswordMessage=Mevcut şifre yanlış.
usernameExistsMessage=Yeni Kullanıcı Adı zaten var. usernameExistsMessage=Yeni Kullanıcı Adı zaten var.
invalidUsernameMessage=Geçersiz kullanıcı adı, Kullanıcı adı yalnızca alfabe karakterleri ve sayılar içermelidir. invalidUsernameMessage=Geçersiz kullanıcı adı, kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır.
deleteCurrentUserMessage=Şu anda oturum açmış olan kullanıcı silinemiyor. deleteCurrentUserMessage=Şu anda oturum açmış olan kullanıcı silinemiyor.
deleteUsernameExistsMessage=Kullanıcı adı mevcut değil ve silinemez. deleteUsernameExistsMessage=Kullanıcı adı mevcut değil ve silinemez.
downgradeCurrentUserMessage=Mevcut kullanıcının rolü düşürülemiyor downgradeCurrentUserMessage=Mevcut kullanıcının rolü düşürülemiyor
downgradeCurrentUserLongMessage=Mevcut kullanıcının rolü düşürülemiyor. Bu nedenle, mevcut kullanıcı gösterilmeyecektir. downgradeCurrentUserLongMessage=Mevcut kullanıcının rolü düşürülemiyor. Bu nedenle, mevcut kullanıcı gösterilmeyecektir.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Hata error=Hata
oops=Tüh! oops=Tüh!
help=Yardım help=Yardım
@ -68,8 +70,8 @@ seeDockerHub=Docker Hub'a bakın
visitGithub=Github Deposunu Ziyaret Edin visitGithub=Github Deposunu Ziyaret Edin
donate=Bağış Yapın donate=Bağış Yapın
color=Renk color=Renk
info=Info
sponsor=Bağış sponsor=Bağış
info=Info
@ -171,7 +173,7 @@ adminUserSettings.header=Yönetici Kullanıcı Kontrol Ayarları
adminUserSettings.admin=Yönetici adminUserSettings.admin=Yönetici
adminUserSettings.user=Kullanıcı adminUserSettings.user=Kullanıcı
adminUserSettings.addUser=Yeni Kullanıcı Ekle adminUserSettings.addUser=Yeni Kullanıcı Ekle
adminUserSettings.usernameInfo=Kullanıcı adı yalnızca harf ve rakamlardan oluşmalı, boşluk veya özel karakter içermemelidir. adminUserSettings.usernameInfo=Kullanıcı adı yalnızca harf, rakam ve aşağıdaki özel karakterleri @._+- içerebilir veya geçerli bir e-posta adresi olmalıdır.
adminUserSettings.roles=Roller adminUserSettings.roles=Roller
adminUserSettings.role=Rol adminUserSettings.role=Rol
adminUserSettings.actions=Eylemler adminUserSettings.actions=Eylemler
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Dahili API Kullanıcısı
adminUserSettings.forceChange=Kullanıcının girişte kullanıcı adı/şifre değiştirmesini zorla adminUserSettings.forceChange=Kullanıcının girişte kullanıcı adı/şifre değiştirmesini zorla
adminUserSettings.submit=Kullanıcıyı Kaydet adminUserSettings.submit=Kullanıcıyı Kaydet
adminUserSettings.changeUserRole=Kullanıcı rolünü değiştir adminUserSettings.changeUserRole=Kullanıcı rolünü değiştir
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(örn. 1,3,2 veya 4-8,2,10-12 veya 2n-1)
#multiTool #multiTool
multiTool.title=PDF Çoklu Araç multiTool.title=PDF Çoklu Araç
multiTool.header=PDF Çoklu Araç multiTool.header=PDF Çoklu Araç
multiTool.uploadPrompts=Lütfen PDF Yükleyin multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=PDF Görüntüle viewPdf.title=PDF Görüntüle
@ -1057,7 +1060,7 @@ licenses.version=Versiyon
licenses.license=Lisans licenses.license=Lisans
# error #error
error.sorry=Sorun için özür dileriz! error.sorry=Sorun için özür dileriz!
error.needHelp=Yardıma mı ihtiyacınız var / Bir sorun mu buldunuz? error.needHelp=Yardıma mı ihtiyacınız var / Bir sorun mu buldunuz?
error.contactTip=Hala sorun yaşıyorsanız, yardım için bize ulaşmaktan çekinmeyin. GitHub sayfamızdan bir bilet gönderebilir veya Discord üzerinden bizimle iletişime geçebilirsiniz: error.contactTip=Hala sorun yaşıyorsanız, yardım için bize ulaşmaktan çekinmeyin. GitHub sayfamızdan bir bilet gönderebilir veya Discord üzerinden bizimle iletişime geçebilirsiniz:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=Користувач не пройшов перевір
userNotFoundMessage=Користувача не знайдено. userNotFoundMessage=Користувача не знайдено.
incorrectPasswordMessage=Поточний пароль невірний. incorrectPasswordMessage=Поточний пароль невірний.
usernameExistsMessage=Нове ім'я користувача вже існує. usernameExistsMessage=Нове ім'я користувача вже існує.
invalidUsernameMessage=Недійсне ім'я користувача, Ім'я користувача повинно містити тільки літери алфавіту та цифри. invalidUsernameMessage=Недійсне ім’я користувача, ім’я користувача може містити лише літери, цифри та наступні спеціальні символи @._+- або має бути дійсною електронною адресою.
deleteCurrentUserMessage=Неможливо видалити користувача, який увійшов в систему. deleteCurrentUserMessage=Неможливо видалити користувача, який увійшов в систему.
deleteUsernameExistsMessage=Ім'я користувача не існує і не може бути видалено. deleteUsernameExistsMessage=Ім'я користувача не існує і не може бути видалено.
downgradeCurrentUserMessage=Неможливо понизити роль поточного користувача downgradeCurrentUserMessage=Неможливо понизити роль поточного користувача
downgradeCurrentUserLongMessage=Неможливо понизити роль поточного користувача. Отже, поточний користувач не відображатиметься. downgradeCurrentUserLongMessage=Неможливо понизити роль поточного користувача. Отже, поточний користувач не відображатиметься.
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=Error error=Error
oops=Oops! oops=Oops!
help=Help help=Help
@ -171,7 +173,7 @@ adminUserSettings.header=Налаштування контролю корист
adminUserSettings.admin=Адміністратор adminUserSettings.admin=Адміністратор
adminUserSettings.user=Користувач adminUserSettings.user=Користувач
adminUserSettings.addUser=Додати нового користувача adminUserSettings.addUser=Додати нового користувача
adminUserSettings.usernameInfo=Ім'я користувача має містити тільки літери та цифри, без пробілів та спеціальних символів. adminUserSettings.usernameInfo=Ім’я користувача може містити лише літери, цифри та наступні спеціальні символи @._+- або має бути дійсною електронною адресою.
adminUserSettings.roles=Ролі adminUserSettings.roles=Ролі
adminUserSettings.role=Роль adminUserSettings.role=Роль
adminUserSettings.actions=Дії adminUserSettings.actions=Дії
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=Внутрішній користувач API
adminUserSettings.forceChange=Примусити користувача змінити пароль при вході в систему adminUserSettings.forceChange=Примусити користувача змінити пароль при вході в систему
adminUserSettings.submit=Зберегти користувача adminUserSettings.submit=Зберегти користувача
adminUserSettings.changeUserRole=Змінити роль користувача adminUserSettings.changeUserRole=Змінити роль користувача
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(наприклад, 1,3,2 або 4-8,2,10-12 або 2n
#multiTool #multiTool
multiTool.title=Мультіінструмент PDF multiTool.title=Мультіінструмент PDF
multiTool.header=Мультіінструмент PDF multiTool.header=Мультіінструмент PDF
multiTool.uploadPrompts=Будь ласка, завантажте PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=Переглянути PDF viewPdf.title=Переглянути PDF
@ -1057,7 +1060,7 @@ licenses.version=Версія
licenses.license=Ліцензія licenses.license=Ліцензія
# error #error
error.sorry=Вибачте за незручності! error.sorry=Вибачте за незручності!
error.needHelp=Потрібна допомога / Знайшли проблему? error.needHelp=Потрібна допомога / Знайшли проблему?
error.contactTip=Якщо у вас досі виникають проблеми, не соромтеся звертатися до нас за допомогою. Ви можете надіслати запит на нашій сторінці GitHub або зв'язатися з нами через Discord: error.contactTip=Якщо у вас досі виникають проблеми, не соромтеся звертатися до нас за допомогою. Ви можете надіслати запит на нашій сторінці GitHub або зв'язатися з нами через Discord:

View file

@ -54,11 +54,13 @@ notAuthenticatedMessage=用户未经过身份验证。
userNotFoundMessage=未找到用户。 userNotFoundMessage=未找到用户。
incorrectPasswordMessage=当前密码不正确。 incorrectPasswordMessage=当前密码不正确。
usernameExistsMessage=新用户名已存在。 usernameExistsMessage=新用户名已存在。
invalidUsernameMessage=用户名无效,用户名只能由字母字符和数字组成 invalidUsernameMessage=用户名无效,用户名只能包含字母、数字和以下特殊字符@._+- 或必须是有效的电子邮件地址
deleteCurrentUserMessage=无法删除当前登录的用户。 deleteCurrentUserMessage=无法删除当前登录的用户。
deleteUsernameExistsMessage=用户名不存在,无法删除。 deleteUsernameExistsMessage=用户名不存在,无法删除。
downgradeCurrentUserMessage=无法降级当前用户的角色 downgradeCurrentUserMessage=无法降级当前用户的角色
downgradeCurrentUserLongMessage=无法降级当前用户的角色。因此,当前用户将不会显示。 downgradeCurrentUserLongMessage=无法降级当前用户的角色。因此,当前用户将不会显示。
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=错误 error=错误
oops=哎呀! oops=哎呀!
help=帮助 help=帮助
@ -171,7 +173,7 @@ adminUserSettings.header=管理员用户控制设置
adminUserSettings.admin=管理员 adminUserSettings.admin=管理员
adminUserSettings.user=用户 adminUserSettings.user=用户
adminUserSettings.addUser=添加新用户 adminUserSettings.addUser=添加新用户
adminUserSettings.usernameInfo=用户名只能由字母和数字组成,不能包含空格或特殊字符 adminUserSettings.usernameInfo=用户名只能包含字母、数字和以下特殊字符@._+-,或者必须是有效的电子邮件地址
adminUserSettings.roles=角色 adminUserSettings.roles=角色
adminUserSettings.role=角色 adminUserSettings.role=角色
adminUserSettings.actions=操作 adminUserSettings.actions=操作
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=内部API用户
adminUserSettings.forceChange=强制用户在登录时更改用户名/密码 adminUserSettings.forceChange=强制用户在登录时更改用户名/密码
adminUserSettings.submit=保存用户 adminUserSettings.submit=保存用户
adminUserSettings.changeUserRole=更改用户角色 adminUserSettings.changeUserRole=更改用户角色
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(例如 1,3,2 或 4-8,2,10-12 或 2n-1
#multiTool #multiTool
multiTool.title=PDF多功能工具 multiTool.title=PDF多功能工具
multiTool.header=PDF多功能工具 multiTool.header=PDF多功能工具
multiTool.uploadPrompts=上传PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=浏览PDF viewPdf.title=浏览PDF
@ -1057,7 +1060,7 @@ licenses.version=版本
licenses.license=许可证 licenses.license=许可证
# error #error
error.sorry=对此问题感到抱歉! error.sorry=对此问题感到抱歉!
error.needHelp=需要帮助 / 发现问题? error.needHelp=需要帮助 / 发现问题?
error.contactTip=如果你仍然遇到问题不要犹豫向我们寻求帮助。你可以在我们的GitHub页面上提交工单或者通过Discord与我们联系 error.contactTip=如果你仍然遇到问题不要犹豫向我们寻求帮助。你可以在我们的GitHub页面上提交工单或者通过Discord与我们联系

View file

@ -54,12 +54,13 @@ notAuthenticatedMessage=使用者未認證。
userNotFoundMessage=找不到使用者。 userNotFoundMessage=找不到使用者。
incorrectPasswordMessage=目前密碼不正確。 incorrectPasswordMessage=目前密碼不正確。
usernameExistsMessage=新使用者名稱已存在。 usernameExistsMessage=新使用者名稱已存在。
invalidUsernameMessage=使用者名無效,使用者名只能包含字母字元和數位 invalidUsernameMessage=使用者名稱無效,使用者名稱只能包含字母、數字和以下特殊字元@._+- 或必須是有效的電子郵件地址
deleteCurrentUserMessage=無法刪除目前登錄的使用者。 deleteCurrentUserMessage=無法刪除目前登錄的使用者。
deleteUsernameExistsMessage=使用者名不存在,無法刪除。 deleteUsernameExistsMessage=使用者名不存在,無法刪除。
info=Info
downgradeCurrentUserMessage=無法降級目前使用者的角色 downgradeCurrentUserMessage=無法降級目前使用者的角色
downgradeCurrentUserLongMessage=無法降級目前使用者的角色。因此,不會顯示目前的使用者。 downgradeCurrentUserLongMessage=無法降級目前使用者的角色。因此,不會顯示目前的使用者。
userAlreadyExistsOAuthMessage=The user already exists as an OAuth2 user.
userAlreadyExistsWebMessage=The user already exists as an web user.
error=錯誤 error=錯誤
oops=哎呀! oops=哎呀!
help=幫助 help=幫助
@ -70,6 +71,7 @@ visitGithub=訪問Github存儲庫
donate=捐贈 donate=捐贈
color=顏色 color=顏色
sponsor=贊助 sponsor=贊助
info=Info
@ -171,7 +173,7 @@ adminUserSettings.header=管理使用者控制設定
adminUserSettings.admin=管理員 adminUserSettings.admin=管理員
adminUserSettings.user=使用者 adminUserSettings.user=使用者
adminUserSettings.addUser=新增使用者 adminUserSettings.addUser=新增使用者
adminUserSettings.usernameInfo=使用者名只能包含字母和數位,不能包含空格或特殊字元 adminUserSettings.usernameInfo=使用者名稱只能包含字母、數字和以下特殊字元@._+-,或必須是有效的電子郵件地址
adminUserSettings.roles=角色 adminUserSettings.roles=角色
adminUserSettings.role=角色 adminUserSettings.role=角色
adminUserSettings.actions=操作 adminUserSettings.actions=操作
@ -183,6 +185,7 @@ adminUserSettings.internalApiUser=內部 API 使用者
adminUserSettings.forceChange=強制使用者在登入時修改使用者名稱/密碼 adminUserSettings.forceChange=強制使用者在登入時修改使用者名稱/密碼
adminUserSettings.submit=儲存 adminUserSettings.submit=儲存
adminUserSettings.changeUserRole=更改使用者身份 adminUserSettings.changeUserRole=更改使用者身份
adminUserSettings.authenticated=Authenticated
############# #############
# HOME-PAGE # # HOME-PAGE #
@ -802,7 +805,7 @@ pdfOrganiser.placeholder=(例如 1,3,2 或 4-8,2,10-12 或 2n-1
#multiTool #multiTool
multiTool.title=PDF 多工具 multiTool.title=PDF 多工具
multiTool.header=PDF 多工具 multiTool.header=PDF 多工具
multiTool.uploadPrompts=Please Upload PDF multiTool.uploadPrompts=File Name
#view pdf #view pdf
viewPdf.title=檢視 PDF viewPdf.title=檢視 PDF
@ -1057,7 +1060,7 @@ licenses.version=版本
licenses.license=許可證 licenses.license=許可證
# error #error
error.sorry=對於這個問題,我們感到抱歉! error.sorry=對於這個問題,我們感到抱歉!
error.needHelp=需要幫助/發現了一個問題? error.needHelp=需要幫助/發現了一個問題?
error.contactTip=如果你仍然遇到問題請不要猶豫隨時向我們尋求幫助。你可以在我們的GitHub頁面提交工單或通過Discord與我們聯繋 error.contactTip=如果你仍然遇到問題請不要猶豫隨時向我們尋求幫助。你可以在我們的GitHub頁面提交工單或通過Discord與我們聯繋

View file

@ -7,12 +7,15 @@ security:
csrfDisabled: true csrfDisabled: true
loginAttemptCount: 5 # lock user account after 5 tries loginAttemptCount: 5 # lock user account after 5 tries
loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts loginResetTimeMinutes : 120 # lock account for 2 hours after x attempts
#oauth2: # oauth2:
# enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work) # enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
# issuer: "" # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point # issuer: "" # set to any provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point
# clientId: "" # Client ID from your provider # clientId: "" # Client ID from your provider
# clientSecret: "" # Client Secret from your provider # clientSecret: "" # Client Secret from your provider
# autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users # autoCreateUser: false # set to 'true' to allow auto-creation of non-existing users
# useAsUsername: "email" # Default is 'email'; custom fields can be used as the username
# scopes: "openid, profile, email" # Specify the scopes for which the application will request permissions
# provider: "google" # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak'
system: system:
defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc) defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)

File diff suppressed because one or more lines are too long

View file

@ -1,12 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org">
xmlns:th="http://www.thymeleaf.org"> <head>
<head>
<th:block th:insert="~{fragments/common :: head(title=#{account.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{account.title})}"></th:block>
</head> </head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
@ -14,25 +12,13 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-9" id="bg-card"> <div class="col-md-9">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2> <h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2>
<th:block th:if="${param.messageType != null and param.messageType.size() > 0}"> <th:block th:if="${messageType}">
<div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger"> <div class="alert alert-danger">
<span th:text="#{notAuthenticatedMessage}">Default message if not found</span> <span th:text="#{${messageType}}">Default message if not found</span>
</div>
<div th:if="${param.messageType[0] == 'userNotFound'}" class="alert alert-danger">
<span th:text="#{userNotFoundMessage}">Default message if not found</span>
</div>
<div th:if="${param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger">
<span th:text="#{incorrectPasswordMessage}">Default message if not found</span>
</div>
<div th:if="${param.messageType[0] == 'usernameExists'}" class="alert alert-danger">
<span th:text="#{usernameExistsMessage}">Default message if not found</span>
</div>
<div th:if="${param.messageType[0] == 'invalidUsername'}" class="alert alert-danger">
<span th:text="#{invalidUsernameMessage}">Default message if not found</span>
</div> </div>
</th:block> </th:block>
<!-- At the top of the user settings --> <!-- At the top of the user settings -->
@ -43,48 +29,44 @@
</div> </div>
</th:block> </th:block>
<!-- Change Username Form --> <!-- Change Username Form -->
<th:block th:if="${!oAuth2Login}">
<h4 th:text="#{account.changeUsername}">Change Username?</h4> <h4 th:text="#{account.changeUsername}">Change Username?</h4>
<form th:if="${!oAuth2Login}" id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-username" method="post"> <form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-username" method="post">
<div class="mb-3"> <div class="mb-3">
<label for="newUsername" th:text="#{account.newUsername}">Change Username</label> <label for="newUsername" th:text="#{account.newUsername}">Change Username</label>
<input type="text" class="form-control" name="newUsername" id="newUsername" <input type="text" class="form-control" name="newUsername" id="newUsername" th:placeholder="#{account.newUsername}">
th:placeholder="#{account.newUsername}">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="currentPassword" th:text="#{password}">Password</label> <label for="currentPassword" th:text="#{password}">Password</label>
<input type="password" class="form-control" name="currentPassword" id="currentPassword" <input type="password" class="form-control" name="currentPassword" id="currentPassword" th:placeholder="#{password}">
th:placeholder="#{password}">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<button type="submit" class="btn btn-primary" th:text="#{account.changeUsername}">Change <button type="submit" class="btn btn-primary" th:text="#{account.changeUsername}">Change Username</button>
Username</button>
</div> </div>
</form> </form>
</th:block>
<!-- Change Password Form --> <!-- Change Password Form -->
<h4 th:if="${!oAuth2Login}" th:text="#{account.changePassword}">Change Password?</h4> <th:block th:if="${!oAuth2Login}">
<h4 th:text="#{account.changePassword}">Change Password?</h4>
<form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-password" method="post"> <form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-password" method="post">
<div class="mb-3"> <div class="mb-3">
<label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label> <label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label>
<input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword" <input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword" th:placeholder="#{account.oldPassword}">
th:placeholder="#{account.oldPassword}">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="newPassword" th:text="#{account.newPassword}">New Password</label> <label for="newPassword" th:text="#{account.newPassword}">New Password</label>
<input type="password" class="form-control" name="newPassword" id="newPassword" <input type="password" class="form-control" name="newPassword" id="newPassword" th:placeholder="#{account.newPassword}">
th:placeholder="#{account.newPassword}">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="confirmNewPassword" th:text="#{account.confirmNewPassword}">Confirm New Password</label> <label for="confirmNewPassword" th:text="#{account.confirmNewPassword}">Confirm New Password</label>
<input type="password" class="form-control" name="confirmNewPassword" id="confirmNewPassword" <input type="password" class="form-control" name="confirmNewPassword" id="confirmNewPassword" th:placeholder="#{account.confirmNewPassword}">
th:placeholder="#{account.confirmNewPassword}">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<button type="submit" class="btn btn-primary" th:text="#{account.changePassword}">Change <button type="submit" class="btn btn-primary" th:text="#{account.changePassword}">Change Password</button>
Password</button>
</div> </div>
</form> </form>
</th:block>
<!-- API Key Form --> <!-- API Key Form -->
<h4 th:text="#{account.yourApiKey}">API Key</h4> <h4 th:text="#{account.yourApiKey}">API Key</h4>
@ -92,8 +74,7 @@
<div class="card-header" th:text="#{account.yourApiKey}"></div> <div class="card-header" th:text="#{account.yourApiKey}"></div>
<div class="card-body"> <div class="card-body">
<div class="input-group mb-3"> <div class="input-group mb-3">
<input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}" <input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}" readonly>
readonly>
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-secondary" id="copyBtn" type="button" onclick="copyToClipboard()"> <button class="btn btn-secondary" id="copyBtn" type="button" onclick="copyToClipboard()">
<span class="material-symbols-rounded"> <span class="material-symbols-rounded">
@ -137,7 +118,7 @@
} }
} }
document.addEventListener("DOMContentLoaded", async function () { document.addEventListener("DOMContentLoaded", async function() {
try { try {
let response = await fetch('/api/v1/user/get-api-key', { method: 'POST' }); let response = await fetch('/api/v1/user/get-api-key', { method: 'POST' });
if (response.status === 200) { if (response.status === 200) {
@ -183,10 +164,10 @@
} }
} }
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function() {
const form = document.querySelector('form[action="api/v1/user/change-password"]'); const form = document.querySelector('form[action="api/v1/user/change-password"]');
form.addEventListener('submit', function (event) { form.addEventListener('submit', function(event) {
const newPassword = document.getElementById('newPassword').value; const newPassword = document.getElementById('newPassword').value;
const confirmNewPassword = document.getElementById('confirmNewPassword').value; const confirmNewPassword = document.getElementById('confirmNewPassword').value;
@ -215,15 +196,13 @@
</table> </table>
<div class="buttons-container mt-3 text-center"> <div class="buttons-container mt-3 text-center">
<button id="syncToBrowser" class="btn btn-primary btn-sm" th:text="#{account.syncToBrowser}">Sync <button id="syncToBrowser" class="btn btn-primary btn-sm" th:text="#{account.syncToBrowser}">Sync Account -> Browser</button>
Account -> Browser</button> <button id="syncToAccount" class="btn btn-secondary btn-sm" th:text="#{account.syncToAccount}">Sync Account <- Browser</button>
<button id="syncToAccount" class="btn btn-secondary btn-sm" th:text="#{account.syncToAccount}">Sync
Account <- Browser</button>
</div> </div>
</div> </div>
<script th:inline="javascript"> <script th:inline="javascript">
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function() {
const settingsTableBody = document.querySelector("#settingsTable tbody"); const settingsTableBody = document.querySelector("#settingsTable tbody");
/*<![CDATA[*/ /*<![CDATA[*/
@ -234,7 +213,7 @@
let allKeys = new Set([...Object.keys(accountSettings), ...Object.keys(localStorage)]); let allKeys = new Set([...Object.keys(accountSettings), ...Object.keys(localStorage)]);
allKeys.forEach(key => { allKeys.forEach(key => {
if (key === 'debug' || key === '0' || key === '1') return; // Ignoring specific keys if(key === 'debug' || key === '0' || key === '1') return; // Ignoring specific keys
const accountValue = accountSettings[key] || '-'; const accountValue = accountSettings[key] || '-';
const browserValue = localStorage.getItem(key) || '-'; const browserValue = localStorage.getItem(key) || '-';
@ -249,27 +228,27 @@
browserCell.textContent = browserValue; browserCell.textContent = browserValue;
}); });
document.getElementById('syncToBrowser').addEventListener('click', function () { document.getElementById('syncToBrowser').addEventListener('click', function() {
// First, clear the local storage // First, clear the local storage
localStorage.clear(); localStorage.clear();
// Then, set the account settings to local storage // Then, set the account settings to local storage
for (let key in accountSettings) { for (let key in accountSettings) {
if (key !== 'debug' && key !== '0' && key !== '1') { // Only sync non-ignored keys if(key !== 'debug' && key !== '0' && key !== '1') { // Only sync non-ignored keys
localStorage.setItem(key, accountSettings[key]); localStorage.setItem(key, accountSettings[key]);
} }
} }
location.reload(); // Refresh the page after sync location.reload(); // Refresh the page after sync
}); });
document.getElementById('syncToAccount').addEventListener('click', function () { document.getElementById('syncToAccount').addEventListener('click', function() {
let form = document.createElement("form"); let form = document.createElement("form");
form.method = "POST"; form.method = "POST";
form.action = "api/v1/user/updateUserSettings"; // Your endpoint URL form.action = "api/v1/user/updateUserSettings"; // Your endpoint URL
for (let i = 0; i < localStorage.length; i++) { for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i); const key = localStorage.key(i);
if (key !== 'debug' && key !== '0' && key !== '1') { // Only send non-ignored keys if(key !== 'debug' && key !== '0' && key !== '1') { // Only send non-ignored keys
let hiddenField = document.createElement("input"); let hiddenField = document.createElement("input");
hiddenField.type = "hidden"; hiddenField.type = "hidden";
hiddenField.name = key; hiddenField.name = key;
@ -286,8 +265,7 @@
</script> </script>
<div class="mb-3 mt-4 text-center"> <div class="mb-3 mt-4 text-center">
<a href="logout" role="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</a> <a href="logout" role="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</a>
<a th:if="${role == 'ROLE_ADMIN'}" class="btn btn-info" href="addUsers" role="button" <a th:if="${role == 'ROLE_ADMIN'}" class="btn btn-info" href="addUsers" role="button" th:text="#{account.adminSettings}" target="_blank">Admin Settings</a>
th:text="#{account.adminSettings}" target="_blank">Admin Settings</a>
</div> </div>
</div> </div>
</div> </div>
@ -295,6 +273,5 @@
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View file

@ -16,9 +16,8 @@
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{adminUserSettings.header}">Admin User Control Settings</h2> <h2 class="text-center" th:text="#{adminUserSettings.header}">Admin User Control Settings</h2>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and (param.messageType[0] == 'deleteCurrentUser' or param.messageType[0] == 'deleteUsernameExists')}" class="alert alert-danger"> <div th:if="${deleteMessage}" class="alert alert-danger">
<span th:if="${param.messageType[0] == 'deleteCurrentUser'}" th:text="#{deleteCurrentUserMessage}">Cannot delete currently logged in user.</span> <span th:text="#{${deleteMessage}}">Message</span>
<span th:if="${param.messageType[0] == 'deleteUsernameExists'}" th:text="#{deleteUsernameExistsMessage}">The username does not exist and cannot be deleted.</span>
</div> </div>
<table class="table"> <table class="table">
<thead> <thead>
@ -26,6 +25,7 @@
<th th:text="#{username}">Username</th> <th th:text="#{username}">Username</th>
<th th:text="#{adminUserSettings.roles}">Roles</th> <th th:text="#{adminUserSettings.roles}">Roles</th>
<th th:text="#{adminUserSettings.actions}">Actions</th> <th th:text="#{adminUserSettings.actions}">Actions</th>
<th th:text="#{adminUserSettings.authenticated}">Authenticated</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -37,19 +37,21 @@
<button type="submit" th:text="#{delete}">Delete</button> <button type="submit" th:text="#{delete}">Delete</button>
</form> </form>
</td> </td>
<td th:text="${user.authenticationType}"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<h2 th:text="#{adminUserSettings.addUser}">Add New User</h2> <h2 th:text="#{adminUserSettings.addUser}">Add New User</h2>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and (param.messageType[0] == 'usernameExists' or param.messageType[0] == 'invalidUsername')}" class="alert alert-danger"> <div th:if="${addMessage}" class="alert alert-danger">
<span th:if="${param.messageType[0] == 'usernameExists'}" th:text="#{usernameExistsMessage}">Default message if not found</span> <span th:text="#{${addMessage}}">Default message if not found</span>
<span th:if="${param.messageType[0] == 'invalidUsername'}" th:text="#{invalidUsernameMessage}">Default message if not found</span>
</div> </div>
<form action="/api/v1/user/admin/saveUser" method="post"> <button class="btn btn-outline-info" data-toggle="tooltip" data-placement="auto" th:title="#{adminUserSettings.usernameInfo}" th:text="#{help}">Help</button>
<form id="formsaveuser" action="/api/v1/user/admin/saveUser" method="post">
<div class="mb-3"> <div class="mb-3">
<label for="username" th:text="#{username}">Username</label> <label for="username" th:text="#{username}">Username</label>
<input type="text" class="form-control" name="username" pattern="[a-zA-Z0-9]+" th:title="#{adminUserSettings.usernameInfo}" required> <input type="text" class="form-control" name="username" id="username" th:title="#{adminUserSettings.usernameInfo}" required>
<span id="usernameError" style="display: none;" th:text="#{invalidUsernameMessage}">Invalid username!</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="password" th:text="#{password}">Password</label> <label for="password" th:text="#{password}">Password</label>
@ -73,9 +75,8 @@
<hr /> <hr />
<h2 th:text="#{adminUserSettings.changeUserRole}">Change User's Role</h2> <h2 th:text="#{adminUserSettings.changeUserRole}">Change User's Role</h2>
<button class="btn btn-outline-info" data-toggle="tooltip" data-placement="auto" th:title="#{downgradeCurrentUserLongMessage}" th:text="#{help}">Help</button> <button class="btn btn-outline-info" data-toggle="tooltip" data-placement="auto" th:title="#{downgradeCurrentUserLongMessage}" th:text="#{help}">Help</button>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and (param.messageType[0] == 'userNotFound' or param.messageType[0] == 'downgradeCurrentUser')}" class="alert alert-danger"> <div th:if="${changeMessage}" class="alert alert-danger">
<span th:if="${param.messageType[0] == 'userNotFound'}" th:text="#{userNotFoundMessage}">Username not found</span> <span th:text="#{${changeMessage}}">Default message if not found</span>
<span th:if="${param.messageType[0] == 'downgradeCurrentUser'}" th:text="#{downgradeCurrentUserMessage}">Cannot downgrade current user's role</span>
</div> </div>
<form action="/api/v1/user/admin/changeRole" method="post"> <form action="/api/v1/user/admin/changeRole" method="post">
<div class="mb-3"> <div class="mb-3">
@ -101,9 +102,55 @@
</div> </div>
</div> </div>
<script th:inline="javascript"> <script th:inline="javascript">
jQuery.validator.addMethod("usernamePattern", function(value, element) {
return this.optional(element) || /^[a-zA-Z0-9][a-zA-Z0-9@._+-]*[a-zA-Z0-9]$|^(?=.{1,64}@)[A-Za-z0-9]+(\.[A-Za-z0-9_+.-]+)*@[^-][A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(\.[A-Za-z]{2,})$/.test(value);
}, /*[[#{invalidUsernameMessage}]]*/ "Invalid username format");
$(document).ready(function() { $(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip();
})
$('#formsaveuser').validate({
rules: {
username: {
required: true,
usernamePattern: true
},
password: {
required: true
}
},
messages: {
username: {
usernamePattern: /*[[#{invalidUsernameMessage}]]*/ "Invalid username format"
},
},
errorPlacement: function(error, element) {
if (element.attr("name") === "username") {
$("#usernameError").text(error.text()).show();
} else {
error.insertAfter(element);
}
},
success: function(label, element) {
if ($(element).attr("name") === "username") {
$("#usernameError").hide();
}
}
});
$('#username').on('input', function() {
var usernameInput = $(this);
var isValid = usernameInput[0].checkValidity();
var errorSpan = $('#usernameError');
if (isValid) {
usernameInput.removeClass('invalid').addClass('valid');
errorSpan.hide();
} else {
usernameInput.removeClass('valid').addClass('invalid');
errorSpan.show();
}
});
});
</script> </script>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>

View file

@ -17,18 +17,9 @@
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{changeCreds.header}">User Settings</h2> <h2 class="text-center" th:text="#{changeCreds.header}">User Settings</h2>
<hr> <hr>
<th:block th:if="${param.messageType != null and param.messageType.size() > 0}"> <th:block th:if="${messageType}">
<div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger"> <div class="alert alert-danger">
<span th:text="#{notAuthenticatedMessage}">Default message if not found</span> <span th:text="#{${messageType}}">Default message if not found</span>
</div>
<div th:if="${param.messageType[0] == 'userNotFound'}" class="alert alert-danger">
<span th:text="#{userNotFoundMessage}">Default message if not found</span>
</div>
<div th:if="${param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger">
<span th:text="#{incorrectPasswordMessage}">Default message if not found</span>
</div>
<div th:if="${param.messageType[0] == 'usernameExists'}" class="alert alert-danger">
<span th:text="#{usernameExistsMessage}">Default message if not found</span>
</div> </div>
</th:block> </th:block>
<!-- At the top of the user settings --> <!-- At the top of the user settings -->

View file

@ -10,12 +10,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Icons --> <!-- Icons -->
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=2"> <link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png?v=2">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=2"> <link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png?v=2">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=2"> <link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png?v=2">
<link rel="manifest" href="/site.webmanifest?v=2"> <link rel="manifest" href="site.webmanifest?v=2">
<link rel="mask-icon" href="/safari-pinned-tab.svg?v=2" color="#ca2b2a"> <link rel="mask-icon" href="safari-pinned-tab.svg?v=2" color="#ca2b2a">
<link rel="shortcut icon" href="/favicon.ico?v=2"> <link rel="shortcut icon" href="favicon.ico?v=2">
<meta name="apple-mobile-web-app-title" content="Stirling PDF"> <meta name="apple-mobile-web-app-title" content="Stirling PDF">
<meta name="application-name" content="Stirling PDF"> <meta name="application-name" content="Stirling PDF">
<meta name="msapplication-TileColor" content="#00aba9"> <meta name="msapplication-TileColor" content="#00aba9">
@ -23,6 +23,7 @@
<!-- jQuery --> <!-- jQuery -->
<script src="js/thirdParty/jquery.min.js"></script> <script src="js/thirdParty/jquery.min.js"></script>
<script src="js/thirdParty/jquery.validate.min.js"></script>
<script src="js/thirdParty/jszip.min.js"></script> <script src="js/thirdParty/jszip.min.js"></script>
<!-- Bootstrap --> <!-- Bootstrap -->
@ -59,7 +60,7 @@
<link rel="stylesheet" href="css/stamp.css" th:if="${currentPage == 'stamp'}"> <link rel="stylesheet" href="css/stamp.css" th:if="${currentPage == 'stamp'}">
<link rel="stylesheet" href="css/fileSelect.css"> <link rel="stylesheet" href="css/fileSelect.css">
<link rel="stylesheet" href="css/footer.css"> <link rel="stylesheet" href="css/footer.css">
<script src="js/thirdParty/fontfaceobserver.standalone.js"></script> <script src="js/thirdParty/fontfaceobserver.standalone.js"></script>
<!-- Google MD Icons --> <!-- Google MD Icons -->
<link rel="stylesheet" href="css/theme/font.css"> <link rel="stylesheet" href="css/theme/font.css">
@ -70,14 +71,13 @@
<script src="js/cacheFormInputs.js"></script> <script src="js/cacheFormInputs.js"></script>
<script src="js/tab-container.js"></script> <script src="js/tab-container.js"></script>
<script src="js/darkmode.js"></script> <script src="js/darkmode.js"></script>
</th:block> </th:block>
<th:block th:fragment="game"> <th:block th:fragment="game">
<dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal> <dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal>
<script th:inline="javascript"> <script th:inline="javascript">
console.log("loaded game"); console.log("loaded game");
$(document).ready(function () { $(document).ready(function() {
// Find the file input within the form // Find the file input within the form
var fileInput = $('input[type="file"]'); var fileInput = $('input[type="file"]');
@ -106,11 +106,11 @@
} }
let gameScriptLoaded = false; let gameScriptLoaded = false;
const gameDialog = document.getElementById('game-container-wrapper'); const gameDialog = document.getElementById('game-container-wrapper');
$('#show-game-btn').on('click', function () { $('#show-game-btn').on('click', function() {
console.log('Show game button clicked'); console.log('Show game button clicked');
if (!gameScriptLoaded) { if (!gameScriptLoaded) {
console.log('Show game button load'); console.log('Show game button load');
loadGameScript(function () { loadGameScript(function() {
console.log('Game script loaded'); console.log('Game script loaded');
window.initializeGame(); window.initializeGame();
gameScriptLoaded = true; gameScriptLoaded = true;
@ -144,28 +144,24 @@
</dialog> </dialog>
</th:block> </th:block>
<th:block th:fragment="fileSelector(name, multiple)" <th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false">
th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false">
<script th:inline="javascript"> <script th:inline="javascript">
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ ''; const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
const multiple = [[${ multiple }]] || false; const multiple = [[${multiple}]] || false;
const remoteCall = [[${ remoteCall }]] || true; const remoteCall = [[${remoteCall}]] || true;
</script> </script>
<script src="js/downloader.js"></script> <script src="js/downloader.js"></script>
<div class="custom-file-chooser" <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}">
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}" multiple <input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple th:required="${notRequired} ? null : 'required'">
th:required="${notRequired} ? null : 'required'">
</div> </div>
<div class="selected-files"></div> <div class="selected-files"></div>
</div> </div>
<div class="progressBarContainer" style="display: none; position: relative;"> <div class="progressBarContainer" style="display: none; position: relative;">
<div class="progress" style="height: 1rem;"> <div class="progress" style="height: 1rem;">
<div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" <div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div> </div>
</div> </div>

View file

@ -112,25 +112,32 @@
} }
} }
</script> </script>
<div th:if="${logoutMessage}" class="alert alert-success" th:text="${logoutMessage}"></div>
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'credsUpdated'}" class="alert alert-success">
<span th:text="#{changedCredsMessage}">Default message if not found</span>
</div>
<form th:action="@{login}" method="post">
<div class="text-center"> <div class="text-center">
<img class="mb-4" src="favicon.svg?v=2" alt="" width="144" height="144"> <img class="mb-4" src="favicon.svg?v=2" alt="favicon" width="144" height="144">
<h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1> <h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1>
<div th:if="${oAuth2Enabled}"> <div th:if="${oAuth2Enabled}">
<a href="oauth2/authorization/oidc" class="w-100 btn btn-lg btn-primary" th:text="#{login.ssoSignIn}">Login Via SSO</a> <a href="oauth2/authorization/oidc" class="w-100 btn btn-lg btn-primary" th:text="#{login.ssoSignIn}">Login Via SSO</a>
<div class="text-danger text-center"> <br>
<div th:if="${error == 'oauth2AutoCreateDisabled'}" th:text="#{login.oauth2AutoCreateDisabled}">OAUTH2 Auto-Create User Disabled.</div> <br>
<div th:if="${erroroauth}" class="alert alert-danger text-center">
<div th:if="${erroroauth}" th:text="#{${erroroauth}}">OAuth2: Error Message</div>
</div> </div>
<hr /> <hr />
</div> </div>
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2>
<div th:if="${error}" class="alert alert-danger text-danger text-center">
<div th:if="${error}" th:text="#{${error}}">OAuth2: Error Message</div>
</div> </div>
<div class="text-danger text-center">
<div th:if="${logoutMessage}" class="alert alert-success" th:text="${logoutMessage}"></div>
<div th:if="${messageType}" class="alert alert-success">
<span th:text="#{${messageType}}">Default message if not found</span>
</div>
</div>
</div>
<form th:action="@{login}" method="post">
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2>
<div class="form-floating"> <div class="form-floating">
<input type="text" class="form-control" id="username" name="username" placeholder="admin"> <input type="text" class="form-control" id="username" name="username" placeholder="admin">
<label for="username" th:text="#{username}">Username</label> <label for="username" th:text="#{username}">Username</label>
@ -160,10 +167,6 @@
</div> </div>
</div> </div>
</div> </div>
<div class="text-danger text-center">
<div th:if="${error == 'badcredentials'}" th:text="#{login.invalid}">Invalid username or password.</div>
<div th:if="${error == 'locked'}" th:text="#{login.locked}">Your account has been locked. </div>
</div>
</main> </main>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>