2021-02-08 11:29:27 +01:00
//
// A P I S e r v i c e + F a v o r i t e . s w i f t
// M a s t o d o n
//
// C r e a t e d b y s x i a o j i a n o n 2 0 2 1 / 2 / 8 .
//
import Foundation
import Combine
import MastodonSDK
import CoreData
import CoreDataStack
import CommonOSLog
extension APIService {
// m a k e l o c a l s t a t e c h a n g e o n l y
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-06-17 10:44:57 +02:00
let favouritesCount : NSNumber
switch favoriteKind {
case . create :
favouritesCount = NSNumber ( value : targetStatus . favouritesCount . intValue + 1 )
case . destroy :
favouritesCount = NSNumber ( value : max ( 0 , targetStatus . favouritesCount . intValue - 1 ) )
}
targetStatus . update ( favouritesCount : favouritesCount )
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 ( )
}
// s e n d f a v o r i t e r e q u e s t t o r e m o t e
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 ,
2021-07-20 10:40:04 +02:00
mastodonAuthenticationBox : MastodonAuthenticationBox
2021-02-08 11:29:27 +01:00
) -> 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 )
2021-03-09 12:41:18 +01:00
if favoriteKind = = . destroy {
2021-04-01 08:39:15 +02:00
oldStatus . update ( favouritesCount : NSNumber ( value : max ( 0 , oldStatus . favouritesCount . intValue - 1 ) ) )
2021-03-09 12:41:18 +01:00
}
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 ,
2021-07-20 10:40:04 +02:00
mastodonAuthenticationBox : MastodonAuthenticationBox
2021-02-08 11:29:27 +01:00
) -> 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 ,
2021-02-24 11:40:47 +01:00
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 ( )
}
}