From ffa453fea13f3e3e508b25c3cef30d22f28338b6 Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Tue, 14 Jun 2022 23:07:18 +0200 Subject: [PATCH] #696 - save backup settings --- ... => BackupSettingsContainerValidator.java} | 11 +- .../settings/SettingsController.java | 160 +++++++-------- .../containers/BackupSettingsContainer.java | 138 +++++++++++++ .../resources/languages/base_de.properties | 2 + .../resources/languages/base_en.properties | 2 + .../src/main/resources/static/js/settings.js | 93 --------- .../settings/containers/settingsBackup.ftl | 194 ++++++++++++++++++ .../settings/containers/settingsContainer.ftl | 4 +- .../resources/templates/settings/settings.ftl | 40 +--- .../templates/settings/settingsMacros.ftl | 14 +- 10 files changed, 427 insertions(+), 231 deletions(-) rename BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/{SettingsValidator.java => BackupSettingsContainerValidator.java} (70%) create mode 100644 BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/containers/BackupSettingsContainer.java create mode 100644 BudgetMasterServer/src/main/resources/templates/settings/containers/settingsBackup.ftl diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsValidator.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/BackupSettingsContainerValidator.java similarity index 70% rename from BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsValidator.java rename to BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/BackupSettingsContainerValidator.java index c85738326..1994ec8a1 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsValidator.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/BackupSettingsContainerValidator.java @@ -1,31 +1,32 @@ package de.deadlocker8.budgetmaster.settings; import de.deadlocker8.budgetmaster.backup.AutoBackupStrategy; +import de.deadlocker8.budgetmaster.settings.containers.BackupSettingsContainer; import de.deadlocker8.budgetmaster.utils.Strings; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; -public class SettingsValidator implements Validator +public class BackupSettingsContainerValidator implements Validator { public boolean supports(Class clazz) { - return Settings.class.equals(clazz); + return BackupSettingsContainer.class.equals(clazz); } public void validate(Object obj, Errors errors) { - final Settings settings = (Settings) obj; + final BackupSettingsContainer backupSettingsContainer = (BackupSettingsContainer) obj; ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupDays", Strings.WARNING_EMPTY_NUMBER); - if(settings.getAutoBackupStrategy() == AutoBackupStrategy.LOCAL) + if(backupSettingsContainer.getAutoBackupStrategy() == AutoBackupStrategy.LOCAL) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupFilesToKeep", Strings.WARNING_EMPTY_NUMBER_ZERO_ALLOWED); } - if(settings.getAutoBackupStrategy() == AutoBackupStrategy.GIT_REMOTE) + if(backupSettingsContainer.getAutoBackupStrategy() == AutoBackupStrategy.GIT_REMOTE) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupGitUrl", Strings.WARNING_EMPTY_GIT_URL); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupGitBranchName", Strings.WARNING_EMPTY_GIT_BRANCH_NAME); diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java index cb2297b24..c7c1ae9af 100644 --- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java @@ -12,10 +12,7 @@ import de.deadlocker8.budgetmaster.database.model.BackupDatabase; import de.deadlocker8.budgetmaster.hints.HintService; import de.deadlocker8.budgetmaster.services.ImportResultItem; import de.deadlocker8.budgetmaster.services.ImportService; -import de.deadlocker8.budgetmaster.settings.containers.PersonalizationSettingsContainer; -import de.deadlocker8.budgetmaster.settings.containers.SecuritySettingsContainer; -import de.deadlocker8.budgetmaster.settings.containers.TransactionsSettingsContainer; -import de.deadlocker8.budgetmaster.settings.containers.UpdateSettingsContainer; +import de.deadlocker8.budgetmaster.settings.containers.*; import de.deadlocker8.budgetmaster.update.BudgetMasterUpdateService; import de.deadlocker8.budgetmaster.utils.Mappings; import de.deadlocker8.budgetmaster.utils.WebRequestUtils; @@ -83,6 +80,7 @@ public class SettingsController extends BaseController public static final String CONTAINER_SECURITY = "settings/containers/settingsSecurity"; public static final String CONTAINER_PERSONALIZATION = "settings/containers/settingsPersonalization"; public static final String CONTAINER_TRANSACTIONS = "settings/containers/settingsTransactions"; + public static final String CONTAINER_BACKUP = "settings/containers/settingsBackup"; public static final String CONTAINER_UPDATE = "settings/containers/settingsUpdate"; public static final String CONTAINER_MISC = "settings/containers/settingsMisc"; } @@ -95,7 +93,7 @@ public class SettingsController extends BaseController public static final String IMPORT_CHARTS = "importCharts"; } - private static final String PASSWORD_PLACEHOLDER = "•••••"; + public static final String PASSWORD_PLACEHOLDER = "•••••"; private final SettingsService settingsService; private final DatabaseService databaseService; private final CategoryService categoryService; @@ -230,6 +228,63 @@ public class SettingsController extends BaseController return ReturnValues.CONTAINER_TRANSACTIONS; } + @PostMapping(value = "/save/backup") + public String saveContainerBackup( Model model, + @ModelAttribute("BackupSettingsContainer") BackupSettingsContainer backupSettingsContainer, + @RequestParam(value = "runBackup", required = false) Boolean runBackup, + BindingResult bindingResult) + { + BackupSettingsContainerValidator backupSettingsContainerValidator = new BackupSettingsContainerValidator(); + backupSettingsContainerValidator.validate(backupSettingsContainer, bindingResult); + + final Settings settings = settingsService.getSettings(); + backupSettingsContainer.fillMissingFieldsWithDefaults(settings); + + final Settings previousSettings = settingsService.getSettings(); + + // update settings here to hand them over to ftl to allow validation to show in case of binding errors + settings.setBackupReminderActivated(backupSettingsContainer.getBackupReminderActivated()); + settings.setAutoBackupStrategy(backupSettingsContainer.getAutoBackupStrategy()); + settings.setAutoBackupDays(backupSettingsContainer.getAutoBackupDays()); + settings.setAutoBackupTime(backupSettingsContainer.getAutoBackupTime()); + settings.setAutoBackupFilesToKeep(backupSettingsContainer.getAutoBackupFilesToKeep()); + settings.setAutoBackupGitUrl(backupSettingsContainer.getAutoBackupGitUrl()); + settings.setAutoBackupGitBranchName(backupSettingsContainer.getAutoBackupGitBranchName()); + settings.setAutoBackupGitUserName(backupSettingsContainer.getAutoBackupGitUserName()); + settings.setAutoBackupGitToken(backupSettingsContainer.getAutoBackupGitToken()); + + if(bindingResult.hasErrors()) + { + model.addAttribute(ModelAttributes.ERROR, bindingResult); + + final JsonObject toastContent = getToastContent("notification.settings.backup.error", NotificationType.ERROR); + model.addAttribute(ModelAttributes.TOAST_CONTENT, toastContent); + prepareModelBackup(model, settings); + return ReturnValues.CONTAINER_BACKUP; + } + + settingsService.updateSettings(settings); + + updateBackupTask(previousSettings, settings); + + // run backup now if requested + JsonObject toastContent = runBackupIfRequested(runBackup); + + model.addAttribute(ModelAttributes.TOAST_CONTENT, toastContent); + prepareModelBackup(model, settings); + return ReturnValues.CONTAINER_BACKUP; + } + + private void prepareModelBackup(Model model, Settings settings) + { + model.addAttribute(ModelAttributes.SETTINGS, settings); + model.addAttribute(ModelAttributes.AUTO_BACKUP_TIME, AutoBackupTime.values()); + + final Optional<LocalDateTime> nextBackupTimeOptional = backupService.getNextRun(); + nextBackupTimeOptional.ifPresent(date -> model.addAttribute(ModelAttributes.NEXT_BACKUP_TIME, date)); + model.addAttribute(ModelAttributes.AUTO_BACKUP_STATUS, backupService.getBackupStatus()); + } + @PostMapping(value = "/save/update") public String saveContainerUpdate(Model model, @ModelAttribute("UpdateSettingsContainer") UpdateSettingsContainer updateSettingsContainer, @@ -282,97 +337,28 @@ public class SettingsController extends BaseController return MessageFormat.format("{0} {1}", notificationType.getBackgroundColor(), notificationType.getTextColor()); } - @PostMapping(value = "/save") - public String post(WebRequest request, Model model, - @ModelAttribute("Settings") Settings settings, BindingResult bindingResult, - @RequestParam(value = "autoBackupStrategyType", required = false) String autoBackupStrategyType, - @RequestParam(value = "runBackup", required = false) Boolean runBackup) - { - if(autoBackupStrategyType == null) - { - settings.setAutoBackupStrategy(AutoBackupStrategy.NONE); - } - else - { - settings.setAutoBackupStrategy(AutoBackupStrategy.fromName(autoBackupStrategyType)); - } - - SettingsValidator settingsValidator = new SettingsValidator(); - settingsValidator.validate(settings, bindingResult); - - fillMissingFieldsWithDefaults(settings); - - if(bindingResult.hasErrors()) - { - model.addAttribute(ModelAttributes.ERROR, bindingResult); - prepareBasicModel(model, settings); - return ReturnValues.ALL_ENTITIES; - } - - updateSettings(settings); - - runBackup(request, runBackup); - - WebRequestUtils.putNotification(request, new Notification(Localization.getString("notification.settings.saved"), NotificationType.SUCCESS)); - return ReturnValues.REDIRECT_ALL_ENTITIES; - } - - private void runBackup(WebRequest request, Boolean runBackup) + private JsonObject runBackupIfRequested(Boolean runBackup) { - if(runBackup == null) + if(runBackup == null || !runBackup) { - return; + return getToastContent("notification.settings.backup.saved", NotificationType.SUCCESS); } - if(runBackup) - { - backupService.runNow(); - - BackupStatus backupStatus = backupService.getBackupStatus(); - if(backupStatus == BackupStatus.OK) - { - WebRequestUtils.putNotification(request, new Notification(Localization.getString("notification.settings.backup.run.success"), NotificationType.SUCCESS)); - } - else - { - WebRequestUtils.putNotification(request, new Notification(Localization.getString("notification.settings.backup.run.error"), NotificationType.ERROR)); - } - } - } + backupService.runNow(); - private void fillMissingFieldsWithDefaults(Settings settings) - { - if(settings.getBackupReminderActivated() == null) + BackupStatus backupStatus = backupService.getBackupStatus(); + if(backupStatus == BackupStatus.OK) { - settings.setBackupReminderActivated(false); + return getToastContent("notification.settings.backup.run.success", NotificationType.SUCCESS); } - - if(settings.getAutoBackupStrategy() == null) - { - settings.setAutoBackupStrategy(AutoBackupStrategy.NONE); - } - - if(settings.getAutoBackupGitToken().equals(PASSWORD_PLACEHOLDER)) - { - settings.setAutoBackupGitToken(settingsService.getSettings().getAutoBackupGitToken()); - } - - if(settings.getAutoBackupStrategy() == AutoBackupStrategy.NONE) + else { - final Settings defaultSettings = Settings.getDefault(); - settings.setAutoBackupDays(defaultSettings.getAutoBackupDays()); - settings.setAutoBackupTime(defaultSettings.getAutoBackupTime()); - settings.setAutoBackupFilesToKeep(defaultSettings.getAutoBackupFilesToKeep()); - settings.setAutoBackupGitUserName(defaultSettings.getAutoBackupGitUserName()); - settings.setAutoBackupGitToken(defaultSettings.getAutoBackupGitToken()); + return getToastContent("notification.settings.backup.run.error", NotificationType.ERROR); } } - public void updateSettings(Settings settings) + public void updateBackupTask(Settings previousSettings, Settings settings) { - final Settings previousSettings = settingsService.getSettings(); - settingsService.updateSettings(settings); - backupService.stopBackupCron(); if(settings.getAutoBackupStrategy() != AutoBackupStrategy.NONE) { @@ -570,10 +556,6 @@ public class SettingsController extends BaseController { model.addAttribute(ModelAttributes.SETTINGS, settings); model.addAttribute(ModelAttributes.SEARCH_RESULTS_PER_PAGE, SEARCH_RESULTS_PER_PAGE_OPTIONS); - model.addAttribute(ModelAttributes.AUTO_BACKUP_TIME, AutoBackupTime.values()); - - final Optional<LocalDateTime> nextBackupTimeOptional = backupService.getNextRun(); - nextBackupTimeOptional.ifPresent(date -> model.addAttribute(ModelAttributes.NEXT_BACKUP_TIME, date)); - model.addAttribute(ModelAttributes.AUTO_BACKUP_STATUS, backupService.getBackupStatus()); + prepareModelBackup(model, settings); } } \ No newline at end of file diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/containers/BackupSettingsContainer.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/containers/BackupSettingsContainer.java new file mode 100644 index 000000000..f295b1934 --- /dev/null +++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/settings/containers/BackupSettingsContainer.java @@ -0,0 +1,138 @@ +package de.deadlocker8.budgetmaster.settings.containers; + +import de.deadlocker8.budgetmaster.backup.AutoBackupStrategy; +import de.deadlocker8.budgetmaster.backup.AutoBackupTime; +import de.deadlocker8.budgetmaster.settings.Settings; +import de.deadlocker8.budgetmaster.utils.Strings; +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; + +import static de.deadlocker8.budgetmaster.settings.SettingsController.PASSWORD_PLACEHOLDER; + +public final class BackupSettingsContainer +{ + private Boolean backupReminderActivated; + + private String autoBackupStrategyType; + private Integer autoBackupDays; + private String autoBackupTimeType; + + private Integer autoBackupFilesToKeep; + private final String autoBackupGitUrl; + private final String autoBackupGitBranchName; + private String autoBackupGitUserName; + private String autoBackupGitToken; + + public BackupSettingsContainer(Boolean backupReminderActivated, String autoBackupStrategyType, Integer autoBackupDays, String autoBackupTimeType, Integer autoBackupFilesToKeep, String autoBackupGitUrl, String autoBackupGitBranchName, String autoBackupGitUserName, String autoBackupGitToken) + { + this.backupReminderActivated = backupReminderActivated; + this.autoBackupStrategyType = autoBackupStrategyType; + this.autoBackupDays = autoBackupDays; + this.autoBackupTimeType = autoBackupTimeType; + this.autoBackupFilesToKeep = autoBackupFilesToKeep; + this.autoBackupGitUrl = autoBackupGitUrl; + this.autoBackupGitBranchName = autoBackupGitBranchName; + this.autoBackupGitUserName = autoBackupGitUserName; + this.autoBackupGitToken = autoBackupGitToken; + } + + public Boolean getBackupReminderActivated() + { + return backupReminderActivated; + } + + public AutoBackupStrategy getAutoBackupStrategy() + { + if(autoBackupStrategyType == null) + { + return AutoBackupStrategy.NONE; + } + else + { + return AutoBackupStrategy.fromName(autoBackupStrategyType); + } + } + + public AutoBackupTime getAutoBackupTime() + { + return AutoBackupTime.valueOf(autoBackupTimeType); + } + + public Integer getAutoBackupDays() + { + return autoBackupDays; + } + + public Integer getAutoBackupFilesToKeep() + { + return autoBackupFilesToKeep; + } + + public String getAutoBackupGitUrl() + { + return autoBackupGitUrl; + } + + public String getAutoBackupGitBranchName() + { + return autoBackupGitBranchName; + } + + public String getAutoBackupGitUserName() + { + return autoBackupGitUserName; + } + + public String getAutoBackupGitToken() + { + return autoBackupGitToken; + } + + public void validate(Object obj, Errors errors) + { + final Settings settings = (Settings) obj; + + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupDays", Strings.WARNING_EMPTY_NUMBER); + + if(settings.getAutoBackupStrategy() == AutoBackupStrategy.LOCAL) + { + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupFilesToKeep", Strings.WARNING_EMPTY_NUMBER_ZERO_ALLOWED); + } + + if(settings.getAutoBackupStrategy() == AutoBackupStrategy.GIT_REMOTE) + { + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupGitUrl", Strings.WARNING_EMPTY_GIT_URL); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupGitBranchName", Strings.WARNING_EMPTY_GIT_BRANCH_NAME); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupGitUserName", Strings.WARNING_EMPTY_GIT_USER_NAME); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "autoBackupGitToken", Strings.WARNING_EMPTY_GIT_TOKEN); + } + } + + public void fillMissingFieldsWithDefaults(Settings settings) + { + if(backupReminderActivated == null) + { + backupReminderActivated = false; + } + + if(autoBackupStrategyType == null) + { + autoBackupStrategyType = AutoBackupStrategy.NONE.getName(); + } + + if(autoBackupGitToken.equals(PASSWORD_PLACEHOLDER)) + { + autoBackupGitToken = settings.getAutoBackupGitToken(); + } + + if(getAutoBackupStrategy() == AutoBackupStrategy.NONE) + { + final Settings defaultSettings = Settings.getDefault(); + autoBackupDays = defaultSettings.getAutoBackupDays(); + autoBackupTimeType = defaultSettings.getAutoBackupTime().name(); + autoBackupFilesToKeep = defaultSettings.getAutoBackupFilesToKeep(); + autoBackupGitUserName = defaultSettings.getAutoBackupGitUserName(); + autoBackupGitToken = defaultSettings.getAutoBackupGitToken(); + } + } +} diff --git a/BudgetMasterServer/src/main/resources/languages/base_de.properties b/BudgetMasterServer/src/main/resources/languages/base_de.properties index b5073104b..64a24ebe1 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_de.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_de.properties @@ -177,6 +177,8 @@ notification.settings.transactions.saved=Buchungseinstellungen gespeichert notification.settings.transactions.error=Fehler beim Speichern der Buchungseinstellungen notification.settings.update.saved=Updateeinstellungen gespeichert notification.settings.update.error=Fehler beim Speichern der Updateeinstellungen +notification.settings.backup.saved=Backupeinstellungen gespeichert +notification.settings.backup.error=Fehler beim Speichern der Backupeinstellungen notification.settings.update.available=BudgetMaster Update "{0}" verfügbar notification.settings.update.not.available=Kein Update verfügbar notification.settings.hints.reset=Alle Tipps zurückgesetzt diff --git a/BudgetMasterServer/src/main/resources/languages/base_en.properties b/BudgetMasterServer/src/main/resources/languages/base_en.properties index 77a27e38c..83ebe7d75 100644 --- a/BudgetMasterServer/src/main/resources/languages/base_en.properties +++ b/BudgetMasterServer/src/main/resources/languages/base_en.properties @@ -176,6 +176,8 @@ notification.settings.personalization.saved=Personalization settings saved notification.settings.personalization.error=Error saving personalization settings notification.settings.transactions.saved=Transactions settings saved notification.settings.transactions.error=Error saving transactions settings +notification.settings.backup.saved=Backup settings saved +notification.settings.backup.error=Error saving backup settings notification.settings.update.saved=Update settings saved notification.settings.update.error=Error saving update settings notification.settings.hints.reset=All hints reset diff --git a/BudgetMasterServer/src/main/resources/static/js/settings.js b/BudgetMasterServer/src/main/resources/static/js/settings.js index 4e35537c0..98aaa3f54 100644 --- a/BudgetMasterServer/src/main/resources/static/js/settings.js +++ b/BudgetMasterServer/src/main/resources/static/js/settings.js @@ -14,70 +14,6 @@ $(document).ready(function() document.getElementById("form-database-import").submit(); }); - $('input[name="autoBackupActivated"]').click(function() - { - $('#settings-auto-backup').toggle($(this).prop("checked")); - }); - - $('#settings-backup-auto-strategy').change(function() - { - onAutoBackupStrategyChange(this.selectedIndex); - }); - - $('#settings-backup-auto-git-test').click(function() - { - $.ajax({ - type: 'POST', - url: $('#settings-backup-auto-git-test').attr('data-url'), - data: { - '_csrf': document.getElementById('token').value, - 'autoBackupGitUrl': document.getElementById('settings-backup-auto-git-url').value, - 'autoBackupGitBranchName': document.getElementById('settings-backup-auto-git-branch-name').value, - 'autoBackupGitUserName': document.getElementById('settings-backup-auto-git-user-name').value, - 'autoBackupGitToken': document.getElementById('settings-backup-auto-git-token').value, - }, - success: function(data) - { - let parsedData = JSON.parse(data); - let isValidConnection = parsedData['isValidConnection'] - M.toast({ - html: parsedData['localizedMessage'], - classes: isValidConnection ? 'green': 'red' - }); - }, - error: function(data) - { - M.toast({ - html: 'Error: ' + data, - classes: 'red' - }); - } - }); - }); - - let autoBackupDays = $('#settings-backup-auto-days'); - if(autoBackupDays.length) - { - autoBackupDays.on('change keydown paste input', function() - { - validateNumber(autoBackupDays.val(), 'settings-backup-auto-days', "hidden-settings-backup-auto-days", numberValidationMessage, REGEX_NUMBER_GREATER_ZERO); - }); - } - - let autoBackupFilesToKeep = $('#settings-backup-auto-files-to-keep'); - if(autoBackupFilesToKeep.length) - { - autoBackupFilesToKeep.on('change keydown paste input', function() - { - validateNumber(autoBackupFilesToKeep.val(), "settings-backup-auto-files-to-keep", "hidden-settings-backup-auto-files-to-keep", numberValidationMessageZeroAllowed, REGEX_NUMBER); - }); - } - - $('#settings-backup-run-now').click(function() - { - document.getElementById('runBackupInput').value = 1; - }); - $('#verificationCode').click(function() { let verificationCodeElement = document.getElementsByName('verificationCode')[0]; @@ -88,37 +24,8 @@ $(document).ready(function() M.toast({html: copiedToClipboard, classes: 'green'}); }); - - // on initial page load - let autoBackupCheckbox = document.getElementsByName("autoBackupActivated")[0]; - $('#settings-auto-backup').toggle(autoBackupCheckbox.checked); - onAutoBackupStrategyChange(document.getElementById('settings-backup-auto-strategy').selectedIndex); }); -function validateForm() -{ - let autoBackupCheckbox = document.getElementsByName("autoBackupActivated")[0]; - if(autoBackupCheckbox.checked) - { - let autoBackupDaysValid = validateNumber($('#settings-backup-auto-days').val(), "settings-backup-auto-days", "hidden-settings-backup-auto-days", numberValidationMessage, REGEX_NUMBER_GREATER_ZERO); - let autoBackupFilesToKeepValid = validateNumber($('#settings-backup-auto-files-to-keep').val(), "settings-backup-auto-files-to-keep", "hidden-settings-backup-auto-files-to-keep", numberValidationMessageZeroAllowed, REGEX_NUMBER); - return autoBackupDaysValid && autoBackupFilesToKeepValid; - } - else - { - document.getElementById('settings-backup-auto-strategy').name = ''; - } - - return true; -} - -function onAutoBackupStrategyChange(newSelectedIndex) -{ - $('#settings-auto-backup-local').toggle(newSelectedIndex === 0); // local backup with file system copies - // index 1 --> git local doesn't have any settings - $('#settings-auto-backup-git-remote').toggle(newSelectedIndex === 2); // git remote -} - function toggleSettingsContainerHeader(id, hide) { document.querySelector('#' + id + ' .collapsible-header-button').classList.toggle('hidden', hide); diff --git a/BudgetMasterServer/src/main/resources/templates/settings/containers/settingsBackup.ftl b/BudgetMasterServer/src/main/resources/templates/settings/containers/settingsBackup.ftl new file mode 100644 index 000000000..320e6f4bf --- /dev/null +++ b/BudgetMasterServer/src/main/resources/templates/settings/containers/settingsBackup.ftl @@ -0,0 +1,194 @@ +<#import "/spring.ftl" as s> +<#import "../../helpers/validation.ftl" as validation> +<#import "../../helpers/header.ftl" as header> +<@header.globals/> + +<#import "settingsContainer.ftl" as settingsContainerMacros> +<#import "../settingsMacros.ftl" as settingsMacros> + +<#macro backupSettingsContainer importScripts settings> + <@settingsContainerMacros.settingsContainer 'BackupSettingsContainer' 'backupSettingsContainer' importScripts true> + <div class="row"> + <div class="col s12"> + <div class="table-container"> + <div class="table-cell"> + <div class="switch-cell-margin">${locale.getString("settings.backupReminder")}</div> + <div class="switch-cell-margin">${locale.getString("settings.backup.auto")}</div> + </div> + <div class="table-cell table-cell-spacer"></div> + <div class="table-cell"> + <@settingsMacros.switch "backupReminder" "backupReminderActivated" settings.getBackupReminderActivated()/> + <@settingsMacros.switch "backup.auto" "autoBackupActivated" settings.isAutoBackupActive()/> + </div> + <div class="table-cell table-cell-spacer"></div> + <div class="table-cell"> + <div class="switch-cell-margin"> + <a class="btn btn-flat tooltipped text-default" data-position="bottom" data-tooltip="${locale.getString("settings.backupReminder.description")}"><i class="material-icons">help_outline</i></a> + </div> + <div class="switch-cell-margin"> + <a class="btn btn-flat tooltipped text-default" data-position="bottom" data-tooltip="${locale.getString("settings.backup.auto.description")}"><i class="material-icons">help_outline</i></a> + </div> + </div> + </div> + </div> + </div> + + <#-- auto backup --> + <@settingsMacros.autoBackup/> + + <div class="row"> + <div class="col s12 center-align"> + <@header.buttonSubmit name='action' icon='save' localizationKey='save' color='background-green' formaction='/settings/save/backup'/> + </div> + </div> + + <script> + function onAutoBackupStrategyChange(newSelectedIndex) + { + $('#settings-auto-backup-local').toggle(newSelectedIndex === 0); // local backup with file system copies + // index 1 --> git local doesn't have any settings + $('#settings-auto-backup-git-remote').toggle(newSelectedIndex === 2); // git remote + } + + function validateForm() + { + let autoBackupCheckbox = document.getElementsByName("autoBackupActivated")[0]; + if(autoBackupCheckbox.checked) + { + let autoBackupDaysValid = validateNumber($('#settings-backup-auto-days').val(), "settings-backup-auto-days", "hidden-settings-backup-auto-days", numberValidationMessage, REGEX_NUMBER_GREATER_ZERO); + let autoBackupFilesToKeepValid = validateNumber($('#settings-backup-auto-files-to-keep').val(), "settings-backup-auto-files-to-keep", "hidden-settings-backup-auto-files-to-keep", numberValidationMessageZeroAllowed, REGEX_NUMBER); + return autoBackupDaysValid && autoBackupFilesToKeepValid; + } + else + { + document.getElementById('settings-backup-auto-strategy').name = ''; + } + + return true; + } + + $('input[name="autoBackupActivated"]').click(function() + { + $('#settings-auto-backup').toggle($(this).prop("checked")); + }); + + $('#settings-backup-auto-strategy').change(function() + { + onAutoBackupStrategyChange(this.selectedIndex); + }); + + $('#settings-backup-auto-git-test').click(function() + { + $.ajax({ + type: 'POST', + url: $('#settings-backup-auto-git-test').attr('data-url'), + data: { + '_csrf': document.getElementById('token').value, + 'autoBackupGitUrl': document.getElementById('settings-backup-auto-git-url').value, + 'autoBackupGitBranchName': document.getElementById('settings-backup-auto-git-branch-name').value, + 'autoBackupGitUserName': document.getElementById('settings-backup-auto-git-user-name').value, + 'autoBackupGitToken': document.getElementById('settings-backup-auto-git-token').value, + }, + success: function(data) + { + let parsedData = JSON.parse(data); + let isValidConnection = parsedData['isValidConnection'] + M.toast({ + html: parsedData['localizedMessage'], + classes: isValidConnection ? 'green': 'red' + }); + }, + error: function(data) + { + M.toast({ + html: 'Error: ' + data, + classes: 'red' + }); + } + }); + }); + + var autoBackupDays = $('#settings-backup-auto-days'); + if(autoBackupDays.length) + { + autoBackupDays.on('change keydown paste input', function() + { + validateNumber(autoBackupDays.val(), 'settings-backup-auto-days', "hidden-settings-backup-auto-days", numberValidationMessage, REGEX_NUMBER_GREATER_ZERO); + }); + } + + var autoBackupFilesToKeep = $('#settings-backup-auto-files-to-keep'); + if(autoBackupFilesToKeep.length) + { + autoBackupFilesToKeep.on('change keydown paste input', function() + { + validateNumber(autoBackupFilesToKeep.val(), "settings-backup-auto-files-to-keep", "hidden-settings-backup-auto-files-to-keep", numberValidationMessageZeroAllowed, REGEX_NUMBER); + }); + } + + $('#settings-backup-run-now').click(function() + { + document.getElementById('runBackupInput').value = 1; + }); + + var autoBackupCheckbox = document.getElementsByName("autoBackupActivated")[0]; + $('#settings-auto-backup').toggle(autoBackupCheckbox.checked); + onAutoBackupStrategyChange(document.getElementById('settings-backup-auto-strategy').selectedIndex); + + + // toggle unsaved changes warning + + $('input[name="backupReminderActivated"]').change(function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('input[name="autoBackupActivated"]').change(function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-days').on('change keydown paste input', function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-time').change(function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-strategy').change(function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-files-to-keep').on('change keydown paste input', function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-git-url').on('change keydown paste input', function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-git-branch-name').on('change keydown paste input', function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-git-user-name').on('change keydown paste input', function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + + $('#settings-backup-auto-git-token').on('change keydown paste input', function() + { + toggleSettingsContainerHeader('backupSettingsContainerHeader', false); + }); + </script> + </@settingsContainerMacros.settingsContainer> +</#macro> + +<@backupSettingsContainer importScripts=true settings=settings/> diff --git a/BudgetMasterServer/src/main/resources/templates/settings/containers/settingsContainer.ftl b/BudgetMasterServer/src/main/resources/templates/settings/containers/settingsContainer.ftl index 41f9aa95d..282aaae51 100644 --- a/BudgetMasterServer/src/main/resources/templates/settings/containers/settingsContainer.ftl +++ b/BudgetMasterServer/src/main/resources/templates/settings/containers/settingsContainer.ftl @@ -1,7 +1,7 @@ <#import "/spring.ftl" as s> -<#macro settingsContainer formName containerId importScripts> - <form name="${formName}" method="post"> +<#macro settingsContainer formName containerId importScripts validateForm=false> + <form name="${formName}" method="post" <#if validateForm>onsubmit="return validateForm()"</#if>> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" id="token"/> <#nested> diff --git a/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl b/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl index 8246e214d..6d9c42368 100644 --- a/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl +++ b/BudgetMasterServer/src/main/resources/templates/settings/settings.ftl @@ -17,6 +17,7 @@ <#import "containers/settingsSecurity.ftl" as settingsSecurityMacros> <#import "containers/settingsPersonalization.ftl" as settingsPersonalizationMacros> <#import "containers/settingsTransactions.ftl" as settingsTransactionsMacros> + <#import "containers/settingsBackup.ftl" as settingsBackupMacros> <#import "containers/settingsUpdate.ftl" as settingsUpdateMacros> <#import "containers/settingsMisc.ftl" as settingsMiscMacros> @@ -50,40 +51,8 @@ <@settingsTransactionsMacros.transactionsSettingsContainer importScripts=false settings=settings/> </@settingsMacros.settingsCollapsibleItem> - <@settingsMacros.settingsCollapsibleItem "" "cloud_download" locale.getString("settings.backup")> - <div class="row"> - <div class="col s12"> - <div class="table-container"> - <div class="table-cell"> - <div class="switch-cell-margin">${locale.getString("settings.backupReminder")}</div> - <div class="switch-cell-margin">${locale.getString("settings.backup.auto")}</div> - </div> - <div class="table-cell table-cell-spacer"></div> - <div class="table-cell"> - <@settingsMacros.switch "backupReminder" "backupReminderActivated" settings.getBackupReminderActivated()/> - <@settingsMacros.switch "backup.auto" "autoBackupActivated" settings.isAutoBackupActive()/> - </div> - <div class="table-cell table-cell-spacer"></div> - <div class="table-cell"> - <div class="switch-cell-margin"> - <a class="btn btn-flat tooltipped text-default" data-position="bottom" data-tooltip="${locale.getString("settings.backupReminder.description")}"><i class="material-icons">help_outline</i></a> - </div> - <div class="switch-cell-margin"> - <a class="btn btn-flat tooltipped text-default" data-position="bottom" data-tooltip="${locale.getString("settings.backup.auto.description")}"><i class="material-icons">help_outline</i></a> - </div> - </div> - </div> - </div> - </div> - - <#-- auto backup --> - <@settingsMacros.autoBackup/> - - <div class="row"> - <div class="col s12 center-align"> - <@header.buttonSubmit name='action' icon='save' localizationKey='save' color='background-green'/> - </div> - </div> + <@settingsMacros.settingsCollapsibleItem "backupSettingsContainer" "cloud_download" locale.getString("settings.backup")> + <@settingsBackupMacros.backupSettingsContainer importScripts=false settings=settings/> </@settingsMacros.settingsCollapsibleItem> <@settingsMacros.settingsCollapsibleItem "updateSettingsContainer" "system_update" locale.getString("settings.updates")> @@ -144,8 +113,9 @@ initSettingsContainer('SecuritySettingsContainer', 'securitySettingsContainer'); initSettingsContainer('PersonalizationSettingsContainer', 'personalizationSettingsContainer'); initSettingsContainer('TransactionsSettingsContainer', 'transactionsSettingsContainer'); - initSettingsContainer('UpdateSettingsContainer', 'updateSettingsContainer'); + initSettingsContainer('BackupSettingsContainer', 'backupSettingsContainer'); initSettingsContainer('MiscSettingsContainer', 'miscSettingsContainer'); + initSettingsContainer('UpdateSettingsContainer', 'updateSettingsContainer'); </script> </@header.body> </html> diff --git a/BudgetMasterServer/src/main/resources/templates/settings/settingsMacros.ftl b/BudgetMasterServer/src/main/resources/templates/settings/settingsMacros.ftl index 79f231c53..efd2b3fa8 100644 --- a/BudgetMasterServer/src/main/resources/templates/settings/settingsMacros.ftl +++ b/BudgetMasterServer/src/main/resources/templates/settings/settingsMacros.ftl @@ -182,7 +182,7 @@ <div class="input-field col s12 m12 l8 offset-l2"> <i class="material-icons prefix">schedule</i> - <select id="settings-backup-auto-time" name="autoBackupTime" <@validation.validation "autoBackupTime"/>> + <select id="settings-backup-auto-time" name="autoBackupTimeType" <@validation.validation "autoBackupTime"/>> <#list autoBackupTimes as time> <#if settings.getAutoBackupTime() == time> <option selected value="${time}">${time.getLocalized()}</option> @@ -291,12 +291,12 @@ <a target="_blank" href="${locale.getString("settings.backup.auto.strategy.git.remote.help.url")}" class="waves-effect waves-light btn btn-flat text-default"><i class="material-icons left">help_outline</i>${locale.getString("settings.backup.auto.strategy.git.remote.help")}</a> </div> </div> - <div class="row"> - <div class="col s12 m12 l8 offset-l2 center-align"> - <input id="runBackupInput" type="hidden" name="runBackup" value="0"> - <@header.buttonSubmit id='settings-backup-run-now' name='action' icon='cloud_download' localizationKey='settings.backup.auto.run.now'/> - </div> - </div> +<#-- <div class="row">--> +<#-- <div class="col s12 m12 l8 offset-l2 center-align">--> +<#-- <input id="runBackupInput" type="hidden" name="runBackup" value="0">--> +<#-- <@header.buttonSubmit id='settings-backup-run-now' name='action' icon='cloud_download' localizationKey='settings.backup.auto.run.now' formaction='/settings/save/backup'/>--> +<#-- </div>--> +<#-- </div>--> </#macro> <#macro settingsCollapsibleItem id icon title isFontAwesomeIcon=false> -- GitLab