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

172 lines
7.5 KiB
Swift
Raw Normal View History

2021-02-08 11:29:27 +01:00
//
// APIService+Favorite.swift
// Mastodon
//
// Created by sxiaojian on 2021/2/8.
//
import Foundation
import Combine
import MastodonSDK
import CoreData
import CoreDataStack
import CommonOSLog
extension APIService {
// make local state change only
2021-04-07 08:24:28 +02:00
func favorite(
2021-04-01 08:39:15 +02:00
statusObjectID: NSManagedObjectID,
2021-02-08 11:29:27 +01:00
mastodonUserObjectID: NSManagedObjectID,
favoriteKind: Mastodon.API.Favorites.FavoriteKind
2021-04-01 08:39:15 +02:00
) -> AnyPublisher<Status.ID, Error> {
var _targetStatusID: Status.ID?
2021-02-08 11:29:27 +01:00
let managedObjectContext = backgroundManagedObjectContext
return managedObjectContext.performChanges {
2021-04-01 08:39:15 +02:00
let status = managedObjectContext.object(with: statusObjectID) as! Status
2021-02-08 11:29:27 +01:00
let mastodonUser = managedObjectContext.object(with: mastodonUserObjectID) as! MastodonUser
2021-04-01 08:39:15 +02:00
let targetStatus = status.reblog ?? status
let targetStatusID = targetStatus.id
_targetStatusID = targetStatusID
2021-02-08 11:29:27 +01:00
2021-04-01 08:39:15 +02:00
targetStatus.update(liked: favoriteKind == .create, by: mastodonUser)
2021-02-08 11:29:27 +01:00
}
.tryMap { result in
switch result {
case .success:
2021-04-01 08:39:15 +02:00
guard let targetStatusID = _targetStatusID else {
2021-02-08 11:29:27 +01:00
throw APIError.implicit(.badRequest)
}
2021-04-01 08:39:15 +02:00
return targetStatusID
2021-02-08 11:29:27 +01:00
case .failure(let error):
assertionFailure(error.localizedDescription)
throw error
}
}
.eraseToAnyPublisher()
}
// send favorite request to remote
2021-04-07 08:24:28 +02:00
func favorite(
2021-02-08 11:29:27 +01:00
statusID: Mastodon.Entity.Status.ID,
favoriteKind: Mastodon.API.Favorites.FavoriteKind,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
let authorization = mastodonAuthenticationBox.userAuthorization
let requestMastodonUserID = mastodonAuthenticationBox.userID
return Mastodon.API.Favorites.favorites(domain: mastodonAuthenticationBox.domain, statusID: statusID, session: session, authorization: authorization, favoriteKind: favoriteKind)
.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
}
}()
2021-04-01 08:39:15 +02:00
let _oldStatus: Status? = {
let request = Status.sortedFetchRequest
request.predicate = Status.predicate(domain: mastodonAuthenticationBox.domain, id: statusID)
2021-03-11 04:43:49 +01:00
request.fetchLimit = 1
2021-02-08 11:29:27 +01:00
request.returnsObjectsAsFaults = false
2021-04-01 08:39:15 +02:00
request.relationshipKeyPathsForPrefetching = [#keyPath(Status.reblog)]
2021-02-08 11:29:27 +01:00
do {
return try managedObjectContext.fetch(request).first
} catch {
assertionFailure(error.localizedDescription)
return nil
}
}()
guard let requestMastodonUser = _requestMastodonUser,
2021-04-01 08:39:15 +02:00
let oldStatus = _oldStatus else {
2021-02-08 11:29:27 +01:00
assertionFailure()
return
}
2021-04-01 08:39:15 +02:00
APIService.CoreData.merge(status: oldStatus, entity: entity, requestMastodonUser: requestMastodonUser, domain: mastodonAuthenticationBox.domain, networkDate: response.networkDate)
if favoriteKind == .destroy {
2021-04-01 08:39:15 +02:00
oldStatus.update(favouritesCount: NSNumber(value: max(0, oldStatus.favouritesCount.intValue - 1)))
}
2021-04-01 08:39:15 +02:00
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: did update status %{public}s like status to: %{public}s. now %ld likes", ((#file as NSString).lastPathComponent), #line, #function, entity.id, entity.favourited.flatMap { $0 ? "like" : "unlike" } ?? "<nil>", entity.favouritesCount )
2021-02-08 11:29:27 +01:00
}
.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):
2021-03-09 08:18:43 +01:00
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: error:", ((#file as NSString).lastPathComponent), #line, #function)
debugPrint(error)
2021-02-08 11:29:27 +01:00
case .finished:
break
}
})
.eraseToAnyPublisher()
}
}
extension APIService {
2021-04-07 08:24:28 +02:00
func favoritedStatuses(
2021-04-01 08:39:15 +02:00
limit: Int = onceRequestStatusMaxCount,
2021-02-08 11:29:27 +01:00
maxID: String? = nil,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Status]>, Error> {
let requestMastodonUserID = mastodonAuthenticationBox.userID
2021-04-07 08:24:28 +02:00
let query = Mastodon.API.Favorites.FavoriteStatusesQuery(limit: limit, minID: nil, maxID: maxID)
return Mastodon.API.Favorites.favoritedStatus(
domain: mastodonAuthenticationBox.domain,
session: session,
authorization: mastodonAuthenticationBox.userAuthorization,
query: query
)
2021-02-08 11:29:27 +01:00
.map { response -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Status]>, Error> in
let log = OSLog.api
2021-03-17 04:33:25 +01:00
return APIService.Persist.persistStatus(
2021-02-08 11:29:27 +01:00
managedObjectContext: self.backgroundManagedObjectContext,
domain: mastodonAuthenticationBox.domain,
query: query,
2021-02-08 11:29:27 +01:00
response: response,
persistType: .likeList,
requestMastodonUserID: requestMastodonUserID,
log: log
)
.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()
.eraseToAnyPublisher()
}
}