diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 4bdfef76ea68cb6d844d3f2ff6fc30997146fd0a..76608a6953980cdf9e3ac94f65ca47618e57b292 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -199,10 +199,10 @@ 47FAE3072524AA4B005A1BCB /* DataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3062524AA4B005A1BCB /* DataProvider.swift */; }; 47FAE30E2524AA97005A1BCB /* DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE30C2524AA97005A1BCB /* DataModel.xcdatamodeld */; }; 47FAE3122524BFDB005A1BCB /* PersistentDataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */; }; - 47FAE31C2524C07B005A1BCB /* CoreMail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE31B2524C07B005A1BCB /* CoreMail.swift */; }; + 47FAE31C2524C07B005A1BCB /* MailRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE31B2524C07B005A1BCB /* MailRecord.swift */; }; 47FAE3222524C1C0005A1BCB /* CoreMailTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3212524C1C0005A1BCB /* CoreMailTest.swift */; }; 47FAE33F2524FAD3005A1BCB /* CoreAddressTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE33E2524FAD3005A1BCB /* CoreAddressTest.swift */; }; - 47FAE3492524FB58005A1BCB /* CoreAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3482524FB58005A1BCB /* CoreAddress.swift */; }; + 47FAE3492524FB58005A1BCB /* AddressRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3482524FB58005A1BCB /* AddressRecord.swift */; }; 50F2E7D66366C779705987A7 /* Pods_enzevalos_iphoneUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF67EF30BB065CC9C0D17940 /* Pods_enzevalos_iphoneUITests.framework */; }; 676C2D3024321F8100B631B3 /* TyposquattingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676C2D2F24321F8100B631B3 /* TyposquattingTests.swift */; }; 6789425F2430C3B300C746D1 /* MailComparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6789425E2430C3B300C746D1 /* MailComparison.swift */; }; @@ -659,10 +659,10 @@ 47FAE3062524AA4B005A1BCB /* DataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataProvider.swift; sourceTree = "<group>"; }; 47FAE30D2524AA97005A1BCB /* DataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DataModel.xcdatamodel; sourceTree = "<group>"; }; 47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDataError.swift; sourceTree = "<group>"; }; - 47FAE31B2524C07B005A1BCB /* CoreMail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreMail.swift; sourceTree = "<group>"; }; + 47FAE31B2524C07B005A1BCB /* MailRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailRecord.swift; sourceTree = "<group>"; }; 47FAE3212524C1C0005A1BCB /* CoreMailTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreMailTest.swift; sourceTree = "<group>"; }; 47FAE33E2524FAD3005A1BCB /* CoreAddressTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreAddressTest.swift; sourceTree = "<group>"; }; - 47FAE3482524FB58005A1BCB /* CoreAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreAddress.swift; sourceTree = "<group>"; }; + 47FAE3482524FB58005A1BCB /* AddressRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressRecord.swift; sourceTree = "<group>"; }; 48C250BB32BF11B683003BA1 /* Pods-enzevalos_iphone-enzevalos_iphoneUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone-enzevalos_iphoneUITests.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone-enzevalos_iphoneUITests/Pods-enzevalos_iphone-enzevalos_iphoneUITests.debug.xcconfig"; sourceTree = "<group>"; }; 66E758F271CD65AB3E5FE7A7 /* Pods-enzevalos_iphoneUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphoneUITests.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphoneUITests/Pods-enzevalos_iphoneUITests.debug.xcconfig"; sourceTree = "<group>"; }; 670159DF240FB4E800797FA5 /* enzevalos_iphone 9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "enzevalos_iphone 9.xcdatamodel"; sourceTree = "<group>"; }; @@ -1389,8 +1389,8 @@ 47FAE3062524AA4B005A1BCB /* DataProvider.swift */, 47FAE30C2524AA97005A1BCB /* DataModel.xcdatamodeld */, 47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */, - 47FAE31B2524C07B005A1BCB /* CoreMail.swift */, - 47FAE3482524FB58005A1BCB /* CoreAddress.swift */, + 47FAE31B2524C07B005A1BCB /* MailRecord.swift */, + 47FAE3482524FB58005A1BCB /* AddressRecord.swift */, 4733B1CD25262CDB00AB5600 /* PersistentDataProtocol.swift */, 4733B1E42527196100AB5600 /* PersistentDataProvider.swift */, ); @@ -2377,7 +2377,7 @@ A1EB057A1D956829008659C1 /* ContactCell.swift in Sources */, A12FC23120221A1400196008 /* ExportInfoViewController.swift in Sources */, 4751C6EE233CA583006B2A4D /* DateExtension.swift in Sources */, - 47FAE31C2524C07B005A1BCB /* CoreMail.swift in Sources */, + 47FAE31C2524C07B005A1BCB /* MailRecord.swift in Sources */, 477548DE21F5DABE000B22A8 /* MailServerConnectionError.swift in Sources */, 475DF47A1F0D54C9009D807F /* Folder+CoreDataProperties.swift in Sources */, 475B00431F7BB6D6006CDD41 /* PersistentKey+CoreDataProperties.swift in Sources */, @@ -2408,7 +2408,7 @@ A1EB05841D956867008659C1 /* TableViewDataDelegate.swift in Sources */, 8428A85E1F436A05007649A5 /* CircleView.swift in Sources */, A182182C21E5072200918A29 /* IntroDescriptionViewController.swift in Sources */, - 47FAE3492524FB58005A1BCB /* CoreAddress.swift in Sources */, + 47FAE3492524FB58005A1BCB /* AddressRecord.swift in Sources */, 4775D7AA243F0E260052F2CC /* SimulatorData.swift in Sources */, F1C7AC821FED6473007629DB /* AboutViewController.swift in Sources */, 47C8225324379EAE005BCE73 /* AttachmentsViewMain.swift in Sources */, diff --git a/enzevalos_iphone/persistentData/CoreAddress.swift b/enzevalos_iphone/persistentData/AddressRecord.swift similarity index 83% rename from enzevalos_iphone/persistentData/CoreAddress.swift rename to enzevalos_iphone/persistentData/AddressRecord.swift index 913beaa72abb0e5213c553cff37bc38d70799356..94014c86906cb2abe0f1679f7d9acbe07ac1a60a 100644 --- a/enzevalos_iphone/persistentData/CoreAddress.swift +++ b/enzevalos_iphone/persistentData/AddressRecord.swift @@ -6,9 +6,9 @@ // Copyright © 2020 fu-berlin. All rights reserved. // -extension CoreAddress: PersistentDataProtocol { +extension AddressRecord: PersistentDataProtocol { typealias T = AddressProperties - static var entityName = "CoreAddress" + static var entityName = "AddressRecord" func update(with addressProperties: AddressProperties){ email = addressProperties.email @@ -19,7 +19,7 @@ struct AddressProperties: DataPropertyProtocol { var entityName = "CoreAddress" func update(m: Any) -> Bool { - if let m = m as? CoreAddress { + if let m = m as? AddressRecord { m.update(with: self) return true } diff --git a/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents b/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents index bc7537718072638a381cfd352045afaac3ec7119..cbb02cc1dece0e630f2092c6beb9dee038369565 100644 --- a/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents +++ b/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents @@ -4,16 +4,16 @@ <attribute name="cryptoProtocol" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="id" attributeType="String"/> </entity> - <entity name="Address" representedClassName="Address" syncable="YES" codeGenerationType="class"> + <entity name="AddressRecord" representedClassName="AddressRecord" syncable="YES" codeGenerationType="class"> <attribute name="email" attributeType="String"/> - <relationship name="inFromField" toMany="YES" deletionRule="Nullify" destinationEntity="CoreMail" inverseName="fromAddress" inverseEntity="CoreMail"/> + <relationship name="inFromField" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="fromAddress" inverseEntity="MailRecord"/> <uniquenessConstraints> <uniquenessConstraint> <constraint value="email"/> </uniquenessConstraint> </uniquenessConstraints> </entity> - <entity name="CoreMail" representedClassName="CoreMail" syncable="YES" codeGenerationType="class"> + <entity name="MailRecord" representedClassName="MailRecord" syncable="YES" codeGenerationType="class"> <attribute name="body" attributeType="String"/> <attribute name="date" attributeType="Date" usesScalarValueType="NO"/> <attribute name="encryptionState" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> @@ -22,10 +22,10 @@ <attribute name="signatureState" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="subject" attributeType="String"/> <attribute name="xMailer" optional="YES" attributeType="String"/> - <relationship name="bccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Address"/> - <relationship name="ccAddresses" toMany="YES" deletionRule="Nullify" destinationEntity="Address"/> - <relationship name="fromAddress" maxCount="1" deletionRule="Nullify" destinationEntity="Address" inverseName="inFromField" inverseEntity="Address"/> - <relationship name="toAddresses" maxCount="1" deletionRule="Nullify" destinationEntity="Address"/> + <relationship name="bccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> + <relationship name="ccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> + <relationship name="fromAddress" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AddressRecord" inverseName="inFromField" inverseEntity="AddressRecord"/> + <relationship name="toAddresses" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AddressRecord"/> <uniquenessConstraints> <uniquenessConstraint> <constraint value="messageID"/> @@ -43,10 +43,10 @@ <attribute name="exported" attributeType="Boolean" usesScalarValueType="YES"/> <attribute name="importedDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/> </entity> - <fetchRequest name="FetchAddressesRequest" entity="Address" fetchLimit="200" fetchBatchSize="200"/> + <fetchRequest name="FetchAddressesRequest" entity="AddressRecord" fetchLimit="200" fetchBatchSize="200"/> <elements> - <element name="Address" positionX="-36" positionY="27" width="128" height="28"/> - <element name="CoreMail" positionX="-54" positionY="-9" width="128" height="28"/> + <element name="AddressRecord" positionX="-36" positionY="27" width="128" height="73"/> + <element name="MailRecord" positionX="-54" positionY="-9" width="128" height="223"/> <element name="AbstractKeyRecord" positionX="-27" positionY="54" width="128" height="28"/> <element name="SecretKeyRecord" positionX="-9" positionY="63" width="128" height="28"/> <element name="PublicKeyRecord" positionX="9" positionY="63" width="128" height="28"/> diff --git a/enzevalos_iphone/persistentData/DataProvider.swift b/enzevalos_iphone/persistentData/DataProvider.swift index f5495661c974775e04b36b8eeb3f2e09e39613b2..ef886b0936b809d7506c3a852e0db6c2a21aa521 100644 --- a/enzevalos_iphone/persistentData/DataProvider.swift +++ b/enzevalos_iphone/persistentData/DataProvider.swift @@ -213,7 +213,7 @@ public class DataProvider { func deleteAll(completionHandler: @escaping (Error?) -> Void) { let taskContext = newTaskContext() taskContext.perform { - for name in [CoreAddress.entityName, CoreMail.entityName] { + for name in [AddressRecord.entityName, MailRecord.entityName] { let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name) let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) batchDeleteRequest.resultType = .resultTypeCount @@ -231,8 +231,8 @@ public class DataProvider { // MARK: - NSFetchedResultsController - lazy var fetchAddressResultController: NSFetchedResultsController<CoreAddress> = { - let freq = NSFetchRequest<CoreAddress>(entityName: CoreAddress.entityName) + lazy var fetchAddressResultController: NSFetchedResultsController<AddressRecord> = { + let freq = NSFetchRequest<AddressRecord>(entityName: AddressRecord.entityName) freq.sortDescriptors = [NSSortDescriptor(key: "email", ascending: false)] let controller = NSFetchedResultsController(fetchRequest: freq, managedObjectContext: persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil) @@ -253,10 +253,10 @@ public class DataProvider { /** A fetched results controller to fetch EMail records sorted by time. */ - lazy var fetchedResultsController: NSFetchedResultsController<CoreMail> = { + lazy var fetchedResultsController: NSFetchedResultsController<MailRecord> = { // Create a fetch request for the Quake entity sorted by time. - let fetchRequest = NSFetchRequest<CoreMail>(entityName: CoreMail.entityName) + let fetchRequest = NSFetchRequest<MailRecord>(entityName: MailRecord.entityName) // Create a fetched results controller and set its fetch request, context, and delegate. fetchRequest.sortDescriptors = [NSSortDescriptor(key: "messageID", ascending: false)] fetchRequest.propertiesToFetch = ["messageID", "subject"] @@ -302,17 +302,4 @@ public class DataProvider { } } -extension DispatchQueue { - static func background(delay: Double = 0.0, background: (()->Void)? = nil, completion: (() -> Void)? = nil) { - DispatchQueue.global(qos: .background).async { - background?() - if let completion = completion { - DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: { - completion() - }) - } - } - } - -} diff --git a/enzevalos_iphone/persistentData/CoreMail.swift b/enzevalos_iphone/persistentData/MailRecord.swift similarity index 87% rename from enzevalos_iphone/persistentData/CoreMail.swift rename to enzevalos_iphone/persistentData/MailRecord.swift index 8e78c79ff01e8d194230fe8149c1aac363432626..a5a4cc60a8aaac83200c192b8606f085b3411072 100644 --- a/enzevalos_iphone/persistentData/CoreMail.swift +++ b/enzevalos_iphone/persistentData/MailRecord.swift @@ -7,10 +7,10 @@ // /** - Managed object subclass extension for the Quake entity. + Managed object subclass extension for the mail entity. */ -extension CoreMail: PersistentDataProtocol { - static let entityName = "CoreMail" +extension MailRecord: PersistentDataProtocol { + static let entityName = "MailRecord" func update(with mailProperties: MailProperties) { messageID = mailProperties.messageID @@ -56,7 +56,7 @@ struct MailProperties: DataPropertyProtocol { } func update(m: Any) -> Bool { - if let m = m as? CoreMail { + if let m = m as? MailRecord { m.update(with: self) return true } diff --git a/enzevalos_iphone/persistentData/PersistentDataProvider.swift b/enzevalos_iphone/persistentData/PersistentDataProvider.swift index 36e63744f81ef570a83cca0eefca5706f5e34669..f474936db4de88c70cc11de5b64afdd4b30c83c0 100644 --- a/enzevalos_iphone/persistentData/PersistentDataProvider.swift +++ b/enzevalos_iphone/persistentData/PersistentDataProvider.swift @@ -113,16 +113,7 @@ class PersitentDataProvider { taskContext.performAndWait { // Create a new record for each mail in the batch. for m in mails { - // Create a managed object on the private queue context. - let from = NSEntityDescription.insertNewObject(forEntityName: CoreAddress.entityName, into: taskContext) as! CoreAddress - from.update(with: m.from) - - let mail = NSEntityDescription.insertNewObject(forEntityName: CoreMail.entityName, into: taskContext) as! CoreMail - mail.fromAddress = from - mail.messageID = m.messageID - - // add relationship -> Update? - + importOneMail(m: m, taskContext: taskContext) } // Save all insertions and deletions from the context to the store. @@ -143,6 +134,83 @@ class PersitentDataProvider { } } + private func importOneMail(m: MailProperties, taskContext: NSManagedObjectContext) { + // Create a managed object on the private queue context. + let from = NSEntityDescription.insertNewObject(forEntityName: AddressRecord.entityName, into: taskContext) as! AddressRecord + from.update(with: m.from) + + let mail = NSEntityDescription.insertNewObject(forEntityName: MailRecord.entityName, into: taskContext) as! MailRecord + mail.fromAddress = from + mail.messageID = m.messageID + + // add relationship -> Update? + } + + /** + Deletes all the records in the Core Data store. + */ + func deleteAll(completionHandler: @escaping (Error?) -> Void) { + let taskContext = newTaskContext() + taskContext.perform { + for name in [AddressRecord.entityName, MailRecord.entityName] { + let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name) + let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) + batchDeleteRequest.resultType = .resultTypeCount + + // Execute the batch insert + guard let batchDeleteResult = try? taskContext.execute(batchDeleteRequest) as? NSBatchDeleteResult, + batchDeleteResult.result != nil else { + completionHandler(PersistentDataError.batchDeleteError) + return + } + } + completionHandler(nil) + } + } + + + func reset(){ + persistentContainer.viewContext.reset() + } + + + // MARK: - NSFetchedResultsController + + lazy var fetchAddressResultController: NSFetchedResultsController<AddressRecord> = { + let freq = NSFetchRequest<AddressRecord>(entityName: AddressRecord.entityName) + freq.sortDescriptors = [NSSortDescriptor(key: "email", ascending: false)] + + let controller = NSFetchedResultsController(fetchRequest: freq, managedObjectContext: persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil) + do { + try controller.performFetch() + } catch { + fatalError("Unresolved error \(error)") + } + return controller + }() + + + lazy var fetchedMailResultsController: NSFetchedResultsController<MailRecord> = { + + // Create a fetch request for the Quake entity sorted by time. + let fetchRequest = NSFetchRequest<MailRecord>(entityName: MailRecord.entityName) + // Create a fetched results controller and set its fetch request, context, and delegate. + fetchRequest.sortDescriptors = [NSSortDescriptor(key: "messageID", ascending: false)] + fetchRequest.propertiesToFetch = ["messageID", "subject"] + let controller = NSFetchedResultsController(fetchRequest: fetchRequest, + managedObjectContext: persistentContainer.viewContext, + sectionNameKeyPath: nil, cacheName: nil) + // Perform the fetch. + do { + try controller.performFetch() + } catch { + fatalError("Unresolved error \(error)") + } + return controller + }() + + + /** Handles remote store change notifications (.NSPersistentStoreRemoteChange). storeRemoteChange runs on the queue where the changes were made. @@ -152,3 +220,18 @@ class PersitentDataProvider { //print("\(#function): Got a persistent store remote change notification!") } } + +extension DispatchQueue { + + static func background(delay: Double = 0.0, background: (()->Void)? = nil, completion: (() -> Void)? = nil) { + DispatchQueue.global(qos: .background).async { + background?() + if let completion = completion { + DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: { + completion() + }) + } + } + } + +}