From 2fe3ea60266119289a9fc3b26322a23f59daedad Mon Sep 17 00:00:00 2001 From: Michelle Tang Date: Thu, 30 Jul 2026 14:06:24 -0400 Subject: [PATCH] Add more updates to group deletion. --- .../v2/exporters/GroupArchiveExporter.kt | 4 +- .../securesms/database/GroupTable.kt | 4 +- .../securesms/database/RecipientTable.kt | 41 +++++++++++++++---- .../migrations/ApplicationMigrations.java | 15 ++++--- .../securesms/recipients/RecipientUtil.java | 4 ++ 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt index 38107f991a..51fd45e2e7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt @@ -51,7 +51,7 @@ class GroupArchiveExporter(private val selfAci: ServiceId.ACI, private val curso val showAsStoryState: GroupTable.ShowAsStoryState = GroupTable.ShowAsStoryState.deserialize(cursor.requireInt(GroupTable.SHOW_AS_STORY_STATE)) val isMember: Boolean = cursor.requireBoolean(GroupTable.IS_MEMBER) - val decryptedGroup: DecryptedGroup = DecryptedGroup.ADAPTER.decode(cursor.requireBlob(GroupTable.V2_DECRYPTED_GROUP)!!) + val decryptedGroup: DecryptedGroup? = cursor.requireBlob(GroupTable.V2_DECRYPTED_GROUP)?.let { DecryptedGroup.ADAPTER.decode(it) } return ArchiveRecipient( id = cursor.requireLong(RecipientTable.ID), @@ -61,7 +61,7 @@ class GroupArchiveExporter(private val selfAci: ServiceId.ACI, private val curso blocked = cursor.requireBoolean(RecipientTable.BLOCKED), hideStory = extras?.hideStory() ?: false, storySendMode = showAsStoryState.toRemote(), - snapshot = decryptedGroup.toRemote(isMember, selfAci), + snapshot = decryptedGroup?.toRemote(isMember, selfAci) ?: Group.GroupSnapshot(), avatarColor = cursor.requireString(RecipientTable.AVATAR_COLOR)?.let { AvatarColor.deserialize(it) }?.toRemote() ) ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt index f4707f1111..b0dac915c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt @@ -1022,7 +1022,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : Log.i(TAG, "Group ${record.id} has been both left and had its thread deleted. Clearing all group data.") val keepGroupIdentifier = SignalStore.account.isMultiDevice || recipients.isBlocked(record.recipientId) - var clearRecipientCache: Boolean = false + var clearRecipientCache = false writableDatabase.withinTransaction { db -> db .delete(MembershipTable.TABLE_NAME) @@ -1087,7 +1087,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : IS_MEMBER to 0, TERMINATED_BY to 0, MMS to 0, - V2_REVISION to null, + V2_REVISION to 0, V2_DECRYPTED_GROUP to null, EXPECTED_V2_ID to null, UNMIGRATED_V1_MEMBERS to null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt index d8d195dbe2..39fdee5343 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -1096,6 +1096,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da groups.setVerifiedGroupNameHash(groupId, update.new.proto.verifiedNameHash.nullIfEmpty()?.toByteArray()) threads.applyStorageSyncUpdate(recipient.id, update.new) AppDependencies.databaseObserver.notifyRecipientChanged(recipient.id) + + if (update.old.proto.blocked && !update.new.proto.blocked) { + groups.clearGroupIfLeftAndDeleted(recipient.id) + } } fun applyStorageSyncAccountUpdate(update: StorageRecordUpdate) { @@ -3891,9 +3895,26 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } fun applyBlockedUpdate(blockedE164s: List, blockedAcis: List, blockedGroupIds: List) { + val oldBlockedGV1: Set = readableDatabase + .select(GROUP_ID) + .from(TABLE_NAME) + .where("$BLOCKED = 1 AND $TYPE = ?", SqlUtil.buildArgs(RecipientType.GV1.id)) + .run() + .readToList { + try { + GroupId.parseNullableOrThrow(it.requireString(GROUP_ID)) + } catch (e: BadGroupIdException) { + Log.w(TAG, "[applyBlockedUpdate] Bad existing GV1 ID!") + null + } + } + .filterNotNull() + .toSet() + writableDatabase.withinTransaction { db -> - db.updateAll(TABLE_NAME) + db.update(TABLE_NAME) .values(BLOCKED to 0) + .where("$TYPE != ?", RecipientType.GV2.id) .run() val blockValues = contentValuesOf( @@ -3918,7 +3939,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } if (blockedGroupIds.isNotEmpty()) { - val groupIds: List = blockedGroupIds.filterNotNull().mapNotNull { raw -> + val groupV1Ids: List = blockedGroupIds.filterNotNull().mapNotNull { raw -> try { raw?.let { GroupId.v1(it) } } catch (e: BadGroupIdException) { @@ -3927,11 +3948,17 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } - val groupIdQuery = SqlUtil.buildFastCollectionQuery(GROUP_ID, groupIds.map { it.toString() }) - db.update(TABLE_NAME) - .values(blockValues) - .where(groupIdQuery.where, groupIdQuery.whereArgs) - .run() + if (groupV1Ids.isNotEmpty()) { + val groupIdQuery = SqlUtil.buildFastCollectionQuery(GROUP_ID, groupV1Ids.map { it.toString() }) + db.update(TABLE_NAME) + .values(blockValues) + .where(groupIdQuery.where, groupIdQuery.whereArgs) + .run() + + for (groupId in oldBlockedGV1 - groupV1Ids.toSet()) { + groups.clearGroupIfLeftAndDeleted(groupId) + } + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index 3bfb2f991c..81fb032568 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -208,11 +208,12 @@ public class ApplicationMigrations { static final int KT_USERNAME_CAPABILITY = 164; static final int FIX_CHANGE_NUMBER_ERROR_2 = 165; static final int LOCAL_ARCHIVE_RECONCILE = 166; - static final int GROUP_DELETED_AT_BACKFILL = 167; +// static final int GROUP_DELETED_AT_BACKFILL = 167; static final int STICKER_PACK_STORAGE_SYNC = 168; + static final int GROUP_DELETED_AT_BACKFILL = 169; } - public static final int CURRENT_VERSION = 168; + public static final int CURRENT_VERSION = 169; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -967,14 +968,18 @@ public class ApplicationMigrations { jobs.put(Version.LOCAL_ARCHIVE_RECONCILE, new LocalArchiveReconciliationMigrationJob()); } - if (lastSeenVersion < Version.GROUP_DELETED_AT_BACKFILL) { - jobs.put(Version.GROUP_DELETED_AT_BACKFILL, new GroupDeletedBackfillMigrationJob()); - } +// if (lastSeenVersion < Version.GROUP_DELETED_AT_BACKFILL) { +// jobs.put(Version.GROUP_DELETED_AT_BACKFILL, new GroupDeletedBackfillMigrationJob()); +// } if (lastSeenVersion < Version.STICKER_PACK_STORAGE_SYNC) { jobs.put(Version.STICKER_PACK_STORAGE_SYNC, new SyncStickerPacksMigrationJob()); } + if (lastSeenVersion < Version.GROUP_DELETED_AT_BACKFILL) { + jobs.put(Version.GROUP_DELETED_AT_BACKFILL, new GroupDeletedBackfillMigrationJob()); + } + return jobs; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java index 883eaef743..b180dd98d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java @@ -203,6 +203,10 @@ public class RecipientUtil { insertUnblockedUpdate(recipient, SignalDatabase.threads().getOrCreateThreadIdFor(recipient)); AppDependencies.getJobManager().add(new MultiDeviceBlockedUpdateJob()); StorageSyncHelper.scheduleSyncForDataChange(); + + if (recipient.isGroup()) { + SignalDatabase.groups().clearGroupIfLeftAndDeleted(recipient.getId()); + } } private static void insertBlockedUpdate(@NonNull Recipient recipient, long threadId) {