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:
		@@ -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);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 
 | 
			
		||||
@@ -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" : ""));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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.");
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ public final class Startup {
 | 
			
		||||
						new MessageStatusChangeProcessor(),
 | 
			
		||||
						new GroupMessageStatusChangeProcessor(),
 | 
			
		||||
						new UserStatusChangeProcessor(),
 | 
			
		||||
						new GroupResizeProcessor(),
 | 
			
		||||
						new IDGeneratorRequestProcessor(),
 | 
			
		||||
						new UserSearchProcessor(),
 | 
			
		||||
						new UserOperationProcessor(),
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ public class Message {
 | 
			
		||||
	@Id
 | 
			
		||||
	protected long id;
 | 
			
		||||
 | 
			
		||||
	@ManyToOne
 | 
			
		||||
	@ManyToOne(cascade = CascadeType.REMOVE)
 | 
			
		||||
	@JoinColumn
 | 
			
		||||
	protected User sender;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<GroupResize> {
 | 
			
		||||
 | 
			
		||||
	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));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user