diff --git a/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java b/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java index c26597f25388fa72edb3d481badcd9073fef543a..103917eccad00747a657904f9d2bb3af6526744b 100644 --- a/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java +++ b/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java @@ -321,4 +321,18 @@ public class ServerConnection return 0; } } + + /* + * DATABASE + */ + public void deleteDatabase() throws Exception + { + URL url = new URL(settings.getUrl() + "/database?secret=" + Helpers.getURLEncodedString(settings.getSecret())); + HttpsURLConnection httpsCon = (HttpsURLConnection)url.openConnection(); + httpsCon.setRequestMethod("DELETE"); + httpsCon.setDoInput(true); + InputStream stream = httpsCon.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + reader.close(); + } } \ No newline at end of file diff --git a/src/de/deadlocker8/budgetmaster/ui/Controller.java b/src/de/deadlocker8/budgetmaster/ui/Controller.java index a9f1c43505417c3255736480922a916ec70b642d..07109ba91f39bcb7e39e0de28d3c29f7d2d4b47b 100644 --- a/src/de/deadlocker8/budgetmaster/ui/Controller.java +++ b/src/de/deadlocker8/budgetmaster/ui/Controller.java @@ -1,7 +1,6 @@ package de.deadlocker8.budgetmaster.ui; import java.io.IOException; -import java.net.ConnectException; import java.util.ArrayList; import java.util.Locale; import java.util.ResourceBundle; diff --git a/src/de/deadlocker8/budgetmaster/ui/Modal.fxml b/src/de/deadlocker8/budgetmaster/ui/Modal.fxml new file mode 100644 index 0000000000000000000000000000000000000000..33759ff9bb89cf861f75e900f957f48ee27a25fd --- /dev/null +++ b/src/de/deadlocker8/budgetmaster/ui/Modal.fxml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.ProgressIndicator?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.text.Font?> + +<AnchorPane fx:id="anchorPaneMain" prefHeight="100.0" prefWidth="375.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.deadlocker8.budgetmaster.ui.ModalController"> + <children> + <HBox alignment="CENTER_LEFT" spacing="10.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0"> + <children> + <Label fx:id="labelMessage" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS"> + <font> + <Font size="15.0" /> + </font> + </Label> + <ProgressIndicator prefHeight="72.0" prefWidth="34.0" /> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/src/de/deadlocker8/budgetmaster/ui/ModalController.java b/src/de/deadlocker8/budgetmaster/ui/ModalController.java new file mode 100644 index 0000000000000000000000000000000000000000..042c7345a46f1f688df26dc19bf4eaf82a317c42 --- /dev/null +++ b/src/de/deadlocker8/budgetmaster/ui/ModalController.java @@ -0,0 +1,18 @@ +package de.deadlocker8.budgetmaster.ui; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.stage.Stage; + +public class ModalController +{ + @FXML private Label labelMessage; + + public void init(Stage stage, String message) + { + labelMessage.setText(message); + stage.setOnCloseRequest((e)->{ + e.consume(); + }); + } +} \ No newline at end of file diff --git a/src/de/deadlocker8/budgetmaster/ui/SettingsController.java b/src/de/deadlocker8/budgetmaster/ui/SettingsController.java index f913b66349ad5ca357b872d20b077efaeb665505..a90283827cf0fba0542b0c17e5f15011a6e9a018 100644 --- a/src/de/deadlocker8/budgetmaster/ui/SettingsController.java +++ b/src/de/deadlocker8/budgetmaster/ui/SettingsController.java @@ -2,20 +2,33 @@ package de.deadlocker8.budgetmaster.ui; import java.io.IOException; import java.util.ArrayList; +import java.util.Optional; +import de.deadlocker8.budgetmaster.logic.ServerConnection; import de.deadlocker8.budgetmaster.logic.Settings; import de.deadlocker8.budgetmaster.logic.Utils; +import javafx.application.Platform; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; +import javafx.scene.control.TextInputDialog; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.AnchorPane; +import javafx.stage.Modality; +import javafx.stage.Stage; import logger.Logger; import tools.AlertGenerator; +import tools.BASE58Type; +import tools.ConvertTo; +import tools.RandomCreations; +import tools.Worker; public class SettingsController { @@ -27,6 +40,8 @@ public class SettingsController @FXML private TextField textFieldCurrency; @FXML private Label labelCurrency; @FXML private Button buttonSave; + @FXML private Button buttonBackupDB; + @FXML private Button buttonDeleteDB; @FXML private RadioButton radioButtonRestActivated; @FXML private RadioButton radioButtonRestDeactivated; @FXML private TextArea textAreaTrustedHosts; @@ -51,21 +66,23 @@ public class SettingsController } setTextAreaTrustedHosts(controller.getSettings().getTrustedHosts()); } - + anchorPaneMain.setStyle("-fx-background-color: #F4F4F4;"); labelSecret.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text")); labelURL.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text")); labelCurrency.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text")); - buttonSave.setStyle("-fx-background-color: #2E79B9; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16;"); + buttonSave.setStyle("-fx-background-color: #2E79B9; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16;"); + buttonBackupDB.setStyle("-fx-background-color: #2E79B9; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16;"); + buttonDeleteDB.setStyle("-fx-background-color: #FF5047; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16;"); textFieldURL.setPromptText("z.B. https://yourdomain.de"); textFieldCurrency.setPromptText("z.B. €, CHF, $"); textAreaTrustedHosts.setPromptText("z.B. localhost"); - + ToggleGroup toggleGroup = new ToggleGroup(); radioButtonRestActivated.setToggleGroup(toggleGroup); radioButtonRestDeactivated.setToggleGroup(toggleGroup); } - + private void setTextAreaTrustedHosts(ArrayList<String> trustedHosts) { StringBuilder trustedHostsString = new StringBuilder(); @@ -83,7 +100,7 @@ public class SettingsController textAreaTrustedHosts.setText(""); } } - + public void save() { String url = textFieldURL.getText().trim(); @@ -107,11 +124,11 @@ public class SettingsController } } setTextAreaTrustedHosts(trustedHosts); - + if(controller.getSettings() != null) { controller.getSettings().setUrl(url); - controller.getSettings().setSecret(secret); + controller.getSettings().setSecret(secret); controller.getSettings().setCurrency(currency); controller.getSettings().setRestActivated(radioButtonRestActivated.isSelected()); controller.getSettings().setTrustedHosts(trustedHosts); @@ -126,7 +143,7 @@ public class SettingsController settings.setTrustedHosts(trustedHosts); controller.setSettings(settings); } - + try { Utils.saveSettings(controller.getSettings()); @@ -135,7 +152,7 @@ public class SettingsController { Logger.error(e); AlertGenerator.showAlert(AlertType.ERROR, "Fehler", "", "Beim Speichern der Einstellungen ist ein Fehler aufgetreten", controller.getIcon(), controller.getStage(), null, false); - } + } controller.refresh(controller.getFilterSettings()); controller.showNotification("Erfolgreich gespeichert"); } @@ -154,4 +171,83 @@ public class SettingsController AlertGenerator.showAlert(AlertType.WARNING, "Warnung", "", "Das Feld für die Server URL darf nicht leer sein!", controller.getIcon(), controller.getStage(), null, false); } } + + public void backupDB() + { + + } + + public void deleteDB() + { + String verificationCode = ConvertTo.toBase58(RandomCreations.generateRandomMixedCaseString(4, true), true, BASE58Type.UPPER); + + TextInputDialog dialog = new TextInputDialog(); + dialog.setTitle("Datenbank löschen"); + dialog.setHeaderText("Soll die Datenbank wirklich gelöscht werden?"); + dialog.setContentText("Zur Bestätigung gib folgenden Code ein:\t" + verificationCode); + Stage dialogStage = (Stage)dialog.getDialogPane().getScene().getWindow(); + dialogStage.getIcons().add(controller.getIcon()); + dialogStage.initOwner(controller.getStage()); + + Optional<String> result = dialog.showAndWait(); + if(result.isPresent()) + { + if(result.get().equals(verificationCode)) + { + Stage modalStage = showModal("Vorgang läuft", "Die Datenbank wird gelöscht, bitte warten..."); + + Worker.runLater(() -> { + try + { + ServerConnection connection = new ServerConnection(controller.getSettings()); + connection.deleteDatabase(); + Platform.runLater(() -> { + if(modalStage != null) + { + modalStage.close(); + } + }); + } + catch(Exception e) + { + Logger.error(e); + Platform.runLater(() -> { + controller.showConnectionErrorAlert(e.getMessage()); + }); + } + }); + } + else + { + AlertGenerator.showAlert(AlertType.WARNING, "Warnung", "", "Die Eingabe stimmt nicht mit dem Bestätigungscode überein.", controller.getIcon(), controller.getStage(), null, false); + deleteDB(); + } + } + } + + private Stage showModal(String title, String message) + { + try + { + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/de/deadlocker8/budgetmaster/ui/Modal.fxml")); + Parent root = (Parent)fxmlLoader.load(); + Stage newStage = new Stage(); + newStage.initOwner(controller.getStage()); + newStage.initModality(Modality.APPLICATION_MODAL); + newStage.setTitle(title); + newStage.setScene(new Scene(root)); + newStage.getIcons().add(controller.getIcon()); + newStage.setResizable(false); + ModalController newController = fxmlLoader.getController(); + newController.init(newStage, message); + newStage.show(); + + return newStage; + } + catch(IOException e) + { + Logger.error(e); + return null; + } + } } \ No newline at end of file diff --git a/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml b/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml index 67116a650dc64d4ef6733f7a176f09d6c3f1588c..7b620aeca8369bbb3f5776ea3d140e67fe0c997e 100644 --- a/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml +++ b/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml @@ -16,7 +16,7 @@ <children> <VBox alignment="TOP_CENTER" layoutY="24.0" prefHeight="562.0" prefWidth="772.0" spacing="25.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="25.0"> <children> - <HBox prefHeight="334.0" prefWidth="722.0"> + <HBox prefHeight="359.0" prefWidth="722.0"> <children> <VBox alignment="CENTER_RIGHT" prefHeight="25.0" prefWidth="158.0" spacing="20.0"> <children> @@ -47,8 +47,11 @@ <font> <Font name="System Bold" size="16.0" /> </font> + <VBox.margin> + <Insets top="-5.0" /> + </VBox.margin> </Label> - <Label fx:id="labelSecret1111" alignment="CENTER" contentDisplay="CENTER" maxHeight="-Infinity" text="(ein Host pro Zeile)" textAlignment="CENTER" wrapText="true"> + <Label fx:id="labelSecret1111" alignment="CENTER" contentDisplay="CENTER" maxHeight="-Infinity" text="(ein Host pro Zeile)" textAlignment="CENTER" wrapText="true" VBox.vgrow="ALWAYS"> <font> <Font size="14.0" /> </font> @@ -56,7 +59,15 @@ <Insets top="-20.0" /> </VBox.margin> </Label> - <Region prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" /> + <Label fx:id="labelSecret1112" alignment="CENTER_RIGHT" contentDisplay="RIGHT" maxHeight="-Infinity" prefWidth="158.0" text="Datenbank:" textAlignment="RIGHT" wrapText="true"> + <font> + <Font name="System Bold" size="16.0" /> + </font> + <VBox.margin> + <Insets top="35.0" /> + </VBox.margin> + </Label> + <Region prefHeight="19.0" prefWidth="158.0" VBox.vgrow="ALWAYS" /> </children> <HBox.margin> <Insets right="25.0" /> @@ -67,14 +78,14 @@ <TextField fx:id="textFieldURL" /> <TextField fx:id="textFieldSecret" /> <TextField fx:id="textFieldCurrency" /> - <HBox alignment="CENTER" prefHeight="11.0" prefWidth="539.0"> + <HBox alignment="CENTER" prefHeight="11.0" prefWidth="539.0" spacing="30.0"> <children> <RadioButton fx:id="radioButtonRestActivated" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="aktiviert"> <font> <Font size="14.0" /> </font> <HBox.margin> - <Insets right="30.0" /> + <Insets /> </HBox.margin> </RadioButton> <RadioButton fx:id="radioButtonRestDeactivated" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="deaktiviert" HBox.hgrow="ALWAYS"> @@ -84,7 +95,25 @@ </RadioButton> </children> </HBox> - <TextArea fx:id="textAreaTrustedHosts" prefHeight="136.0" prefWidth="539.0" VBox.vgrow="ALWAYS" /> + <TextArea fx:id="textAreaTrustedHosts" prefWidth="539.0" VBox.vgrow="ALWAYS"> + <VBox.margin> + <Insets /> + </VBox.margin></TextArea> + <HBox alignment="CENTER_LEFT" prefHeight="11.0" prefWidth="539.0" spacing="30.0"> + <children> + <Button fx:id="buttonBackupDB" mnemonicParsing="false" onAction="#backupDB" text="Backup"> + <font> + <Font name="System Bold" size="14.0" /> + </font> + </Button> + <Button fx:id="buttonDeleteDB" mnemonicParsing="false" onAction="#deleteDB" text="Löschen"> + <font> + <Font name="System Bold" size="14.0" /> + </font> + </Button> + </children> + </HBox> + <Region prefHeight="19.0" prefWidth="158.0" VBox.vgrow="ALWAYS" /> </children> </VBox> </children> diff --git a/src/de/deadlocker8/budgetmasterserver/main/DatabaseHandler.java b/src/de/deadlocker8/budgetmasterserver/main/DatabaseHandler.java index 43097810d2388eba3369dcce329922ed1a7623e2..bda5b7ff175dac16a7559927aa7b25c923e5a4c2 100644 --- a/src/de/deadlocker8/budgetmasterserver/main/DatabaseHandler.java +++ b/src/de/deadlocker8/budgetmasterserver/main/DatabaseHandler.java @@ -624,6 +624,46 @@ public class DatabaseHandler } } } + + public void deleteDatabase() + { + Statement stmt = null; + String tableCategory = "DROP TABLE IF EXISTS category;"; + String tablePayment = "DROP TABLE IF EXISTS payment;"; + String tableRepeatingPayment = "DROP TABLE IF EXISTS repeating_payment;"; + String tableRepeatingEntry= "DROP TABLE IF EXISTS repeating_entry;"; + try + { + stmt = connection.createStatement(); + stmt.execute("SET FOREIGN_KEY_CHECKS = 0;"); + stmt.execute(tableCategory); + Logger.info("Deleted table: category"); + stmt.execute(tablePayment); + Logger.info("Deleted table: payment"); + stmt.execute(tableRepeatingPayment); + Logger.info("Deleted table: repeating_payment"); + stmt.execute(tableRepeatingEntry); + Logger.info("Deleted table: repeating_entry"); + stmt.execute("SET FOREIGN_KEY_CHECKS = 1;"); + } + catch(SQLException e) + { + Logger.error(e); + } + finally + { + if(stmt != null) + { + try + { + stmt.close(); + } + catch(SQLException e) + { + } + } + } + } /* * ADD diff --git a/src/de/deadlocker8/budgetmasterserver/server/SparkServer.java b/src/de/deadlocker8/budgetmasterserver/server/SparkServer.java index 760e6fb7424d0554da7e51d061f5606d4114d328..62aea0bf86195a23219742d1af73105f4d776270 100644 --- a/src/de/deadlocker8/budgetmasterserver/server/SparkServer.java +++ b/src/de/deadlocker8/budgetmasterserver/server/SparkServer.java @@ -25,6 +25,7 @@ import de.deadlocker8.budgetmasterserver.server.category.CategoryGet; import de.deadlocker8.budgetmasterserver.server.category.CategoryGetAll; import de.deadlocker8.budgetmasterserver.server.category.CategoryUpdate; import de.deadlocker8.budgetmasterserver.server.categorybudget.CategoryBudgetGet; +import de.deadlocker8.budgetmasterserver.server.database.DatabaseDelete; import de.deadlocker8.budgetmasterserver.server.payment.normal.PaymentAdd; import de.deadlocker8.budgetmasterserver.server.payment.normal.PaymentDelete; import de.deadlocker8.budgetmasterserver.server.payment.normal.PaymentGet; @@ -110,6 +111,9 @@ public class SparkServer // Rest get("/rest", new RestGet(handler, gson)); + + // Database + delete("/database", new DatabaseDelete(handler, settings)); after((request, response) -> { new RepeatingPaymentUpdater(handler).updateRepeatingPayments(DateTime.now()); diff --git a/src/de/deadlocker8/budgetmasterserver/server/database/DatabaseDelete.java b/src/de/deadlocker8/budgetmasterserver/server/database/DatabaseDelete.java new file mode 100644 index 0000000000000000000000000000000000000000..24e50ef9c9519e874381dba116134ff4f9c6d820 --- /dev/null +++ b/src/de/deadlocker8/budgetmasterserver/server/database/DatabaseDelete.java @@ -0,0 +1,39 @@ +package de.deadlocker8.budgetmasterserver.server.database; + +import static spark.Spark.halt; + +import de.deadlocker8.budgetmasterserver.main.DatabaseHandler; +import de.deadlocker8.budgetmasterserver.main.Settings; +import spark.Request; +import spark.Response; +import spark.Route; + +public class DatabaseDelete implements Route +{ + private DatabaseHandler handler; + private Settings settings; + + public DatabaseDelete(DatabaseHandler handler, Settings settings) + { + this.handler = handler; + this.settings = settings; + } + + @Override + public Object handle(Request req, Response res) throws Exception + { + try + { + handler.deleteDatabase(); + handler = new DatabaseHandler(settings); + + return ""; + } + catch(IllegalStateException ex) + { + halt(500, "Internal Server Error"); + } + + return "EIMER"; + } +} \ No newline at end of file