// // APIService+Mute.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 MastodonMuteContext { let sourceUserID: MastodonUser.ID let targetUserID: MastodonUser.ID let targetUsername: String let isMuting: Bool } func toggleMute( user: ManagedObjectRecord, authenticationBox: MastodonAuthenticationBox ) async throws -> Mastodon.Response.Content { let logger = Logger(subsystem: "APIService", category: "Mute") let managedObjectContext = backgroundManagedObjectContext let muteContext: MastodonMuteContext = 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 isMuting = user.mutingBy.contains(me) // toggle mute state user.update(isMuting: !isMuting, 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)) mute state: \(!isMuting)") return MastodonMuteContext( sourceUserID: me.id, targetUserID: user.id, targetUsername: user.username, isMuting: isMuting ) } let result: Result, Error> do { if muteContext.isMuting { let response = try await Mastodon.API.Account.unmute( session: session, domain: authenticationBox.domain, accountID: muteContext.targetUserID, authorization: authenticationBox.userAuthorization ).singleOutput() result = .success(response) } else { let response = try await Mastodon.API.Account.mute( session: session, domain: authenticationBox.domain, accountID: muteContext.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[\(muteContext.targetUserID)](\(muteContext.targetUsername)) mute 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[\(muteContext.targetUserID)](\(muteContext.targetUsername)) mute state: \(relationship.muting.debugDescription)") case .failure: // rollback user.update(isMuting: muteContext.isMuting, by: me) logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Remote] rollback user[\(muteContext.targetUserID)](\(muteContext.targetUsername)) mute state") } } let response = try result.get() return response } }