From 186c62cf047c96936156a3c6f6a6b46af7a83e10 Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sun, 17 Apr 2022 11:51:44 +0200 Subject: [PATCH] #663 - added migration settings page --- .../migration/MigrationController.java | 46 +++++++++++++-- .../migration/MigrationSettings.java | 5 ++ .../migration/MigrationSettingsValidator.java | 24 ++++++++ .../budgetmaster/utils/Strings.java | 6 ++ .../resources/languages/base_de.properties | 14 ++++- .../resources/languages/base_en.properties | 16 +++++- .../main/resources/templates/migration.ftl | 57 +++++++++++++++++-- 7 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettings.java create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettingsValidator.java diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationController.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationController.java index 321225c9a..2e2cecf02 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationController.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationController.java @@ -5,16 +5,29 @@ import de.deadlocker8.budgetmaster.settings.SettingsService; import de.deadlocker8.budgetmaster.utils.Mappings; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; @Controller @RequestMapping(Mappings.MIGRATION) public class MigrationController extends BaseController { + private static class ModelAttributes + { + public static final String ERROR = "error"; + public static final String MIGRATION_SETTINGS = "migrationSettings"; + } + + private static class ReturnValues + { + public static final String MIGRATION_SETTINGS = "migration"; + } + private final SettingsService settingsService; @Autowired @@ -31,8 +44,33 @@ public class MigrationController extends BaseController } @GetMapping - public String migrate() + public String migrate(Model model) { - return "migration"; + model.addAttribute(ModelAttributes.MIGRATION_SETTINGS, new MigrationSettings(null, null, null, null, null)); + return ReturnValues.MIGRATION_SETTINGS; + } + + @PostMapping + public String post(Model model, + @ModelAttribute("MigrationSettings") @Valid MigrationSettings migrationSettings, BindingResult bindingResult, + @RequestParam(value = "verificationPassword") String verificationPassword) + { + // TODO validate verification password +// final Optional<FieldError> passwordErrorOptional = settingsService.validatePassword(password, passwordConfirmation); +// passwordErrorOptional.ifPresent(bindingResult::addError); + + + final MigrationSettingsValidator migrationSettingsValidator = new MigrationSettingsValidator(); + migrationSettingsValidator.validate(migrationSettings, bindingResult); + + if(bindingResult.hasErrors()) + { + model.addAttribute(ModelAttributes.ERROR, bindingResult); + model.addAttribute(ModelAttributes.MIGRATION_SETTINGS, migrationSettings); + return ReturnValues.MIGRATION_SETTINGS; + } + + // TODO + return ReturnValues.MIGRATION_SETTINGS; } } \ No newline at end of file diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettings.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettings.java new file mode 100644 index 000000000..c909cb3fa --- /dev/null +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettings.java @@ -0,0 +1,5 @@ +package de.deadlocker8.budgetmaster.migration; + +public record MigrationSettings(String hostname, Integer port, String databaseName, String username, String password) +{ +} diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettingsValidator.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettingsValidator.java new file mode 100644 index 000000000..7a7f3687a --- /dev/null +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/migration/MigrationSettingsValidator.java @@ -0,0 +1,24 @@ +package de.deadlocker8.budgetmaster.migration; + +import de.deadlocker8.budgetmaster.utils.Strings; +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + + +public class MigrationSettingsValidator implements Validator +{ + public boolean supports(Class clazz) + { + return MigrationSettings.class.equals(clazz); + } + + public void validate(Object obj, Errors errors) + { + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "hostname", Strings.WARNING_EMPTY_MIGRATION_HOSTNAME); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "port", Strings.WARNING_EMPTY_NUMBER); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "databaseName", Strings.WARNING_EMPTY_MIGRATION_DATABASE_NAME); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", Strings.WARNING_EMPTY_MIGRATION_USERNAME); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", Strings.WARNING_EMPTY_MIGRATION_PASSWORD); + } +} \ No newline at end of file diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java index a8d059ae9..14e3cfc24 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java @@ -38,6 +38,12 @@ public class Strings public static final String WARNING_EMPTY_GIT_USER_NAME = "warning.empty.git.user.name"; public static final String WARNING_EMPTY_GIT_TOKEN = "warning.empty.git.token"; + public static final String WARNING_EMPTY_MIGRATION_HOSTNAME = "warning.empty.migration.hostname"; + public static final String WARNING_EMPTY_MIGRATION_DATABASE_NAME = "warning.empty.migration.databaseName"; + public static final String WARNING_EMPTY_MIGRATION_USERNAME = "warning.empty.migration.username"; + public static final String WARNING_EMPTY_MIGRATION_PASSWORD = "warning.empty.migration.password"; + + //REPORT public static final String REPORT_FOOTER_LEFT = "report.footer.left"; public static final String REPORT_FOOTER_CENTER = "report.footer.center"; diff --git a/BudgetMasterServer/src/main/resources/languages/base_de.properties b/BudgetMasterServer/src/main/resources/languages/base_de.properties index 01ad3d3eb..fb7442c89 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_de.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_de.properties @@ -164,7 +164,7 @@ info.title.backup.reminder=Zeit für ein Backup info.text.backup.reminder=Schon mal über ein Backup nachgedacht?<br>Du solltest deine BudgetMaster Datenbank regelmäßig sichern.<br>Dies geht besonders einfach in den Einstellungen.<br>Du kannst auch ein automatisches Backup konfigurieren.<br><br>(Du wilst diese Erinnerung nicht jeden Monat sehen? Dann deaktiviere die Backuperinnerung in den Einstellungen.) info.button.backup.reminder=Zu den Einstellungen info.title.migration=Kommst du von einer früheren Version? -info.text.migration=BudgetMaster 2.10.0 führt ein neues Datenbank-Backend ein.<br>Deine aktuelle Datenbank scheint leer zu sein.<br>Hast du BudgetMaster bereits vor Version 2.10.0 benutzt und möchtest deine bestehende Datenbank migrieren?<br><br><span class="text-red bold">ACHTUNG: Wenn du diesen Dialog abbrichst, wirst du nicht mehr nach der Migration gefragt!</span> +info.text.migration=BudgetMaster 2.10.0 führt ein neues Datenbank-Backend ein.<br>Deine aktuelle Datenbank scheint leer zu sein.<br>Hast du BudgetMaster bereits vor Version 2.10.0 benutzt und möchtest deine bestehende Datenbank migrieren?<br><br><span class="red-text bold">ACHTUNG: Wenn du diesen Dialog abbrichst, wirst du nicht mehr nach der Migration gefragt!</span> info.button.migration=Bestehende Datenbank migrieren notification.settings.saved=Einstellungen gespeichert notification.settings.update.available=BudgetMaster Update "{0}" verfügbar @@ -214,6 +214,10 @@ warning.empty.git.url=Bitte gib die URL zum git-Server ein. warning.empty.git.branch.name=Bitte gib den Namen des git-Branches ein. warning.empty.git.user.name=Bitte gib deinen git-Nutzernamen ein. warning.empty.git.token=Bitte gib dein git-Zugriffstoken ein. +warning.empty.migration.hostname=Bitte gib den Hostnamen des Datenbankservers ein. +warning.empty.migration.databaseName=Bitte gib den Namen der Datenbank ein. +warning.empty.migration.username=Bitte gib den Nutzernamen ein. +warning.empty.migration.password=Bitte gib das Datenbankpasswort ein. # UI @@ -630,3 +634,11 @@ import.entity.image=Icons werden automatisch mit den zugehörigen Konten, Vorlag import.entity.chart=Es werden nur die benutzerdefinierten Diagramme importiert.<br>Der Import von Diagrammen ist optional. copied=Kopiert! + +migration.settings.description=Alle Daten aus deiner bestehenden BudgetMaster Datenbank werden in die neue Datenbank migriert.<br> Bitte gib die Einstellungen für das neue Datenbank-Backend (z.B. postgresql) ein. +migration.settings.hostname=Hostname +migration.settings.port=Port +migration.settings.databaseName=Datenbankname +migration.settings.username=Nutzername +migration.settings.password=Passwort +migration.settings.verification.password=Bisheriges BudgetMaster Passwort diff --git a/BudgetMasterServer/src/main/resources/languages/base_en.properties b/BudgetMasterServer/src/main/resources/languages/base_en.properties index 0623ebde5..c897ac010 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_en.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_en.properties @@ -165,7 +165,7 @@ info.title.backup.reminder=Time for a backup info.text.backup.reminder=Have you ever thought about a backup?<br>You should back up your BudgetMaster database regularly.<br>This can be done on the settings page.<br>You can also enable an automatic backup.<br><br>(You don''t want to see this reminder every month? Disable the backup reminder in the settings.) info.button.backup.reminder=To the settings info.title.migration=Are you coming from a previous version? -info.text.migration=BudgetMaster 2.10.0 introduces a new database backend.<br>Your current database seems to be empty.<br>Have you used BudgetMaster before version 2.10.0 and want to migrate your existing database?<br><br> <span class="text-red bold">CAUTION: If you cancel this dialog, you will not be asked again about the migration!</span> +info.text.migration=BudgetMaster 2.10.0 introduces a new database backend.<br>Your current database seems to be empty.<br>Have you used BudgetMaster before version 2.10.0 and want to migrate your existing database?<br><br> <span class="red-text bold">CAUTION: If you cancel this dialog, you will not be asked again about the migration!</span> info.button.migration=Migrate existing database notification.settings.saved=Settings saved notification.settings.update.available=BudgetMaster update "{0}" available @@ -213,8 +213,12 @@ warning.duplicate.template.name=A template with this name is already existing. warning.transaction.date=The specified date does not correspond to the allowed format. Expected format: DD.MM.YY, DDMMYY, DD.MM.YYYY, DDMMYYYY. warning.empty.git.url=Please insert the git server's URL. warning.empty.git.branch.name=Please insert the git branch name. -warning.empty.git.user.name=Please insert your git user name. +warning.empty.git.user.name=Please insert your git username. warning.empty.git.token=Please insert your git access token. +warning.empty.migration.hostname=Please insert the hostname of the database server. +warning.empty.migration.databaseName=Please insert the database name +warning.empty.migration.username=Please insert the username. +warning.empty.migration.password=Please insert the database password. # UI @@ -629,3 +633,11 @@ import.entity.image=Icons are automatically imported with their associated accou import.entity.chart=Only user-defined charts will be imported.<br>The import of charts is optional. copied=Copied! + +migration.settings.description=All data from your existing BudgetMaster database will be migrated to the new database.<br> Please enter the settings for the new database backend (e.g. postgresql). +migration.settings.hostname=Hostname +migration.settings.port=Port +migration.settings.databaseName=Database name +migration.settings.username=Username +migration.settings.password=Password +migration.settings.verification.password=Current BudgetMaster password diff --git a/BudgetMasterServer/src/main/resources/templates/migration.ftl b/BudgetMasterServer/src/main/resources/templates/migration.ftl index 4aa039d95..d152179b4 100644 --- a/BudgetMasterServer/src/main/resources/templates/migration.ftl +++ b/BudgetMasterServer/src/main/resources/templates/migration.ftl @@ -8,6 +8,7 @@ <@header.body> <#import "helpers/navbar.ftl" as navbar> <@navbar.navbar "migration" settings/> + <#import "helpers/validation.ftl" as validation> <main> <div class="card main-card background-color"> @@ -16,15 +17,61 @@ <div class="headline">${locale.getString("title.migration")}</div> </div> </div> - <div class="container"> - <form name="Import" action="<@s.url '/migration/start'/>" method="post"> + <form name="MigrationSettings" action="<@s.url '/migration'/>" method="post"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> <div class="row"> - <div class="col s12 m10 offset-m1 l10 offset-l1 xl8 offset-xl2"> - <table class="bordered"> - </table> + <div class="col s12 m12 l8 offset-l2"> + ${locale.getString("migration.settings.description")} + </div> + </div> + + <div class="row"> + <div class="input-field col s12 m12 l8 offset-l2"> + <i class="material-icons prefix">public</i> + <input id="migration-hostname" type="text" name="hostname" <@validation.validation "hostname"/> value="<#if migrationSettings.hostname()??>${migrationSettings.hostname()}</#if>" placeholder="localhost"> + <label for="migration-hostname">${locale.getString("migration.settings.hostname")}</label> + </div> + </div> + + <div class="row"> + <div class="input-field col s12 m12 l8 offset-l2"> + <i class="material-icons prefix">dns</i> + <input id="migration-port" type="text" name="port" <@validation.validation "port"/> value="<#if migrationSettings.port()??>${migrationSettings.port()?c}</#if>" placeholder="5432"> + <label for="migration-port">${locale.getString("migration.settings.port")}</label> + </div> + </div> + + <div class="row"> + <div class="input-field col s12 m12 l8 offset-l2"> + <i class="material-icons prefix">inventory</i> + <input id="migration-database-name" type="text" name="port" <@validation.validation "databaseName"/> value="<#if migrationSettings.databaseName()??>${migrationSettings.databaseName()}</#if>"> + <label for="migration-database-name">${locale.getString("migration.settings.databaseName")}</label> + </div> + </div> + + <div class="row"> + <div class="input-field col s12 m12 l8 offset-l2"> + <i class="material-icons prefix">person</i> + <input id="migration-username" type="text" name="port" <@validation.validation "username"/> value="<#if migrationSettings.username()??>${migrationSettings.username()}</#if>"> + <label for="migration-username">${locale.getString("migration.settings.username")}</label> + </div> + </div> + + <div class="row"> + <div class="input-field col s12 m12 l8 offset-l2"> + <i class="material-icons prefix">vpn_key</i> + <input id="migration-password" type="text" name="port" <@validation.validation "password"/> value="<#if migrationSettings.password()??>${migrationSettings.password()}</#if>"> + <label for="migration-password">${locale.getString("migration.settings.password")}</label> + </div> + </div> + + <div class="row"> + <div class="input-field col s12 m12 l8 offset-l2"> + <i class="material-icons prefix">vpn_key</i> + <input id="migration-verification-password" type="password" name="verificationPassword" <@validation.validation "verificationPassword"/> value=""> + <label for="migration-verification-password">${locale.getString("migration.settings.verification.password")}</label> </div> </div> -- GitLab