From 9901f04dc337358901d23bbc50069eb92d81a4a9 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 18 Dec 2020 09:47:18 +1100 Subject: [PATCH] Implement contacts migration --- SessionMessagingKit/Contacts/Contact.swift | 20 +++++++ .../Database/Storage+Contacts.swift | 11 ++++ Signal.xcodeproj/project.pbxproj | 4 ++ .../Migration/ContactsMigration.swift | 57 +++++++++++++++++++ .../Migration/OWSDatabaseMigrationRunner.m | 4 +- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 1 + 6 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 SignalUtilitiesKit/Database/Migration/ContactsMigration.swift diff --git a/SessionMessagingKit/Contacts/Contact.swift b/SessionMessagingKit/Contacts/Contact.swift index b70609e8f..c7ef87541 100644 --- a/SessionMessagingKit/Contacts/Contact.swift +++ b/SessionMessagingKit/Contacts/Contact.swift @@ -39,4 +39,24 @@ public class Contact : NSObject, NSCoding { // NSObject/NSCoding conformance is coder.encode(profilePictureEncryptionKey, forKey: "profilePictureEncryptionKey") coder.encode(threadID, forKey: "threadID") } + + // MARK: Equality + override public func isEqual(_ other: Any?) -> Bool { + guard let other = other as? Contact else { return false } + return sessionID == other.sessionID + } + + // MARK: Hashing + override public var hash: Int { // Override NSObject.hash and not Hashable.hashValue or Hashable.hash(into:) + return sessionID.hash + } + + // MARK: Description + override public var description: String { + if let displayName = displayName { + return displayName + } else { + return sessionID + } + } } diff --git a/SessionMessagingKit/Database/Storage+Contacts.swift b/SessionMessagingKit/Database/Storage+Contacts.swift index 5c124e602..7d6404e51 100644 --- a/SessionMessagingKit/Database/Storage+Contacts.swift +++ b/SessionMessagingKit/Database/Storage+Contacts.swift @@ -15,4 +15,15 @@ extension Storage { public func setContact(_ contact: Contact, using transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).setObject(contact, forKey: contact.sessionID, inCollection: Storage.contactCollection) } + + public func getAllContacts() -> Set { + var result: Set = [] + Storage.read { transaction in + transaction.enumerateRows(inCollection: Storage.contactCollection) { _, object, _, _ in + guard let contact = object as? Contact else { return } + result.insert(contact) + } + } + return result + } } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 124a60b50..4bb9eace2 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -284,6 +284,7 @@ B8B26C8F234D629C004ED98C /* MentionCandidateSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */; }; B8B32021258B1A650020074B /* Contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B32020258B1A650020074B /* Contact.swift */; }; B8B32033258B235D0020074B /* Storage+Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B32032258B235D0020074B /* Storage+Contacts.swift */; }; + B8B3204E258C15C80020074B /* ContactsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B32044258C117C0020074B /* ContactsMigration.swift */; }; B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BB82A4238F627000BA5194 /* HomeVC.swift */; }; B8BC00C0257D90E30032E807 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BC00BF257D90E30032E807 /* General.swift */; }; B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C2B2C72563685C00551B4D /* CircleView.swift */; }; @@ -1379,6 +1380,7 @@ B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionCandidateSelectionView.swift; sourceTree = ""; }; B8B32020258B1A650020074B /* Contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contact.swift; sourceTree = ""; }; B8B32032258B235D0020074B /* Storage+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Contacts.swift"; sourceTree = ""; }; + B8B32044258C117C0020074B /* ContactsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsMigration.swift; sourceTree = ""; }; B8B5BCEB2394D869003823C9 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; B8BB829F238F322400BA5194 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; B8BB82A1238F356100BA5194 /* Values.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Values.swift; sourceTree = ""; }; @@ -3073,6 +3075,7 @@ C379DCE82567330E0002D4EB /* Migration */ = { isa = PBXGroup; children = ( + B8B32044258C117C0020074B /* ContactsMigration.swift */, C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */, @@ -5037,6 +5040,7 @@ C38EF3F2255B6DF7007E1867 /* DisappearingTimerConfigurationView.swift in Sources */, C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */, + B8B3204E258C15C80020074B /* ContactsMigration.swift in Sources */, C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */, C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */, C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */, diff --git a/SignalUtilitiesKit/Database/Migration/ContactsMigration.swift b/SignalUtilitiesKit/Database/Migration/ContactsMigration.swift new file mode 100644 index 000000000..43fe4497f --- /dev/null +++ b/SignalUtilitiesKit/Database/Migration/ContactsMigration.swift @@ -0,0 +1,57 @@ + +@objc(SNContactsMigration) +public class ContactsMigration : OWSDatabaseMigration { + + @objc + class func migrationId() -> String { + return "004" + } + + override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { + self.doMigrationAsync(completion: completion) + } + + private func doMigrationAsync(completion: @escaping OWSDatabaseMigrationCompletion) { + var contacts: Set = [] + Storage.write(with: { transaction in + // One-on-one chats + TSContactThread.enumerateCollectionObjects(with: transaction) { object, _ in + guard let thread = object as? TSContactThread else { return } + let sessionID = thread.contactIdentifier() + let contact = Contact(sessionID: sessionID) + if let profile = OWSUserProfile.fetch(uniqueId: sessionID, transaction: transaction) { + contact.displayName = profile.profileName + contact.profilePictureURL = profile.avatarUrlPath + contact.profilePictureFileName = profile.avatarFileName + contact.profilePictureEncryptionKey = profile.profileKey + } + contact.threadID = thread.uniqueId + contacts.insert(contact) + } + // Closed groups + TSGroupThread.enumerateCollectionObjects(with: transaction) { object, _ in + guard let thread = object as? TSGroupThread, thread.usesSharedSenderKeys else { return } + let memberSessionIDs = thread.groupModel.groupMemberIds + memberSessionIDs.forEach { memberSessionID in + guard !contacts.contains(where: { $0.sessionID == memberSessionID }) else { return } + let contact = Contact(sessionID: memberSessionID) + if let profile = OWSUserProfile.fetch(uniqueId: memberSessionID, transaction: transaction) { + contact.displayName = profile.profileName + contact.profilePictureURL = profile.avatarUrlPath + contact.profilePictureFileName = profile.avatarFileName + contact.profilePictureEncryptionKey = profile.profileKey + } + // At this point we know we don't have a one-on-one thread with this contact + contacts.insert(contact) + } + } + // Save + contacts.forEach { contact in + Storage.shared.setContact(contact, using: transaction) + } + self.save(with: transaction) // Intentionally capture self + }, completion: { + completion() + }) + } +} diff --git a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m index 14a981e03..fd8ea2d2c 100644 --- a/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m +++ b/SignalUtilitiesKit/Database/Migration/OWSDatabaseMigrationRunner.m @@ -25,7 +25,9 @@ NS_ASSUME_NONNULL_BEGIN // This should all migrations which do NOT qualify as safeBlockingMigrations: - (NSArray *)allMigrations { - return @[]; + return @[ + [SNContactsMigration new] + ]; } - (void)assumeAllExistingMigrationsRun diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 56dda12db..691dacfdb 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -16,6 +16,7 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import +#import #import #import #import