From 65ed6650e817b3c388da606a9ed6eb7db21b4cb7 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Thu, 24 Nov 2022 07:53:04 +0100 Subject: [PATCH] feat: Implement deletion of records for blocked users --- ...omeTimelineViewModel+LoadLatestState.swift | 2 + .../Service/API/APIService+Block.swift | 30 ++++++++++++ .../Service/InstanceService.swift | 5 ++ .../API/Mastodon+API+Account+Friendship.swift | 47 +++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift index 8bf1421b1..d243c9a96 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift @@ -86,6 +86,8 @@ extension HomeTimelineViewModel.LoadLatestState { await enter(state: Idle.self) viewModel.homeTimelineNavigationBarTitleViewModel.receiveLoadingStateCompletion(.finished) + viewModel.context.instanceService.updateMutesAndBlocks() + // stop refresher if no new statuses let statuses = response.value let newStatuses = statuses.filter { !latestStatusIDs.contains($0.id) } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift index 7c78a65f7..d138d0401 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift @@ -22,6 +22,36 @@ extension APIService { let isFollowing: Bool } + @discardableResult + public func getBlocked( + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Account]> { + let managedObjectContext = backgroundManagedObjectContext + + let response = try await Mastodon.API.Account.blocks( + session: session, + domain: authenticationBox.domain, + authorization: authenticationBox.userAuthorization + ).singleOutput() + + let userIDs = response.value.map { $0.id } + let predicate = NSPredicate(format: "%K IN %@", #keyPath(MastodonUser.id), userIDs) + + let fetchRequest = MastodonUser.fetchRequest() + fetchRequest.predicate = predicate + fetchRequest.includesPropertyValues = false + + try await managedObjectContext.performChanges { + let accounts = try managedObjectContext.fetch(fetchRequest) as! [MastodonUser] + + for account in accounts { + managedObjectContext.delete(account) + } + } + + return response + } + public func toggleBlock( user: ManagedObjectRecord, authenticationBox: MastodonAuthenticationBox diff --git a/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift b/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift index 742476c28..99ad6d0a2 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift @@ -110,6 +110,11 @@ public extension InstanceService { try await apiService?.getMutes( authenticationBox: authBox ) + + try await apiService?.getBlocked( + authenticationBox: authBox + ) + self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update mutes and blocks succeeded") } catch { self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update mutes and blocks failure: \(error.localizedDescription)") diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift index c461466e7..65045fbd0 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift @@ -215,6 +215,53 @@ extension Mastodon.API.Account { } +public extension Mastodon.API.Account { + + static func blocksEndpointURL(domain: String) -> URL { + return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("blocks") + } + + /// Block + /// + /// Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline). + /// + /// - Since: 0.0.0 + /// - Version: 3.3.0 + /// # Last Update + /// 2021/4/1 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/blocks/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - authorization: User token. + /// - Returns: `AnyPublisher` contains `Relationship` nested in the response + static func blocks( + session: URLSession, + domain: String, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: blocksEndpointURL(domain: domain), + query: BlocksQuery(), + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Account].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + private struct BlocksQuery: GetQuery { + var queryItems: [URLQueryItem]? { + [URLQueryItem(name: "limit", value: "-1")] + } + } + +} + extension Mastodon.API.Account { static func blockEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL {