// Copyright © 2020 Metabolist. All rights reserved. import Combine import DB import Foundation import Mastodon import MastodonAPI public struct AccountService { public let account: Account public let relationship: Relationship? public let identityProofs: [IdentityProof] public let featuredTags: [FeaturedTag] public let navigationService: NavigationService private let mastodonAPIClient: MastodonAPIClient private let contentDatabase: ContentDatabase public init(account: Account, relationship: Relationship? = nil, identityProofs: [IdentityProof] = [], featuredTags: [FeaturedTag] = [], mastodonAPIClient: MastodonAPIClient, contentDatabase: ContentDatabase) { self.account = account self.relationship = relationship self.identityProofs = identityProofs self.featuredTags = featuredTags navigationService = NavigationService(mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase) self.mastodonAPIClient = mastodonAPIClient self.contentDatabase = contentDatabase } } public extension AccountService { var isLocal: Bool { account.url.host == mastodonAPIClient.instanceURL.host } var domain: String? { account.url.host } func follow() -> AnyPublisher { relationshipAction(.accountsFollow(id: account.id)) } func unfollow() -> AnyPublisher { relationshipAction(.accountsUnfollow(id: account.id)) .collect() .flatMap { _ in contentDatabase.unfollow(id: account.id) } .eraseToAnyPublisher() } func hideReblogs() -> AnyPublisher { relationshipAction(.accountsFollow(id: account.id, showReblogs: false)) } func showReblogs() -> AnyPublisher { relationshipAction(.accountsFollow(id: account.id, showReblogs: true)) } func block() -> AnyPublisher { relationshipAction(.accountsBlock(id: account.id)) .collect() .flatMap { _ in contentDatabase.block(id: account.id) } .eraseToAnyPublisher() } func unblock() -> AnyPublisher { relationshipAction(.accountsUnblock(id: account.id)) } func mute() -> AnyPublisher { relationshipAction(.accountsMute(id: account.id)) .collect() .flatMap { _ in contentDatabase.mute(id: account.id) } .eraseToAnyPublisher() } func unmute() -> AnyPublisher { relationshipAction(.accountsUnmute(id: account.id)) } func pin() -> AnyPublisher { relationshipAction(.accountsPin(id: account.id)) } func unpin() -> AnyPublisher { relationshipAction(.accountsUnpin(id: account.id)) } func set(note: String) -> AnyPublisher { relationshipAction(.note(note, id: account.id)) } func report(_ elements: ReportElements) -> AnyPublisher { mastodonAPIClient.request(ReportEndpoint.create(elements)).ignoreOutput().eraseToAnyPublisher() } func domainBlock() -> AnyPublisher { guard let domain = domain else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } return domainAction(EmptyEndpoint.blockDomain(domain)) } func domainUnblock() -> AnyPublisher { guard let domain = domain else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } return domainAction(EmptyEndpoint.unblockDomain(domain)) } func followingService() -> AccountListService { AccountListService( endpoint: .accountsFollowing(id: account.id), mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase, titleComponents: ["account.followed-by-%@", "@".appending(account.acct)]) } func followersService() -> AccountListService { AccountListService( endpoint: .accountsFollowers(id: account.id), mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase, titleComponents: ["account.%@-followers", "@".appending(account.acct)]) } } private extension AccountService { func relationshipAction(_ endpoint: RelationshipEndpoint) -> AnyPublisher { mastodonAPIClient.request(endpoint) .flatMap { contentDatabase.insert(relationships: [$0]) } .eraseToAnyPublisher() } func domainAction(_ endpoint: EmptyEndpoint) -> AnyPublisher { mastodonAPIClient.request(endpoint) .flatMap { _ in mastodonAPIClient.request(RelationshipsEndpoint.relationships(ids: [account.id])) } .flatMap { contentDatabase.insert(relationships: $0) } .ignoreOutput() .eraseToAnyPublisher() } }