Promptly remove terminated groups from shortcuts.

This commit is contained in:
Cody Henthorne
2026-04-13 12:01:00 -04:00
committed by jeffrey-signal
parent 3c68e29679
commit 7aadc208e1
3 changed files with 19 additions and 1 deletions
@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.database.model.GroupRecord;
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
import org.thoughtcrime.securesms.groups.v2.GroupLinkPassword;
import org.thoughtcrime.securesms.groups.v2.processing.GroupUpdateResult;
import org.thoughtcrime.securesms.jobs.ConversationShortcutUpdateJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException;
@@ -82,6 +83,7 @@ public final class GroupManager {
try (GroupManagerV2.GroupEditor edit = new GroupManagerV2(context).edit(groupId.requireV2())) {
edit.terminateGroup();
SignalDatabase.groups().setTerminatedBy(groupId, Recipient.self().getId());
ConversationShortcutUpdateJob.enqueue();
Log.i(TAG, "Terminated group " + groupId);
} catch (GroupInsufficientRightsException e) {
Log.w(TAG, "Insufficient rights to terminate " + groupId, e);
@@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.groups.GroupProtoUtil
import org.thoughtcrime.securesms.groups.v2.ProfileKeySet
import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor.Companion.LATEST
import org.thoughtcrime.securesms.jobs.AvatarGroupsV2DownloadJob
import org.thoughtcrime.securesms.jobs.ConversationShortcutUpdateJob
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob
import org.thoughtcrime.securesms.jobs.LeaveGroupV2Job
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
@@ -543,7 +544,8 @@ class GroupsV2StateProcessor private constructor(
Log.i(TAG, "$logPrefix Local state (revision: ${currentLocalState?.revision}) does not match, updating to ${updatedGroupState.revision}")
}
val terminatorRecipientId: RecipientId? = if (updatedGroupState.terminated && (currentLocalState == null || !currentLocalState.terminated)) {
val wasTerminated = updatedGroupState.terminated && (currentLocalState == null || !currentLocalState.terminated)
val terminatorRecipientId: RecipientId? = if (wasTerminated) {
groupStateDiff.serverHistory
.mapNotNull { it.change }
.firstOrNull { it.terminateGroup }
@@ -559,6 +561,10 @@ class GroupsV2StateProcessor private constructor(
profileAndMessageHelper.stopAllTypingForGroup()
}
if (wasTerminated) {
ConversationShortcutUpdateJob.enqueue()
}
if (currentLocalState == null || currentLocalState.revision == RESTORE_PLACEHOLDER_REVISION) {
if (!updatedGroupState.terminated) {
Log.i(TAG, "$logPrefix Inserting single update message for no local state or restore placeholder")
@@ -787,6 +793,7 @@ class GroupsV2StateProcessor private constructor(
}
SignalDatabase.groups.update(masterKey, simulatedGroupState, null)
ConversationShortcutUpdateJob.enqueue()
}
fun markJoinRequestRejectedLocally() {
@@ -56,6 +56,7 @@ import org.thoughtcrime.securesms.groups.GroupsV2Authorization
import org.thoughtcrime.securesms.groups.v2.ProfileKeySet
import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor.ProfileAndMessageHelper
import org.thoughtcrime.securesms.jobmanager.JobManager
import org.thoughtcrime.securesms.jobs.ConversationShortcutUpdateJob
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
@@ -1066,6 +1067,7 @@ class GroupsV2StateProcessorTest {
}
every { recipientTable.getAndPossiblyMerge(adminAci, null) } returns adminRecipientId
justRun { jobManager.add(any()) }
val signedChange = DecryptedGroupChange(
revision = 6,
@@ -1088,6 +1090,7 @@ class GroupsV2StateProcessorTest {
}
verify { groupTable.update(masterKey, match { it.terminated }, null, adminRecipientId) }
verify { jobManager.add(ofType(ConversationShortcutUpdateJob::class)) }
}
@Test
@@ -1100,6 +1103,8 @@ class GroupsV2StateProcessorTest {
expectTableUpdate = true
}
justRun { jobManager.add(any()) }
val signedChange = DecryptedGroupChange(
revision = 6,
terminateGroup = true
@@ -1120,6 +1125,7 @@ class GroupsV2StateProcessorTest {
}
verify(exactly = 0) { groupTable.setTerminatedBy(any(), any()) }
verify { jobManager.add(ofType(ConversationShortcutUpdateJob::class)) }
}
@Test
@@ -1139,6 +1145,8 @@ class GroupsV2StateProcessorTest {
expectTableUpdate = true
}
justRun { jobManager.add(any()) }
val result = processor.forceSanityUpdateFromServer(0)
assertThat(result.updateStatus).isEqualTo(GroupUpdateResult.UpdateStatus.GROUP_UPDATED)
@@ -1149,6 +1157,7 @@ class GroupsV2StateProcessorTest {
}
verify(exactly = 0) { groupTable.setTerminatedBy(any(), any()) }
verify { jobManager.add(ofType(ConversationShortcutUpdateJob::class)) }
}
@Test