Add notification profile id for backupsv2.

This commit is contained in:
Cody Henthorne
2025-04-21 16:43:19 -04:00
parent b4a9189068
commit 4304ae2a96
21 changed files with 114 additions and 10 deletions

View File

@@ -187,6 +187,10 @@ object ImportSkips {
return log(0, "Failed to parse chatFolderId for the provided chat folder.")
}
fun notificationProfileIdNotFound(): String {
return log(0, "Failed to parse notificationProfileId for the provided notification profile.")
}
private fun log(sentTimestamp: Long, message: String): String {
return "[SKIP][$sentTimestamp] $message"
}

View File

@@ -5,10 +5,12 @@
package org.thoughtcrime.securesms.backup.v2.processor
import okio.ByteString.Companion.toByteString
import org.signal.core.util.insertInto
import org.signal.core.util.logging.Log
import org.signal.core.util.toInt
import org.thoughtcrime.securesms.backup.v2.ExportState
import org.thoughtcrime.securesms.backup.v2.ImportSkips
import org.thoughtcrime.securesms.backup.v2.ImportState
import org.thoughtcrime.securesms.backup.v2.proto.Frame
import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter
@@ -20,7 +22,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.serialize
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import org.thoughtcrime.securesms.recipients.RecipientId
import java.lang.IllegalStateException
import org.whispersystems.signalservice.api.util.UuidUtil
import java.time.DayOfWeek
import org.thoughtcrime.securesms.backup.v2.proto.NotificationProfile as NotificationProfileProto
@@ -41,6 +43,12 @@ object NotificationProfileProcessor {
}
fun import(profile: NotificationProfileProto, importState: ImportState) {
val notificationProfileUuid = UuidUtil.parseOrNull(profile.id)
if (notificationProfileUuid == null) {
ImportSkips.notificationProfileIdNotFound()
return
}
val profileId = SignalDatabase
.writableDatabase
.insertInto(NotificationProfileTable.TABLE_NAME)
@@ -50,7 +58,8 @@ object NotificationProfileProcessor {
NotificationProfileTable.COLOR to (AvatarColor.fromColor(profile.color) ?: AvatarColor.random()).serialize(),
NotificationProfileTable.CREATED_AT to profile.createdAtMs,
NotificationProfileTable.ALLOW_ALL_CALLS to profile.allowAllCalls.toInt(),
NotificationProfileTable.ALLOW_ALL_MENTIONS to profile.allowAllMentions.toInt()
NotificationProfileTable.ALLOW_ALL_MENTIONS to profile.allowAllMentions.toInt(),
NotificationProfileTable.NOTIFICATION_PROFILE_ID to notificationProfileUuid.toString()
)
.run()
@@ -89,6 +98,7 @@ object NotificationProfileProcessor {
private fun NotificationProfile.toBackupFrame(includeRecipient: (RecipientId) -> Boolean): Frame {
val profile = NotificationProfileProto(
id = UuidUtil.toByteArray(this.notificationProfileId.uuid).toByteString(),
name = this.name,
emoji = this.emoji.takeIf { it.isNotBlank() },
color = this.color.colorInt(),

View File

@@ -11,12 +11,14 @@ import org.signal.core.util.logging.Log
import org.signal.core.util.requireBoolean
import org.signal.core.util.requireInt
import org.signal.core.util.requireLong
import org.signal.core.util.requireNonNullString
import org.signal.core.util.requireString
import org.signal.core.util.toInt
import org.signal.core.util.update
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileId
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileSchedule
import org.thoughtcrime.securesms.recipients.RecipientId
import java.time.DayOfWeek
@@ -46,6 +48,7 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
const val CREATED_AT = "created_at"
const val ALLOW_ALL_CALLS = "allow_all_calls"
const val ALLOW_ALL_MENTIONS = "allow_all_mentions"
const val NOTIFICATION_PROFILE_ID = "notification_profile_id"
val CREATE_TABLE = """
CREATE TABLE $TABLE_NAME (
@@ -55,7 +58,8 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
$COLOR TEXT NOT NULL,
$CREATED_AT INTEGER NOT NULL,
$ALLOW_ALL_CALLS INTEGER NOT NULL DEFAULT 0,
$ALLOW_ALL_MENTIONS INTEGER NOT NULL DEFAULT 0
$ALLOW_ALL_MENTIONS INTEGER NOT NULL DEFAULT 0,
$NOTIFICATION_PROFILE_ID TEXT DEFAULT NULL
)
"""
}
@@ -110,12 +114,14 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
db.beginTransaction()
try {
val notificationProfileId = NotificationProfileId.generate()
val profileValues = ContentValues().apply {
put(NotificationProfileTable.NAME, name)
put(NotificationProfileTable.EMOJI, emoji)
put(NotificationProfileTable.COLOR, color.serialize())
put(NotificationProfileTable.CREATED_AT, createdAt)
put(NotificationProfileTable.ALLOW_ALL_CALLS, 1)
put(NotificationProfileTable.NOTIFICATION_PROFILE_ID, notificationProfileId.serialize())
}
val profileId = db.insert(NotificationProfileTable.TABLE_NAME, null, profileValues)
@@ -140,7 +146,8 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
emoji = emoji,
createdAt = createdAt,
schedule = getProfileSchedule(profileId),
allowAllCalls = true
allowAllCalls = true,
notificationProfileId = notificationProfileId
)
)
} finally {
@@ -323,7 +330,8 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
allowAllCalls = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_CALLS),
allowAllMentions = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_MENTIONS),
schedule = getProfileSchedule(profileId),
allowedMembers = getProfileAllowedMembers(profileId)
allowedMembers = getProfileAllowedMembers(profileId),
notificationProfileId = NotificationProfileId.from(cursor.requireNonNullString(NotificationProfileTable.NOTIFICATION_PROFILE_ID))
)
}

View File

@@ -125,6 +125,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V267_FixGroupInvita
import org.thoughtcrime.securesms.database.helpers.migration.V268_FixInAppPaymentsErrorStateConsistency
import org.thoughtcrime.securesms.database.helpers.migration.V269_BackupMediaSnapshotChanges
import org.thoughtcrime.securesms.database.helpers.migration.V270_FixChatFolderColumnsForStorageSync
import org.thoughtcrime.securesms.database.helpers.migration.V271_AddNotificationProfileIdColumn
import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSqliteDatabase
/**
@@ -255,10 +256,11 @@ object SignalDatabaseMigrations {
267 to V267_FixGroupInvitationDeclinedUpdate,
268 to V268_FixInAppPaymentsErrorStateConsistency,
269 to V269_BackupMediaSnapshotChanges,
270 to V270_FixChatFolderColumnsForStorageSync
270 to V270_FixChatFolderColumnsForStorageSync,
271 to V271_AddNotificationProfileIdColumn
)
const val DATABASE_VERSION = 270
const val DATABASE_VERSION = 271
@JvmStatic
fun migrate(context: Application, db: SignalSqliteDatabase, oldVersion: Int, newVersion: Int) {

View File

@@ -0,0 +1,28 @@
/*
* 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.signal.core.util.readToList
import org.signal.core.util.requireLong
import org.thoughtcrime.securesms.database.SQLiteDatabase
import java.util.UUID
/**
* Add notification_profile_id column to Notification Profiles to support backups.
*/
@Suppress("ClassName")
object V271_AddNotificationProfileIdColumn : SignalDatabaseMigration {
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("ALTER TABLE notification_profile ADD COLUMN notification_profile_id TEXT DEFAULT NULL")
db.rawQuery("SELECT _id FROM notification_profile")
.readToList { it.requireLong("_id") }
.forEach { id ->
db.execSQL("UPDATE notification_profile SET notification_profile_id = '${UUID.randomUUID()}' WHERE _id = $id")
}
}
}

View File

@@ -12,7 +12,8 @@ data class NotificationProfile(
val allowAllCalls: Boolean = true,
val allowAllMentions: Boolean = false,
val schedule: NotificationProfileSchedule,
val allowedMembers: Set<RecipientId> = emptySet()
val allowedMembers: Set<RecipientId> = emptySet(),
val notificationProfileId: NotificationProfileId
) : Comparable<NotificationProfile> {
fun isRecipientAllowed(id: RecipientId): Boolean {

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.notifications.profiles
import org.signal.core.util.DatabaseId
import org.whispersystems.signalservice.api.util.UuidUtil
import java.util.UUID
/**
* Typed wrapper for notification profile uuid.
*/
data class NotificationProfileId(val uuid: UUID) : DatabaseId {
companion object {
fun from(id: String): NotificationProfileId {
return NotificationProfileId(UuidUtil.parseOrThrow(id))
}
fun generate(): NotificationProfileId {
return NotificationProfileId(UUID.randomUUID())
}
}
override fun serialize(): String {
return uuid.toString()
}
}