From 4a4bb7f6bc90edd4bbbbe8340778c6c314344214 Mon Sep 17 00:00:00 2001 From: Griefed Date: Sun, 17 Sep 2023 20:30:52 +0200 Subject: [PATCH] improv: Validate settings and inform about unsaved changes --- serverpackcreator-gui/build.gradle.kts | 1 + .../gui/window/settings/GlobalSettings.kt | 63 +++++++++++- .../gui/window/settings/GuiSettings.kt | 26 ++++- .../gui/window/settings/SettingsEditorsTab.kt | 1 - .../{components => }/SettingsHandling.kt | 6 +- .../gui/window/settings/WebserviceSettings.kt | 96 +++++++++++++++++-- 6 files changed, 173 insertions(+), 20 deletions(-) rename serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/{components => }/SettingsHandling.kt (95%) diff --git a/serverpackcreator-gui/build.gradle.kts b/serverpackcreator-gui/build.gradle.kts index 300df1fdf..a6f3e69f2 100644 --- a/serverpackcreator-gui/build.gradle.kts +++ b/serverpackcreator-gui/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { api("com.formdev:svgSalamander:1.1.4") api("net.java.balloontip:balloontip:1.2.4.1") api("com.github.dyorgio.runtime:run-as-root:1.2.3") + api("com.cronutils:cron-utils:9.2.1") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.3") diff --git a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GlobalSettings.kt b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GlobalSettings.kt index 9cd880bbc..28aaaad1c 100644 --- a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GlobalSettings.kt +++ b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GlobalSettings.kt @@ -30,6 +30,7 @@ import de.griefed.serverpackcreator.gui.window.configs.components.ComponentResiz import de.griefed.serverpackcreator.gui.window.settings.components.* import java.awt.event.ActionListener import java.io.File +import java.net.MalformedURLException import java.net.URL import javax.swing.DefaultComboBoxModel import javax.swing.JCheckBox @@ -37,7 +38,7 @@ import javax.swing.JComboBox import javax.swing.JFileChooser class GlobalSettings( - guiProps: GuiProps, + private val guiProps: GuiProps, private val apiProperties: ApiProperties, componentResizer: ComponentResizer, mainFrame: MainFrame, @@ -351,11 +352,61 @@ class GlobalSettings( } override fun validateSettings(): List { - return listOf("") + val errors = mutableListOf() + if (!homeSetting.file.absoluteFile.isDirectory || !homeSetting.file.absoluteFile.canWrite()) { + homeIcon.error("Home-directory either does not exist or is not writable.") + errors.add("Home-directory either does not exist or is not writable.") + } else { + homeIcon.info() + } + + if (!javaSetting.file.absoluteFile.isFile || !javaSetting.file.absoluteFile.canRead() || !javaSetting.file.absoluteFile.canExecute()) { + javaIcon.error("Java executable/binary either does not exist, is not readable, or is not executable.") + errors.add("Java executable/binary either does not exist, is not readable, or is not executable.") + } else { + javaIcon.info() + } + + if (!serverPacksSetting.file.absoluteFile.isDirectory || !serverPacksSetting.file.absoluteFile.canWrite()) { + serverPacksIcon.error("Server packs directory either does not exist or is not writable.") + errors.add("Server packs directory either does not exist or is not writable.") + } else { + serverPacksIcon.info() + } + + if (zipSetting.text.matches(guiProps.whitespace)) { + zipIcon.error("Must not end with ','!") + errors.add("Must not end with ','!") + } else { + zipIcon.info() + } + + if (inclusionsSetting.text.matches(guiProps.whitespace)) { + inclusionsIcon.error("Must not end with ','!") + errors.add("Must not end with ','!") + } else { + inclusionsIcon.info() + } + + if (scriptSetting.text.matches(guiProps.whitespace)) { + scriptIcon.error("Must not end with ','!") + errors.add("Must not end with ','!") + } else { + scriptIcon.info() + } + + try { + URL(fallbackURLSetting.text) + fallbackURLIcon.info() + } catch (ex: MalformedURLException) { + fallbackURLIcon.error("Invalid URL format!") + errors.add("Invalid URL format!") + } + return errors.toList() } override fun hasUnsavedChanges(): Boolean { - return homeSetting.file != apiProperties.homeDirectory.absoluteFile || + val changes = homeSetting.file != apiProperties.homeDirectory.absoluteFile || javaSetting.file != File(apiProperties.javaPath).absoluteFile || serverPacksSetting.file != apiProperties.serverPacksDirectory.absoluteFile || zipSetting.text != apiProperties.zipArchiveExclusions.joinToString(", ") || @@ -372,5 +423,11 @@ class GlobalSettings( cleanupSetting.isSelected != apiProperties.isServerPackCleanupEnabled || snapshotsSetting.isSelected != apiProperties.isMinecraftPreReleasesAvailabilityEnabled || autodetectionSetting.isSelected != apiProperties.isAutoExcludingModsEnabled + if (changes) { + title.showWarningIcon() + } else { + title.hideWarningIcon() + } + return changes } } \ No newline at end of file diff --git a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GuiSettings.kt b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GuiSettings.kt index ff456d642..94c04dc6d 100644 --- a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GuiSettings.kt +++ b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/GuiSettings.kt @@ -103,12 +103,30 @@ class GuiSettings( } override fun validateSettings(): List { - return listOf("") + val errors = mutableListOf() + if (fontSizeSetting.value < 8 || fontSizeSetting.value > 76) { + fontSizeIcon.error("Font size must be a value from 8 to 76.") + errors.add("Font size must be a value from 8 to 76.") + } else { + fontSizeIcon.info() + } + if (errors.isNotEmpty()) { + title.setAndShowErrorIcon("Your GUI settings contain errors!") + } else { + title.hideErrorIcon() + } + return errors.toList() } override fun hasUnsavedChanges(): Boolean { - return fontSizeSetting.value != guiProps.fontSize || - startFocusSetting.isSelected != guiProps.startFocusEnabled || - generationFocusSetting.isSelected != guiProps.generationFocusEnabled + val changes = fontSizeSetting.value != guiProps.fontSize || + startFocusSetting.isSelected != guiProps.startFocusEnabled || + generationFocusSetting.isSelected != guiProps.generationFocusEnabled + if (changes) { + title.showWarningIcon() + } else { + title.hideWarningIcon() + } + return changes } } \ No newline at end of file diff --git a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/SettingsEditorsTab.kt b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/SettingsEditorsTab.kt index 1b2bd2d9d..3b575428e 100644 --- a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/SettingsEditorsTab.kt +++ b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/SettingsEditorsTab.kt @@ -27,7 +27,6 @@ import de.griefed.serverpackcreator.gui.window.MainFrame import de.griefed.serverpackcreator.gui.window.configs.components.ComponentResizer import de.griefed.serverpackcreator.gui.window.settings.components.Editor import de.griefed.serverpackcreator.gui.window.settings.components.SettingsCheckTimer -import de.griefed.serverpackcreator.gui.window.settings.components.SettingsHandling import de.griefed.serverpackcreator.gui.window.settings.components.SettingsTitle import java.awt.BorderLayout import java.awt.event.ActionListener diff --git a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/components/SettingsHandling.kt b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/SettingsHandling.kt similarity index 95% rename from serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/components/SettingsHandling.kt rename to serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/SettingsHandling.kt index 88c622122..150133411 100644 --- a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/components/SettingsHandling.kt +++ b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/SettingsHandling.kt @@ -17,13 +17,13 @@ * * The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE */ -package de.griefed.serverpackcreator.gui.window.settings.components +package de.griefed.serverpackcreator.gui.window.settings import de.griefed.serverpackcreator.api.ApiProperties import de.griefed.serverpackcreator.gui.GuiProps import de.griefed.serverpackcreator.gui.components.BalloonTipButton import de.griefed.serverpackcreator.gui.window.MainFrame -import de.griefed.serverpackcreator.gui.window.settings.SettingsEditorsTab +import de.griefed.serverpackcreator.gui.window.settings.components.PropertiesChooser import dyorgio.runtime.run.`as`.root.RootExecutor import net.miginfocom.swing.MigLayout import java.io.File @@ -107,7 +107,7 @@ class SettingsHandling( settingsEditorsTab.gui.saveSettings() settingsEditorsTab.webservice.saveSettings() apiProperties.saveProperties(apiProperties.serverPackCreatorPropertiesFile) - if (!apiProperties.overrideProperties.canWrite()) { + if (!apiProperties.overrideProperties.parentFile.canWrite()) { if (rootWarning() == JOptionPane.OK_OPTION) { val overridePath = apiProperties.overrideProperties.absolutePath val overrides = apiProperties.overridesAsString() diff --git a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/WebserviceSettings.kt b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/WebserviceSettings.kt index 7f4780502..e067b58e9 100644 --- a/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/WebserviceSettings.kt +++ b/serverpackcreator-gui/src/main/kotlin/de/griefed/serverpackcreator/gui/window/settings/WebserviceSettings.kt @@ -19,6 +19,9 @@ */ package de.griefed.serverpackcreator.gui.window.settings +import com.cronutils.model.CronType +import com.cronutils.model.definition.CronDefinitionBuilder +import com.cronutils.parser.CronParser import de.griefed.serverpackcreator.api.ApiProperties import de.griefed.serverpackcreator.gui.GuiProps import de.griefed.serverpackcreator.gui.components.* @@ -36,6 +39,9 @@ class WebserviceSettings( changeListener: ChangeListener ) : Editor("Webservice", guiProps) { + private val cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.SPRING) + private val cronParser = CronParser(cronDefinition) + val artemisDataDirectoryIcon = StatusIcon(guiProps, "Data directory for Artemis Queue System") val artemisDataDirectoryLabel = ElementLabel("Artemis Data Directory") val artemisDataDirectorySetting = ScrollTextFileField(guiProps,apiProperties.artemisDataDirectory.absoluteFile, documentChangeListener) @@ -199,17 +205,89 @@ class WebserviceSettings( } override fun validateSettings(): List { - return listOf("") + val errors = mutableListOf() + if (!artemisDataDirectorySetting.file.absoluteFile.isDirectory || !artemisDataDirectorySetting.file.absoluteFile.canWrite()) { + artemisDataDirectoryIcon.error("Artemis Data directory either does not exist or is not writable.") + errors.add("Artemis Data directory either does not exist or is not writable.") + } else { + artemisDataDirectoryIcon.info() + } + + if (artemisQueueMaxDiskUsageSetting.value < 10 || artemisQueueMaxDiskUsageSetting.value > 90 ) { + artemisQueueMaxDiskUsageIcon.error("Artemis max disk usage must be a value from 10 to 90.") + errors.add("Artemis max disk usage must be a value from 10 to 90.") + } else { + artemisQueueMaxDiskUsageIcon.info() + } + + if (!databaseFileSetting.file.absoluteFile.parentFile.isDirectory || !databaseFileSetting.file.absoluteFile.parentFile.canWrite()) { + databaseFileIcon.error("Database directory does not exist or is not writable.") + errors.add("Database directory does not exist or is not writable.") + } else { + databaseFileIcon.info() + } + + try { + cronParser.parse(cleanupScheduleSetting.text).validate() + cleanupScheduleIcon.info() + } catch (ex: IllegalArgumentException) { + cleanupScheduleIcon.error("Invalid Cleanup Schedule QUARTZ CRON expression.") + errors.add("Invalid Cleanup Schedule QUARTZ CRON expression.") + } + + if (!logDirectorySetting.file.absoluteFile.isDirectory || !logDirectorySetting.file.absoluteFile.canWrite()) { + logDirectoryIcon.error("Tomcat Log directory does not exist or is not writable.") + errors.add("Tomcat Log directory does not exist or is not writable.") + } else { + logDirectoryIcon.info() + } + + if (!baseDirSetting.file.absoluteFile.isDirectory || !baseDirSetting.file.absoluteFile.canWrite()) { + baseDirIcon.error("Tomcat base-directory does not exist or is not writable.") + errors.add("Tomcat base-directory does not exist or is not writable.") + } else { + baseDirIcon.info() + } + + try { + cronParser.parse(versionScheduleSetting.text).validate() + versionScheduleIcon.info() + } catch (ex: IllegalArgumentException) { + versionScheduleIcon.error("Invalid Version Update Schedule QUARTZ CRON expression.") + errors.add("Invalid Version Update Schedule QUARTZ CRON expression.") + } + + try { + cronParser.parse(databaseCleanupScheduleSetting.text).validate() + databaseCleanupScheduleIcon.info() + } catch (ex: IllegalArgumentException) { + databaseCleanupScheduleIcon.error("Invalid Database Cleanup Schedule QUARTZ CRON expression.") + errors.add("Invalid Database Cleanup Schedule QUARTZ CRON expression.") + } + + if (errors.isNotEmpty()) { + title.setAndShowErrorIcon("Your Webservice settings contain errors!") + } else { + title.hideErrorIcon() + } + + return errors.toList() } override fun hasUnsavedChanges(): Boolean { - return artemisDataDirectorySetting.file != apiProperties.artemisDataDirectory.absoluteFile || - artemisQueueMaxDiskUsageSetting.value != apiProperties.artemisQueueMaxDiskUsage || - databaseFileSetting.file != apiProperties.serverPackCreatorDatabase.absoluteFile || - cleanupScheduleSetting.text != apiProperties.webserviceCleanupSchedule || - logDirectorySetting.file != apiProperties.tomcatLogsDirectory.absoluteFile || - baseDirSetting.file != apiProperties.tomcatBaseDirectory.absoluteFile || - versionScheduleSetting.text != apiProperties.webserviceVersionSchedule || - databaseCleanupScheduleSetting.text != apiProperties.webserviceDatabaseCleanupSchedule + val changes = artemisDataDirectorySetting.file != apiProperties.artemisDataDirectory.absoluteFile || + artemisQueueMaxDiskUsageSetting.value != apiProperties.artemisQueueMaxDiskUsage || + databaseFileSetting.file != apiProperties.serverPackCreatorDatabase.absoluteFile || + cleanupScheduleSetting.text != apiProperties.webserviceCleanupSchedule || + logDirectorySetting.file != apiProperties.tomcatLogsDirectory.absoluteFile || + baseDirSetting.file != apiProperties.tomcatBaseDirectory.absoluteFile || + versionScheduleSetting.text != apiProperties.webserviceVersionSchedule || + databaseCleanupScheduleSetting.text != apiProperties.webserviceDatabaseCleanupSchedule + if (changes) { + title.showWarningIcon() + } else { + title.hideWarningIcon() + } + return changes } } \ No newline at end of file