You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/SessionMessagingKit/Database/Migrations/_018_DisappearingMessagesCo...

190 lines
8.6 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import GRDB
import SessionUtilitiesKit
Merge remote-tracking branch 'upstream/dev' into disappearing-message-redesign # Conflicts: # Session.xcodeproj/project.pbxproj # Session/Meta/Translations/ar.lproj/Localizable.strings # Session/Meta/Translations/be.lproj/Localizable.strings # Session/Meta/Translations/bg.lproj/Localizable.strings # Session/Meta/Translations/bn.lproj/Localizable.strings # Session/Meta/Translations/cs.lproj/Localizable.strings # Session/Meta/Translations/da.lproj/Localizable.strings # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/el.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/eo.lproj/Localizable.strings # Session/Meta/Translations/es-ES.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fil.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/hu.lproj/Localizable.strings # Session/Meta/Translations/id.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/ko.lproj/Localizable.strings # Session/Meta/Translations/ku.lproj/Localizable.strings # Session/Meta/Translations/lt.lproj/Localizable.strings # Session/Meta/Translations/lv.lproj/Localizable.strings # Session/Meta/Translations/ne-NP.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/no.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt-BR.lproj/Localizable.strings # Session/Meta/Translations/pt-PT.lproj/Localizable.strings # Session/Meta/Translations/ro.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si-LK.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sl.lproj/Localizable.strings # Session/Meta/Translations/sv-SE.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/tr.lproj/Localizable.strings # Session/Meta/Translations/uk.lproj/Localizable.strings # Session/Meta/Translations/vi.lproj/Localizable.strings # Session/Meta/Translations/zh-CN.lproj/Localizable.strings # Session/Meta/Translations/zh-TW.lproj/Localizable.strings # SessionMessagingKit/Configuration.swift # SessionUtilitiesKit/Database/Storage.swift
1 year ago
enum _018_DisappearingMessagesConfiguration: Migration {
static let target: TargetMigrations.Identifier = .messagingKit
static let identifier: String = "DisappearingMessagesWithTypes"
static let minExpectedRunDuration: TimeInterval = 0.1
static let createdTables: [(TableRecord & FetchableRecord).Type] = []
static func migrate(_ db: Database, using dependencies: Dependencies) throws {
try db.alter(table: "disappearingMessagesConfiguration") { t in
t.add(column: "type", .integer)
}
try db.alter(table: "contact") { t in
t.add(column: "lastKnownClientVersion", .integer)
}
/// Add index on interaction table for wasRead and variant
///
/// This is due to new disappearing messages will need some info messages to be able to be unread,
/// but we only want to count the unread message number by incoming visible messages and call messages.
try db.create(
indexOn: "interaction",
columns: ["wasRead", "variant"]
)
// If there isn't already a user account then we can just finish here (there will be no
// threads/configs to update and the configs won't be setup which would cause this to crash
guard
MigrationHelper.userExists(db),
let userEd25519SecretKey: Data = MigrationHelper.fetchIdentityValue(db, key: "ed25519SecretKey")
else { return Storage.update(progress: 1, for: self, in: target, using: dependencies) }
// Set the disappearing messages type per conversation
let userSessionId: SessionId = MigrationHelper.userSessionId(db)
let timestampMs: Int64 = Int64(dependencies.dateNow.timeIntervalSince1970 * TimeInterval(1000))
let userProfileType: DisappearingMessagesConfiguration.DisappearingMessageType = .disappearAfterSend
let contactType: DisappearingMessagesConfiguration.DisappearingMessageType = .disappearAfterRead
let legacyGroupType: DisappearingMessagesConfiguration.DisappearingMessageType = .disappearAfterSend
try db.execute(sql: """
UPDATE disappearingMessagesConfiguration
SET type = \(userProfileType.rawValue)
WHERE disappearingMessagesConfiguration.threadId = '\(userSessionId.hexString)'
""")
try db.execute(sql: """
UPDATE disappearingMessagesConfiguration
SET type = \(contactType.rawValue)
WHERE threadId IN (
SELECT id FROM thread WHERE variant = \(SessionThread.Variant.contact.rawValue)
)
""")
try db.execute(sql: """
UPDATE disappearingMessagesConfiguration
SET type = \(legacyGroupType.rawValue)
WHERE threadId IN (
SELECT id FROM thread WHERE variant = \(SessionThread.Variant.legacyGroup.rawValue)
)
""")
// Also need to update libSession with the new settings
let disappearingMessageInfo: [Row] = try Row.fetchAll(db, sql: """
SELECT
thread.id,
thread.variant,
disappearingMessagesConfiguration.isEnabled,
disappearingMessagesConfiguration.durationSeconds
FROM disappearingMessagesConfiguration
JOIN thread ON thread.id = disappearingMessagesConfiguration.threadId
""")
let cache: LibSession.Cache = LibSession.Cache(userSessionId: userSessionId, using: dependencies)
let userProfileConfig: LibSession.Config = try cache.loadState(
for: .userProfile,
sessionId: userSessionId,
userEd25519SecretKey: Array(userEd25519SecretKey),
groupEd25519SecretKey: nil,
cachedData: MigrationHelper.configDump(db, for: ConfigDump.Variant.userProfile.rawValue)
)
let contactsConfig: LibSession.Config = try cache.loadState(
for: .contacts,
sessionId: userSessionId,
userEd25519SecretKey: Array(userEd25519SecretKey),
groupEd25519SecretKey: nil,
cachedData: MigrationHelper.configDump(db, for: ConfigDump.Variant.contacts.rawValue)
)
let userGroupsConfig: LibSession.Config = try cache.loadState(
for: .userGroups,
sessionId: userSessionId,
userEd25519SecretKey: Array(userEd25519SecretKey),
groupEd25519SecretKey: nil,
cachedData: MigrationHelper.configDump(db, for: ConfigDump.Variant.userGroups.rawValue)
)
// Update the configs so the settings are synced
if let noteToSelfInfo: Row = disappearingMessageInfo.first(where: { $0["id"] == userSessionId.hexString }) {
try LibSession.updateNoteToSelf(
disappearingMessagesConfig: DisappearingMessagesConfiguration(
threadId: noteToSelfInfo["id"],
isEnabled: noteToSelfInfo["isEnabled"],
durationSeconds: noteToSelfInfo["durationSeconds"],
type: userProfileType
),
in: userProfileConfig
)
}
try LibSession.upsert(
contactData: disappearingMessageInfo
.filter {
$0["id"] != userSessionId.hexString &&
$0["variant"] == SessionThread.Variant.contact.rawValue
}
.map {
LibSession.SyncedContactInfo(
id: $0["id"],
disappearingMessagesConfig: DisappearingMessagesConfiguration(
threadId: $0["id"],
isEnabled: $0["isEnabled"],
durationSeconds: $0["durationSeconds"],
type: contactType
)
)
},
in: contactsConfig,
using: dependencies
)
try LibSession.upsert(
legacyGroups: disappearingMessageInfo
.filter { $0["variant"] == SessionThread.Variant.legacyGroup.rawValue }
.map {
LibSession.LegacyGroupInfo(
id: $0["id"],
disappearingMessageInfo: LibSession.DisappearingMessageInfo(
isEnabled: $0["isEnabled"],
durationSeconds: $0["durationSeconds"],
rawType: legacyGroupType.rawValue
)
)
},
in: userGroupsConfig
)
// Now that the state is updated we need to save the updated config dumps
if cache.configNeedsDump(userProfileConfig), let dumpData: Data = try userProfileConfig.dump() {
try db.execute(
sql: """
INSERT INTO configDump (variant, publicKey, data, timestampMs)
VALUES ('userProfile', '\(userSessionId.hexString)', ?, \(timestampMs))
ON CONFLICT(variant, publicKey) DO UPDATE SET
data = ?,
timestampMs = \(timestampMs)
""",
arguments: [dumpData, dumpData]
)
}
if cache.configNeedsDump(contactsConfig), let dumpData: Data = try contactsConfig.dump() {
try db.execute(
sql: """
INSERT INTO configDump (variant, publicKey, data, timestampMs)
VALUES ('contacts', '\(userSessionId.hexString)', ?, \(timestampMs))
ON CONFLICT(variant, publicKey) DO UPDATE SET
data = ?,
timestampMs = \(timestampMs)
""",
arguments: [dumpData, dumpData]
)
}
if cache.configNeedsDump(userGroupsConfig), let dumpData: Data = try userGroupsConfig.dump() {
try db.execute(
sql: """
INSERT INTO configDump (variant, publicKey, data, timestampMs)
VALUES ('userGroups', '\(userSessionId.hexString)', ?, \(timestampMs))
ON CONFLICT(variant, publicKey) DO UPDATE SET
data = ?,
timestampMs = \(timestampMs)
""",
arguments: [dumpData, dumpData]
)
}
Storage.update(progress: 1, for: self, in: target, using: dependencies)
}
}