From f1ac2282ffdcf66b76836565fbffb29ae41796ab Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 26 Jun 2025 16:30:04 -0300 Subject: [PATCH] Ensure proper thread snippet restore. --- .../securesms/database/AttachmentTable.kt | 12 ++++++++++- .../securesms/database/ThreadTable.kt | 18 ++++++++++++----- .../helpers/SignalDatabaseMigrations.kt | 6 ++++-- ..._AddSnippetMessageIdColumnToThreadTable.kt | 20 +++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V282_AddSnippetMessageIdColumnToThreadTable.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt index 961a4e7c72..40158bce6b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt @@ -75,6 +75,16 @@ import org.thoughtcrime.securesms.crypto.AttachmentSecret import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream +import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.COPY_PENDING +import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.FINISHED +import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.NONE +import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.PERMANENT_FAILURE +import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.UPLOAD_IN_PROGRESS +import org.thoughtcrime.securesms.database.AttachmentTable.Companion.DATA_FILE +import org.thoughtcrime.securesms.database.AttachmentTable.Companion.DATA_HASH_END +import org.thoughtcrime.securesms.database.AttachmentTable.Companion.PREUPLOAD_MESSAGE_ID +import org.thoughtcrime.securesms.database.AttachmentTable.Companion.REMOTE_KEY +import org.thoughtcrime.securesms.database.AttachmentTable.Companion.TRANSFER_PROGRESS_DONE import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId import org.thoughtcrime.securesms.database.SignalDatabase.Companion.messages import org.thoughtcrime.securesms.database.SignalDatabase.Companion.threads @@ -1227,7 +1237,7 @@ class AttachmentTable( val threadId = messages.getThreadIdForMessage(mmsId) if (!messages.isStory(mmsId)) { - threads.updateSnippetUriSilently(threadId, PartAuthority.getAttachmentDataUri(attachmentId)) + threads.updateSnippetUriSilently(threadId, snippetMessageId = mmsId, attachment = PartAuthority.getAttachmentDataUri(attachmentId)) } notifyConversationListeners(threadId) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt index 548478d871..4ebc0295e5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt @@ -107,6 +107,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa const val SNIPPET_CONTENT_TYPE = "snippet_content_type" const val SNIPPET_EXTRAS = "snippet_extras" const val SNIPPET_MESSAGE_EXTRAS = "snippet_message_extras" + const val SNIPPET_MESSAGE_ID = "snippet_message_id" const val ARCHIVED = "archived" const val STATUS = "status" const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt" @@ -148,7 +149,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa $PINNED_ORDER INTEGER UNIQUE DEFAULT NULL, $UNREAD_SELF_MENTION_COUNT INTEGER DEFAULT 0, $ACTIVE INTEGER DEFAULT 0, - $SNIPPET_MESSAGE_EXTRAS BLOB DEFAULT NULL + $SNIPPET_MESSAGE_EXTRAS BLOB DEFAULT NULL, + $SNIPPET_MESSAGE_ID INTEGER DEFAULT 0 ) """ @@ -222,6 +224,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa private fun updateThread( threadId: Long, + messageId: Long, meaningfulMessages: Boolean, body: String?, attachment: Uri?, @@ -263,7 +266,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa ACTIVE to 1, UNREAD_COUNT to unreadCount, UNREAD_SELF_MENTION_COUNT to unreadMentionCount, - SNIPPET_MESSAGE_EXTRAS to messageExtras?.encode() + SNIPPET_MESSAGE_EXTRAS to messageExtras?.encode(), + SNIPPET_MESSAGE_ID to messageId ) writableDatabase @@ -291,11 +295,11 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa return threadRecipientId == null || !recipients.isMuted(threadRecipientId) } - fun updateSnippetUriSilently(threadId: Long, attachment: Uri?) { + fun updateSnippetUriSilently(threadId: Long, snippetMessageId: Long, attachment: Uri?) { writableDatabase .update(TABLE_NAME) .values(SNIPPET_URI to attachment?.toString()) - .where("$ID = ?", threadId) + .where("$ID = ? AND $SNIPPET_MESSAGE_ID = ?", threadId, snippetMessageId) .run() } @@ -310,7 +314,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa SNIPPET_URI to attachment?.toString(), SNIPPET_TYPE to type, SNIPPET_CONTENT_TYPE to null, - SNIPPET_EXTRAS to null + SNIPPET_EXTRAS to null, + SNIPPET_MESSAGE_ID to 0 ) if (unarchive && allowedToUnarchive(threadId)) { @@ -1777,6 +1782,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa } else if (isPinned) { updateThread( threadId = threadId, + messageId = 0, meaningfulMessages = meaningfulMessages, body = null, attachment = null, @@ -1807,6 +1813,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa updateThread( threadId = threadId, + messageId = record.id, meaningfulMessages = meaningfulMessages, body = threadBody.body.toString(), attachment = getAttachmentUriFor(record), @@ -1991,6 +1998,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa SNIPPET_CONTENT_TYPE to null, SNIPPET_EXTRAS to null, SNIPPET_MESSAGE_EXTRAS to null, + SNIPPET_MESSAGE_ID to 0, UNREAD_COUNT to 0, STATUS to 0, HAS_DELIVERY_RECEIPT to 0, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index b9365c1560..d9c2449ce8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -136,6 +136,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V278_BackupSnapshot import org.thoughtcrime.securesms.database.helpers.migration.V279_AddNotificationProfileForeignKey import org.thoughtcrime.securesms.database.helpers.migration.V280_RemoveAttachmentIv import org.thoughtcrime.securesms.database.helpers.migration.V281_RemoveArchiveTransferFile +import org.thoughtcrime.securesms.database.helpers.migration.V282_AddSnippetMessageIdColumnToThreadTable import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSqliteDatabase /** @@ -277,10 +278,11 @@ object SignalDatabaseMigrations { 278 to V278_BackupSnapshotTableVersions, 279 to V279_AddNotificationProfileForeignKey, 280 to V280_RemoveAttachmentIv, - 281 to V281_RemoveArchiveTransferFile + 281 to V281_RemoveArchiveTransferFile, + 282 to V282_AddSnippetMessageIdColumnToThreadTable ) - const val DATABASE_VERSION = 281 + const val DATABASE_VERSION = 282 @JvmStatic fun migrate(context: Application, db: SignalSqliteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V282_AddSnippetMessageIdColumnToThreadTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V282_AddSnippetMessageIdColumnToThreadTable.kt new file mode 100644 index 0000000000..9646b134ed --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V282_AddSnippetMessageIdColumnToThreadTable.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import org.thoughtcrime.securesms.database.SQLiteDatabase + +/** + * In order to make sure the snippet URI is not overwritten by the wrong message attachment, we want to + * track the snippet message id in the thread table. + */ +@Suppress("ClassName") +object V282_AddSnippetMessageIdColumnToThreadTable : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE thread ADD COLUMN snippet_message_id INTEGER DEFAULT 0") + } +}