forked from zelo72/mastodon-ios
113 lines
4.9 KiB
Swift
113 lines
4.9 KiB
Swift
//
|
|
// APIService+Block.swift
|
|
// Mastodon
|
|
//
|
|
// Created by MainasuK Cirno on 2021-4-2.
|
|
//
|
|
|
|
import UIKit
|
|
import Combine
|
|
import CoreData
|
|
import CoreDataStack
|
|
import CommonOSLog
|
|
import MastodonSDK
|
|
|
|
extension APIService {
|
|
|
|
private struct MastodonBlockContext {
|
|
let sourceUserID: MastodonUser.ID
|
|
let targetUserID: MastodonUser.ID
|
|
let targetUsername: String
|
|
let isBlocking: Bool
|
|
let isFollowing: Bool
|
|
}
|
|
|
|
func toggleBlock(
|
|
user: ManagedObjectRecord<MastodonUser>,
|
|
authenticationBox: MastodonAuthenticationBox
|
|
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Relationship> {
|
|
let logger = Logger(subsystem: "APIService", category: "Block")
|
|
|
|
let managedObjectContext = backgroundManagedObjectContext
|
|
let blockContext: MastodonBlockContext = try await managedObjectContext.performChanges {
|
|
guard let user = user.object(in: managedObjectContext),
|
|
let authentication = authenticationBox.authenticationRecord.object(in: managedObjectContext)
|
|
else {
|
|
throw APIError.implicit(.badRequest)
|
|
}
|
|
let me = authentication.user
|
|
let isBlocking = user.blockingBy.contains(me)
|
|
let isFollowing = user.followingBy.contains(me)
|
|
// toggle block state
|
|
user.update(isBlocking: !isBlocking, by: me)
|
|
// update follow state implicitly
|
|
if !isBlocking {
|
|
// will do block action. set to unfollow
|
|
user.update(isFollowing: false, by: me)
|
|
}
|
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Local] update user[\(user.id)](\(user.username)) block state: \(!isBlocking)")
|
|
return MastodonBlockContext(
|
|
sourceUserID: me.id,
|
|
targetUserID: user.id,
|
|
targetUsername: user.username,
|
|
isBlocking: isBlocking,
|
|
isFollowing: isFollowing
|
|
)
|
|
}
|
|
|
|
let result: Result<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error>
|
|
do {
|
|
if blockContext.isBlocking {
|
|
let response = try await Mastodon.API.Account.unblock(
|
|
session: session,
|
|
domain: authenticationBox.domain,
|
|
accountID: blockContext.targetUserID,
|
|
authorization: authenticationBox.userAuthorization
|
|
).singleOutput()
|
|
result = .success(response)
|
|
} else {
|
|
let response = try await Mastodon.API.Account.block(
|
|
session: session,
|
|
domain: authenticationBox.domain,
|
|
accountID: blockContext.targetUserID,
|
|
authorization: authenticationBox.userAuthorization
|
|
).singleOutput()
|
|
result = .success(response)
|
|
}
|
|
} catch {
|
|
result = .failure(error)
|
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Remote] update user[\(blockContext.targetUserID)](\(blockContext.targetUsername)) block failure: \(error.localizedDescription)")
|
|
}
|
|
|
|
try await managedObjectContext.performChanges {
|
|
guard let user = user.object(in: managedObjectContext),
|
|
let authentication = authenticationBox.authenticationRecord.object(in: managedObjectContext)
|
|
else { return }
|
|
let me = authentication.user
|
|
|
|
switch result {
|
|
case .success(let response):
|
|
let relationship = response.value
|
|
Persistence.MastodonUser.update(
|
|
mastodonUser: user,
|
|
context: Persistence.MastodonUser.RelationshipContext(
|
|
entity: relationship,
|
|
me: me,
|
|
networkDate: response.networkDate
|
|
)
|
|
)
|
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Remote] update user[\(blockContext.targetUserID)](\(blockContext.targetUsername)) block state: \(relationship.blocking)")
|
|
case .failure:
|
|
// rollback
|
|
user.update(isBlocking: blockContext.isBlocking, by: me)
|
|
user.update(isFollowing: blockContext.isFollowing, by: me)
|
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Remote] rollback user[\(blockContext.targetUserID)](\(blockContext.targetUsername)) block state")
|
|
}
|
|
}
|
|
|
|
let response = try result.get()
|
|
return response
|
|
}
|
|
|
|
}
|