diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 547c9a0..da368ba 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -283,6 +283,15 @@ public final class LocalDB implements EventListener { * @since Envoy Client v0.3-beta */ public void delete() { + try { + + // Save ID generator - can be used for other users in that db + if (hasIDGenerator()) + SerializationUtils.write(idGeneratorFile, idGenerator); + } catch (final IOException e) { + EnvoyLog.getLogger(LocalDB.class).log(Level.SEVERE, "Unable to save local database: ", + e); + } if (lastLoginFile != null) lastLoginFile.delete(); userFile.delete(); @@ -427,10 +436,7 @@ public final class LocalDB implements EventListener { if (user.getID() == deletion.get()) logger.log(Level.WARNING, "I have been informed by the server that I have been deleted without even knowing it..."); - getChat(deletion.get()).ifPresent(chat -> { - chat.setDisabled(true); - chat.setUnderlyingContactDeleted(true); - }); + getChat(deletion.get()).ifPresent(chat -> chat.setDisabled(true)); } /** diff --git a/common/src/main/java/envoy/event/contact/AccountDeletion.java b/client/src/main/java/envoy/client/event/AccountDeletion.java similarity index 93% rename from common/src/main/java/envoy/event/contact/AccountDeletion.java rename to client/src/main/java/envoy/client/event/AccountDeletion.java index dabc0be..ef73462 100644 --- a/common/src/main/java/envoy/event/contact/AccountDeletion.java +++ b/client/src/main/java/envoy/client/event/AccountDeletion.java @@ -1,4 +1,4 @@ -package envoy.event.contact; +package envoy.client.event; import envoy.event.Event; diff --git a/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java b/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java index af5c054..f1f1b58 100644 --- a/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java +++ b/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java @@ -18,7 +18,7 @@ import envoy.event.contact.*; import envoy.util.Bounds; import envoy.client.data.*; -import envoy.client.event.BackEvent; +import envoy.client.event.*; import envoy.client.ui.control.*; import envoy.client.ui.listcell.ListCellFactory; diff --git a/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java index aa194c5..3a35061 100644 --- a/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java @@ -13,6 +13,7 @@ import javafx.scene.image.*; import javafx.scene.input.InputEvent; import javafx.scene.layout.HBox; import javafx.stage.FileChooser; +import javafx.util.Duration; import dev.kske.eventbus.EventBus; @@ -38,7 +39,7 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane { private final PasswordField newPasswordField = new PasswordField(); private final PasswordField repeatNewPasswordField = new PasswordField(); private final Button saveButton = new Button("Save"); - private final Button deleteAccountButton = new Button("Delete Account"); + private final Button deleteAccountButton = new Button("Delete Account (Locally)"); private static final EventBus eventBus = EventBus.getInstance(); private static final Logger logger = EnvoyLog.getLogger(UserSettingsPane.class); @@ -148,6 +149,13 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane { // Displaying the delete account button deleteAccountButton.setAlignment(Pos.BASELINE_CENTER); deleteAccountButton.setOnAction(e -> UserUtil.deleteAccount()); + deleteAccountButton.setText("Delete Account (locally)"); + deleteAccountButton.setPrefHeight(25); + deleteAccountButton.getStyleClass().clear(); + deleteAccountButton.getStyleClass().add("danger-button"); + final var tooltip = new Tooltip("Remote deletion is currently unsupported."); + tooltip.setShowDelay(Duration.millis(100)); + deleteAccountButton.setTooltip(tooltip); getChildren().add(deleteAccountButton); } diff --git a/client/src/main/java/envoy/client/util/UserUtil.java b/client/src/main/java/envoy/client/util/UserUtil.java index aba9557..bc7d7fe 100644 --- a/client/src/main/java/envoy/client/util/UserUtil.java +++ b/client/src/main/java/envoy/client/util/UserUtil.java @@ -10,7 +10,7 @@ import dev.kske.eventbus.EventBus; import envoy.data.*; import envoy.data.User.UserStatus; import envoy.event.*; -import envoy.event.contact.*; +import envoy.event.contact.UserOperation; import envoy.util.EnvoyLog; import envoy.client.data.Context; @@ -129,32 +129,27 @@ public final class UserUtil { * @since Envoy Client v0.3-beta */ public static void deleteAccount() { - if (!context.getClient().isOnline()) - return; - else { - // Show the first wall of defense, if not disabled by the user - final var outerAlert = new Alert(AlertType.CONFIRMATION); - outerAlert.setContentText( - "Are you sure you want to delete your account entirely? This action can seriously not be undone."); - outerAlert.setTitle("Delete Account?"); - AlertHelper.confirmAction(outerAlert, () -> { + // Show the first wall of defense, if not disabled by the user + final var outerAlert = new Alert(AlertType.CONFIRMATION); + outerAlert.setContentText( + "Are you sure you want to delete your account entirely? This action can seriously not be undone."); + outerAlert.setTitle("Delete Account?"); + AlertHelper.confirmAction(outerAlert, () -> { - // Show the final wall of defense in every case - final var lastAlert = new Alert(AlertType.WARNING, - "Do you REALLY want to delete your account? Last Warning. Proceed?", - ButtonType.CANCEL, ButtonType.OK); - lastAlert.setTitle("Delete Account?"); - lastAlert.showAndWait().filter(ButtonType.OK::equals).ifPresent(b2 -> { + // Show the final wall of defense in every case + final var lastAlert = new Alert(AlertType.WARNING, + "Do you REALLY want to delete your account? Last Warning. Proceed?", + ButtonType.CANCEL, ButtonType.OK); + lastAlert.setTitle("Delete Account?"); + lastAlert.showAndWait().filter(ButtonType.OK::equals).ifPresent(b2 -> { - // Delete the account - context.getClient() - .send(new AccountDeletion(context.getLocalDB().getUser().getID())); - context.getLocalDB().delete(); - logger.log(Level.INFO, "The user just deleted his account. Goodbye."); - ShutdownHelper.exit(true); - }); + // Delete the account + // TODO: Notify server of account deletion + context.getLocalDB().delete(); + logger.log(Level.INFO, "The user just deleted his account. Goodbye."); + ShutdownHelper.exit(true); }); - } + }); } } diff --git a/client/src/main/resources/css/base.css b/client/src/main/resources/css/base.css index 4c46161..fdfc1b2 100644 --- a/client/src/main/resources/css/base.css +++ b/client/src/main/resources/css/base.css @@ -70,6 +70,17 @@ -fx-text-fill: gray; } +.danger-button { + -fx-background-color: red; + -fx-text-fill: white; + -fx-background-radius: 0.2em; +} + +.danger-button:hover { + -fx-scale-x: 1.05; + -fx-scale-y: 1.05; +} + .received-message { -fx-alignment: center-left; -fx-background-radius: 1.3em; diff --git a/client/src/main/resources/css/light.css b/client/src/main/resources/css/light.css index 7cd3ac1..81ac69b 100644 --- a/client/src/main/resources/css/light.css +++ b/client/src/main/resources/css/light.css @@ -30,6 +30,10 @@ -fx-background-color: black; } +.tooltip { + -fx-text-fill: black; +} + #login-input-field { -fx-border-color: black; } diff --git a/server/src/main/java/envoy/server/Startup.java b/server/src/main/java/envoy/server/Startup.java index 413aa04..e34cf91 100755 --- a/server/src/main/java/envoy/server/Startup.java +++ b/server/src/main/java/envoy/server/Startup.java @@ -59,8 +59,7 @@ public final class Startup { new NameChangeProcessor(), new ProfilePicChangeProcessor(), new PasswordChangeRequestProcessor(), - new IssueProposalProcessor(), - new AccountDeletionProcessor()))); + new IssueProposalProcessor()))); // Initialize the current message ID final var persistenceManager = PersistenceManager.getInstance(); diff --git a/server/src/main/java/envoy/server/data/Message.java b/server/src/main/java/envoy/server/data/Message.java index 72849b0..036c47a 100755 --- a/server/src/main/java/envoy/server/data/Message.java +++ b/server/src/main/java/envoy/server/data/Message.java @@ -27,18 +27,14 @@ import envoy.data.Message.MessageStatus; @Entity @Table(name = "messages") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@NamedQueries({ - @NamedQuery(name = Message.getPending, query = "SELECT m FROM Message m WHERE " - // Send to or by the user before last seen - + "(m.sender = :user OR m.recipient = :user) AND m.creationDate > :lastSeen " - // SENT to the user - + "OR m.recipient = :user AND m.status = envoy.data.Message$MessageStatus.SENT " - // Sent by the user and RECEIVED / READ after last seen - + "OR m.sender = :user AND (m.status = envoy.data.Message$MessageStatus.RECEIVED AND m.receivedDate > :lastSeen " - + "OR m.status = envoy.data.Message$MessageStatus.READ AND m.readDate > :lastSeen)"), - @NamedQuery(name = Message.deleteByRecipient, query = "DELETE FROM Message m WHERE m.recipient = :deleted OR m.sender = :deleted") - -}) +@NamedQuery(name = Message.getPending, query = "SELECT m FROM Message m WHERE " + // Send to or by the user before last seen + + "(m.sender = :user OR m.recipient = :user) AND m.creationDate > :lastSeen " + // SENT to the user + + "OR m.recipient = :user AND m.status = envoy.data.Message$MessageStatus.SENT " + // Sent by the user and RECEIVED / READ after last seen + + "OR m.sender = :user AND (m.status = envoy.data.Message$MessageStatus.RECEIVED AND m.receivedDate > :lastSeen " + + "OR m.status = envoy.data.Message$MessageStatus.READ AND m.readDate > :lastSeen)") public class Message { /** @@ -49,13 +45,6 @@ public class Message { */ public static final String getPending = "Message.getPending"; - /** - * Named query deleting all messages of a user (parameter {@code :deleted}). - * - * @since Envoy Server v0.3-beta - */ - public static final String deleteByRecipient = "Message.deleteByRecipient"; - @Id protected long id; diff --git a/server/src/main/java/envoy/server/data/PersistenceManager.java b/server/src/main/java/envoy/server/data/PersistenceManager.java index ce61d17..23f19d9 100755 --- a/server/src/main/java/envoy/server/data/PersistenceManager.java +++ b/server/src/main/java/envoy/server/data/PersistenceManager.java @@ -121,12 +121,9 @@ public final class PersistenceManager { transaction(() -> { // Remove this contact from the contact list of his contacts - for (final var remainingContact : contact.getContacts()) + for (final var remainingContact : contact.contacts) remainingContact.getContacts().remove(contact); - - entityManager - .createNamedQuery(Message.deleteByRecipient).setParameter("deleted", contact) - .executeUpdate(); + contact.contacts.clear(); }); remove(contact); } diff --git a/server/src/main/java/envoy/server/processors/AccountDeletionProcessor.java b/server/src/main/java/envoy/server/processors/AccountDeletionProcessor.java deleted file mode 100644 index 5282fb8..0000000 --- a/server/src/main/java/envoy/server/processors/AccountDeletionProcessor.java +++ /dev/null @@ -1,33 +0,0 @@ -package envoy.server.processors; - -import java.io.IOException; -import java.time.Instant; - -import envoy.event.contact.AccountDeletion; - -import envoy.server.data.*; -import envoy.server.net.ObjectWriteProxy; - -/** - * @author Leon Hofmeister - * @since Envoy Server v0.3-beta - */ -public class AccountDeletionProcessor implements ObjectProcessor { - - private static final PersistenceManager persistenceManager = PersistenceManager.getInstance(); - - @Override - public void process(AccountDeletion input, long socketID, ObjectWriteProxy writeProxy) - throws IOException { - final var contact = persistenceManager.getContactByID(input.get()); - - contact.getContacts().forEach(c -> { - persistenceManager.removeContactBidirectional(contact, c); - if (c instanceof User) - ((User) c).setLatestContactDeletion(Instant.now()); - }); - - writeProxy.writeToOnlineContacts(contact.getContacts(), input); - persistenceManager.deleteContact(contact); - } -} diff --git a/server/src/main/java/envoy/server/processors/GroupMessageStatusChangeProcessor.java b/server/src/main/java/envoy/server/processors/GroupMessageStatusChangeProcessor.java index fffe41b..b9482f1 100644 --- a/server/src/main/java/envoy/server/processors/GroupMessageStatusChangeProcessor.java +++ b/server/src/main/java/envoy/server/processors/GroupMessageStatusChangeProcessor.java @@ -38,6 +38,8 @@ public final class GroupMessageStatusChangeProcessor } GroupMessage gmsg = (GroupMessage) persistenceManager.getMessageByID(statusChange.getID()); + if (gmsg == null) + return; // Any other status than READ is not supposed to be sent to the server if (statusChange.get() != MessageStatus.READ) { diff --git a/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java b/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java index 9efaf60..92b3f84 100644 --- a/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java +++ b/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java @@ -4,7 +4,6 @@ import java.time.Instant; import java.util.logging.Level; import envoy.event.GroupResize; -import envoy.event.contact.AccountDeletion; import envoy.util.EnvoyLog; import envoy.server.data.*; @@ -25,11 +24,9 @@ public final class GroupResizeProcessor implements ObjectProcessor final var group = persistenceManager.getGroupByID(groupResize.getGroupID()); final var sender = persistenceManager.getUserByID(groupResize.get().getID()); - // Inform the sender that this group has already been deleted - if (group == null) { - writeProxy.write(socketID, new AccountDeletion(groupResize.getGroupID())); + // TODO: Inform the sender that this group has already been deleted + if (group == null) return; - } // Perform the desired operation switch (groupResize.getOperation()) { diff --git a/server/src/main/java/envoy/server/processors/MessageStatusChangeProcessor.java b/server/src/main/java/envoy/server/processors/MessageStatusChangeProcessor.java index d954af5..efc407b 100755 --- a/server/src/main/java/envoy/server/processors/MessageStatusChangeProcessor.java +++ b/server/src/main/java/envoy/server/processors/MessageStatusChangeProcessor.java @@ -32,6 +32,8 @@ public final class MessageStatusChangeProcessor implements ObjectProcessor