mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 09:49:30 +01:00
Add initial support for backup and restore of message and media to staging.
Co-authored-by: Cody Henthorne <cody@signal.org>
This commit is contained in:
@@ -52,13 +52,16 @@ import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.requireNonNullBlob
|
||||
import org.signal.core.util.requireNonNullString
|
||||
import org.signal.core.util.requireObject
|
||||
import org.signal.core.util.requireString
|
||||
import org.signal.core.util.select
|
||||
import org.signal.core.util.toInt
|
||||
import org.signal.core.util.update
|
||||
import org.signal.core.util.withinTransaction
|
||||
import org.thoughtcrime.securesms.attachments.ArchivedAttachment
|
||||
import org.thoughtcrime.securesms.attachments.Attachment
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId
|
||||
import org.thoughtcrime.securesms.attachments.Cdn
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.audio.AudioHash
|
||||
import org.thoughtcrime.securesms.blurhash.BlurHash
|
||||
@@ -140,6 +143,10 @@ class AttachmentTable(
|
||||
const val TRANSFORM_PROPERTIES = "transform_properties"
|
||||
const val DISPLAY_ORDER = "display_order"
|
||||
const val UPLOAD_TIMESTAMP = "upload_timestamp"
|
||||
const val ARCHIVE_CDN = "archive_cdn"
|
||||
const val ARCHIVE_MEDIA_NAME = "archive_media_name"
|
||||
const val ARCHIVE_MEDIA_ID = "archive_media_id"
|
||||
const val ARCHIVE_TRANSFER_FILE = "archive_transfer_file"
|
||||
|
||||
const val ATTACHMENT_JSON_ALIAS = "attachment_json"
|
||||
|
||||
@@ -150,6 +157,8 @@ class AttachmentTable(
|
||||
const val TRANSFER_PROGRESS_PENDING = 2
|
||||
const val TRANSFER_PROGRESS_FAILED = 3
|
||||
const val TRANSFER_PROGRESS_PERMANENT_FAILURE = 4
|
||||
const val TRANSFER_NEEDS_RESTORE = 5
|
||||
const val TRANSFER_RESTORE_IN_PROGRESS = 6
|
||||
const val PREUPLOAD_MESSAGE_ID: Long = -8675309
|
||||
|
||||
private val PROJECTION = arrayOf(
|
||||
@@ -185,7 +194,11 @@ class AttachmentTable(
|
||||
DISPLAY_ORDER,
|
||||
UPLOAD_TIMESTAMP,
|
||||
DATA_HASH_START,
|
||||
DATA_HASH_END
|
||||
DATA_HASH_END,
|
||||
ARCHIVE_CDN,
|
||||
ARCHIVE_MEDIA_NAME,
|
||||
ARCHIVE_MEDIA_ID,
|
||||
ARCHIVE_TRANSFER_FILE
|
||||
)
|
||||
|
||||
const val CREATE_TABLE = """
|
||||
@@ -222,7 +235,11 @@ class AttachmentTable(
|
||||
$DISPLAY_ORDER INTEGER DEFAULT 0,
|
||||
$UPLOAD_TIMESTAMP INTEGER DEFAULT 0,
|
||||
$DATA_HASH_START TEXT DEFAULT NULL,
|
||||
$DATA_HASH_END TEXT DEFAULT NULL
|
||||
$DATA_HASH_END TEXT DEFAULT NULL,
|
||||
$ARCHIVE_CDN INTEGER DEFAULT 0,
|
||||
$ARCHIVE_MEDIA_NAME TEXT DEFAULT NULL,
|
||||
$ARCHIVE_MEDIA_ID TEXT DEFAULT NULL,
|
||||
$ARCHIVE_TRANSFER_FILE TEXT DEFAULT NULL
|
||||
)
|
||||
"""
|
||||
|
||||
@@ -239,7 +256,6 @@ class AttachmentTable(
|
||||
val ATTACHMENT_POINTER_REUSE_THRESHOLD = 7.days.inWholeMilliseconds
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun newDataFile(context: Context): File {
|
||||
val partsDirectory = context.getDir(DIRECTORY, Context.MODE_PRIVATE)
|
||||
@@ -388,6 +404,27 @@ class AttachmentTable(
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fun getArchivableAttachments(): Cursor {
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$ARCHIVE_MEDIA_ID IS NULL AND $REMOTE_DIGEST IS NOT NULL AND ($TRANSFER_STATE = ? OR $TRANSFER_STATE = ?)", TRANSFER_PROGRESS_DONE.toString(), TRANSFER_NEEDS_RESTORE.toString())
|
||||
.orderBy("$ID DESC")
|
||||
.run()
|
||||
}
|
||||
|
||||
fun getRestorableAttachments(batchSize: Int): List<DatabaseAttachment> {
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE.toString())
|
||||
.limit(batchSize)
|
||||
.orderBy("$ID DESC")
|
||||
.run().readToList {
|
||||
it.readAttachments()
|
||||
}.flatten()
|
||||
}
|
||||
|
||||
fun deleteAttachmentsForMessage(mmsId: Long): Boolean {
|
||||
Log.d(TAG, "[deleteAttachmentsForMessage] mmsId: $mmsId")
|
||||
|
||||
@@ -679,6 +716,7 @@ class AttachmentTable(
|
||||
values.put(TRANSFER_STATE, TRANSFER_PROGRESS_DONE)
|
||||
values.put(TRANSFER_FILE, null as String?)
|
||||
values.put(TRANSFORM_PROPERTIES, TransformProperties.forSkipTransform().serialize())
|
||||
values.put(ARCHIVE_TRANSFER_FILE, null as String?)
|
||||
|
||||
db.update(TABLE_NAME)
|
||||
.values(values)
|
||||
@@ -734,7 +772,7 @@ class AttachmentTable(
|
||||
|
||||
val values = contentValuesOf(
|
||||
TRANSFER_STATE to TRANSFER_PROGRESS_DONE,
|
||||
CDN_NUMBER to attachment.cdnNumber,
|
||||
CDN_NUMBER to attachment.cdn.serialize(),
|
||||
REMOTE_LOCATION to attachment.remoteLocation,
|
||||
REMOTE_DIGEST to attachment.remoteDigest,
|
||||
REMOTE_INCREMENTAL_DIGEST to attachment.incrementalDigest,
|
||||
@@ -774,7 +812,7 @@ class AttachmentTable(
|
||||
DATA_SIZE to sourceDataInfo.length,
|
||||
DATA_RANDOM to sourceDataInfo.random,
|
||||
TRANSFER_STATE to sourceAttachment.transferState,
|
||||
CDN_NUMBER to sourceAttachment.cdnNumber,
|
||||
CDN_NUMBER to sourceAttachment.cdn.serialize(),
|
||||
REMOTE_LOCATION to sourceAttachment.remoteLocation,
|
||||
REMOTE_DIGEST to sourceAttachment.remoteDigest,
|
||||
REMOTE_INCREMENTAL_DIGEST to sourceAttachment.incrementalDigest,
|
||||
@@ -865,7 +903,11 @@ class AttachmentTable(
|
||||
val attachmentId = if (attachment.uri != null) {
|
||||
insertAttachmentWithData(mmsId, attachment, attachment.quote)
|
||||
} else {
|
||||
insertUndownloadedAttachment(mmsId, attachment, attachment.quote)
|
||||
if (attachment is ArchivedAttachment) {
|
||||
insertArchivedAttachment(mmsId, attachment, attachment.quote)
|
||||
} else {
|
||||
insertUndownloadedAttachment(mmsId, attachment, attachment.quote)
|
||||
}
|
||||
}
|
||||
|
||||
insertedAttachments[attachment] = attachmentId
|
||||
@@ -890,6 +932,75 @@ class AttachmentTable(
|
||||
return insertedAttachments
|
||||
}
|
||||
|
||||
fun debugCopyAttachmentForArchiveRestore(
|
||||
mmsId: Long,
|
||||
attachment: DatabaseAttachment
|
||||
) {
|
||||
val copy =
|
||||
"""
|
||||
INSERT INTO $TABLE_NAME
|
||||
(
|
||||
$MESSAGE_ID,
|
||||
$CONTENT_TYPE,
|
||||
$TRANSFER_STATE,
|
||||
$CDN_NUMBER,
|
||||
$REMOTE_LOCATION,
|
||||
$REMOTE_DIGEST,
|
||||
$REMOTE_INCREMENTAL_DIGEST,
|
||||
$REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE,
|
||||
$REMOTE_KEY,
|
||||
$FILE_NAME,
|
||||
$DATA_SIZE,
|
||||
$VOICE_NOTE,
|
||||
$BORDERLESS,
|
||||
$VIDEO_GIF,
|
||||
$WIDTH,
|
||||
$HEIGHT,
|
||||
$CAPTION,
|
||||
$UPLOAD_TIMESTAMP,
|
||||
$BLUR_HASH,
|
||||
$DATA_SIZE,
|
||||
$DATA_RANDOM,
|
||||
$DATA_HASH_START,
|
||||
$DATA_HASH_END,
|
||||
$ARCHIVE_MEDIA_ID,
|
||||
$ARCHIVE_MEDIA_NAME,
|
||||
$ARCHIVE_CDN
|
||||
)
|
||||
SELECT
|
||||
$mmsId,
|
||||
$CONTENT_TYPE,
|
||||
$TRANSFER_PROGRESS_PENDING,
|
||||
$CDN_NUMBER,
|
||||
$REMOTE_LOCATION,
|
||||
$REMOTE_DIGEST,
|
||||
$REMOTE_INCREMENTAL_DIGEST,
|
||||
$REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE,
|
||||
$REMOTE_KEY,
|
||||
$FILE_NAME,
|
||||
$DATA_SIZE,
|
||||
$VOICE_NOTE,
|
||||
$BORDERLESS,
|
||||
$VIDEO_GIF,
|
||||
$WIDTH,
|
||||
$HEIGHT,
|
||||
$CAPTION,
|
||||
${System.currentTimeMillis()},
|
||||
$BLUR_HASH,
|
||||
$DATA_SIZE,
|
||||
$DATA_RANDOM,
|
||||
$DATA_HASH_START,
|
||||
$DATA_HASH_END,
|
||||
"${attachment.archiveMediaId}",
|
||||
"${attachment.archiveMediaName}",
|
||||
${attachment.archiveCdn}
|
||||
FROM $TABLE_NAME
|
||||
WHERE $ID = ${attachment.attachmentId.id}
|
||||
"""
|
||||
|
||||
writableDatabase.execSQL(copy)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the data stored for an existing attachment. This happens after transformations, like transcoding.
|
||||
*/
|
||||
@@ -956,6 +1067,24 @@ class AttachmentTable(
|
||||
return transferFile
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getOrCreateArchiveTransferFile(attachmentId: AttachmentId): File {
|
||||
val existing = getArchiveTransferFile(writableDatabase, attachmentId)
|
||||
if (existing != null) {
|
||||
return existing
|
||||
}
|
||||
|
||||
val transferFile = newTransferFile()
|
||||
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(ARCHIVE_TRANSFER_FILE to transferFile.absolutePath)
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
|
||||
return transferFile
|
||||
}
|
||||
|
||||
fun getDataFileInfo(attachmentId: AttachmentId): DataFileInfo? {
|
||||
return readableDatabase
|
||||
.select(ID, DATA_FILE, DATA_SIZE, DATA_RANDOM, DATA_HASH_START, DATA_HASH_END, TRANSFORM_PROPERTIES, UPLOAD_TIMESTAMP)
|
||||
@@ -1087,7 +1216,7 @@ class AttachmentTable(
|
||||
transferProgress = jsonObject.getInt(TRANSFER_STATE),
|
||||
size = jsonObject.getLong(DATA_SIZE),
|
||||
fileName = jsonObject.getString(FILE_NAME),
|
||||
cdnNumber = jsonObject.getInt(CDN_NUMBER),
|
||||
cdn = Cdn.deserialize(jsonObject.getInt(CDN_NUMBER)),
|
||||
location = jsonObject.getString(REMOTE_LOCATION),
|
||||
key = jsonObject.getString(REMOTE_KEY),
|
||||
digest = null,
|
||||
@@ -1116,7 +1245,10 @@ class AttachmentTable(
|
||||
transformProperties = TransformProperties.parse(jsonObject.getString(TRANSFORM_PROPERTIES)),
|
||||
displayOrder = jsonObject.getInt(DISPLAY_ORDER),
|
||||
uploadTimestamp = jsonObject.getLong(UPLOAD_TIMESTAMP),
|
||||
dataHash = jsonObject.getString(DATA_HASH_END)
|
||||
dataHash = jsonObject.getString(DATA_HASH_END),
|
||||
archiveCdn = jsonObject.getInt(ARCHIVE_CDN),
|
||||
archiveMediaName = jsonObject.getString(ARCHIVE_MEDIA_NAME),
|
||||
archiveMediaId = jsonObject.getString(ARCHIVE_MEDIA_ID)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1156,6 +1288,45 @@ class AttachmentTable(
|
||||
return readableDatabase.rawQuery(query, null)
|
||||
}
|
||||
|
||||
fun setArchiveData(attachmentId: AttachmentId, archiveCdn: Int, archiveMediaName: String, archiveMediaId: String) {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
ARCHIVE_CDN to archiveCdn,
|
||||
ARCHIVE_MEDIA_ID to archiveMediaId,
|
||||
ARCHIVE_MEDIA_NAME to archiveMediaName
|
||||
)
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.run()
|
||||
}
|
||||
|
||||
fun clearArchiveData(attachmentIds: List<AttachmentId>) {
|
||||
SqlUtil.buildCollectionQuery(ID, attachmentIds.map { it.id })
|
||||
.forEach { query ->
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
ARCHIVE_CDN to 0,
|
||||
ARCHIVE_MEDIA_ID to null,
|
||||
ARCHIVE_MEDIA_NAME to null
|
||||
)
|
||||
.where(query.where, query.whereArgs)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
|
||||
fun clearAllArchiveData() {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
ARCHIVE_CDN to 0,
|
||||
ARCHIVE_MEDIA_ID to null,
|
||||
ARCHIVE_MEDIA_NAME to null
|
||||
)
|
||||
.where("$ARCHIVE_CDN > 0 OR $ARCHIVE_MEDIA_ID IS NOT NULL OR $ARCHIVE_MEDIA_NAME IS NOT NULL")
|
||||
.run()
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the data file if there's no strong references to other attachments.
|
||||
* If deleted, it will also clear all weak references (i.e. quotes) of the attachment.
|
||||
@@ -1338,7 +1509,7 @@ class AttachmentTable(
|
||||
put(MESSAGE_ID, messageId)
|
||||
put(CONTENT_TYPE, attachment.contentType)
|
||||
put(TRANSFER_STATE, attachment.transferState)
|
||||
put(CDN_NUMBER, attachment.cdnNumber)
|
||||
put(CDN_NUMBER, attachment.cdn.serialize())
|
||||
put(REMOTE_LOCATION, attachment.remoteLocation)
|
||||
put(REMOTE_DIGEST, attachment.remoteDigest)
|
||||
put(REMOTE_INCREMENTAL_DIGEST, attachment.incrementalDigest)
|
||||
@@ -1373,6 +1544,59 @@ class AttachmentTable(
|
||||
return attachmentId
|
||||
}
|
||||
|
||||
/**
|
||||
* Attachments need records in the database even if they haven't been downloaded yet. That allows us to store the info we need to download it, what message
|
||||
* it's associated with, etc. We treat this case separately from attachments with data (see [insertAttachmentWithData]) because it's much simpler,
|
||||
* and splitting the two use cases makes the code easier to understand.
|
||||
*
|
||||
* Callers are expected to later call [finalizeAttachmentAfterDownload] once they have downloaded the data for this attachment.
|
||||
*/
|
||||
@Throws(MmsException::class)
|
||||
private fun insertArchivedAttachment(messageId: Long, attachment: ArchivedAttachment, quote: Boolean): AttachmentId {
|
||||
Log.d(TAG, "[insertAttachment] Inserting attachment for messageId $messageId.")
|
||||
|
||||
val attachmentId: AttachmentId = writableDatabase.withinTransaction { db ->
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MESSAGE_ID, messageId)
|
||||
put(CONTENT_TYPE, attachment.contentType)
|
||||
put(TRANSFER_STATE, attachment.transferState)
|
||||
put(CDN_NUMBER, attachment.cdn.serialize())
|
||||
put(REMOTE_LOCATION, attachment.remoteLocation)
|
||||
put(REMOTE_DIGEST, attachment.remoteDigest)
|
||||
put(REMOTE_INCREMENTAL_DIGEST, attachment.incrementalDigest)
|
||||
put(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE, attachment.incrementalMacChunkSize)
|
||||
put(REMOTE_KEY, attachment.remoteKey)
|
||||
put(FILE_NAME, StorageUtil.getCleanFileName(attachment.fileName))
|
||||
put(DATA_SIZE, attachment.size)
|
||||
put(FAST_PREFLIGHT_ID, attachment.fastPreflightId)
|
||||
put(VOICE_NOTE, attachment.voiceNote.toInt())
|
||||
put(BORDERLESS, attachment.borderless.toInt())
|
||||
put(VIDEO_GIF, attachment.videoGif.toInt())
|
||||
put(WIDTH, attachment.width)
|
||||
put(HEIGHT, attachment.height)
|
||||
put(QUOTE, quote)
|
||||
put(CAPTION, attachment.caption)
|
||||
put(UPLOAD_TIMESTAMP, attachment.uploadTimestamp)
|
||||
put(ARCHIVE_CDN, attachment.archiveCdn)
|
||||
put(ARCHIVE_MEDIA_NAME, attachment.archiveMediaName)
|
||||
put(ARCHIVE_MEDIA_ID, attachment.archiveMediaId)
|
||||
|
||||
attachment.stickerLocator?.let { sticker ->
|
||||
put(STICKER_PACK_ID, sticker.packId)
|
||||
put(STICKER_PACK_KEY, sticker.packKey)
|
||||
put(STICKER_ID, sticker.stickerId)
|
||||
put(STICKER_EMOJI, sticker.emoji)
|
||||
}
|
||||
}
|
||||
|
||||
val rowId = db.insert(TABLE_NAME, null, contentValues)
|
||||
AttachmentId(rowId)
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
return attachmentId
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an attachment with existing data. This is likely an outgoing attachment that we're in the process of sending.
|
||||
*/
|
||||
@@ -1462,7 +1686,7 @@ class AttachmentTable(
|
||||
contentValues.put(MESSAGE_ID, messageId)
|
||||
contentValues.put(CONTENT_TYPE, uploadTemplate?.contentType ?: attachment.contentType)
|
||||
contentValues.put(TRANSFER_STATE, attachment.transferState) // Even if we have a template, we let AttachmentUploadJob have the final say so it can re-check and make sure the template is still valid
|
||||
contentValues.put(CDN_NUMBER, uploadTemplate?.cdnNumber ?: 0)
|
||||
contentValues.put(CDN_NUMBER, uploadTemplate?.cdn?.serialize() ?: Cdn.CDN_0.serialize())
|
||||
contentValues.put(REMOTE_LOCATION, uploadTemplate?.remoteLocation)
|
||||
contentValues.put(REMOTE_DIGEST, uploadTemplate?.remoteDigest)
|
||||
contentValues.put(REMOTE_INCREMENTAL_DIGEST, uploadTemplate?.incrementalDigest)
|
||||
@@ -1520,6 +1744,18 @@ class AttachmentTable(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getArchiveTransferFile(db: SQLiteDatabase, attachmentId: AttachmentId): File? {
|
||||
return db
|
||||
.select(ARCHIVE_TRANSFER_FILE)
|
||||
.from(TABLE_NAME)
|
||||
.where("$ID = ?", attachmentId.id)
|
||||
.limit(1)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
cursor.requireString(ARCHIVE_TRANSFER_FILE)?.let { File(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAttachment(cursor: Cursor): DatabaseAttachment {
|
||||
val contentType = cursor.requireString(CONTENT_TYPE)
|
||||
|
||||
@@ -1532,7 +1768,7 @@ class AttachmentTable(
|
||||
transferProgress = cursor.requireInt(TRANSFER_STATE),
|
||||
size = cursor.requireLong(DATA_SIZE),
|
||||
fileName = cursor.requireString(FILE_NAME),
|
||||
cdnNumber = cursor.requireInt(CDN_NUMBER),
|
||||
cdn = cursor.requireObject(CDN_NUMBER, Cdn.Serializer),
|
||||
location = cursor.requireString(REMOTE_LOCATION),
|
||||
key = cursor.requireString(REMOTE_KEY),
|
||||
digest = cursor.requireBlob(REMOTE_DIGEST),
|
||||
@@ -1552,7 +1788,10 @@ class AttachmentTable(
|
||||
transformProperties = TransformProperties.parse(cursor.requireString(TRANSFORM_PROPERTIES)),
|
||||
displayOrder = cursor.requireInt(DISPLAY_ORDER),
|
||||
uploadTimestamp = cursor.requireLong(UPLOAD_TIMESTAMP),
|
||||
dataHash = cursor.requireString(DATA_HASH_END)
|
||||
dataHash = cursor.requireString(DATA_HASH_END),
|
||||
archiveCdn = cursor.requireInt(ARCHIVE_CDN),
|
||||
archiveMediaName = cursor.requireString(ARCHIVE_MEDIA_NAME),
|
||||
archiveMediaId = cursor.requireString(ARCHIVE_MEDIA_ID)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1603,7 +1842,7 @@ class AttachmentTable(
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$TRANSFER_STATE == $TRANSFER_PROGRESS_DONE AND $REMOTE_LOCATION IS NOT NULL AND $DATA_HASH_END IS NOT NULL")
|
||||
.where("$REMOTE_LOCATION IS NOT NULL AND $REMOTE_KEY IS NOT NULL")
|
||||
.orderBy("$ID DESC")
|
||||
.limit(30)
|
||||
.run()
|
||||
|
||||
@@ -56,6 +56,7 @@ import org.whispersystems.signalservice.api.groupsv2.findRequestingByAci
|
||||
import org.whispersystems.signalservice.api.groupsv2.toAciList
|
||||
import org.whispersystems.signalservice.api.groupsv2.toAciListWithUnknowns
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId
|
||||
import org.whispersystems.signalservice.api.push.DistributionId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
@@ -746,7 +747,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
values.put(MMS, groupId.isMms)
|
||||
|
||||
if (avatar != null) {
|
||||
values.put(AVATAR_ID, avatar.remoteId.v2.get())
|
||||
values.put(AVATAR_ID, (avatar.remoteId as SignalServiceAttachmentRemoteId.V2).cdnId)
|
||||
values.put(AVATAR_KEY, avatar.key)
|
||||
values.put(AVATAR_CONTENT_TYPE, avatar.contentType)
|
||||
values.put(AVATAR_DIGEST, avatar.digest.orElse(null))
|
||||
@@ -822,7 +823,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
}
|
||||
|
||||
if (avatar != null) {
|
||||
put(AVATAR_ID, avatar.remoteId.v2.get())
|
||||
put(AVATAR_ID, (avatar.remoteId as SignalServiceAttachmentRemoteId.V2).cdnId)
|
||||
put(AVATAR_CONTENT_TYPE, avatar.contentType)
|
||||
put(AVATAR_KEY, avatar.key)
|
||||
put(AVATAR_DIGEST, avatar.digest.orElse(null))
|
||||
|
||||
@@ -50,6 +50,9 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_HASH_END},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_CDN},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_NAME},
|
||||
${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_ID},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.TYPE},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_SENT},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
|
||||
|
||||
@@ -376,7 +376,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
'${AttachmentTable.BLUR_HASH}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.BLUR_HASH},
|
||||
'${AttachmentTable.TRANSFORM_PROPERTIES}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.TRANSFORM_PROPERTIES},
|
||||
'${AttachmentTable.DISPLAY_ORDER}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DISPLAY_ORDER},
|
||||
'${AttachmentTable.UPLOAD_TIMESTAMP}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.UPLOAD_TIMESTAMP}
|
||||
'${AttachmentTable.UPLOAD_TIMESTAMP}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.UPLOAD_TIMESTAMP},
|
||||
'${AttachmentTable.DATA_HASH_END}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.DATA_HASH_END},
|
||||
'${AttachmentTable.ARCHIVE_CDN}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_CDN},
|
||||
'${AttachmentTable.ARCHIVE_MEDIA_NAME}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_NAME},
|
||||
'${AttachmentTable.ARCHIVE_MEDIA_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_ID}
|
||||
)
|
||||
) AS ${AttachmentTable.ATTACHMENT_JSON_ALIAS}
|
||||
""".toSingleLine()
|
||||
|
||||
@@ -81,6 +81,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V220_PreKeyConstrai
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V221_AddReadColumnToCallEventsTable
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V222_DataHashRefactor
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V223_AddNicknameAndNoteFieldsToRecipientTable
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V224_AddAttachmentArchiveColumns
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
@@ -164,10 +165,11 @@ object SignalDatabaseMigrations {
|
||||
220 to V220_PreKeyConstraints,
|
||||
221 to V221_AddReadColumnToCallEventsTable,
|
||||
222 to V222_DataHashRefactor,
|
||||
223 to V223_AddNicknameAndNoteFieldsToRecipientTable
|
||||
223 to V223_AddNicknameAndNoteFieldsToRecipientTable,
|
||||
224 to V224_AddAttachmentArchiveColumns
|
||||
)
|
||||
|
||||
const val DATABASE_VERSION = 223
|
||||
const val DATABASE_VERSION = 224
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* Adds archive_cdn and archive_media to attachment.
|
||||
*/
|
||||
@Suppress("ClassName")
|
||||
object V224_AddAttachmentArchiveColumns : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("ALTER TABLE attachment ADD COLUMN archive_cdn INTEGER DEFAULT 0")
|
||||
db.execSQL("ALTER TABLE attachment ADD COLUMN archive_media_name TEXT DEFAULT NULL")
|
||||
db.execSQL("ALTER TABLE attachment ADD COLUMN archive_media_id TEXT DEFAULT NULL")
|
||||
db.execSQL("ALTER TABLE attachment ADD COLUMN archive_transfer_file TEXT DEFAULT NULL")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user