Implement contacts migration

pull/320/head
Niels Andriesse 4 years ago
parent 9b3f71172b
commit 9901f04dc3

@ -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
}
}
}

@ -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<Contact> {
var result: Set<Contact> = []
Storage.read { transaction in
transaction.enumerateRows(inCollection: Storage.contactCollection) { _, object, _, _ in
guard let contact = object as? Contact else { return }
result.insert(contact)
}
}
return result
}
}

@ -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 = "<group>"; };
B8B32020258B1A650020074B /* Contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contact.swift; sourceTree = "<group>"; };
B8B32032258B235D0020074B /* Storage+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Contacts.swift"; sourceTree = "<group>"; };
B8B32044258C117C0020074B /* ContactsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsMigration.swift; sourceTree = "<group>"; };
B8B5BCEB2394D869003823C9 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
B8BB829F238F322400BA5194 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
B8BB82A1238F356100BA5194 /* Values.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Values.swift; sourceTree = "<group>"; };
@ -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 */,

@ -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<Contact> = []
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()
})
}
}

@ -25,7 +25,9 @@ NS_ASSUME_NONNULL_BEGIN
// This should all migrations which do NOT qualify as safeBlockingMigrations:
- (NSArray<OWSDatabaseMigration *> *)allMigrations
{
return @[];
return @[
[SNContactsMigration new]
];
}
- (void)assumeAllExistingMigrationsRun

@ -16,6 +16,7 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[];
#import <SignalUtilitiesKit/NSURLSessionDataTask+StatusCode.h>
#import <SignalUtilitiesKit/OWSAnyTouchGestureRecognizer.h>
#import <SignalUtilitiesKit/OWSAttachmentDownloads.h>
#import <SignalUtilitiesKit/OWSDatabaseMigration.h>
#import <SignalUtilitiesKit/OWSDispatch.h>
#import <SignalUtilitiesKit/OWSError.h>
#import <SignalUtilitiesKit/OWSFormat.h>

Loading…
Cancel
Save