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
This commit is contained in:
Leon Hofmeister 2020-10-16 20:21:22 +02:00
parent bdb964a0d1
commit c4d4708988
Signed by: delvh
GPG Key ID: 3DECE05F6D9A647C
8 changed files with 66 additions and 34 deletions

View File

@ -379,12 +379,27 @@ public final class LocalDB implements EventListener {
*/ */
public void setUserAndMergeContacts(User user) { public void setUserAndMergeContacts(User user) {
this.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 // Mark chats as disabled if a contact is no longer in this users contact list
changedChats = chats.stream() final var changedUserChats = chats.stream()
.filter(not(chat -> user.getContacts().contains(chat.getRecipient()))) .filter(not(chat -> contacts.contains(chat.getRecipient())))
.peek(chat -> { chat.setDisabled(true); logger.log(Level.INFO, String.format("Marked %s as blocked.", 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);
}
} }
/** /**

View File

@ -16,5 +16,7 @@ public final class GroupSizeLabel extends Label {
* @param recipient the group whose members to show * @param recipient the group whose members to show
* @since Envoy Client v0.3-beta * @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" : ""));
}
} }

View File

@ -281,7 +281,8 @@ public final class ChatScene implements EventListener, Restorable {
// Update the top-bar status label if all conditions apply // Update the top-bar status label if all conditions apply
if (currentChat != null && currentChat.getRecipient().equals(chatFound.get().getRecipient())) 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); topBarStatusLabel.setVisible(true);
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43)); recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
} else { } else {
topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " members"); topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " member"
+ (currentChat.getRecipient().getContacts().size() != 1 ? "s" : ""));
topBarStatusLabel.getStyleClass().clear(); topBarStatusLabel.getStyleClass().clear();
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43)); recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
} }
@ -752,7 +754,13 @@ public final class ChatScene implements EventListener, Restorable {
* @since Envoy Client v0.3-beta * @since Envoy Client v0.3-beta
*/ */
public void disableChat(Contact recipient, boolean refreshChatList) { 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)) { if (currentChat != null && currentChat.getRecipient().equals(recipient)) {
messageTextArea.setDisable(true); messageTextArea.setDisable(true);
voiceButton.setDisable(true); voiceButton.setDisable(true);

View File

@ -82,15 +82,19 @@ public final class UserUtil {
if (!context.getClient().isOnline() || block == null) return; if (!context.getClient().isOnline() || block == null) return;
else { else {
final var alert = new Alert(AlertType.CONFIRMATION); 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, () -> { AlertHelper.confirmAction(alert, () -> {
context.getClient() context.getClient()
.send(block instanceof User ? new UserOperation((User) block, ElementOperation.REMOVE) .send(block instanceof User ? new UserOperation((User) block, ElementOperation.REMOVE)
: new GroupResize(context.getLocalDB().getUser(), (Group) block, ElementOperation.REMOVE)); : new GroupResize(context.getLocalDB().getUser(), (Group) block, ElementOperation.REMOVE));
context.getLocalDB().getChat(block.getID()).ifPresent(chat -> chat.setDisabled(true)); 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(); final var controller = context.getSceneContext().getController();
if (controller instanceof ChatScene) ((ChatScene) controller).disableChat(block, true); if (controller instanceof ChatScene) ((ChatScene) controller).disableChat(block, true);
logger.log(Level.INFO, "A contact was blocked.");
}); });
} }
} }

View File

@ -49,6 +49,7 @@ public final class Startup {
new MessageStatusChangeProcessor(), new MessageStatusChangeProcessor(),
new GroupMessageStatusChangeProcessor(), new GroupMessageStatusChangeProcessor(),
new UserStatusChangeProcessor(), new UserStatusChangeProcessor(),
new GroupResizeProcessor(),
new IDGeneratorRequestProcessor(), new IDGeneratorRequestProcessor(),
new UserSearchProcessor(), new UserSearchProcessor(),
new UserOperationProcessor(), new UserOperationProcessor(),

View File

@ -51,7 +51,7 @@ public class Message {
@Id @Id
protected long id; protected long id;
@ManyToOne @ManyToOne(cascade = CascadeType.REMOVE)
@JoinColumn @JoinColumn
protected User sender; protected User sender;

View File

@ -105,11 +105,6 @@ public final class PersistenceManager {
// Remove this contact from the contact list of his contacts // Remove this contact from the contact list of his contacts
for (final var remainingContact : contact.getContacts()) for (final var remainingContact : contact.getContacts())
remainingContact.getContacts().remove(contact); 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); remove(contact);
} }

View File

@ -1,8 +1,12 @@
package envoy.server.processors; package envoy.server.processors;
import java.time.Instant;
import java.util.logging.Level;
import envoy.event.GroupResize; import envoy.event.GroupResize;
import envoy.server.data.*; import envoy.server.data.*;
import envoy.server.net.*; import envoy.server.net.ObjectWriteProxy;
import envoy.util.EnvoyLog;
/** /**
* @author Maximilian Käfer * @author Maximilian Käfer
@ -10,35 +14,38 @@ import envoy.server.net.*;
*/ */
public final class GroupResizeProcessor implements ObjectProcessor<GroupResize> { public final class GroupResizeProcessor implements ObjectProcessor<GroupResize> {
private static final PersistenceManager persistenceManager = PersistenceManager.getInstance(); private static final PersistenceManager persistenceManager = PersistenceManager.getInstance();
private static final ConnectionManager connectionManager = ConnectionManager.getInstance();
@Override @Override
public void process(GroupResize groupResize, long socketID, ObjectWriteProxy writeProxy) { public void process(GroupResize groupResize, long socketID, ObjectWriteProxy writeProxy) {
// Acquire the group to resize from the database // 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 // Perform the desired operation
switch (groupResize.getOperation()) { switch (groupResize.getOperation()) {
case ADD: case ADD:
group.getContacts().add(persistenceManager.getUserByID(groupResize.get().getID())); persistenceManager.addContactBidirectional(sender, group);
break; writeProxy.writeToOnlineContacts(group.getContacts(), group.toCommon());
return;
case REMOVE: 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())); 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));
} }
} }