Add Local Account Deletion #108
@@ -22,20 +22,21 @@ import envoy.client.net.WriteProxy;
 | 
			
		||||
 */
 | 
			
		||||
public class Chat implements Serializable {
 | 
			
		||||
 | 
			
		||||
	protected boolean disabled;
 | 
			
		||||
	protected transient ObservableList<Message> messages = FXCollections.observableArrayList();
 | 
			
		||||
 | 
			
		||||
	protected final Contact recipient;
 | 
			
		||||
 | 
			
		||||
	protected boolean	disabled;
 | 
			
		||||
	protected boolean	underlyingContactDeleted;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Stores the last time an {@link envoy.event.IsTyping} event has been sent.
 | 
			
		||||
	 */
 | 
			
		||||
	protected transient long lastWritingEvent;
 | 
			
		||||
 | 
			
		||||
	protected transient ObservableList<Message> messages = FXCollections.observableArrayList();
 | 
			
		||||
 | 
			
		||||
	protected int						unreadAmount;
 | 
			
		||||
	protected static IntegerProperty	totalUnreadAmount	= new SimpleIntegerProperty();
 | 
			
		||||
 | 
			
		||||
	protected final Contact recipient;
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 2L;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 
 | 
			
		||||
@@ -248,6 +248,10 @@ public final class LocalDB implements EventListener {
 | 
			
		||||
	 */
 | 
			
		||||
	@Event(eventType = EnvoyCloseEvent.class, priority = 500)
 | 
			
		||||
	private synchronized void save() {
 | 
			
		||||
 | 
			
		||||
		// Stop saving if this account has been deleted
 | 
			
		||||
		if (userFile == null)
 | 
			
		||||
			return;
 | 
			
		||||
		EnvoyLog.getLogger(LocalDB.class).log(Level.FINER, "Saving local database...");
 | 
			
		||||
 | 
			
		||||
		// Save users
 | 
			
		||||
@@ -273,6 +277,20 @@ public final class LocalDB implements EventListener {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Deletes any local remnant of this user.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @since Envoy Client v0.3-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void delete() {
 | 
			
		||||
		if (lastLoginFile != null)
 | 
			
		||||
			lastLoginFile.delete();
 | 
			
		||||
		userFile.delete();
 | 
			
		||||
		users.remove(user.getName());
 | 
			
		||||
		userFile = null;
 | 
			
		||||
		onLogout();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Event(priority = 500)
 | 
			
		||||
	private void onMessage(Message msg) {
 | 
			
		||||
		if (msg.getStatus() == MessageStatus.SENT)
 | 
			
		||||
@@ -404,6 +422,17 @@ public final class LocalDB implements EventListener {
 | 
			
		||||
		getChat(event.get().getID()).ifPresent(chat -> chat.setDisabled(true));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Event(priority = 500)
 | 
			
		||||
	private void onAccountDeletion(AccountDeletion deletion) {
 | 
			
		||||
		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);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return a {@code Map<String, User>} of all users stored locally with their user names as keys
 | 
			
		||||
	 * @since Envoy Client v0.2-alpha
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import java.io.*;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.format.DateTimeFormatter;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.logging.*;
 | 
			
		||||
 | 
			
		||||
import javafx.animation.RotateTransition;
 | 
			
		||||
@@ -25,9 +25,8 @@ import javafx.scene.shape.Rectangle;
 | 
			
		||||
import javafx.stage.FileChooser;
 | 
			
		||||
import javafx.util.Duration;
 | 
			
		||||
 | 
			
		||||
import dev.kske.eventbus.*;
 | 
			
		||||
import dev.kske.eventbus.Event;
 | 
			
		||||
import dev.kske.eventbus.EventBus;
 | 
			
		||||
import dev.kske.eventbus.EventListener;
 | 
			
		||||
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
import envoy.data.Attachment.AttachmentType;
 | 
			
		||||
@@ -882,24 +881,22 @@ public final class ChatScene implements EventListener, Restorable, KeyboardMappi
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Map<KeyCombination, Runnable> getKeyboardShortcuts() {
 | 
			
		||||
		final var map = new HashMap<KeyCombination, Runnable>();
 | 
			
		||||
		return Map.<KeyCombination, Runnable>of(
 | 
			
		||||
 | 
			
		||||
		// Delete text before the caret with "Control" + U
 | 
			
		||||
		map.put(new KeyCodeCombination(KeyCode.U, KeyCombination.CONTROL_DOWN), () -> {
 | 
			
		||||
			messageTextArea
 | 
			
		||||
				.setText(messageTextArea.getText().substring(messageTextArea.getCaretPosition()));
 | 
			
		||||
			checkPostConditions(false);
 | 
			
		||||
		});
 | 
			
		||||
			// Delete text before the caret with "Control" + U
 | 
			
		||||
			new KeyCodeCombination(KeyCode.U, KeyCombination.CONTROL_DOWN), () -> {
 | 
			
		||||
				messageTextArea
 | 
			
		||||
					.setText(
 | 
			
		||||
						messageTextArea.getText().substring(messageTextArea.getCaretPosition()));
 | 
			
		||||
				checkPostConditions(false);
 | 
			
		||||
 | 
			
		||||
		// Delete text after the caret with "Control" + K
 | 
			
		||||
		map.put(new KeyCodeCombination(KeyCode.K, KeyCombination.CONTROL_DOWN), () -> {
 | 
			
		||||
			messageTextArea
 | 
			
		||||
				.setText(
 | 
			
		||||
					messageTextArea.getText().substring(0, messageTextArea.getCaretPosition()));
 | 
			
		||||
			checkPostConditions(false);
 | 
			
		||||
			messageTextArea.positionCaret(messageTextArea.getText().length());
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		return map;
 | 
			
		||||
				// Delete text after the caret with "Control" + K
 | 
			
		||||
			}, new KeyCodeCombination(KeyCode.K, KeyCombination.CONTROL_DOWN), () -> {
 | 
			
		||||
				messageTextArea
 | 
			
		||||
					.setText(
 | 
			
		||||
						messageTextArea.getText().substring(0, messageTextArea.getCaretPosition()));
 | 
			
		||||
				checkPostConditions(false);
 | 
			
		||||
				messageTextArea.positionCaret(messageTextArea.getText().length());
 | 
			
		||||
			});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import dev.kske.eventbus.*;
 | 
			
		||||
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
import envoy.event.GroupCreation;
 | 
			
		||||
import envoy.event.contact.UserOperation;
 | 
			
		||||
import envoy.event.contact.*;
 | 
			
		||||
import envoy.util.Bounds;
 | 
			
		||||
 | 
			
		||||
import envoy.client.data.*;
 | 
			
		||||
@@ -252,4 +252,10 @@ public class GroupCreationTab implements EventListener {
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Event
 | 
			
		||||
	private void onAccountDeletion(AccountDeletion deletion) {
 | 
			
		||||
		final var deletedID = deletion.get();
 | 
			
		||||
		Platform.runLater(() -> userList.getItems().removeIf(user -> (user.getID() == deletedID)));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ import envoy.event.*;
 | 
			
		||||
import envoy.util.*;
 | 
			
		||||
 | 
			
		||||
import envoy.client.ui.control.ProfilePicImageView;
 | 
			
		||||
import envoy.client.util.IconUtil;
 | 
			
		||||
import envoy.client.util.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Leon Hofmeister
 | 
			
		||||
@@ -38,6 +38,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 static final EventBus	eventBus	= EventBus.getInstance();
 | 
			
		||||
	private static final Logger		logger		= EnvoyLog.getLogger(UserSettingsPane.class);
 | 
			
		||||
@@ -112,16 +113,19 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane {
 | 
			
		||||
 | 
			
		||||
		final PasswordField[]					passwordFields	=
 | 
			
		||||
			{ currentPasswordField, newPasswordField, repeatNewPasswordField };
 | 
			
		||||
		final EventHandler<? super InputEvent>	passwordEntered	= e -> {
 | 
			
		||||
																	newPassword		=
 | 
			
		||||
																		newPasswordField.getText();
 | 
			
		||||
																	validPassword	= newPassword
 | 
			
		||||
																		.equals(
 | 
			
		||||
																			repeatNewPasswordField
 | 
			
		||||
																				.getText())
 | 
			
		||||
																		&& !newPasswordField
 | 
			
		||||
																			.getText().isBlank();
 | 
			
		||||
																};
 | 
			
		||||
		final EventHandler<? super InputEvent>	passwordEntered	=
 | 
			
		||||
			e -> {
 | 
			
		||||
																		newPassword	=
 | 
			
		||||
																			newPasswordField
 | 
			
		||||
																				.getText();
 | 
			
		||||
																		validPassword =
 | 
			
		||||
																			newPassword.equals(
 | 
			
		||||
																				repeatNewPasswordField
 | 
			
		||||
																					.getText())
 | 
			
		||||
																				&& !newPasswordField
 | 
			
		||||
																					.getText()
 | 
			
		||||
																					.isBlank();
 | 
			
		||||
																	};
 | 
			
		||||
		newPasswordField.setOnInputMethodTextChanged(passwordEntered);
 | 
			
		||||
		newPasswordField.setOnKeyTyped(passwordEntered);
 | 
			
		||||
		repeatNewPasswordField.setOnInputMethodTextChanged(passwordEntered);
 | 
			
		||||
@@ -140,6 +144,11 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane {
 | 
			
		||||
			.setOnAction(e -> save(currentPasswordField.getText()));
 | 
			
		||||
		saveButton.setAlignment(Pos.BOTTOM_RIGHT);
 | 
			
		||||
		getChildren().add(saveButton);
 | 
			
		||||
 | 
			
		||||
		// Displaying the delete account button
 | 
			
		||||
		deleteAccountButton.setAlignment(Pos.BASELINE_CENTER);
 | 
			
		||||
		deleteAccountButton.setOnAction(e -> UserUtil.deleteAccount());
 | 
			
		||||
		getChildren().add(deleteAccountButton);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package envoy.client.util;
 | 
			
		||||
 | 
			
		||||
import java.util.logging.*;
 | 
			
		||||
 | 
			
		||||
import javafx.scene.control.Alert;
 | 
			
		||||
import javafx.scene.control.*;
 | 
			
		||||
import javafx.scene.control.Alert.AlertType;
 | 
			
		||||
 | 
			
		||||
import dev.kske.eventbus.EventBus;
 | 
			
		||||
@@ -10,7 +10,7 @@ import dev.kske.eventbus.EventBus;
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
import envoy.data.User.UserStatus;
 | 
			
		||||
import envoy.event.*;
 | 
			
		||||
import envoy.event.contact.UserOperation;
 | 
			
		||||
import envoy.event.contact.*;
 | 
			
		||||
import envoy.util.EnvoyLog;
 | 
			
		||||
 | 
			
		||||
import envoy.client.data.Context;
 | 
			
		||||
@@ -121,4 +121,40 @@ public final class UserUtil {
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Deletes anything pointing to this user, independent of client or server. Will do nothing if
 | 
			
		||||
	 * the client is currently offline.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @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 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);
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
package envoy.event.contact;
 | 
			
		||||
 | 
			
		||||
import envoy.event.Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Signifies the deletion of an account.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Leon Hofmeister
 | 
			
		||||
 * @since Envoy Common v0.3-beta
 | 
			
		||||
 */
 | 
			
		||||
public class AccountDeletion extends Event<Long> {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param value the ID of the contact that was deleted
 | 
			
		||||
	 * @since Envoy Common v0.3-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public AccountDeletion(Long value) {
 | 
			
		||||
		super(value);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -59,7 +59,8 @@ public final class Startup {
 | 
			
		||||
				new NameChangeProcessor(),
 | 
			
		||||
				new ProfilePicChangeProcessor(),
 | 
			
		||||
				new PasswordChangeRequestProcessor(),
 | 
			
		||||
				new IssueProposalProcessor())));
 | 
			
		||||
				new IssueProposalProcessor(),
 | 
			
		||||
				new AccountDeletionProcessor())));
 | 
			
		||||
 | 
			
		||||
		// Initialize the current message ID
 | 
			
		||||
		final var persistenceManager = PersistenceManager.getInstance();
 | 
			
		||||
 
 | 
			
		||||
@@ -27,14 +27,18 @@ import envoy.data.Message.MessageStatus;
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = "messages")
 | 
			
		||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
 | 
			
		||||
@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)")
 | 
			
		||||
@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")
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
public class Message {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -45,6 +49,13 @@ 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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -123,6 +123,10 @@ public final class PersistenceManager {
 | 
			
		||||
			// Remove this contact from the contact list of his contacts
 | 
			
		||||
			for (final var remainingContact : contact.getContacts())
 | 
			
		||||
				remainingContact.getContacts().remove(contact);
 | 
			
		||||
 | 
			
		||||
			entityManager
 | 
			
		||||
				.createNamedQuery(Message.deleteByRecipient).setParameter("deleted", contact)
 | 
			
		||||
				.executeUpdate();
 | 
			
		||||
		});
 | 
			
		||||
		remove(contact);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,8 +49,10 @@ public final class ConnectionManager implements ISocketIdListener {
 | 
			
		||||
			// Notify contacts of this users offline-going
 | 
			
		||||
			final envoy.server.data.User user =
 | 
			
		||||
				PersistenceManager.getInstance().getUserByID(getUserIDBySocketID(socketID));
 | 
			
		||||
			user.setLastSeen(Instant.now());
 | 
			
		||||
			UserStatusChangeProcessor.updateUserStatus(user, UserStatus.OFFLINE);
 | 
			
		||||
			if (user != null) {
 | 
			
		||||
				user.setLastSeen(Instant.now());
 | 
			
		||||
				UserStatusChangeProcessor.updateUserStatus(user, UserStatus.OFFLINE);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Remove the socket
 | 
			
		||||
			sockets.entrySet().removeIf(e -> e.getValue() == socketID);
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
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<AccountDeletion> {
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -4,6 +4,7 @@ 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.*;
 | 
			
		||||
@@ -24,6 +25,12 @@ public final class GroupResizeProcessor implements ObjectProcessor<GroupResize>
 | 
			
		||||
		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()));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Perform the desired operation
 | 
			
		||||
		switch (groupResize.getOperation()) {
 | 
			
		||||
			case ADD:
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import java.time.Instant;
 | 
			
		||||
import java.util.logging.*;
 | 
			
		||||
 | 
			
		||||
import envoy.event.ElementOperation;
 | 
			
		||||
import envoy.event.contact.UserOperation;
 | 
			
		||||
import envoy.event.contact.*;
 | 
			
		||||
import envoy.util.EnvoyLog;
 | 
			
		||||
 | 
			
		||||
import envoy.server.data.PersistenceManager;
 | 
			
		||||
@@ -22,10 +22,18 @@ public final class UserOperationProcessor implements ObjectProcessor<UserOperati
 | 
			
		||||
	private static final PersistenceManager	persistenceManager	= PersistenceManager.getInstance();
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void process(UserOperation evt, long socketId, ObjectWriteProxy writeProxy) {
 | 
			
		||||
		final long	userID		= ConnectionManager.getInstance().getUserIDBySocketID(socketId);
 | 
			
		||||
	public void process(UserOperation evt, long socketID, ObjectWriteProxy writeProxy) {
 | 
			
		||||
		final long	userID		= ConnectionManager.getInstance().getUserIDBySocketID(socketID);
 | 
			
		||||
		final long	contactID	= evt.get().getID();
 | 
			
		||||
		final var	sender		= persistenceManager.getUserByID(userID);
 | 
			
		||||
		final var	recipient	= persistenceManager.getUserByID(contactID);
 | 
			
		||||
 | 
			
		||||
		// Inform the sender if the requested contact has already been deleted
 | 
			
		||||
		if (recipient == null) {
 | 
			
		||||
			writeProxy.write(socketID, new AccountDeletion(contactID));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		final var sender = persistenceManager.getUserByID(userID);
 | 
			
		||||
		switch (evt.getOperationType()) {
 | 
			
		||||
			case ADD:
 | 
			
		||||
				logger.log(Level.FINE,
 | 
			
		||||
@@ -45,7 +53,7 @@ public final class UserOperationProcessor implements ObjectProcessor<UserOperati
 | 
			
		||||
				sender.setLatestContactDeletion(Instant.now());
 | 
			
		||||
 | 
			
		||||
				// Notify the removed contact on next startup(s) of this deletion
 | 
			
		||||
				persistenceManager.getUserByID(contactID).setLatestContactDeletion(Instant.now());
 | 
			
		||||
				recipient.setLatestContactDeletion(Instant.now());
 | 
			
		||||
 | 
			
		||||
				// Notify the removed contact if online
 | 
			
		||||
				if (connectionManager.isOnline(contactID))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user