From a0812f193eabfabd5a23a512e2596ec1104aa72a Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 16 Oct 2020 20:21:22 +0200 Subject: [PATCH] Add working leaving of a group Additionally fixed a two bugs: - one group member will no longer show "1 members" - deletion of empty groups no longer throws an exception --- .../main/java/envoy/client/data/LocalDB.java | 21 +++++++-- .../client/ui/control/GroupSizeLabel.java | 4 +- .../envoy/client/ui/controller/ChatScene.java | 14 ++++-- .../main/java/envoy/client/util/UserUtil.java | 8 +++- .../src/main/java/envoy/server/Startup.java | 1 + .../main/java/envoy/server/data/Message.java | 2 +- .../envoy/server/data/PersistenceManager.java | 5 --- .../processors/GroupResizeProcessor.java | 45 +++++++++++-------- 8 files changed, 66 insertions(+), 34 deletions(-) diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 28b7ccd..7f93c18 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -379,12 +379,27 @@ public final class LocalDB implements EventListener { */ public void setUserAndMergeContacts(User user) { this.user = user; - if (contactsChanged) + if (contactsChanged) { + final var contacts = user.getContacts(); // Mark chats as disabled if a contact is no longer in this users contact list - changedChats = chats.stream() - .filter(not(chat -> user.getContacts().contains(chat.getRecipient()))) + final var changedUserChats = chats.stream() + .filter(not(chat -> contacts.contains(chat.getRecipient()))) .peek(chat -> { chat.setDisabled(true); logger.log(Level.INFO, String.format("Marked %s as blocked.", chat.getRecipient())); }); + + // Also update groups with a different member count + final var changedGroupChats = contacts.stream().filter(Group.class::isInstance).flatMap(group -> { + final var potentialChat = getChat(group.getID()); + if (potentialChat.isEmpty()) return Stream.empty(); + final var chat = potentialChat.get(); + if (group.getContacts().size() != chat.getRecipient().getContacts().size()) { + logger.log(Level.INFO, "Removed one (or more) members from " + group); + return Stream.of(chat); + } else return Stream.empty(); + }); + + changedChats = Stream.concat(changedUserChats, changedGroupChats); + } } /** diff --git a/client/src/main/java/envoy/client/ui/control/GroupSizeLabel.java b/client/src/main/java/envoy/client/ui/control/GroupSizeLabel.java index 8413744..120206d 100644 --- a/client/src/main/java/envoy/client/ui/control/GroupSizeLabel.java +++ b/client/src/main/java/envoy/client/ui/control/GroupSizeLabel.java @@ -16,5 +16,7 @@ public final class GroupSizeLabel extends Label { * @param recipient the group whose members to show * @since Envoy Client v0.3-beta */ - public GroupSizeLabel(Group recipient) { super(recipient.getContacts().size() + " members"); } + public GroupSizeLabel(Group recipient) { + super(recipient.getContacts().size() + " member" + (recipient.getContacts().size() != 1 ? "s" : "")); + } } diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index b28e428..fa072b6 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -281,7 +281,8 @@ public final class ChatScene implements EventListener, Restorable { // Update the top-bar status label if all conditions apply if (currentChat != null && currentChat.getRecipient().equals(chatFound.get().getRecipient())) - topBarStatusLabel.setText(chatFound.get().getRecipient().getContacts().size() + " members"); + topBarStatusLabel.setText(chatFound.get().getRecipient().getContacts().size() + " member" + + (currentChat.getRecipient().getContacts().size() != 1 ? "s" : "")); }); } @@ -383,7 +384,8 @@ public final class ChatScene implements EventListener, Restorable { topBarStatusLabel.setVisible(true); recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43)); } else { - topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " members"); + topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " member" + + (currentChat.getRecipient().getContacts().size() != 1 ? "s" : "")); topBarStatusLabel.getStyleClass().clear(); recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43)); } @@ -752,7 +754,13 @@ public final class ChatScene implements EventListener, Restorable { * @since Envoy Client v0.3-beta */ public void disableChat(Contact recipient, boolean refreshChatList) { - if (refreshChatList) chatList.refresh(); + if (refreshChatList) { + chatList.refresh(); + + // Decrement member count for groups + if (recipient instanceof Group) + topBarStatusLabel.setText(recipient.getContacts().size() + " member" + (recipient.getContacts().size() != 1 ? "s" : "")); + } if (currentChat != null && currentChat.getRecipient().equals(recipient)) { messageTextArea.setDisable(true); voiceButton.setDisable(true); diff --git a/client/src/main/java/envoy/client/util/UserUtil.java b/client/src/main/java/envoy/client/util/UserUtil.java index c6477b1..404dd23 100644 --- a/client/src/main/java/envoy/client/util/UserUtil.java +++ b/client/src/main/java/envoy/client/util/UserUtil.java @@ -82,15 +82,19 @@ public final class UserUtil { if (!context.getClient().isOnline() || block == null) return; else { final var alert = new Alert(AlertType.CONFIRMATION); - alert.setContentText("Are you sure you want to block " + block.getName() + "?"); + alert.setContentText("Are you sure you want to " + (block instanceof User ? "block " : "leave group ") + block.getName() + "?"); AlertHelper.confirmAction(alert, () -> { context.getClient() .send(block instanceof User ? new UserOperation((User) block, ElementOperation.REMOVE) : new GroupResize(context.getLocalDB().getUser(), (Group) block, ElementOperation.REMOVE)); context.getLocalDB().getChat(block.getID()).ifPresent(chat -> chat.setDisabled(true)); + if (block instanceof User) logger.log(Level.INFO, "A user was blocked."); + else { + block.getContacts().remove(context.getLocalDB().getUser()); + logger.log(Level.INFO, "The user left a group."); + } final var controller = context.getSceneContext().getController(); if (controller instanceof ChatScene) ((ChatScene) controller).disableChat(block, true); - logger.log(Level.INFO, "A contact was blocked."); }); } } diff --git a/server/src/main/java/envoy/server/Startup.java b/server/src/main/java/envoy/server/Startup.java index db890ac..13065ba 100755 --- a/server/src/main/java/envoy/server/Startup.java +++ b/server/src/main/java/envoy/server/Startup.java @@ -49,6 +49,7 @@ public final class Startup { new MessageStatusChangeProcessor(), new GroupMessageStatusChangeProcessor(), new UserStatusChangeProcessor(), + new GroupResizeProcessor(), new IDGeneratorRequestProcessor(), new UserSearchProcessor(), new UserOperationProcessor(), diff --git a/server/src/main/java/envoy/server/data/Message.java b/server/src/main/java/envoy/server/data/Message.java index b4c5fe1..4b9cb12 100755 --- a/server/src/main/java/envoy/server/data/Message.java +++ b/server/src/main/java/envoy/server/data/Message.java @@ -51,7 +51,7 @@ public class Message { @Id protected long id; - @ManyToOne + @ManyToOne(cascade = CascadeType.REMOVE) @JoinColumn protected User sender; diff --git a/server/src/main/java/envoy/server/data/PersistenceManager.java b/server/src/main/java/envoy/server/data/PersistenceManager.java index 2c9bf33..e7acc61 100755 --- a/server/src/main/java/envoy/server/data/PersistenceManager.java +++ b/server/src/main/java/envoy/server/data/PersistenceManager.java @@ -105,11 +105,6 @@ public final class PersistenceManager { // Remove this contact from the contact list of his contacts for (final var remainingContact : contact.getContacts()) remainingContact.getContacts().remove(contact); - - // Delete messages sent or received by this contact - entityManager.createQuery("DELETE FROM Message m WHERE (m.sender = :contact OR m.recipient = :contact )") - .setParameter("contact", contact) - .executeUpdate(); }); remove(contact); } diff --git a/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java b/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java index 0a5b697..b0cacd9 100644 --- a/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java +++ b/server/src/main/java/envoy/server/processors/GroupResizeProcessor.java @@ -1,8 +1,12 @@ package envoy.server.processors; +import java.time.Instant; +import java.util.logging.Level; + import envoy.event.GroupResize; import envoy.server.data.*; -import envoy.server.net.*; +import envoy.server.net.ObjectWriteProxy; +import envoy.util.EnvoyLog; /** * @author Maximilian Käfer @@ -10,35 +14,38 @@ import envoy.server.net.*; */ public final class GroupResizeProcessor implements ObjectProcessor { - private static final PersistenceManager persistenceManager = PersistenceManager.getInstance(); - private static final ConnectionManager connectionManager = ConnectionManager.getInstance(); + private static final PersistenceManager persistenceManager = PersistenceManager.getInstance(); @Override public void process(GroupResize groupResize, long socketID, ObjectWriteProxy writeProxy) { // Acquire the group to resize from the database - var group = persistenceManager.getGroupByID(groupResize.getGroupID()); + final var group = persistenceManager.getGroupByID(groupResize.getGroupID()); + final var sender = persistenceManager.getUserByID(groupResize.get().getID()); // Perform the desired operation switch (groupResize.getOperation()) { case ADD: - group.getContacts().add(persistenceManager.getUserByID(groupResize.get().getID())); - break; + persistenceManager.addContactBidirectional(sender, group); + writeProxy.writeToOnlineContacts(group.getContacts(), group.toCommon()); + return; case REMOVE: + persistenceManager.removeContactBidirectional(sender, group); + sender.setLatestContactDeletion(Instant.now()); + + // The group has no more members and hence will be deleted + if (group.getContacts().isEmpty()) { + EnvoyLog.getLogger(GroupResizeProcessor.class).log(Level.INFO, "Deleting now empty group " + group.getName()); + persistenceManager.deleteContact(group); + } else { + + // Informing the other members + writeProxy.writeToOnlineContacts(group.getContacts(), groupResize); + group.getContacts().forEach(c -> ((User) c).setLatestContactDeletion(Instant.now())); + } + group.getContacts().remove(persistenceManager.getUserByID(groupResize.get().getID())); - break; + return; } - - // Update the group in the database - persistenceManager.updateContact(group); - - // Send the updated group to all of its members - var commonGroup = group.toCommon(); - group.getContacts() - .stream() - .map(Contact::getID) - .filter(connectionManager::isOnline) - .map(connectionManager::getSocketID) - .forEach(memberSocketID -> writeProxy.write(memberSocketID, commonGroup)); } }