mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 20:48:43 +00:00
Add notification profile id for backupsv2.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -187,6 +187,10 @@ object ImportSkips {
|
|||||||
return log(0, "Failed to parse chatFolderId for the provided chat folder.")
|
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 {
|
private fun log(sentTimestamp: Long, message: String): String {
|
||||||
return "[SKIP][$sentTimestamp] $message"
|
return "[SKIP][$sentTimestamp] $message"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
package org.thoughtcrime.securesms.backup.v2.processor
|
package org.thoughtcrime.securesms.backup.v2.processor
|
||||||
|
|
||||||
|
import okio.ByteString.Companion.toByteString
|
||||||
import org.signal.core.util.insertInto
|
import org.signal.core.util.insertInto
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.signal.core.util.toInt
|
import org.signal.core.util.toInt
|
||||||
import org.thoughtcrime.securesms.backup.v2.ExportState
|
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.ImportState
|
||||||
import org.thoughtcrime.securesms.backup.v2.proto.Frame
|
import org.thoughtcrime.securesms.backup.v2.proto.Frame
|
||||||
import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter
|
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.database.serialize
|
||||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
import java.lang.IllegalStateException
|
import org.whispersystems.signalservice.api.util.UuidUtil
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
import org.thoughtcrime.securesms.backup.v2.proto.NotificationProfile as NotificationProfileProto
|
import org.thoughtcrime.securesms.backup.v2.proto.NotificationProfile as NotificationProfileProto
|
||||||
|
|
||||||
@@ -41,6 +43,12 @@ object NotificationProfileProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun import(profile: NotificationProfileProto, importState: ImportState) {
|
fun import(profile: NotificationProfileProto, importState: ImportState) {
|
||||||
|
val notificationProfileUuid = UuidUtil.parseOrNull(profile.id)
|
||||||
|
if (notificationProfileUuid == null) {
|
||||||
|
ImportSkips.notificationProfileIdNotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val profileId = SignalDatabase
|
val profileId = SignalDatabase
|
||||||
.writableDatabase
|
.writableDatabase
|
||||||
.insertInto(NotificationProfileTable.TABLE_NAME)
|
.insertInto(NotificationProfileTable.TABLE_NAME)
|
||||||
@@ -50,7 +58,8 @@ object NotificationProfileProcessor {
|
|||||||
NotificationProfileTable.COLOR to (AvatarColor.fromColor(profile.color) ?: AvatarColor.random()).serialize(),
|
NotificationProfileTable.COLOR to (AvatarColor.fromColor(profile.color) ?: AvatarColor.random()).serialize(),
|
||||||
NotificationProfileTable.CREATED_AT to profile.createdAtMs,
|
NotificationProfileTable.CREATED_AT to profile.createdAtMs,
|
||||||
NotificationProfileTable.ALLOW_ALL_CALLS to profile.allowAllCalls.toInt(),
|
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()
|
.run()
|
||||||
|
|
||||||
@@ -89,6 +98,7 @@ object NotificationProfileProcessor {
|
|||||||
|
|
||||||
private fun NotificationProfile.toBackupFrame(includeRecipient: (RecipientId) -> Boolean): Frame {
|
private fun NotificationProfile.toBackupFrame(includeRecipient: (RecipientId) -> Boolean): Frame {
|
||||||
val profile = NotificationProfileProto(
|
val profile = NotificationProfileProto(
|
||||||
|
id = UuidUtil.toByteArray(this.notificationProfileId.uuid).toByteString(),
|
||||||
name = this.name,
|
name = this.name,
|
||||||
emoji = this.emoji.takeIf { it.isNotBlank() },
|
emoji = this.emoji.takeIf { it.isNotBlank() },
|
||||||
color = this.color.colorInt(),
|
color = this.color.colorInt(),
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ import org.signal.core.util.logging.Log
|
|||||||
import org.signal.core.util.requireBoolean
|
import org.signal.core.util.requireBoolean
|
||||||
import org.signal.core.util.requireInt
|
import org.signal.core.util.requireInt
|
||||||
import org.signal.core.util.requireLong
|
import org.signal.core.util.requireLong
|
||||||
|
import org.signal.core.util.requireNonNullString
|
||||||
import org.signal.core.util.requireString
|
import org.signal.core.util.requireString
|
||||||
import org.signal.core.util.toInt
|
import org.signal.core.util.toInt
|
||||||
import org.signal.core.util.update
|
import org.signal.core.util.update
|
||||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
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.notifications.profiles.NotificationProfileSchedule
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
@@ -46,6 +48,7 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
|
|||||||
const val CREATED_AT = "created_at"
|
const val CREATED_AT = "created_at"
|
||||||
const val ALLOW_ALL_CALLS = "allow_all_calls"
|
const val ALLOW_ALL_CALLS = "allow_all_calls"
|
||||||
const val ALLOW_ALL_MENTIONS = "allow_all_mentions"
|
const val ALLOW_ALL_MENTIONS = "allow_all_mentions"
|
||||||
|
const val NOTIFICATION_PROFILE_ID = "notification_profile_id"
|
||||||
|
|
||||||
val CREATE_TABLE = """
|
val CREATE_TABLE = """
|
||||||
CREATE TABLE $TABLE_NAME (
|
CREATE TABLE $TABLE_NAME (
|
||||||
@@ -55,7 +58,8 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
|
|||||||
$COLOR TEXT NOT NULL,
|
$COLOR TEXT NOT NULL,
|
||||||
$CREATED_AT INTEGER NOT NULL,
|
$CREATED_AT INTEGER NOT NULL,
|
||||||
$ALLOW_ALL_CALLS INTEGER NOT NULL DEFAULT 0,
|
$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()
|
db.beginTransaction()
|
||||||
try {
|
try {
|
||||||
|
val notificationProfileId = NotificationProfileId.generate()
|
||||||
val profileValues = ContentValues().apply {
|
val profileValues = ContentValues().apply {
|
||||||
put(NotificationProfileTable.NAME, name)
|
put(NotificationProfileTable.NAME, name)
|
||||||
put(NotificationProfileTable.EMOJI, emoji)
|
put(NotificationProfileTable.EMOJI, emoji)
|
||||||
put(NotificationProfileTable.COLOR, color.serialize())
|
put(NotificationProfileTable.COLOR, color.serialize())
|
||||||
put(NotificationProfileTable.CREATED_AT, createdAt)
|
put(NotificationProfileTable.CREATED_AT, createdAt)
|
||||||
put(NotificationProfileTable.ALLOW_ALL_CALLS, 1)
|
put(NotificationProfileTable.ALLOW_ALL_CALLS, 1)
|
||||||
|
put(NotificationProfileTable.NOTIFICATION_PROFILE_ID, notificationProfileId.serialize())
|
||||||
}
|
}
|
||||||
|
|
||||||
val profileId = db.insert(NotificationProfileTable.TABLE_NAME, null, profileValues)
|
val profileId = db.insert(NotificationProfileTable.TABLE_NAME, null, profileValues)
|
||||||
@@ -140,7 +146,8 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
|
|||||||
emoji = emoji,
|
emoji = emoji,
|
||||||
createdAt = createdAt,
|
createdAt = createdAt,
|
||||||
schedule = getProfileSchedule(profileId),
|
schedule = getProfileSchedule(profileId),
|
||||||
allowAllCalls = true
|
allowAllCalls = true,
|
||||||
|
notificationProfileId = notificationProfileId
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -323,7 +330,8 @@ class NotificationProfileTables(context: Context, databaseHelper: SignalDatabase
|
|||||||
allowAllCalls = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_CALLS),
|
allowAllCalls = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_CALLS),
|
||||||
allowAllMentions = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_MENTIONS),
|
allowAllMentions = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_MENTIONS),
|
||||||
schedule = getProfileSchedule(profileId),
|
schedule = getProfileSchedule(profileId),
|
||||||
allowedMembers = getProfileAllowedMembers(profileId)
|
allowedMembers = getProfileAllowedMembers(profileId),
|
||||||
|
notificationProfileId = NotificationProfileId.from(cursor.requireNonNullString(NotificationProfileTable.NOTIFICATION_PROFILE_ID))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.V268_FixInAppPaymentsErrorStateConsistency
|
||||||
import org.thoughtcrime.securesms.database.helpers.migration.V269_BackupMediaSnapshotChanges
|
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.V270_FixChatFolderColumnsForStorageSync
|
||||||
|
import org.thoughtcrime.securesms.database.helpers.migration.V271_AddNotificationProfileIdColumn
|
||||||
import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSqliteDatabase
|
import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSqliteDatabase
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -255,10 +256,11 @@ object SignalDatabaseMigrations {
|
|||||||
267 to V267_FixGroupInvitationDeclinedUpdate,
|
267 to V267_FixGroupInvitationDeclinedUpdate,
|
||||||
268 to V268_FixInAppPaymentsErrorStateConsistency,
|
268 to V268_FixInAppPaymentsErrorStateConsistency,
|
||||||
269 to V269_BackupMediaSnapshotChanges,
|
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
|
@JvmStatic
|
||||||
fun migrate(context: Application, db: SignalSqliteDatabase, oldVersion: Int, newVersion: Int) {
|
fun migrate(context: Application, db: SignalSqliteDatabase, oldVersion: Int, newVersion: Int) {
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@ data class NotificationProfile(
|
|||||||
val allowAllCalls: Boolean = true,
|
val allowAllCalls: Boolean = true,
|
||||||
val allowAllMentions: Boolean = false,
|
val allowAllMentions: Boolean = false,
|
||||||
val schedule: NotificationProfileSchedule,
|
val schedule: NotificationProfileSchedule,
|
||||||
val allowedMembers: Set<RecipientId> = emptySet()
|
val allowedMembers: Set<RecipientId> = emptySet(),
|
||||||
|
val notificationProfileId: NotificationProfileId
|
||||||
) : Comparable<NotificationProfile> {
|
) : Comparable<NotificationProfile> {
|
||||||
|
|
||||||
fun isRecipientAllowed(id: RecipientId): Boolean {
|
fun isRecipientAllowed(id: RecipientId): Boolean {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -724,11 +724,30 @@ message FilePointer {
|
|||||||
message InvalidAttachmentLocator {
|
message InvalidAttachmentLocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// References attachments in a local encrypted backup.
|
||||||
|
// Importers should first attempt to read the file from the local backup,
|
||||||
|
// and on failure fallback to backup and transit cdn if possible.
|
||||||
|
message LocalLocator {
|
||||||
|
string mediaName = 1;
|
||||||
|
// Separate key used to encrypt this file for the local backup.
|
||||||
|
// Generally required. Missing field indicates attachment was not
|
||||||
|
// available locally when the backup was generated, but remote
|
||||||
|
// backup or transit info was available.
|
||||||
|
optional bytes localKey = 2;
|
||||||
|
bytes remoteKey = 3;
|
||||||
|
bytes remoteDigest = 4;
|
||||||
|
uint32 size = 5;
|
||||||
|
optional uint32 backupCdnNumber = 6;
|
||||||
|
optional string transitCdnKey = 7;
|
||||||
|
optional uint32 transitCdnNumber = 8;
|
||||||
|
}
|
||||||
|
|
||||||
// If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error.
|
// If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error.
|
||||||
oneof locator {
|
oneof locator {
|
||||||
BackupLocator backupLocator = 1;
|
BackupLocator backupLocator = 1;
|
||||||
AttachmentLocator attachmentLocator = 2;
|
AttachmentLocator attachmentLocator = 2;
|
||||||
InvalidAttachmentLocator invalidAttachmentLocator = 3;
|
InvalidAttachmentLocator invalidAttachmentLocator = 3;
|
||||||
|
LocalLocator localLocator = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional string contentType = 4;
|
optional string contentType = 4;
|
||||||
@@ -1291,6 +1310,7 @@ message NotificationProfile {
|
|||||||
uint32 scheduleStartTime = 9; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345)
|
uint32 scheduleStartTime = 9; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345)
|
||||||
uint32 scheduleEndTime = 10; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345)
|
uint32 scheduleEndTime = 10; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345)
|
||||||
repeated DayOfWeek scheduleDaysEnabled = 11;
|
repeated DayOfWeek scheduleDaysEnabled = 11;
|
||||||
|
bytes id = 12; // should be 16 bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
message ChatFolder {
|
message ChatFolder {
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ class NotificationProfilesTest {
|
|||||||
"first",
|
"first",
|
||||||
"",
|
"",
|
||||||
createdAt = 1000L,
|
createdAt = 1000L,
|
||||||
schedule = NotificationProfileSchedule(1)
|
schedule = NotificationProfileSchedule(1),
|
||||||
|
notificationProfileId = NotificationProfileId.generate()
|
||||||
)
|
)
|
||||||
|
|
||||||
private val second = NotificationProfile(
|
private val second = NotificationProfile(
|
||||||
@@ -49,7 +50,8 @@ class NotificationProfilesTest {
|
|||||||
"second",
|
"second",
|
||||||
"",
|
"",
|
||||||
createdAt = 2000L,
|
createdAt = 2000L,
|
||||||
schedule = NotificationProfileSchedule(2)
|
schedule = NotificationProfileSchedule(2),
|
||||||
|
notificationProfileId = NotificationProfileId.generate()
|
||||||
)
|
)
|
||||||
|
|
||||||
private lateinit var notificationProfileValues: NotificationProfileValues
|
private lateinit var notificationProfileValues: NotificationProfileValues
|
||||||
|
|||||||
Reference in New Issue
Block a user