Sync backup tier to account record.

This commit is contained in:
Michelle Tang
2025-06-18 14:37:00 -04:00
parent fc1ed8934c
commit c75a6c9715
7 changed files with 62 additions and 0 deletions

View File

@@ -100,6 +100,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels
import org.thoughtcrime.securesms.notifications.NotificationIds
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.ServiceUtil
import org.thoughtcrime.securesms.util.toMillis
@@ -168,6 +169,7 @@ object BackupRepository {
Log.w(TAG, "Local device thought it was on PAID tier. Downgrading to FREE tier.")
SignalStore.backup.backupTier = MessageBackupTier.FREE
SignalStore.backup.backupExpiredAndDowngraded = true
scheduleSyncForAccountChange()
}
SignalStore.uiHints.markHasEverEnabledRemoteBackups()
@@ -1137,6 +1139,7 @@ object BackupRepository {
SignalStore.backup.lastCheckInMillis = System.currentTimeMillis()
SignalStore.backup.lastCheckInSnoozeMillis = 0
SignalStore.backup.clearDownloadNotifierState()
scheduleSyncForAccountChange()
}
/**
@@ -1655,6 +1658,11 @@ object BackupRepository {
RemoteConfig.restoreAfterRegistration
}
private fun scheduleSyncForAccountChange() {
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
StorageSyncHelper.scheduleSyncForDataChange()
}
private fun File.deleteAllFilesWithPrefix(prefix: String) {
this.listFiles()?.filter { it.name.startsWith(prefix) }?.forEach { it.delete() }
}

View File

@@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.jobs.InAppPaymentPurchaseTokenJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.RemoteConfig
import org.whispersystems.signalservice.api.storage.IAPSubscriptionId
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
@@ -236,6 +237,10 @@ class MessageBackupsFlowViewModel(
private fun validateTypeAndUpdateState(state: MessageBackupsFlowState): MessageBackupsFlowState {
return when (state.selectedMessageBackupTier!!) {
MessageBackupTier.FREE -> {
viewModelScope.launch(SignalDispatchers.IO) {
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
StorageSyncHelper.scheduleSyncForDataChange()
}
SignalStore.backup.backupTier = MessageBackupTier.FREE
SignalStore.uiHints.markHasEverEnabledRemoteBackups()

View File

@@ -26,6 +26,8 @@ import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.Environment
import org.thoughtcrime.securesms.util.InternetConnectionObserver
import org.thoughtcrime.securesms.util.RemoteConfig
@@ -108,6 +110,10 @@ class BackupsSettingsViewModel : ViewModel() {
fun onBackupTierInternalOverrideChanged(tier: MessageBackupTier?) {
SignalStore.backup.backupTierInternalOverride = tier
SignalStore.backup.deletionState = DeletionState.NONE
viewModelScope.launch(SignalDispatchers.Default) {
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
StorageSyncHelper.scheduleSyncForDataChange()
}
refreshState()
}
}

View File

@@ -18,6 +18,8 @@ import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.jobs.protos.BackupDeleteJobData
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.whispersystems.signalservice.api.NetworkResult
/**
@@ -219,6 +221,8 @@ class BackupDeleteJob private constructor(
Log.d(TAG, "Clearing local backup state.")
SignalStore.backup.disableBackups()
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
StorageSyncHelper.scheduleSyncForDataChange()
SignalDatabase.attachments.clearAllArchiveData()
addStageToCompletions(BackupDeleteJobData.Stage.CLEAR_LOCAL_STATE)
return Result.success()

View File

@@ -22,6 +22,8 @@ import org.thoughtcrime.securesms.jobmanager.impl.WifiConstraint
import org.thoughtcrime.securesms.jobs.protos.BackupMessagesJobData
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.providers.BlobProvider
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.whispersystems.signalservice.api.NetworkResult
import org.whispersystems.signalservice.api.messages.AttachmentTransferProgress
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment
@@ -150,6 +152,11 @@ class BackupMessagesJob private constructor(
when (val result = BackupRepository.uploadBackupFile(backupSpec, it, tempBackupFile.length(), progressListener)) {
is NetworkResult.Success -> {
Log.i(TAG, "Successfully uploaded backup file.")
if (!SignalStore.backup.hasBackupBeenUploaded) {
Log.i(TAG, "First time making a backup - scheduling a storage sync.")
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
StorageSyncHelper.scheduleSyncForDataChange()
}
SignalStore.backup.hasBackupBeenUploaded = true
}

View File

@@ -7,6 +7,7 @@ import okio.ByteString.Companion.toByteString
import org.signal.core.util.Base64.encodeWithPadding
import org.signal.core.util.SqlUtil
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository.getSubscriber
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository.isUserManuallyCancelled
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository.setSubscriber
@@ -174,6 +175,14 @@ object StorageSyncHelper {
color = StorageSyncModels.localToRemoteUsernameColor(SignalStore.misc.usernameQrCodeColorScheme)
)
}
hasBackup = SignalStore.backup.areBackupsEnabled && SignalStore.backup.hasBackupBeenUploaded
if (SignalStore.backup.areBackupsEnabled && SignalStore.backup.backupTier != null) {
backupTier = getBackupLevelValue(SignalStore.backup.backupTier!!)
} else if (SignalStore.backup.backupTierInternalOverride != null) {
backupTier = getBackupLevelValue(SignalStore.backup.backupTierInternalOverride!!)
}
notificationProfileManualOverride = getNotificationProfileManualOverride()
getSubscriber(InAppPaymentSubscriberRecord.Type.DONATION)?.let {
@@ -190,6 +199,14 @@ object StorageSyncHelper {
return accountRecord.toSignalAccountRecord(StorageId.forAccount(storageId)).toSignalStorageRecord()
}
// TODO: Currently we don't have access to the private values of the BackupLevel. Update when it becomes available.
private fun getBackupLevelValue(tier: MessageBackupTier): Long {
return when (tier) {
MessageBackupTier.FREE -> 200
MessageBackupTier.PAID -> 201
}
}
private fun getNotificationProfileManualOverride(): AccountRecord.NotificationProfileManualOverride {
val profile = SignalDatabase.notificationProfiles.getProfile(SignalStore.notificationProfile.manuallyEnabledProfile)
return if (profile != null && profile.deletedTimestampMs == 0L) {

View File

@@ -9,6 +9,7 @@ import assertk.assertions.isTrue
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.verify
import org.junit.Before
import org.junit.Rule
@@ -23,11 +24,14 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaym
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository.toInAppPaymentDataChargeFailure
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsTestRule
import org.thoughtcrime.securesms.database.InAppPaymentTable
import org.thoughtcrime.securesms.database.RecipientTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.BadgeList
import org.thoughtcrime.securesms.database.model.databaseprotos.InAppPaymentData
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.testutil.MockAppDependenciesRule
import org.thoughtcrime.securesms.testutil.MockSignalStoreRule
import org.thoughtcrime.securesms.testutil.SystemOutLogger
@@ -51,6 +55,8 @@ class InAppPaymentRecurringContextJobTest {
@get:Rule
val inAppPaymentsTestRule = InAppPaymentsTestRule()
lateinit var recipientTable: RecipientTable
@Before
fun setUp() {
Log.initialize(SystemOutLogger())
@@ -58,6 +64,15 @@ class InAppPaymentRecurringContextJobTest {
every { mockSignalStore.account.isRegistered } returns true
every { mockSignalStore.inAppPayments.setLastEndOfPeriod(any()) } returns Unit
recipientTable = mockk(relaxed = true)
every { SignalDatabase.recipients } returns recipientTable
mockkObject(Recipient)
every { Recipient.self() } returns Recipient()
mockkStatic(StorageSyncHelper::class)
every { StorageSyncHelper.scheduleSyncForDataChange() } returns Unit
mockkObject(InAppPaymentsRepository)
every { InAppPaymentsRepository.generateRequestCredential() } returns mockk {
every { serialize() } returns byteArrayOf()