2021-03-09 08:18:43 +01:00
//
// A P I S e r v i c e + R e b l o g . s w i f t
// M a s t o d o n
//
// C r e a t e d b y M a i n a s u K C i r n o o n 2 0 2 1 - 3 - 9 .
//
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-03-15 11:19:45 +01:00
func reblog (
2021-04-01 08:39:15 +02:00
statusObjectID : NSManagedObjectID ,
2021-03-09 08:18:43 +01:00
mastodonUserObjectID : NSManagedObjectID ,
2021-03-15 11:19:45 +01:00
reblogKind : Mastodon . API . Reblog . ReblogKind
2021-04-01 08:39:15 +02:00
) -> AnyPublisher < Status . ID , Error > {
var _targetStatusID : Status . ID ?
2021-03-09 08:18:43 +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-03-09 08:18:43 +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-03-09 08:18:43 +01:00
2021-06-17 10:44:57 +02:00
let reblogsCount : NSNumber
2021-03-15 11:19:45 +01:00
switch reblogKind {
case . reblog :
2021-04-01 08:39:15 +02:00
targetStatus . update ( reblogged : true , by : mastodonUser )
2021-06-17 10:44:57 +02:00
reblogsCount = NSNumber ( value : targetStatus . reblogsCount . intValue + 1 )
2021-03-15 11:19:45 +01:00
case . undoReblog :
2021-04-01 08:39:15 +02:00
targetStatus . update ( reblogged : false , by : mastodonUser )
2021-06-17 10:44:57 +02:00
reblogsCount = NSNumber ( value : max ( 0 , targetStatus . reblogsCount . intValue - 1 ) )
2021-03-15 11:19:45 +01:00
}
2021-06-17 10:44:57 +02:00
targetStatus . update ( reblogsCount : reblogsCount )
2021-03-09 08:18:43 +01:00
}
. tryMap { result in
switch result {
case . success :
2021-04-01 08:39:15 +02:00
guard let targetStatusID = _targetStatusID else {
2021-03-09 08:18:43 +01:00
throw APIError . implicit ( . badRequest )
}
2021-04-01 08:39:15 +02:00
return targetStatusID
2021-03-09 08:18:43 +01:00
case . failure ( let error ) :
assertionFailure ( error . localizedDescription )
throw error
}
}
. eraseToAnyPublisher ( )
}
2021-03-15 11:19:45 +01:00
// s e n d r e b l o g r e q u e s t t o r e m o t e
func reblog (
2021-03-09 08:18:43 +01:00
statusID : Mastodon . Entity . Status . ID ,
2021-03-15 11:19:45 +01:00
reblogKind : Mastodon . API . Reblog . ReblogKind ,
2021-07-20 10:40:04 +02:00
mastodonAuthenticationBox : MastodonAuthenticationBox
2021-03-09 08:18:43 +01:00
) -> AnyPublisher < Mastodon . Response . Content < Mastodon . Entity . Status > , Error > {
let domain = mastodonAuthenticationBox . domain
let authorization = mastodonAuthenticationBox . userAuthorization
let requestMastodonUserID = mastodonAuthenticationBox . userID
2021-03-15 11:19:45 +01:00
return Mastodon . API . Reblog . reblog (
2021-03-09 08:18:43 +01:00
session : session ,
domain : domain ,
statusID : statusID ,
2021-03-15 11:19:45 +01:00
reblogKind : reblogKind ,
2021-03-09 08:18:43 +01:00
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 {
2021-03-11 07:08:00 +01:00
guard let requestMastodonUser : MastodonUser = {
2021-03-09 08:18:43 +01:00
let request = MastodonUser . sortedFetchRequest
request . predicate = MastodonUser . predicate ( domain : mastodonAuthenticationBox . domain , id : requestMastodonUserID )
request . fetchLimit = 1
request . returnsObjectsAsFaults = false
2021-03-11 07:34:10 +01:00
return managedObjectContext . safeFetch ( request ) . first
2021-03-11 07:08:00 +01:00
} ( ) else {
return
}
2021-04-01 08:39:15 +02:00
guard let oldStatus : Status = {
let request = Status . sortedFetchRequest
request . predicate = Status . 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
2021-04-01 08:39:15 +02:00
request . relationshipKeyPathsForPrefetching = [ # keyPath ( Status . reblog ) ]
2021-03-11 07:34:10 +01:00
return managedObjectContext . safeFetch ( request ) . first
2021-03-11 07:08:00 +01:00
} ( ) else {
2021-03-09 08:18:43 +01:00
return
}
2021-03-11 07:08:00 +01:00
2021-04-01 08:39:15 +02:00
APIService . CoreData . merge ( status : oldStatus , entity : entity . reblog ? ? entity , requestMastodonUser : requestMastodonUser , domain : mastodonAuthenticationBox . domain , networkDate : response . networkDate )
2021-03-15 11:19:45 +01:00
switch reblogKind {
case . undoReblog :
2021-07-26 09:18:20 +02:00
// u p d a t e r e b l o g g e d s t a t u s
2021-04-01 08:39:15 +02:00
oldStatus . update ( reblogsCount : NSNumber ( value : max ( 0 , oldStatus . reblogsCount . intValue - 1 ) ) )
2021-07-26 09:18:20 +02:00
// r e m o v e r e b l o g f r o m s t a t u s e s
let reblogFroms = oldStatus . reblogFrom ? . filter { status in
return status . author . domain = = domain && status . author . id = = requestMastodonUserID
} ? ? Set ( )
reblogFroms . forEach { reblogFrom in
managedObjectContext . delete ( reblogFrom )
}
2021-03-15 11:19:45 +01:00
default :
break
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 reblog status to: %{public}s. now %ld reblog " , ( ( #file as NSString ) . lastPathComponent ) , #line , #function , entity . id , entity . reblogged . flatMap { $0 ? " reblog " : " unreblog " } ? ? " <nil> " , entity . reblogsCount )
2021-03-09 08:18:43 +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 ) :
os_log ( . info , log : . debug , " %{public}s[%{public}ld], %{public}s: error: " , ( ( #file as NSString ) . lastPathComponent ) , #line , #function )
debugPrint ( error )
case . finished :
break
}
} )
. eraseToAnyPublisher ( )
}
}