mastodon-ios/Mastodon/Service/APIService/APIService+Reblog.swift

135 lines
5.4 KiB
Swift
Raw Normal View History

2021-03-09 08:18:43 +01:00
//
// APIService+Reblog.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-3-9.
//
import Foundation
import Combine
import MastodonSDK
import CoreData
import CoreDataStack
import CommonOSLog
extension APIService {
// make local state change only
func boost(
tootObjectID: NSManagedObjectID,
mastodonUserObjectID: NSManagedObjectID,
2021-03-09 12:39:44 +01:00
boostKind: Mastodon.API.Reblog.BoostKind
2021-03-09 08:18:43 +01:00
) -> AnyPublisher<Toot.ID, Error> {
var _targetTootID: Toot.ID?
let managedObjectContext = backgroundManagedObjectContext
return managedObjectContext.performChanges {
let toot = managedObjectContext.object(with: tootObjectID) as! Toot
let mastodonUser = managedObjectContext.object(with: mastodonUserObjectID) as! MastodonUser
let targetToot = toot.reblog ?? toot
let targetTootID = targetToot.id
_targetTootID = targetTootID
targetToot.update(reblogged: boostKind == .boost, mastodonUser: mastodonUser)
}
.tryMap { result in
switch result {
case .success:
guard let targetTootID = _targetTootID else {
throw APIError.implicit(.badRequest)
}
return targetTootID
case .failure(let error):
assertionFailure(error.localizedDescription)
throw error
}
}
.eraseToAnyPublisher()
}
// send boost request to remote
func boost(
statusID: Mastodon.Entity.Status.ID,
2021-03-09 12:39:44 +01:00
boostKind: Mastodon.API.Reblog.BoostKind,
2021-03-09 08:18:43 +01:00
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
let domain = mastodonAuthenticationBox.domain
let authorization = mastodonAuthenticationBox.userAuthorization
let requestMastodonUserID = mastodonAuthenticationBox.userID
2021-03-09 12:39:44 +01:00
return Mastodon.API.Reblog.boost(
2021-03-09 08:18:43 +01:00
session: session,
domain: domain,
statusID: statusID,
boostKind: boostKind,
authorization: authorization
)
.map { response -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> in
let log = OSLog.api
let entity = response.value
let managedObjectContext = self.backgroundManagedObjectContext
return managedObjectContext.performChanges {
let _requestMastodonUser: MastodonUser? = {
let request = MastodonUser.sortedFetchRequest
request.predicate = MastodonUser.predicate(domain: mastodonAuthenticationBox.domain, id: requestMastodonUserID)
request.fetchLimit = 1
request.returnsObjectsAsFaults = false
do {
return try managedObjectContext.fetch(request).first
} catch {
assertionFailure(error.localizedDescription)
return nil
}
}()
let _oldToot: Toot? = {
let request = Toot.sortedFetchRequest
request.predicate = Toot.predicate(domain: domain, id: statusID)
2021-03-11 04:43:49 +01:00
request.fetchLimit = 1
2021-03-09 08:18:43 +01:00
request.returnsObjectsAsFaults = false
request.relationshipKeyPathsForPrefetching = [#keyPath(Toot.reblog)]
do {
return try managedObjectContext.fetch(request).first
} catch {
assertionFailure(error.localizedDescription)
return nil
}
}()
guard let requestMastodonUser = _requestMastodonUser,
let oldToot = _oldToot else {
assertionFailure()
return
}
APIService.CoreData.merge(toot: oldToot, entity: entity.reblog ?? entity, requestMastodonUser: requestMastodonUser, domain: mastodonAuthenticationBox.domain, networkDate: response.networkDate)
if boostKind == .undoBoost {
oldToot.update(reblogsCount: NSNumber(value: max(0, oldToot.reblogsCount.intValue - 1)))
}
2021-03-09 08:18:43 +01:00
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: did update toot %{public}s reblog status to: %{public}s. now %ld boosts", ((#file as NSString).lastPathComponent), #line, #function, entity.id, entity.reblogged.flatMap { $0 ? "boost" : "unboost" } ?? "<nil>", entity.reblogsCount )
}
.setFailureType(to: Error.self)
.tryMap { result -> Mastodon.Response.Content<Mastodon.Entity.Status> in
switch result {
case .success:
return response
case .failure(let error):
throw error
}
}
.eraseToAnyPublisher()
}
.switchToLatest()
.handleEvents(receiveCompletion: { completion in
switch completion {
case .failure(let error):
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: error:", ((#file as NSString).lastPathComponent), #line, #function)
debugPrint(error)
case .finished:
break
}
})
.eraseToAnyPublisher()
}
}