@@ -7,8 +7,6 @@ import WordPressKit
77/// connections, and keyring connections.
88///
99@objc public class SharingService : NSObject {
10- let SharingAPIErrorNotFound = " not_found "
11-
1210 private let coreDataStack : CoreDataStackSwift
1311
1412 /// The initialiser for Objective-C code.
@@ -23,348 +21,6 @@ import WordPressKit
2321 self . coreDataStack = coreDataStack
2422 }
2523
26- // MARK: - Publicize Related Methods
27-
28- /// Syncs the list of Publicize services. The list is expected to very rarely change.
29- ///
30- /// - Parameters:
31- /// - blog: The `Blog` for which to sync publicize services
32- /// - success: An optional success block accepting no parameters
33- /// - failure: An optional failure block accepting an `NSError` parameter
34- ///
35- @objc public func syncPublicizeServicesForBlog( _ blog: Blog , success: ( ( ) -> Void ) ? , failure: ( ( NSError ? ) -> Void ) ? ) {
36- guard let remote = remoteForBlog ( blog) ,
37- let blogID = blog. dotComID else {
38- failure ? ( nil )
39- return
40- }
41-
42- remote. getPublicizeServices ( for: blogID, success: { remoteServices in
43- // Process the results
44- self . mergePublicizeServices ( remoteServices, success: success)
45- } , failure: failure)
46- }
47-
48- /// Fetches the current user's list of keyring connections. Nothing is saved to core data.
49- /// The success block should accept an array of `KeyringConnection` objects.
50- ///
51- /// - Parameters:
52- /// - blog: The `Blog` for which to sync keyring connections
53- /// - success: An optional success block accepting an array of `KeyringConnection` objects
54- /// - failure: An optional failure block accepting an `NSError` parameter
55- ///
56- @objc public func fetchKeyringConnectionsForBlog( _ blog: Blog , success: ( ( [ KeyringConnection ] ) -> Void ) ? , failure: ( ( NSError ? ) -> Void ) ? ) {
57- guard let remote = remoteForBlog ( blog) else {
58- return
59- }
60- remote. getKeyringConnections ( { keyringConnections in
61- // Just return the result
62- success ? ( keyringConnections)
63- } ,
64- failure: failure)
65- }
66-
67- /// Creates a new publicize connection for the specified `Blog`, using the specified
68- /// keyring. Optionally the connection can target a particular external user account.
69- ///
70- /// - Parameters
71- /// - blog: The `Blog` for which to sync publicize connections
72- /// - keyring: The `KeyringConnection` to use
73- /// - externalUserID: An optional string representing a user ID on the external service.
74- /// - success: An optional success block accepting a `PublicizeConnection` parameter.
75- /// - failure: An optional failure block accepting an NSError parameter.
76- ///
77- @objc public func createPublicizeConnectionForBlog( _ blog: Blog ,
78- keyring: KeyringConnection ,
79- externalUserID: String ? ,
80- success: ( ( PublicizeConnection ) -> Void ) ? ,
81- failure: ( ( NSError ? ) -> Void ) ? ) {
82- let blogObjectID = blog. objectID
83- guard let remote = remoteForBlog ( blog) else {
84- return
85- }
86- let dotComID = blog. dotComID!
87- remote. createPublicizeConnection (
88- dotComID,
89- keyringConnectionID: keyring. keyringID,
90- externalUserID: externalUserID,
91- success: { remoteConnection in
92- let properties = [
93- " service " : keyring. service
94- ]
95- WPAppAnalytics . track ( . sharingPublicizeConnected, properties: properties, blogID: dotComID)
96-
97- self . coreDataStack. performAndSave ( { context -> NSManagedObjectID in
98- try self . createOrReplacePublicizeConnectionForBlogWithObjectID ( blogObjectID, remoteConnection: remoteConnection, in: context)
99- } , completion: { result in
100- let transformed = result. flatMap { objectID in
101- Result {
102- let object = try self . coreDataStack. mainContext. existingObject ( with: objectID)
103- return object as! PublicizeConnection
104- }
105- }
106- switch transformed {
107- case let . success( object) :
108- success ? ( object)
109- case let . failure( error) :
110- DDLogError ( " Error creating publicize connection from remote: \( error) " )
111- failure ? ( error as NSError )
112- }
113- } , on: . main)
114- } ,
115- failure: { ( error: NSError ? ) in
116- failure ? ( error)
117- } )
118- }
119-
120- /// Update the specified `PublicizeConnection`. The update to core data is performed
121- /// optimistically. In case of failure the original value will be restored.
122- ///
123- /// - Parameters:
124- /// - shared: True if the connection should be shared with all users of the blog.
125- /// - pubConn: The `PublicizeConnection` to update
126- /// - success: An optional success block accepting no parameters.
127- /// - failure: An optional failure block accepting an NSError parameter.
128- ///
129- @objc public func updateSharedForBlog(
130- _ blog: Blog ,
131- shared: Bool ,
132- forPublicizeConnection pubConn: PublicizeConnection ,
133- success: ( ( ) -> Void ) ? ,
134- failure: ( ( NSError ? ) -> Void ) ?
135- ) {
136- typealias PubConnUpdateResult = ( oldValue: Bool , siteID: NSNumber , connectionID: NSNumber , service: String , remote: SharingServiceRemote ? )
137-
138- let blogObjectID = blog. objectID
139- coreDataStack. performAndSave ( { context -> PubConnUpdateResult in
140- let blogInContext = try context. existingObject ( with: blogObjectID) as! Blog
141- let pubConnInContext = try context. existingObject ( with: pubConn. objectID) as! PublicizeConnection
142- let oldValue = pubConnInContext. shared
143- pubConnInContext. shared = shared
144- return (
145- oldValue: oldValue,
146- siteID: pubConnInContext. siteID,
147- connectionID: pubConnInContext. connectionID,
148- service: pubConnInContext. service,
149- remote: self . remoteForBlog ( blogInContext)
150- )
151- } , completion: { result in
152- switch result {
153- case let . success( value) :
154- if value. oldValue == shared {
155- success ? ( )
156- return
157- }
158-
159- value. remote? . updatePublicizeConnectionWithID (
160- value. connectionID,
161- shared: shared,
162- forSite: value. siteID,
163- success: { remoteConnection in
164- let properties = [
165- " service " : value. service,
166- " is_site_wide " : NSNumber ( value: shared) . stringValue
167- ]
168- WPAppAnalytics . track ( . sharingPublicizeConnectionAvailableToAllChanged, properties: properties, blogID: value. siteID)
169-
170- self . coreDataStack. performAndSave ( { context in
171- try self . createOrReplacePublicizeConnectionForBlogWithObjectID ( blogObjectID, remoteConnection: remoteConnection, in: context)
172- } , completion: { result in
173- switch result {
174- case . success:
175- success ? ( )
176- case let . failure( error) :
177- DDLogError ( " Error creating publicize connection from remote: \( error) " )
178- failure ? ( error as NSError )
179- }
180- } , on: . main)
181- } ,
182- failure: { ( error: NSError ? ) in
183- self . coreDataStack. performAndSave ( { context in
184- let pubConnInContext = try context. existingObject ( with: pubConn. objectID) as! PublicizeConnection
185- pubConnInContext. shared = value. oldValue
186- } , completion: { _ in
187- failure ? ( error)
188- } , on: . main)
189- }
190- )
191- case let . failure( error) :
192- failure ? ( error as NSError )
193- }
194- } , on: . main)
195- }
196-
197- /// Update the specified `PublicizeConnection`. The update to core data is performed
198- /// optimistically. In case of failure the original value will be restored.
199- ///
200- /// - Parameters:
201- /// - externalID: True if the connection should be shared with all users of the blog.
202- /// - pubConn: The `PublicizeConnection` to update
203- /// - success: An optional success block accepting no parameters.
204- /// - failure: An optional failure block accepting an NSError parameter.
205- ///
206- @objc public func updateExternalID( _ externalID: String ,
207- forBlog blog: Blog ,
208- forPublicizeConnection pubConn: PublicizeConnection ,
209- success: ( ( ) -> Void ) ? ,
210- failure: ( ( NSError ? ) -> Void ) ? ) {
211- if pubConn. externalID == externalID {
212- success ? ( )
213- return
214- }
215-
216- let blogObjectID = blog. objectID
217- let siteID = pubConn. siteID
218- guard let remote = remoteForBlog ( blog) else {
219- return
220- }
221- remote. updatePublicizeConnectionWithID ( pubConn. connectionID,
222- externalID: externalID,
223- forSite: siteID,
224- success: { remoteConnection in
225- self . coreDataStack. performAndSave ( { context in
226- try self . createOrReplacePublicizeConnectionForBlogWithObjectID ( blogObjectID, remoteConnection: remoteConnection, in: context)
227- } , completion: { result in
228- switch result {
229- case . success:
230- success ? ( )
231- case let . failure( error) :
232- DDLogError ( " Error creating publicize connection from remote: \( error) " )
233- failure ? ( error as NSError )
234- }
235- } , on: . main)
236- } ,
237- failure: failure)
238- }
239-
240- /// Deletes the specified `PublicizeConnection`. The delete from core data is performed
241- /// optimistically. The caller's `failure` block should be responsible for resyncing
242- /// the deleted connection.
243- ///
244- /// - Parameters:
245- /// - pubConn: The `PublicizeConnection` to delete
246- /// - success: An optional success block accepting no parameters.
247- /// - failure: An optional failure block accepting an NSError parameter.
248- ///
249- @objc public func deletePublicizeConnectionForBlog( _ blog: Blog , pubConn: PublicizeConnection , success: ( ( ) -> Void ) ? , failure: ( ( NSError ? ) -> Void ) ? ) {
250- // optimistically delete the connection locally.
251- coreDataStack. performAndSave ( { context in
252- let blogInContext = try context. existingObject ( with: blog. objectID) as! Blog
253- let pubConnInContext = try context. existingObject ( with: pubConn. objectID) as! PublicizeConnection
254-
255- let siteID = pubConnInContext. siteID
256- context. delete ( pubConnInContext)
257- return ( siteID, pubConnInContext. connectionID, pubConnInContext. service, self . remoteForBlog ( blogInContext) )
258- } , completion: { result in
259- switch result {
260- case let . success( ( siteID, connectionID, service, remote) ) :
261- remote? . deletePublicizeConnection (
262- siteID,
263- connectionID: connectionID,
264- success: {
265- let properties = [
266- " service " : service
267- ]
268- WPAppAnalytics . track ( . sharingPublicizeDisconnected, properties: properties, blogID: siteID)
269- success ? ( )
270- } ,
271- failure: { ( error: NSError ? ) in
272- if let errorCode = error? . userInfo [ WordPressComRestApi . ErrorKeyErrorCode] as? String {
273- if errorCode == self . SharingAPIErrorNotFound {
274- // This is a special situation. If the call to disconnect the service returns not_found then the service
275- // has probably already been disconnected and the call was made with stale data.
276- // Assume this is the case and treat this error as a successful disconnect.
277- success ? ( )
278- return
279- }
280- }
281- failure ? ( error)
282- }
283- )
284- case let . failure( error) :
285- failure ? ( error as NSError )
286- }
287- } , on: . main)
288- }
289-
290- // MARK: - Private PublicizeService Methods
291-
292- /// Called when syncing Publicize services. Merges synced and cached data, removing
293- /// anything that does not exist on the server. Saves the context.
294- ///
295- /// - Parameters
296- /// - remoteServices: An array of `RemotePublicizeService` objects to merge.
297- /// - success: An optional callback block to be performed when core data has saved the changes.
298- ///
299- private func mergePublicizeServices( _ remoteServices: [ RemotePublicizeService ] , success: ( ( ) -> Void ) ? ) {
300- coreDataStack. performAndSave ( { context in
301- let currentPublicizeServices = ( try ? PublicizeService . allPublicizeServices ( in: context) ) ?? [ ]
302-
303- // Create or update based on the contents synced.
304- let servicesToKeep = remoteServices. map { ( remoteService) -> PublicizeService in
305- self . createOrReplaceFromRemotePublicizeService ( remoteService, in: context)
306- }
307-
308- // Delete any cached PublicizeServices that were not synced.
309- for pubService in currentPublicizeServices {
310- if !servicesToKeep. contains ( pubService) {
311- context. delete ( pubService)
312- }
313- }
314- } , completion: success, on: . main)
315- }
316-
317- /// Composes a new `PublicizeService`, or updates an existing one, with data represented by the passed `RemotePublicizeService`.
318- ///
319- /// - Parameter remoteService: The remote publicize service representing a `PublicizeService`
320- ///
321- /// - Returns: A `PublicizeService`.
322- ///
323- private func createOrReplaceFromRemotePublicizeService( _ remoteService: RemotePublicizeService , in context: NSManagedObjectContext ) -> PublicizeService {
324- var pubService = try ? PublicizeService . lookupPublicizeServiceNamed ( remoteService. serviceID, in: context)
325- if pubService == nil {
326- pubService = NSEntityDescription . insertNewObject ( forEntityName: PublicizeService . entityName ( ) ,
327- into: context) as? PublicizeService
328- }
329- pubService? . connectURL = remoteService. connectURL
330- pubService? . detail = remoteService. detail
331- pubService? . externalUsersOnly = remoteService. externalUsersOnly
332- pubService? . icon = remoteService. icon
333- pubService? . jetpackModuleRequired = remoteService. jetpackModuleRequired
334- pubService? . jetpackSupport = remoteService. jetpackSupport
335- pubService? . label = remoteService. label
336- pubService? . multipleExternalUserIDSupport = remoteService. multipleExternalUserIDSupport
337- pubService? . order = remoteService. order
338- pubService? . serviceID = remoteService. serviceID
339- pubService? . type = remoteService. type
340- pubService? . status = ( remoteService. status. isEmpty ? PublicizeService . defaultStatus : remoteService. status)
341-
342- return pubService!
343- }
344-
345- // MARK: - Private PublicizeConnection Methods
346-
347- /// Composes a new `PublicizeConnection`, with data represented by the passed `RemotePublicizeConnection`.
348- /// Throws an error if unable to find a `Blog` for the `blogObjectID`
349- ///
350- /// - Parameter blogObjectID: And `NSManagedObjectID` for for a `Blog` entity.
351- ///
352- /// - Returns: A `PublicizeConnection`.
353- ///
354- private func createOrReplacePublicizeConnectionForBlogWithObjectID(
355- _ blogObjectID: NSManagedObjectID ,
356- remoteConnection: RemotePublicizeConnection ,
357- in context: NSManagedObjectContext
358- ) throws -> NSManagedObjectID {
359- let blog = try context. existingObject ( with: blogObjectID) as! Blog
360- let pubConn = PublicizeConnection . createOrReplace ( from: remoteConnection, in: context)
361- pubConn. blog = blog
362-
363- try context. obtainPermanentIDs ( for: [ pubConn] )
364-
365- return pubConn. objectID
366- }
367-
36824 // MARK: Sharing Button Related Methods
36925
37026 /// Syncs `SharingButton`s for the specified wpcom blog.
0 commit comments