diff --git a/build.gradle b/build.gradle index 1c04334bb5..90e130f6c4 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,9 @@ sourceSets { if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") { exclude "stirling/software/SPDF/config/security/**" exclude "stirling/software/SPDF/controller/api/UserController.java" + exclude "stirling/software/SPDF/controller/api/DatabaseController.java" exclude "stirling/software/SPDF/controller/web/AccountWebController.java" + exclude "stirling/software/SPDF/controller/web/DatabaseWebController.java" exclude "stirling/software/SPDF/model/ApiKeyAuthenticationToken.java" exclude "stirling/software/SPDF/model/Authority.java" exclude "stirling/software/SPDF/model/PersistentLogin.java" @@ -120,6 +122,7 @@ dependencies { //2.2.x requires rebuild of DB file.. need migration path implementation "com.h2database:h2:2.1.214" + // implementation "com.h2database:h2:2.2.224" } testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion" diff --git a/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java b/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java index e568b327c1..8c1ed05f2a 100644 --- a/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java +++ b/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java @@ -22,7 +22,8 @@ public class CleanUrlInterceptor implements HandlerInterceptor { "error", "erroroauth", "file", - "messageType"); + "messageType", + "infoMessage"); @Override public boolean preHandle( diff --git a/src/main/java/stirling/software/SPDF/config/DatabaseBackupInterface.java b/src/main/java/stirling/software/SPDF/config/DatabaseBackupInterface.java new file mode 100644 index 0000000000..267981d188 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/DatabaseBackupInterface.java @@ -0,0 +1,16 @@ +package stirling.software.SPDF.config; + +import java.io.IOException; +import java.util.List; + +import stirling.software.SPDF.utils.FileInfo; + +public interface DatabaseBackupInterface { + void exportDatabase() throws IOException; + + boolean importDatabase(); + + boolean hasBackup(); + + List getBackupList(); +} diff --git a/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java b/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java index e696c6bc19..689b5df03f 100644 --- a/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java +++ b/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java @@ -6,28 +6,33 @@ import java.nio.file.Paths; import java.util.UUID; import org.simpleyaml.configuration.file.YamlFile; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.config.DatabaseBackupInterface; import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.Role; @Component +@Slf4j public class InitialSecuritySetup { @Autowired private UserService userService; @Autowired private ApplicationProperties applicationProperties; - private static final Logger logger = LoggerFactory.getLogger(InitialSecuritySetup.class); + @Autowired private DatabaseBackupInterface databaseBackupHelper; @PostConstruct - public void init() { - if (!userService.hasUsers()) { + public void init() throws IllegalArgumentException, IOException { + if (databaseBackupHelper.hasBackup() && !userService.hasUsers()) { + databaseBackupHelper.importDatabase(); + } else if (!userService.hasUsers()) { initializeAdminUser(); + } else { + databaseBackupHelper.exportDatabase(); } initializeInternalApiUser(); } @@ -41,12 +46,11 @@ public class InitialSecuritySetup { } } - private void initializeAdminUser() { + private void initializeAdminUser() throws IOException { String initialUsername = applicationProperties.getSecurity().getInitialLogin().getUsername(); String initialPassword = applicationProperties.getSecurity().getInitialLogin().getPassword(); - if (initialUsername != null && !initialUsername.isEmpty() && initialPassword != null @@ -54,9 +58,9 @@ public class InitialSecuritySetup { && !userService.findByUsernameIgnoreCase(initialUsername).isPresent()) { try { userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId()); - logger.info("Admin user created: " + initialUsername); + log.info("Admin user created: " + initialUsername); } catch (IllegalArgumentException e) { - logger.error("Failed to initialize security setup", e); + log.error("Failed to initialize security setup", e); System.exit(1); } } else { @@ -64,23 +68,23 @@ public class InitialSecuritySetup { } } - private void createDefaultAdminUser() { + private void createDefaultAdminUser() throws IllegalArgumentException, IOException { 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); + log.info("Default admin user created: " + defaultUsername); } } - private void initializeInternalApiUser() { + private void initializeInternalApiUser() throws IllegalArgumentException, IOException { 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()); + log.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId()); } } diff --git a/src/main/java/stirling/software/SPDF/config/security/UserService.java b/src/main/java/stirling/software/SPDF/config/security/UserService.java index 0a6898f8ae..f6cdfb91a3 100644 --- a/src/main/java/stirling/software/SPDF/config/security/UserService.java +++ b/src/main/java/stirling/software/SPDF/config/security/UserService.java @@ -1,5 +1,6 @@ package stirling.software.SPDF.config.security; +import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -19,6 +20,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import stirling.software.SPDF.config.DatabaseBackupInterface; import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; import stirling.software.SPDF.model.AuthenticationType; import stirling.software.SPDF.model.Authority; @@ -38,8 +40,11 @@ public class UserService implements UserServiceInterface { @Autowired private MessageSource messageSource; + @Autowired DatabaseBackupInterface databaseBackupHelper; + // Handle OAUTH2 login and user auto creation. - public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) { + public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) + throws IllegalArgumentException, IOException { if (!isUsernameValid(username)) { return false; } @@ -131,7 +136,7 @@ public class UserService implements UserServiceInterface { } public void saveUser(String username, AuthenticationType authenticationType) - throws IllegalArgumentException { + throws IllegalArgumentException, IOException { if (!isUsernameValid(username)) { throw new IllegalArgumentException(getInvalidUsernameMessage()); } @@ -142,9 +147,11 @@ public class UserService implements UserServiceInterface { user.addAuthority(new Authority(Role.USER.getRoleId(), user)); user.setAuthenticationType(authenticationType); userRepository.save(user); + databaseBackupHelper.exportDatabase(); } - public void saveUser(String username, String password) throws IllegalArgumentException { + public void saveUser(String username, String password) + throws IllegalArgumentException, IOException { if (!isUsernameValid(username)) { throw new IllegalArgumentException(getInvalidUsernameMessage()); } @@ -154,10 +161,11 @@ public class UserService implements UserServiceInterface { user.setEnabled(true); user.setAuthenticationType(AuthenticationType.WEB); userRepository.save(user); + databaseBackupHelper.exportDatabase(); } public void saveUser(String username, String password, String role, boolean firstLogin) - throws IllegalArgumentException { + throws IllegalArgumentException, IOException { if (!isUsernameValid(username)) { throw new IllegalArgumentException(getInvalidUsernameMessage()); } @@ -169,10 +177,11 @@ public class UserService implements UserServiceInterface { user.setAuthenticationType(AuthenticationType.WEB); user.setFirstLogin(firstLogin); userRepository.save(user); + databaseBackupHelper.exportDatabase(); } public void saveUser(String username, String password, String role) - throws IllegalArgumentException { + throws IllegalArgumentException, IOException { saveUser(username, password, role, false); } @@ -206,7 +215,8 @@ public class UserService implements UserServiceInterface { return userCount > 0; } - public void updateUserSettings(String username, Map updates) { + public void updateUserSettings(String username, Map updates) + throws IOException { Optional userOpt = userRepository.findByUsernameIgnoreCase(username); if (userOpt.isPresent()) { User user = userOpt.get(); @@ -220,6 +230,7 @@ public class UserService implements UserServiceInterface { user.setSettings(settingsMap); userRepository.save(user); + databaseBackupHelper.exportDatabase(); } } @@ -235,22 +246,26 @@ public class UserService implements UserServiceInterface { return authorityRepository.findByUserId(user.getId()); } - public void changeUsername(User user, String newUsername) throws IllegalArgumentException { + public void changeUsername(User user, String newUsername) + throws IllegalArgumentException, IOException { if (!isUsernameValid(newUsername)) { throw new IllegalArgumentException(getInvalidUsernameMessage()); } user.setUsername(newUsername); userRepository.save(user); + databaseBackupHelper.exportDatabase(); } - public void changePassword(User user, String newPassword) { + public void changePassword(User user, String newPassword) throws IOException { user.setPassword(passwordEncoder.encode(newPassword)); userRepository.save(user); + databaseBackupHelper.exportDatabase(); } - public void changeFirstUse(User user, boolean firstUse) { + public void changeFirstUse(User user, boolean firstUse) throws IOException { user.setFirstLogin(firstUse); userRepository.save(user); + databaseBackupHelper.exportDatabase(); } public void changeRole(User user, String newRole) { diff --git a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseBackupHelper.java b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseBackupHelper.java new file mode 100644 index 0000000000..026a968435 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseBackupHelper.java @@ -0,0 +1,202 @@ +package stirling.software.SPDF.config.security.database; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.config.DatabaseBackupInterface; +import stirling.software.SPDF.utils.FileInfo; + +@Slf4j +@Configuration +public class DatabaseBackupHelper implements DatabaseBackupInterface { + + @Value("${spring.datasource.url}") + private String url; + + private Path backupPath = Paths.get("configs/db/backup/"); + + @Override + public boolean hasBackup() { + // Check if there is at least one backup + return !getBackupList().isEmpty(); + } + + @Override + public List getBackupList() { + // Check if the backup directory exists, and create it if it does not + ensureBackupDirectoryExists(); + + List backupFiles = new ArrayList<>(); + + // Read the backup directory and filter for files with the prefix "backup_" and suffix + // ".sql" + try (DirectoryStream stream = + Files.newDirectoryStream( + backupPath, + path -> + path.getFileName().toString().startsWith("backup_") + && path.getFileName().toString().endsWith(".sql"))) { + for (Path entry : stream) { + BasicFileAttributes attrs = Files.readAttributes(entry, BasicFileAttributes.class); + LocalDateTime modificationDate = + LocalDateTime.ofInstant( + attrs.lastModifiedTime().toInstant(), ZoneId.systemDefault()); + LocalDateTime creationDate = + LocalDateTime.ofInstant( + attrs.creationTime().toInstant(), ZoneId.systemDefault()); + long fileSize = attrs.size(); + backupFiles.add( + new FileInfo( + entry.getFileName().toString(), + entry.toString(), + modificationDate, + fileSize, + creationDate)); + } + } catch (IOException e) { + log.error("Error reading backup directory: {}", e.getMessage(), e); + } + return backupFiles; + } + + // Imports a database backup from the specified file. + public boolean importDatabaseFromUI(String fileName) throws IOException { + return this.importDatabaseFromUI(getBackupFilePath(fileName)); + } + + // Imports a database backup from the specified path. + public boolean importDatabaseFromUI(Path tempTemplatePath) throws IOException { + boolean success = executeDatabaseScript(tempTemplatePath); + if (success) { + LocalDateTime dateNow = LocalDateTime.now(); + DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm"); + Path insertOutputFilePath = + this.getBackupFilePath("backup_user_" + dateNow.format(myFormatObj) + ".sql"); + Files.copy(tempTemplatePath, insertOutputFilePath); + Files.deleteIfExists(tempTemplatePath); + } + return success; + } + + @Override + public boolean importDatabase() { + if (!this.hasBackup()) return false; + + List backupList = this.getBackupList(); + backupList.sort(Comparator.comparing(FileInfo::getModificationDate).reversed()); + + return executeDatabaseScript(Paths.get(backupList.get(0).getFilePath())); + } + + @Override + public void exportDatabase() throws IOException { + // Check if the backup directory exists, and create it if it does not + ensureBackupDirectoryExists(); + + // Filter and delete old backups if there are more than 5 + List filteredBackupList = + this.getBackupList().stream() + .filter(backup -> !backup.getFileName().startsWith("backup_user_")) + .collect(Collectors.toList()); + + if (filteredBackupList.size() > 5) { + filteredBackupList.sort( + Comparator.comparing( + p -> p.getFileName().substring(7, p.getFileName().length() - 4))); + Files.deleteIfExists(Paths.get(filteredBackupList.get(0).getFilePath())); + log.info("Deleted oldest backup: {}", filteredBackupList.get(0).getFileName()); + } + + LocalDateTime dateNow = LocalDateTime.now(); + DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm"); + Path insertOutputFilePath = + this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql"); + String query = "SCRIPT SIMPLE COLUMNS DROP to '" + insertOutputFilePath.toString() + "';"; + + try (Connection conn = DriverManager.getConnection(url, "sa", ""); + Statement stmt = conn.createStatement()) { + stmt.execute(query); + log.info("Database export completed: {}", insertOutputFilePath); + } catch (SQLException e) { + log.error("Error during database export: {}", e.getMessage(), e); + } + } + + // Retrieves the H2 database version. + public String getH2Version() { + String version = "Unknown"; + try (Connection conn = DriverManager.getConnection(url, "sa", "")) { + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) { + if (rs.next()) { + version = rs.getString("version"); + log.info("H2 Database Version: {}", version); + } + } + } catch (SQLException e) { + log.error("Error retrieving H2 version: {}", e.getMessage(), e); + } + return version; + } + + // Deletes a backup file. + public boolean deleteBackupFile(String fileName) throws IOException { + Path filePath = this.getBackupFilePath(fileName); + if (Files.deleteIfExists(filePath)) { + log.info("Deleted backup file: {}", fileName); + return true; + } else { + log.error("File not found or could not be deleted: {}", fileName); + return false; + } + } + + // Gets the Path object for a given backup file name. + public Path getBackupFilePath(String fileName) { + return Paths.get(backupPath.toString(), fileName); + } + + private boolean executeDatabaseScript(Path scriptPath) { + try (Connection conn = DriverManager.getConnection(url, "sa", ""); + Statement stmt = conn.createStatement()) { + + String query = "RUNSCRIPT from '" + scriptPath.toString() + "';"; + stmt.execute(query); + log.info("Database import completed: {}", scriptPath); + return true; + } catch (SQLException e) { + log.error("Error during database import: {}", e.getMessage(), e); + return false; + } + } + + private void ensureBackupDirectoryExists() { + if (Files.notExists(backupPath)) { + try { + Files.createDirectories(backupPath); + } catch (IOException e) { + log.error("Error creating directories: {}", e.getMessage()); + } + } + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/database/ScheduledTasks.java b/src/main/java/stirling/software/SPDF/config/security/database/ScheduledTasks.java new file mode 100644 index 0000000000..2ddc47e12a --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/database/ScheduledTasks.java @@ -0,0 +1,18 @@ +package stirling.software.SPDF.config.security.database; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +public class ScheduledTasks { + + @Autowired private DatabaseBackupHelper databaseBackupService; + + @Scheduled(cron = "0 0 0 * * ?") + public void performBackup() throws IOException { + databaseBackupService.exportDatabase(); + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/api/DatabaseController.java b/src/main/java/stirling/software/SPDF/controller/api/DatabaseController.java new file mode 100644 index 0000000000..2f7e207bcf --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/DatabaseController.java @@ -0,0 +1,144 @@ +package stirling.software.SPDF.controller.api; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import org.eclipse.jetty.http.HttpStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.config.security.database.DatabaseBackupHelper; + +@Slf4j +@Controller +@RequestMapping("/api/v1/database") +@PreAuthorize("hasRole('ROLE_ADMIN')") +@Tag(name = "Database", description = "Database APIs") +public class DatabaseController { + + @Autowired DatabaseBackupHelper databaseBackupHelper; + + @Hidden + @PostMapping(consumes = "multipart/form-data", value = "import-database") + @Operation( + summary = "Import database backup", + description = "This endpoint imports a database backup from a SQL file.") + public String importDatabase( + @RequestParam("fileInput") MultipartFile file, RedirectAttributes redirectAttributes) + throws IllegalArgumentException, IOException { + if (file == null || file.isEmpty()) { + redirectAttributes.addAttribute("error", "fileNullOrEmpty"); + return "redirect:/database"; + } + log.info("Received file: {}", file.getOriginalFilename()); + Path tempTemplatePath = Files.createTempFile("backup_", ".sql"); + try (InputStream in = file.getInputStream()) { + Files.copy(in, tempTemplatePath, StandardCopyOption.REPLACE_EXISTING); + boolean importSuccess = databaseBackupHelper.importDatabaseFromUI(tempTemplatePath); + if (importSuccess) { + redirectAttributes.addAttribute("infoMessage", "importIntoDatabaseSuccessed"); + } else { + redirectAttributes.addAttribute("error", "failedImportFile"); + } + } catch (Exception e) { + log.error("Error importing database: {}", e.getMessage()); + redirectAttributes.addAttribute("error", "failedImportFile"); + } + return "redirect:/database"; + } + + @Hidden + @GetMapping("/import-database-file/{fileName}") + public String importDatabaseFromBackupUI(@PathVariable String fileName) + throws IllegalArgumentException, IOException { + if (fileName == null || fileName.isEmpty()) { + return "redirect:/database?error=fileNullOrEmpty"; + } + + // Check if the file exists in the backup list + boolean fileExists = + databaseBackupHelper.getBackupList().stream() + .anyMatch(backup -> backup.getFileName().equals(fileName)); + if (!fileExists) { + log.error("File {} not found in backup list", fileName); + return "redirect:/database?error=fileNotFound"; + } + log.info("Received file: {}", fileName); + if (databaseBackupHelper.importDatabaseFromUI(fileName)) { + log.info("File {} imported to database", fileName); + return "redirect:/database?infoMessage=importIntoDatabaseSuccessed"; + } + return "redirect:/database?error=failedImportFile"; + } + + @Hidden + @GetMapping("/delete/{fileName}") + @Operation( + summary = "Delete a database backup file", + description = + "This endpoint deletes a database backup file with the specified file name.") + public String deleteFile(@PathVariable String fileName) { + if (fileName == null || fileName.isEmpty()) { + throw new IllegalArgumentException("File must not be null or empty"); + } + try { + if (databaseBackupHelper.deleteBackupFile(fileName)) { + log.info("Deleted file: {}", fileName); + } else { + log.error("Failed to delete file: {}", fileName); + return "redirect:/database?error=failedToDeleteFile"; + } + } catch (IOException e) { + log.error("Error deleting file: {}", e.getMessage()); + return "redirect:/database?error=" + e.getMessage(); + } + return "redirect:/database"; + } + + @Hidden + @GetMapping("/download/{fileName}") + @Operation( + summary = "Download a database backup file", + description = + "This endpoint downloads a database backup file with the specified file name.") + public ResponseEntity downloadFile(@PathVariable String fileName) { + if (fileName == null || fileName.isEmpty()) { + throw new IllegalArgumentException("File must not be null or empty"); + } + try { + Path filePath = databaseBackupHelper.getBackupFilePath(fileName); + InputStreamResource resource = new InputStreamResource(Files.newInputStream(filePath)); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .contentLength(Files.size(filePath)) + .body(resource); + } catch (IOException e) { + log.error("Error downloading file: {}", e.getMessage()); + return ResponseEntity.status(HttpStatus.SEE_OTHER_303) + .location(URI.create("/database?error=downloadFailed")) + .build(); + } + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/api/UserController.java b/src/main/java/stirling/software/SPDF/controller/api/UserController.java index ec316fbc4f..b0deefa068 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/UserController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/UserController.java @@ -1,5 +1,6 @@ package stirling.software.SPDF.controller.api; +import java.io.IOException; import java.security.Principal; import java.util.HashMap; import java.util.Map; @@ -42,7 +43,8 @@ public class UserController { @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PostMapping("/register") - public String register(@ModelAttribute UsernameAndPass requestModel, Model model) { + public String register(@ModelAttribute UsernameAndPass requestModel, Model model) + throws IOException { if (userService.usernameExistsIgnoreCase(requestModel.getUsername())) { model.addAttribute("error", "Username already exists"); return "register"; @@ -63,7 +65,8 @@ public class UserController { @RequestParam(name = "newUsername") String newUsername, HttpServletRequest request, HttpServletResponse response, - RedirectAttributes redirectAttributes) { + RedirectAttributes redirectAttributes) + throws IOException { if (!userService.isUsernameValid(newUsername)) { return new RedirectView("/account?messageType=invalidUsername", true); @@ -116,7 +119,8 @@ public class UserController { @RequestParam(name = "newPassword") String newPassword, HttpServletRequest request, HttpServletResponse response, - RedirectAttributes redirectAttributes) { + RedirectAttributes redirectAttributes) + throws IOException { if (principal == null) { return new RedirectView("/change-creds?messageType=notAuthenticated", true); } @@ -149,7 +153,8 @@ public class UserController { @RequestParam(name = "newPassword") String newPassword, HttpServletRequest request, HttpServletResponse response, - RedirectAttributes redirectAttributes) { + RedirectAttributes redirectAttributes) + throws IOException { if (principal == null) { return new RedirectView("/account?messageType=notAuthenticated", true); } @@ -176,7 +181,8 @@ public class UserController { @PreAuthorize("!hasAuthority('ROLE_DEMO_USER')") @PostMapping("/updateUserSettings") - public String updateUserSettings(HttpServletRequest request, Principal principal) { + public String updateUserSettings(HttpServletRequest request, Principal principal) + throws IOException { Map paramMap = request.getParameterMap(); Map updates = new HashMap<>(); @@ -201,7 +207,8 @@ public class UserController { @RequestParam(name = "password") String password, @RequestParam(name = "role") String role, @RequestParam(name = "forceChange", required = false, defaultValue = "false") - boolean forceChange) { + boolean forceChange) + throws IllegalArgumentException, IOException { if (!userService.isUsernameValid(username)) { return new RedirectView("/addUsers?messageType=invalidUsername", true); diff --git a/src/main/java/stirling/software/SPDF/controller/web/DatabaseWebController.java b/src/main/java/stirling/software/SPDF/controller/web/DatabaseWebController.java new file mode 100644 index 0000000000..3fd68ad596 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/web/DatabaseWebController.java @@ -0,0 +1,41 @@ +package stirling.software.SPDF.controller.web; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.servlet.http.HttpServletRequest; +import stirling.software.SPDF.config.security.database.DatabaseBackupHelper; +import stirling.software.SPDF.utils.FileInfo; + +@Controller +@Tag(name = "Database Management", description = "Database management and security APIs") +public class DatabaseWebController { + + @Autowired private DatabaseBackupHelper databaseBackupHelper; + + @PreAuthorize("hasRole('ROLE_ADMIN')") + @GetMapping("/database") + public String database(HttpServletRequest request, Model model, Authentication authentication) { + String error = request.getParameter("error"); + String confirmed = request.getParameter("infoMessage"); + + if (error != null) { + model.addAttribute("error", error); + } else if (confirmed != null) { + model.addAttribute("infoMessage", confirmed); + } + + List backupList = databaseBackupHelper.getBackupList(); + model.addAttribute("systemUpdate", backupList); + + return "database"; + } +} diff --git a/src/main/java/stirling/software/SPDF/utils/FileInfo.java b/src/main/java/stirling/software/SPDF/utils/FileInfo.java new file mode 100644 index 0000000000..4e236756a8 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/FileInfo.java @@ -0,0 +1,50 @@ +package stirling.software.SPDF.utils; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@AllArgsConstructor +@Data +public class FileInfo { + private String fileName; + private String filePath; + private LocalDateTime modificationDate; + private long fileSize; + private LocalDateTime creationDate; + + private static final DateTimeFormatter DATE_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + // Converts the file path string to a Path object. + public Path getFilePathAsPath() { + return Paths.get(filePath); + } + + // Formats the file size into a human-readable string. + public String getFormattedFileSize() { + if (fileSize >= 1024 * 1024 * 1024) { + return String.format("%.2f GB", fileSize / (1024.0 * 1024 * 1024)); + } else if (fileSize >= 1024 * 1024) { + return String.format("%.2f MB", fileSize / (1024.0 * 1024)); + } else if (fileSize >= 1024) { + return String.format("%.2f KB", fileSize / 1024.0); + } else { + return String.format("%d Bytes", fileSize); + } + } + + // Formats the modification date to a string. + public String getFormattedModificationDate() { + return modificationDate.format(DATE_FORMATTER); + } + + // Formats the creation date to a string. + public String getFormattedCreationDate() { + return creationDate.format(DATE_FORMATTER); + } +} diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index 66902b18a1..4633c9f64b 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Save User adminUserSettings.changeUserRole=تغيير دور المستخدم adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_bg_BG.properties b/src/main/resources/messages_bg_BG.properties index ac4971deb5..3ab9cb477f 100644 --- a/src/main/resources/messages_bg_BG.properties +++ b/src/main/resources/messages_bg_BG.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Съхранете потребителя adminUserSettings.changeUserRole=Промяна на ролята на потребителя adminUserSettings.authenticated=Удостоверен + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties index f6003fbaf0..ce4b3c964e 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Desar Usuari adminUserSettings.changeUserRole=Canvia el rol de l'usuari adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_cs_CZ.properties b/src/main/resources/messages_cs_CZ.properties index 9df08b5691..64774be0f0 100644 --- a/src/main/resources/messages_cs_CZ.properties +++ b/src/main/resources/messages_cs_CZ.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Uložit Uživatele adminUserSettings.changeUserRole=Zmenit Roli Uživatele adminUserSettings.authenticated=Ověřeno + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties index e685e7f5cd..2082599211 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Benutzer speichern adminUserSettings.changeUserRole=Benutzerrolle ändern adminUserSettings.authenticated=Authentifiziert + +database.title=Datenbank Import/Export +database.header=Datenbank Import/Export +database.fileName=Dateiname +database.creationDate=Erstellungsdatum +database.fileSize=Dateigröße +database.deleteBackupFile=Sicherungsdatei löschen +database.importBackupFile=Sicherungsdatei importieren +database.downloadBackupFile=Sicherungsdatei herunterladen +database.info_1=Beim Importieren der Daten ist es von größter Bedeutung, die korrekte Struktur zu gewährleisten. Wenn Sie nicht sicher sind, was Sie tun, suchen Sie Rat und Unterstützung von einem Fachmann. Ein Fehler in der Struktur kann zu Fehlfunktionen der Anwendung führen, bis hin zur vollständigen Nicht-Lauffähigkeit der Anwendung. +database.info_2=Der Dateiname spielt beim Hochladen keine Rolle. Dieser wird nachträglich in das Format backup_user_yyyyMMddHHmm.sql geändert, um eine einheitliche Benennung zu gewährleisten. +database.submit=Sicherungsdatei importieren +database.importIntoDatabaseSuccessed=Import in die Datenbank erfolgreich +database.fileNotFound=Datei nicht gefunden +database.fileNullOrEmpty=Datei darf nicht null oder leer sein +database.failedImportFile=Dateiimport fehlgeschlagen + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_el_GR.properties b/src/main/resources/messages_el_GR.properties index c140c12c5a..b7bfabdb4f 100644 --- a/src/main/resources/messages_el_GR.properties +++ b/src/main/resources/messages_el_GR.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Αποθήκευση Χρήστη adminUserSettings.changeUserRole=Αλλαγή ρόλου χρήστη adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 744cbbd760..7add06f62a 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Save User adminUserSettings.changeUserRole=Change User's Role adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed to import file + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 6717272be0..5f20e450c6 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Save User adminUserSettings.changeUserRole=Change User's Role adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index 0c0504602b..94e668777f 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Guardar Usuario adminUserSettings.changeUserRole=Cambiar rol de usuario adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties index 45bdb032c7..3cd8fbb456 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Gorde Erabiltzailea adminUserSettings.changeUserRole=Erabiltzailearen rola aldatu adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index 7ff1c61b7c..a1c4495875 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Ajouter adminUserSettings.changeUserRole=Changer le rôle de l'utilisateur adminUserSettings.authenticated=Authentifié + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_hi_IN.properties b/src/main/resources/messages_hi_IN.properties index 080d9bb379..e8dea13541 100644 --- a/src/main/resources/messages_hi_IN.properties +++ b/src/main/resources/messages_hi_IN.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=उपयोगकर्ता को सहेजे adminUserSettings.changeUserRole=यूज़र की भूमिका बदलें adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_hr_HR.properties b/src/main/resources/messages_hr_HR.properties index a98e8ef734..fc26615b05 100644 --- a/src/main/resources/messages_hr_HR.properties +++ b/src/main/resources/messages_hr_HR.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Spremi korisnika adminUserSettings.changeUserRole=Promijenite korisničku ulogu adminUserSettings.authenticated=Autentificirano + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_hu_HU.properties b/src/main/resources/messages_hu_HU.properties index 759fae669a..895ef84001 100644 --- a/src/main/resources/messages_hu_HU.properties +++ b/src/main/resources/messages_hu_HU.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Felhasználó mentése adminUserSettings.changeUserRole=Felhasználó szerepkörének módosítása adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_id_ID.properties b/src/main/resources/messages_id_ID.properties index 4ffaec2f78..e8f4f3c100 100644 --- a/src/main/resources/messages_id_ID.properties +++ b/src/main/resources/messages_id_ID.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Simpan Pengguna adminUserSettings.changeUserRole=Ubah Peran Pengguna adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index 7589e4c522..b9117019d2 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Salva utente adminUserSettings.changeUserRole=Cambia il ruolo dell'utente adminUserSettings.authenticated=Autenticato + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index bab67998bb..648f16336d 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=ユーザーの保存 adminUserSettings.changeUserRole=ユーザーの役割を変更する adminUserSettings.authenticated=認証済 + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index 2a9d3461dd..40c48a21b9 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=사용자 저장 adminUserSettings.changeUserRole=사용자의 역할 변경 adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_nl_NL.properties b/src/main/resources/messages_nl_NL.properties index 02718c3a00..e0b8aa2f7d 100644 --- a/src/main/resources/messages_nl_NL.properties +++ b/src/main/resources/messages_nl_NL.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Gebruiker opslaan adminUserSettings.changeUserRole=De rol van de gebruiker wijzigen adminUserSettings.authenticated=Geauthenticeerd + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_no_NB.properties b/src/main/resources/messages_no_NB.properties index 8597ebd81d..84ed25f4f2 100644 --- a/src/main/resources/messages_no_NB.properties +++ b/src/main/resources/messages_no_NB.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Lagre Bruker adminUserSettings.changeUserRole=Endre Brukerens Rolle adminUserSettings.authenticated=Autentisert + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index 519cc59fd4..18017dba5b 100755 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Zapisz użytkownika adminUserSettings.changeUserRole=Zmień rolę użytkownika adminUserSettings.authenticated=Zalogowany + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index cc7fe4e89f..c1a41ff232 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Save User adminUserSettings.changeUserRole=Alterar Função de Usuário adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_pt_PT.properties b/src/main/resources/messages_pt_PT.properties index 74246eb6ba..f7905ea01e 100644 --- a/src/main/resources/messages_pt_PT.properties +++ b/src/main/resources/messages_pt_PT.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Save User adminUserSettings.changeUserRole=Alterar usuário adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties index 836bfc430d..b186c4c7ae 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Save User adminUserSettings.changeUserRole=Schimbați rolul utilizatorului adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties index ab7a1ac9dc..cbd5c285ec 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Сохранить пользователя adminUserSettings.changeUserRole=Изменить роль пользователя adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_sk_SK.properties b/src/main/resources/messages_sk_SK.properties index 6ca3173da9..599ef7bae9 100644 --- a/src/main/resources/messages_sk_SK.properties +++ b/src/main/resources/messages_sk_SK.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Uložiť používateľa adminUserSettings.changeUserRole=Zmeniť rolu používateľa adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_sr_LATN_RS.properties b/src/main/resources/messages_sr_LATN_RS.properties index 5e0e7ec3b5..102fee73fd 100644 --- a/src/main/resources/messages_sr_LATN_RS.properties +++ b/src/main/resources/messages_sr_LATN_RS.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Sačuvaj korisnika adminUserSettings.changeUserRole=Promenite ulogu korisnika adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties index 00381ee8b1..ecbd13baca 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Save User adminUserSettings.changeUserRole=Ändra användarens roll adminUserSettings.authenticated=Authenticated + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_tr_TR.properties b/src/main/resources/messages_tr_TR.properties index 4dfe0e1902..16e4b5aeaa 100644 --- a/src/main/resources/messages_tr_TR.properties +++ b/src/main/resources/messages_tr_TR.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Kullanıcıyı Kaydet adminUserSettings.changeUserRole=Kullanıcı rolünü değiştir adminUserSettings.authenticated=Onaylandı + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_uk_UA.properties b/src/main/resources/messages_uk_UA.properties index 2f9356c702..ebe2d98973 100644 --- a/src/main/resources/messages_uk_UA.properties +++ b/src/main/resources/messages_uk_UA.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=Зберегти користувача adminUserSettings.changeUserRole=Змінити роль користувача adminUserSettings.authenticated=Автентифіковано + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties index ce70cb86d4..46e46fbc33 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=保存用户 adminUserSettings.changeUserRole=更改用户角色 adminUserSettings.authenticated=已验证 + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/messages_zh_TW.properties b/src/main/resources/messages_zh_TW.properties index 8bcc59eed1..ead961d01e 100644 --- a/src/main/resources/messages_zh_TW.properties +++ b/src/main/resources/messages_zh_TW.properties @@ -191,6 +191,23 @@ adminUserSettings.submit=儲存 adminUserSettings.changeUserRole=更改使用者身份 adminUserSettings.authenticated=已驗證 + +database.title=Database Import/Export +database.header=Database Import/Export +database.fileName=File Name +database.creationDate=Creation Date +database.fileSize=File Size +database.deleteBackupFile=Delete Backup File +database.importBackupFile=Import Backup File +database.downloadBackupFile=Download Backup File +database.info_1=When importing data, it is crucial to ensure the correct structure. If you are unsure of what you are doing, seek advice and support from a professional. An error in the structure can cause application malfunctions, up to and including the complete inability to run the application. +database.info_2=The file name does not matter when uploading. It will be renamed afterward to follow the format backup_user_yyyyMMddHHmm.sql, ensuring a consistent naming convention. +database.submit=Import Backup +database.importIntoDatabaseSuccessed=Import into database successed +database.fileNotFound=File not Found +database.fileNullOrEmpty=File must not be null or empty +database.failedImportFile=Failed Import File + ############# # HOME-PAGE # ############# diff --git a/src/main/resources/templates/database.html b/src/main/resources/templates/database.html new file mode 100644 index 0000000000..4f6f8a8641 --- /dev/null +++ b/src/main/resources/templates/database.html @@ -0,0 +1,71 @@ + + + + + + + +
+
+ +

+
+
+
+
+ database + Database Im-/Export +
+

+

+
+ + + + + + + + + + + + + + + + + + + + + +
File NameCreation DateFile Size
deletebackupdownload
+
+
+
+
+

+

+
+
+
+ +
+
+ +
+
+
+
+
+ + + +
+ + \ No newline at end of file