}
public Pair<Long, List<SendMessageResult>> updateGroup(
- GroupId groupId, String name, String description, List<String> members, File avatarFile
+ GroupId groupId,
+ String name,
+ String description,
+ List<String> members,
+ List<String> removeMembers,
+ File avatarFile
) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException {
return updateGroup(groupId,
name,
description,
members == null ? null : getSignalServiceAddresses(members),
+ removeMembers == null ? null : getSignalServiceAddresses(removeMembers),
avatarFile);
}
private Pair<Long, List<SendMessageResult>> updateGroup(
- GroupId groupId, String name, String description, Set<RecipientId> members, File avatarFile
+ GroupId groupId,
+ String name,
+ String description,
+ Set<RecipientId> members,
+ final Set<RecipientId> removeMembers,
+ File avatarFile
) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException {
var group = getGroupForUpdating(groupId);
if (group instanceof GroupInfoV2) {
- return updateGroupV2((GroupInfoV2) group, name, description, members, avatarFile);
+ return updateGroupV2((GroupInfoV2) group, name, description, members, removeMembers, avatarFile);
}
return updateGroupV1((GroupInfoV1) group, name, members, avatarFile);
final String name,
final String description,
final Set<RecipientId> members,
+ final Set<RecipientId> removeMembers,
final File avatarFile
) throws IOException {
Pair<Long, List<SendMessageResult>> result = null;
result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
}
}
+
+ if (removeMembers != null) {
+ var existingRemoveMembers = new HashSet<>(removeMembers);
+ existingRemoveMembers.retainAll(group.getMembers());
+ existingRemoveMembers.remove(getSelfRecipientId());// self can be removed with sendQuitGroupMessage
+ if (existingRemoveMembers.size() > 0) {
+ var groupGroupChangePair = groupHelper.removeMembers(group, existingRemoveMembers);
+ result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
+ }
+
+ var pendingRemoveMembers = new HashSet<>(removeMembers);
+ pendingRemoveMembers.retainAll(group.getPendingMembers());
+ if (pendingRemoveMembers.size() > 0) {
+ var groupGroupChangePair = groupHelper.revokeInvitedMembers(group, pendingRemoveMembers);
+ result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
+ }
+ }
+
if (result == null || name != null || description != null || avatarFile != null) {
var groupGroupChangePair = groupHelper.updateGroupV2(group, name, description, avatarFile);
if (avatarFile != null) {
private Pair<Long, List<SendMessageResult>> sendUpdateGroupV2Message(
GroupInfoV2 group, DecryptedGroup newDecryptedGroup, GroupChange groupChange
) throws IOException {
+ final var selfRecipientId = account.getSelfRecipientId();
+ final var members = group.getMembersIncludingPendingWithout(selfRecipientId);
group.setGroup(newDecryptedGroup, this::resolveRecipient);
+ members.addAll(group.getMembersIncludingPendingWithout(selfRecipientId));
+
final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChange.toByteArray());
account.getGroupStore().updateGroup(group);
- return sendMessage(messageBuilder, group.getMembersIncludingPendingWithout(account.getSelfRecipientId()));
+ return sendMessage(messageBuilder, members);
}
private static int currentTimeDays() {
}
}
+ public Pair<DecryptedGroup, GroupChange> removeMembers(
+ GroupInfoV2 groupInfoV2, Set<RecipientId> members
+ ) throws IOException {
+ final var memberUuids = members.stream()
+ .map(addressResolver::resolveSignalServiceAddress)
+ .map(SignalServiceAddress::getUuid)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toSet());
+ return ejectMembers(groupInfoV2, memberUuids);
+ }
+
+ public Pair<DecryptedGroup, GroupChange> revokeInvitedMembers(
+ GroupInfoV2 groupInfoV2, Set<RecipientId> members
+ ) throws IOException {
+ var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
+ final var memberUuids = members.stream()
+ .map(addressResolver::resolveSignalServiceAddress)
+ .map(SignalServiceAddress::getUuid)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .map(uuid -> DecryptedGroupUtil.findPendingByUuid(pendingMembersList, uuid))
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toSet());
+ return revokeInvites(groupInfoV2, memberUuids);
+ }
+
public GroupChange joinGroup(
GroupMasterKey groupMasterKey,
GroupLinkPassword groupLinkPassword,
return commitChange(groupInfoV2, change);
}
- public Pair<DecryptedGroup, GroupChange> revokeInvites(
+ private Pair<DecryptedGroup, GroupChange> revokeInvites(
GroupInfoV2 groupInfoV2, Set<DecryptedPendingMember> pendingMembers
) throws IOException {
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
return commitChange(groupInfoV2, groupOperations.createRemoveInvitationChange(uuidCipherTexts));
}
- public Pair<DecryptedGroup, GroupChange> ejectMembers(GroupInfoV2 groupInfoV2, Set<UUID> uuids) throws IOException {
+ private Pair<DecryptedGroup, GroupChange> ejectMembers(
+ GroupInfoV2 groupInfoV2, Set<UUID> uuids
+ ) throws IOException {
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
final var groupOperations = groupsV2Operations.forGroup(groupSecretParams);
return commitChange(groupInfoV2, groupOperations.createRemoveMembersChange(uuids));