diff --git a/build.gradle b/build.gradle index 1c04334b..90e130f6 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 e568b327..8c1ed05f 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 00000000..267981d1 --- /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 e696c6bc..689b5df0 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 0a6898f8..f6cdfb91 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 00000000..026a9684 --- /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 00000000..2ddc47e1 --- /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 00000000..2f7e207b --- /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 ec316fbc..b0deefa0 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 00000000..3fd68ad5 --- /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 00000000..4e236756 --- /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 66902b18..4633c9f6 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 ac4971de..3ab9cb47 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 f6003fba..ce4b3c96 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 9df08b56..64774be0 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 e685e7f5..20825992 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 c140c12c..b7bfabdb 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 744cbbd7..7add06f6 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 6717272b..5f20e450 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 0c050460..94e66877 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 45bdb032..3cd8fbb4 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 7ff1c61b..a1c44958 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 080d9bb3..e8dea135 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 a98e8ef7..fc26615b 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 759fae66..895ef840 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 4ffaec2f..e8f4f3c1 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 7589e4c5..b9117019 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 bab67998..648f1633 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 2a9d3461..40c48a21 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 02718c3a..e0b8aa2f 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 8597ebd8..84ed25f4 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 519cc59f..18017dba 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 cc7fe4e8..c1a41ff2 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 74246eb6..f7905ea0 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 836bfc43..b186c4c7 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 ab7a1ac9..cbd5c285 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 6ca3173d..599ef7ba 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 5e0e7ec3..102fee73 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 00381ee8..ecbd13ba 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 4dfe0e19..16e4b5ae 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 2f9356c7..ebe2d989 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 ce70cb86..46e46fbc 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 8bcc59ee..ead961d0 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 00000000..4f6f8a86 --- /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