Contact Deletion #97

Merged
delvh merged 6 commits from f/contact-deletion into develop 2020-10-19 18:09:21 +02:00
8 changed files with 66 additions and 34 deletions
Showing only changes of commit c4d4708988 - Show all commits

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())); });
delvh marked this conversation as resolved Outdated
Outdated
Review

Maybe log 'Disabled chat ...' here instead.

Maybe log 'Disabled chat ...' here instead.
// 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" : ""));
delvh marked this conversation as resolved
Review

We could just use parentheses, but I guess this is less ambiguous.

We could just use parentheses, but I guess this is less ambiguous.
}
} }

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);
delvh marked this conversation as resolved Outdated
Outdated
Review

This is unnecessary (your words).

This is unnecessary (your words).
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);
delvh marked this conversation as resolved
Review

Use an event here instead. This would also simplify the interaction with the local database.

Use an event here instead. This would also simplify the interaction with the local database.
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));
} }
} }