Improve delete sync coverage for partial expiring threads.
This commit is contained in:
parent
070174fee6
commit
6659700a1c
13 changed files with 127 additions and 51 deletions
|
@ -260,7 +260,7 @@ class SyncMessageProcessorTest_synchronizeDeleteForMe {
|
|||
}
|
||||
|
||||
messageHelper.syncDeleteForMeConversation(
|
||||
DeleteForMeSync(conversationId = messageHelper.alice, randomFutureMessages, true)
|
||||
DeleteForMeSync(conversationId = messageHelper.alice, randomFutureMessages, isFullDelete = true)
|
||||
)
|
||||
|
||||
// THEN
|
||||
|
@ -271,6 +271,38 @@ class SyncMessageProcessorTest_synchronizeDeleteForMe {
|
|||
harness.inMemoryLogger.entries().filter { it.message?.contains("Unable to find most recent received at timestamp") == true }.size assertIs 1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun singleConversationNoRecentsFoundNonExpiringRecentsFoundDelete() {
|
||||
// GIVEN
|
||||
val messages = mutableListOf<MessageTable.SyncMessageId>()
|
||||
|
||||
for (i in 0 until 10) {
|
||||
messages += MessageTable.SyncMessageId(messageHelper.alice, messageHelper.incomingText().timestamp)
|
||||
messages += MessageTable.SyncMessageId(harness.self.id, messageHelper.outgoingText().timestamp)
|
||||
}
|
||||
|
||||
val threadId = SignalDatabase.threads.getThreadIdFor(messageHelper.alice)!!
|
||||
SignalDatabase.messages.getMessageCountForThread(threadId) assertIs 20
|
||||
|
||||
// WHEN
|
||||
val nonExpiringMessages = messages.takeLast(5).map { it.recipientId to it.timetamp }
|
||||
|
||||
val randomFutureMessages = (1..5).map {
|
||||
messageHelper.alice to messageHelper.nextStartTime(it)
|
||||
}
|
||||
|
||||
messageHelper.syncDeleteForMeConversation(
|
||||
DeleteForMeSync(conversationId = messageHelper.alice, randomFutureMessages, nonExpiringMessages, true)
|
||||
)
|
||||
|
||||
// THEN
|
||||
SignalDatabase.messages.getMessageCountForThread(threadId) assertIs 0
|
||||
SignalDatabase.threads.getThreadRecord(threadId) assertIs null
|
||||
|
||||
harness.inMemoryLogger.flush()
|
||||
harness.inMemoryLogger.entries().filter { it.message?.contains("Using backup non-expiring messages") == true }.size assertIs 1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun localOnlyRemainingAfterConversationDeleteWithFullDelete() {
|
||||
// GIVEN
|
||||
|
@ -389,8 +421,8 @@ class SyncMessageProcessorTest_synchronizeDeleteForMe {
|
|||
|
||||
// WHEN
|
||||
messageHelper.syncDeleteForMeConversation(
|
||||
DeleteForMeSync(conversationId = messageHelper.alice, allMessages[messageHelper.alice]!!.takeLast(5).map { it.recipientId to it.timetamp }, true),
|
||||
DeleteForMeSync(conversationId = messageHelper.bob, allMessages[messageHelper.bob]!!.takeLast(5).map { it.recipientId to it.timetamp }, true)
|
||||
DeleteForMeSync(conversationId = messageHelper.alice, allMessages[messageHelper.alice]!!.takeLast(5).map { it.recipientId to it.timetamp }, isFullDelete = true),
|
||||
DeleteForMeSync(conversationId = messageHelper.bob, allMessages[messageHelper.bob]!!.takeLast(5).map { it.recipientId to it.timetamp }, isFullDelete = true)
|
||||
)
|
||||
|
||||
// THEN
|
||||
|
|
|
@ -187,8 +187,8 @@ object MessageContentFuzzer {
|
|||
.syncMessage(
|
||||
SyncMessage(
|
||||
deleteForMe = SyncMessage.DeleteForMe(
|
||||
conversationDeletes = allDeletes.map { (conversationId, conversationDeletes, isFullDelete) ->
|
||||
val conversation = Recipient.resolved(conversationId)
|
||||
conversationDeletes = allDeletes.map { delete ->
|
||||
val conversation = Recipient.resolved(delete.conversationId)
|
||||
SyncMessage.DeleteForMe.ConversationDelete(
|
||||
conversation = if (conversation.isGroup) {
|
||||
SyncMessage.DeleteForMe.ConversationIdentifier(threadGroupId = conversation.requireGroupId().decodedId.toByteString())
|
||||
|
@ -196,14 +196,21 @@ object MessageContentFuzzer {
|
|||
SyncMessage.DeleteForMe.ConversationIdentifier(threadServiceId = conversation.requireAci().toString())
|
||||
},
|
||||
|
||||
mostRecentMessages = conversationDeletes.map { (author, timestamp) ->
|
||||
mostRecentMessages = delete.messages.map { (author, timestamp) ->
|
||||
SyncMessage.DeleteForMe.AddressableMessage(
|
||||
authorServiceId = Recipient.resolved(author).requireAci().toString(),
|
||||
sentTimestamp = timestamp
|
||||
)
|
||||
},
|
||||
|
||||
isFullDelete = isFullDelete
|
||||
mostRecentNonExpiringMessages = delete.nonExpiringMessages.map { (author, timestamp) ->
|
||||
SyncMessage.DeleteForMe.AddressableMessage(
|
||||
authorServiceId = Recipient.resolved(author).requireAci().toString(),
|
||||
sentTimestamp = timestamp
|
||||
)
|
||||
},
|
||||
|
||||
isFullDelete = delete.isFullDelete
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -405,6 +412,7 @@ object MessageContentFuzzer {
|
|||
data class DeleteForMeSync(
|
||||
val conversationId: RecipientId,
|
||||
val messages: List<Pair<RecipientId, Long>>,
|
||||
val nonExpiringMessages: List<Pair<RecipientId, Long>> = emptyList(),
|
||||
val isFullDelete: Boolean = true,
|
||||
val attachments: List<Pair<Long, AttachmentTable.SyncAttachmentId>> = emptyList()
|
||||
) {
|
||||
|
|
|
@ -209,6 +209,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||
const val QUOTE_NOT_PRESENT_ID = 0L
|
||||
const val QUOTE_TARGET_MISSING_ID = -1L
|
||||
|
||||
const val ADDRESSABLE_MESSAGE_LIMIT = 5
|
||||
|
||||
const val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
@ -4972,26 +4974,26 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||
return !hasMessages
|
||||
}
|
||||
|
||||
fun getMostRecentAddressableMessages(threadId: Long): Set<MessageRecord> {
|
||||
fun getMostRecentAddressableMessages(threadId: Long, excludeExpiring: Boolean): Set<MessageRecord> {
|
||||
return readableDatabase
|
||||
.select(*MMS_PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$IS_ADDRESSABLE_CLAUSE AND $THREAD_ID = ?", threadId)
|
||||
.where("$IS_ADDRESSABLE_CLAUSE AND $THREAD_ID = ? ${if (excludeExpiring) "AND $EXPIRES_IN = 0" else ""}", threadId)
|
||||
.orderBy("$DATE_RECEIVED DESC")
|
||||
.limit(5)
|
||||
.limit(ADDRESSABLE_MESSAGE_LIMIT)
|
||||
.run()
|
||||
.use {
|
||||
MmsReader(it).toSet()
|
||||
}
|
||||
}
|
||||
|
||||
fun getAddressableMessagesBefore(threadId: Long, beforeTimestamp: Long): Set<MessageRecord> {
|
||||
fun getAddressableMessagesBefore(threadId: Long, beforeTimestamp: Long, excludeExpiring: Boolean): Set<MessageRecord> {
|
||||
return readableDatabase
|
||||
.select(*MMS_PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$IS_ADDRESSABLE_CLAUSE AND $THREAD_ID = ? AND $DATE_RECEIVED < ?", threadId, beforeTimestamp)
|
||||
.where("$IS_ADDRESSABLE_CLAUSE AND $THREAD_ID = ? AND $DATE_RECEIVED < ? ${if (excludeExpiring) "AND $EXPIRES_IN = 0" else ""}", threadId, beforeTimestamp)
|
||||
.orderBy("$DATE_RECEIVED DESC")
|
||||
.limit(5)
|
||||
.limit(ADDRESSABLE_MESSAGE_LIMIT)
|
||||
.run()
|
||||
.use {
|
||||
MmsReader(it).toSet()
|
||||
|
|
|
@ -50,7 +50,7 @@ import org.thoughtcrime.securesms.database.model.serialize
|
|||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.groups.BadGroupIdException
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSendSyncJob
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob
|
||||
import org.thoughtcrime.securesms.jobs.OptimizeMessageSearchIndexJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck
|
||||
|
@ -326,7 +326,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
}
|
||||
|
||||
val syncThreadTrimDeletes = SignalStore.settings().shouldSyncThreadTrimDeletes() && Recipient.self().deleteSyncCapability.isSupported
|
||||
val threadTrimsToSync = mutableListOf<Pair<Long, Set<MessageRecord>>>()
|
||||
val threadTrimsToSync = mutableListOf<ThreadDeleteSyncInfo>()
|
||||
|
||||
readableDatabase
|
||||
.select(ID)
|
||||
|
@ -358,7 +358,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
}
|
||||
|
||||
if (syncThreadTrimDeletes && threadTrimsToSync.isNotEmpty()) {
|
||||
MultiDeviceDeleteSendSyncJob.enqueueThreadDeletes(threadTrimsToSync, isFullDelete = false)
|
||||
MultiDeviceDeleteSyncJob.enqueueThreadDeletes(threadTrimsToSync, isFullDelete = false)
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
|
@ -377,7 +377,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
return
|
||||
}
|
||||
|
||||
var threadTrimToSync: Pair<Long, Set<MessageRecord>>? = null
|
||||
var threadTrimToSync: ThreadDeleteSyncInfo? = null
|
||||
val deletes = writableDatabase.withinTransaction {
|
||||
threadTrimToSync = trimThreadInternal(threadId, syncThreadTrimDeletes, length, trimBeforeDate, inclusive)
|
||||
messages.deleteAbandonedMessages()
|
||||
|
@ -392,7 +392,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
}
|
||||
|
||||
if (syncThreadTrimDeletes && threadTrimToSync != null) {
|
||||
MultiDeviceDeleteSendSyncJob.enqueueThreadDeletes(listOf(threadTrimToSync!!), isFullDelete = false)
|
||||
MultiDeviceDeleteSyncJob.enqueueThreadDeletes(listOf(threadTrimToSync!!), isFullDelete = false)
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
|
@ -406,7 +406,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
length: Int,
|
||||
trimBeforeDate: Long,
|
||||
inclusive: Boolean = false
|
||||
): Pair<Long, Set<MessageRecord>>? {
|
||||
): ThreadDeleteSyncInfo? {
|
||||
if (length == NO_TRIM_MESSAGE_COUNT_SET && trimBeforeDate == NO_TRIM_BEFORE_DATE_SET) {
|
||||
return null
|
||||
}
|
||||
|
@ -427,7 +427,18 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
if (finalTrimBeforeDate != NO_TRIM_BEFORE_DATE_SET) {
|
||||
Log.i(TAG, "Trimming thread: $threadId before: $finalTrimBeforeDate inclusive: $inclusive")
|
||||
|
||||
val addressableMessages: Set<MessageRecord> = if (syncThreadTrimDeletes) messages.getAddressableMessagesBefore(threadId, finalTrimBeforeDate) else emptySet()
|
||||
val addressableMessages: Set<MessageRecord> = if (syncThreadTrimDeletes) {
|
||||
messages.getAddressableMessagesBefore(threadId, finalTrimBeforeDate, excludeExpiring = false)
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
|
||||
val nonExpiringAddressableMessages: Set<MessageRecord> = if (syncThreadTrimDeletes && addressableMessages.size == MessageTable.ADDRESSABLE_MESSAGE_LIMIT && addressableMessages.any { it.expiresIn > 0 }) {
|
||||
messages.getAddressableMessagesBefore(threadId, finalTrimBeforeDate, excludeExpiring = true)
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
|
||||
val deletes = messages.deleteMessagesInThreadBeforeDate(threadId, finalTrimBeforeDate, inclusive)
|
||||
|
||||
if (deletes > 0) {
|
||||
|
@ -438,7 +449,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
SignalDatabase.calls.updateCallEventDeletionTimestamps()
|
||||
|
||||
return if (syncThreadTrimDeletes && (threadDeleted || addressableMessages.isNotEmpty())) {
|
||||
threadId to addressableMessages
|
||||
ThreadDeleteSyncInfo(threadId, addressableMessages, nonExpiringAddressableMessages)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
@ -1132,13 +1143,20 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
fun deleteConversations(selectedConversations: Set<Long>, syncThreadDeletes: Boolean = true) {
|
||||
val recipientIds = getRecipientIdsForThreadIds(selectedConversations)
|
||||
|
||||
val addressableMessages = mutableListOf<Pair<Long, Set<MessageRecord>>>()
|
||||
val addressableMessages = mutableListOf<ThreadDeleteSyncInfo>()
|
||||
|
||||
val queries: List<SqlUtil.Query> = SqlUtil.buildCollectionQuery(ID, selectedConversations)
|
||||
writableDatabase.withinTransaction { db ->
|
||||
if (syncThreadDeletes && Recipient.self().deleteSyncCapability.isSupported) {
|
||||
for (threadId in selectedConversations) {
|
||||
addressableMessages += threadId to messages.getMostRecentAddressableMessages(threadId)
|
||||
val mostRecentMessages = messages.getMostRecentAddressableMessages(threadId, excludeExpiring = false)
|
||||
val mostRecentNonExpiring = if (mostRecentMessages.size == MessageTable.ADDRESSABLE_MESSAGE_LIMIT && mostRecentMessages.any { it.expiresIn > 0 }) {
|
||||
messages.getMostRecentAddressableMessages(threadId, excludeExpiring = true)
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
|
||||
addressableMessages += ThreadDeleteSyncInfo(threadId, mostRecentMessages, mostRecentNonExpiring)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1160,7 +1178,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
}
|
||||
|
||||
if (syncThreadDeletes) {
|
||||
MultiDeviceDeleteSendSyncJob.enqueueThreadDeletes(addressableMessages, isFullDelete = true)
|
||||
MultiDeviceDeleteSyncJob.enqueueThreadDeletes(addressableMessages, isFullDelete = true)
|
||||
}
|
||||
|
||||
notifyConversationListListeners()
|
||||
|
@ -2206,4 +2224,6 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
val threadId: Long,
|
||||
val newlyCreated: Boolean
|
||||
)
|
||||
|
||||
data class ThreadDeleteSyncInfo(val threadId: Long, val addressableMessages: Set<MessageRecord>, val nonExpiringAddressableMessages: Set<MessageRecord>)
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ public final class JobManagerFactories {
|
|||
put(MultiDeviceConfigurationUpdateJob.KEY, new MultiDeviceConfigurationUpdateJob.Factory());
|
||||
put(MultiDeviceContactSyncJob.KEY, new MultiDeviceContactSyncJob.Factory());
|
||||
put(MultiDeviceContactUpdateJob.KEY, new MultiDeviceContactUpdateJob.Factory());
|
||||
put(MultiDeviceDeleteSendSyncJob.KEY, new MultiDeviceDeleteSendSyncJob.Factory());
|
||||
put(MultiDeviceDeleteSyncJob.KEY, new MultiDeviceDeleteSyncJob.Factory());
|
||||
put(MultiDeviceKeysUpdateJob.KEY, new MultiDeviceKeysUpdateJob.Factory());
|
||||
put(MultiDeviceMessageRequestResponseJob.KEY, new MultiDeviceMessageRequestResponseJob.Factory());
|
||||
put(MultiDeviceOutgoingPaymentSyncJob.KEY, new MultiDeviceOutgoingPaymentSyncJob.Factory());
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.signal.core.util.logging.Log
|
|||
import org.signal.core.util.orNull
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.ThreadTable
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
|
@ -37,7 +38,7 @@ import kotlin.time.Duration.Companion.days
|
|||
/**
|
||||
* Send delete for me sync messages for the various type of delete syncs.
|
||||
*/
|
||||
class MultiDeviceDeleteSendSyncJob private constructor(
|
||||
class MultiDeviceDeleteSyncJob private constructor(
|
||||
private var data: DeleteSyncJobData,
|
||||
parameters: Parameters = Parameters.Builder()
|
||||
.addConstraint(NetworkConstraint.KEY)
|
||||
|
@ -48,7 +49,7 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
|
||||
companion object {
|
||||
const val KEY = "MultiDeviceDeleteSendSyncJob"
|
||||
private val TAG = Log.tag(MultiDeviceDeleteSendSyncJob::class.java)
|
||||
private val TAG = Log.tag(MultiDeviceDeleteSyncJob::class.java)
|
||||
|
||||
private const val CHUNK_SIZE = 500
|
||||
private const val THREAD_CHUNK_SIZE = CHUNK_SIZE / 5
|
||||
|
@ -68,7 +69,7 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
messageRecords.chunked(CHUNK_SIZE).forEach { chunk ->
|
||||
val deletes = createMessageDeletes(chunk)
|
||||
if (deletes.isNotEmpty()) {
|
||||
AppDependencies.jobManager.add(MultiDeviceDeleteSendSyncJob(messages = deletes))
|
||||
AppDependencies.jobManager.add(MultiDeviceDeleteSyncJob(messages = deletes))
|
||||
} else {
|
||||
Log.i(TAG, "No valid message deletes to sync")
|
||||
}
|
||||
|
@ -89,14 +90,14 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
|
||||
val delete = createAttachmentDelete(message, attachment)
|
||||
if (delete != null) {
|
||||
AppDependencies.jobManager.add(MultiDeviceDeleteSendSyncJob(attachments = listOf(delete)))
|
||||
AppDependencies.jobManager.add(MultiDeviceDeleteSyncJob(attachments = listOf(delete)))
|
||||
} else {
|
||||
Log.i(TAG, "No valid attachment deletes to sync attachment:${attachment.attachmentId}")
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun enqueueThreadDeletes(threads: List<Pair<Long, Set<MessageRecord>>>, isFullDelete: Boolean) {
|
||||
fun enqueueThreadDeletes(threads: List<ThreadTable.ThreadDeleteSyncInfo>, isFullDelete: Boolean) {
|
||||
if (!TextSecurePreferences.isMultiDevice(AppDependencies.application)) {
|
||||
return
|
||||
}
|
||||
|
@ -110,7 +111,7 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
val threadDeletes = createThreadDeletes(chunk, isFullDelete)
|
||||
if (threadDeletes.isNotEmpty()) {
|
||||
AppDependencies.jobManager.add(
|
||||
MultiDeviceDeleteSendSyncJob(
|
||||
MultiDeviceDeleteSyncJob(
|
||||
threads = threadDeletes.filter { it.messages.isNotEmpty() },
|
||||
localOnlyThreads = threadDeletes.filter { it.messages.isEmpty() }
|
||||
)
|
||||
|
@ -186,8 +187,8 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun createThreadDeletes(threads: List<Pair<Long, Set<MessageRecord>>>, isFullDelete: Boolean): List<ThreadDelete> {
|
||||
return threads.mapNotNull { (threadId, messages) ->
|
||||
private fun createThreadDeletes(threads: List<ThreadTable.ThreadDeleteSyncInfo>, isFullDelete: Boolean): List<ThreadDelete> {
|
||||
return threads.mapNotNull { (threadId, messages, nonExpiringMessages) ->
|
||||
val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(threadId)
|
||||
if (threadRecipient == null) {
|
||||
Log.w(TAG, "Unable to find thread recipient for thread: $threadId")
|
||||
|
@ -206,6 +207,12 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
sentTimestamp = it.dateSent,
|
||||
authorRecipientId = it.fromRecipient.id.toLong()
|
||||
)
|
||||
},
|
||||
nonExpiringMessages = nonExpiringMessages.map {
|
||||
AddressableMessage(
|
||||
sentTimestamp = it.dateSent,
|
||||
authorRecipientId = it.fromRecipient.id.toLong()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -269,16 +276,17 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
if (data.threadDeletes.isNotEmpty()) {
|
||||
val success = syncDelete(
|
||||
DeleteForMe(
|
||||
conversationDeletes = data.threadDeletes.mapNotNull {
|
||||
val conversation = Recipient.resolved(RecipientId.from(it.threadRecipientId)).toDeleteSyncConversationId()
|
||||
conversationDeletes = data.threadDeletes.mapNotNull { threadDelete ->
|
||||
val conversation = Recipient.resolved(RecipientId.from(threadDelete.threadRecipientId)).toDeleteSyncConversationId()
|
||||
if (conversation != null) {
|
||||
DeleteForMe.ConversationDelete(
|
||||
conversation = conversation,
|
||||
mostRecentMessages = it.messages.mapNotNull { m -> m.toDeleteSyncMessage() },
|
||||
isFullDelete = it.isFullDelete
|
||||
mostRecentMessages = threadDelete.messages.mapNotNull { it.toDeleteSyncMessage() },
|
||||
isFullDelete = threadDelete.isFullDelete,
|
||||
mostRecentNonExpiringMessages = threadDelete.messages.mapNotNull { it.toDeleteSyncMessage() }
|
||||
)
|
||||
} else {
|
||||
Log.w(TAG, "Unable to resolve ${it.threadRecipientId} to conversation id")
|
||||
Log.w(TAG, "Unable to resolve ${threadDelete.threadRecipientId} to conversation id")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -408,9 +416,9 @@ class MultiDeviceDeleteSendSyncJob private constructor(
|
|||
}
|
||||
}
|
||||
|
||||
class Factory : Job.Factory<MultiDeviceDeleteSendSyncJob> {
|
||||
override fun create(parameters: Parameters, serializedData: ByteArray?): MultiDeviceDeleteSendSyncJob {
|
||||
return MultiDeviceDeleteSendSyncJob(DeleteSyncJobData.ADAPTER.decode(serializedData!!), parameters)
|
||||
class Factory : Job.Factory<MultiDeviceDeleteSyncJob> {
|
||||
override fun create(parameters: Parameters, serializedData: ByteArray?): MultiDeviceDeleteSyncJob {
|
||||
return MultiDeviceDeleteSyncJob(DeleteSyncJobData.ADAPTER.decode(serializedData!!), parameters)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.MediaTable;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSendSyncJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
||||
|
@ -87,7 +87,7 @@ final class MediaActions {
|
|||
}
|
||||
|
||||
if (Recipient.self().getDeleteSyncCapability().isSupported() && Util.hasItems(deletedMessageRecords)) {
|
||||
MultiDeviceDeleteSendSyncJob.enqueueMessageDeletes(deletedMessageRecords);
|
||||
MultiDeviceDeleteSyncJob.enqueueMessageDeletes(deletedMessageRecords);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase
|
|||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.media
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSendSyncJob
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob
|
||||
import org.thoughtcrime.securesms.longmessage.resolveBody
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
@ -86,7 +86,7 @@ class MediaPreviewRepository {
|
|||
return Completable.fromRunnable {
|
||||
val deletedMessageRecord = AttachmentUtil.deleteAttachment(attachment)
|
||||
if (deletedMessageRecord != null && Recipient.self().deleteSyncCapability.isSupported) {
|
||||
MultiDeviceDeleteSendSyncJob.enqueueMessageDeletes(setOf(deletedMessageRecord))
|
||||
MultiDeviceDeleteSyncJob.enqueueMessageDeletes(setOf(deletedMessageRecord))
|
||||
}
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
|
|
@ -1536,8 +1536,12 @@ object SyncMessageProcessor {
|
|||
continue
|
||||
}
|
||||
|
||||
val mostRecentMessagesToDelete: List<MessageTable.SyncMessageId> = delete.mostRecentMessages.mapNotNull { it.toSyncMessageId(envelopeTimestamp) }
|
||||
val latestReceivedAt = SignalDatabase.messages.getLatestReceivedAt(threadId, mostRecentMessagesToDelete)
|
||||
var latestReceivedAt = SignalDatabase.messages.getLatestReceivedAt(threadId, delete.mostRecentMessages.mapNotNull { it.toSyncMessageId(envelopeTimestamp) })
|
||||
|
||||
if (latestReceivedAt == null && delete.mostRecentNonExpiringMessages.isNotEmpty()) {
|
||||
log(envelopeTimestamp, "[handleSynchronizeDeleteForMe] Using backup non-expiring messages")
|
||||
latestReceivedAt = SignalDatabase.messages.getLatestReceivedAt(threadId, delete.mostRecentNonExpiringMessages.mapNotNull { it.toSyncMessageId(envelopeTimestamp) })
|
||||
}
|
||||
|
||||
if (latestReceivedAt != null) {
|
||||
SignalDatabase.threads.trimThread(threadId = threadId, syncThreadTrimDeletes = false, trimBeforeDate = latestReceivedAt, inclusive = true)
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
|||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NotInCallConstraint;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSendSyncJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -105,7 +105,7 @@ public class AttachmentUtil {
|
|||
} else {
|
||||
SignalDatabase.attachments().deleteAttachment(attachmentId);
|
||||
if (Recipient.self().getDeleteSyncCapability().isSupported()) {
|
||||
MultiDeviceDeleteSendSyncJob.enqueueAttachmentDelete(SignalDatabase.messages().getMessageRecordOrNull(mmsId), attachment);
|
||||
MultiDeviceDeleteSyncJob.enqueueAttachmentDelete(SignalDatabase.messages().getMessageRecordOrNull(mmsId), attachment);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.signal.core.util.concurrent.SignalExecutors
|
|||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSendSyncJob
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.sms.MessageSender
|
||||
|
@ -122,7 +122,7 @@ object DeleteDialog {
|
|||
}
|
||||
|
||||
if (Recipient.self().deleteSyncCapability.isSupported) {
|
||||
MultiDeviceDeleteSendSyncJob.enqueueMessageDeletes(messageRecords)
|
||||
MultiDeviceDeleteSyncJob.enqueueMessageDeletes(messageRecords)
|
||||
}
|
||||
|
||||
return threadDeleted
|
||||
|
|
|
@ -100,6 +100,7 @@ message DeleteSyncJobData {
|
|||
uint64 threadRecipientId = 1;
|
||||
repeated AddressableMessage messages = 2;
|
||||
bool isFullDelete = 3;
|
||||
repeated AddressableMessage nonExpiringMessages = 4;
|
||||
}
|
||||
|
||||
repeated AddressableMessage messageDeletes = 1;
|
||||
|
|
|
@ -687,6 +687,7 @@ message SyncMessage {
|
|||
message ConversationDelete {
|
||||
optional ConversationIdentifier conversation = 1;
|
||||
repeated AddressableMessage mostRecentMessages = 2;
|
||||
repeated AddressableMessage mostRecentNonExpiringMessages = 4;
|
||||
optional bool isFullDelete = 3;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue