// // Mastodon+API+Account+Friendship.swift // // // Created by MainasuK Cirno on 2021-4-1. // import Foundation import Combine extension Mastodon.API.Account { static func accountsRelationshipsEndpointURL(domain: String) -> URL { return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("accounts/relationships") } /// Check relationships to other accounts /// /// Find out whether a given account is followed, blocked, muted, etc. /// /// - Since: 0.0.0 /// - Version: 3.3.0 /// # Last Update /// 2021/4/1 /// # Reference /// [Document](https://docs.joinmastodon.org/methods/accounts/#perform-actions-on-an-account/) /// - Parameters: /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - query: `RelationshipQuery` /// - authorization: User token /// - Returns: `AnyPublisher` contains `[Relationship]` nested in the response public static func relationships( session: URLSession, domain: String, query: RelationshipQuery, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.get( url: accountsRelationshipsEndpointURL(domain: domain), query: query, authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in let value = try Mastodon.API.decode(type: [Mastodon.Entity.Relationship].self, from: data, response: response) return Mastodon.Response.Content(value: value, response: response) } .eraseToAnyPublisher() } public struct RelationshipQuery: GetQuery { public let ids: [Mastodon.Entity.Account.ID] public init(ids: [Mastodon.Entity.Account.ID]) { self.ids = ids } var queryItems: [URLQueryItem]? { var items: [URLQueryItem] = [] for id in ids { items.append(URLQueryItem(name: "id[]", value: id)) } guard !items.isEmpty else { return nil } return items } } } extension Mastodon.API.Account { public enum FollowQueryType { case follow(query: FollowQuery) case unfollow } public static func follow( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, followQueryType: FollowQueryType, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { switch followQueryType { case .follow(let query): return follow(session: session, domain: domain, accountID: accountID, query: query, authorization: authorization) case .unfollow: return unfollow(session: session, domain: domain, accountID: accountID, authorization: authorization) } } } extension Mastodon.API.Account { static func followEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL { let pathComponent = "accounts/" + accountID + "/follow" return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) } /// Follow /// /// Follow the given account. Can also be used to update whether to show reblogs or enable notifications. /// /// - Since: 0.0.0 /// - Version: 3.3.0 /// # Last Update /// 2021/4/1 /// # Reference /// [Document](https://docs.joinmastodon.org/methods/accounts/) /// - Parameters: /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - accountID: id for account /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Relationship` nested in the response public static func follow( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, query: FollowQuery, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.post( url: followEndpointURL(domain: domain, accountID: accountID), query: query, authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in let value = try Mastodon.API.decode(type: Mastodon.Entity.Relationship.self, from: data, response: response) return Mastodon.Response.Content(value: value, response: response) } .eraseToAnyPublisher() } public struct FollowQuery: Codable, PostQuery { public let reblogs: Bool? public let notify: Bool? public init(reblogs: Bool? = nil , notify: Bool? = nil) { self.reblogs = reblogs self.notify = notify } } } extension Mastodon.API.Account { static func unfollowEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL { let pathComponent = "accounts/" + accountID + "/unfollow" return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) } /// Unfollow /// /// Unfollow the given account. /// /// - Since: 0.0.0 /// - Version: 3.3.0 /// # Last Update /// 2021/4/1 /// # Reference /// [Document](https://docs.joinmastodon.org/methods/accounts/) /// - Parameters: /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - accountID: id for account /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Relationship` nested in the response public static func unfollow( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.post( url: unfollowEndpointURL(domain: domain, accountID: accountID), query: nil, authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in let value = try Mastodon.API.decode(type: Mastodon.Entity.Relationship.self, from: data, response: response) return Mastodon.Response.Content(value: value, response: response) } .eraseToAnyPublisher() } } extension Mastodon.API.Account { public enum BlockQueryType { case block case unblock } public static func block( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, blockQueryType: BlockQueryType, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { switch blockQueryType { case .block: return block(session: session, domain: domain, accountID: accountID, authorization: authorization) case .unblock: return unblock(session: session, domain: domain, accountID: accountID, authorization: authorization) } } } extension Mastodon.API.Account { static func blockEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL { let pathComponent = "accounts/" + accountID + "/block" return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) } /// 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/accounts/) /// - Parameters: /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - accountID: id for account /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Relationship` nested in the response public static func block( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.post( url: blockEndpointURL(domain: domain, accountID: accountID), query: nil, authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in let value = try Mastodon.API.decode(type: Mastodon.Entity.Relationship.self, from: data, response: response) return Mastodon.Response.Content(value: value, response: response) } .eraseToAnyPublisher() } } extension Mastodon.API.Account { static func unblockEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL { let pathComponent = "accounts/" + accountID + "/unblock" return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) } /// Unblock /// /// Unblock the given account. /// /// - Since: 0.0.0 /// - Version: 3.3.0 /// # Last Update /// 2021/4/1 /// # Reference /// [Document](https://docs.joinmastodon.org/methods/accounts/) /// - Parameters: /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - accountID: id for account /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Relationship` nested in the response public static func unblock( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.post( url: unblockEndpointURL(domain: domain, accountID: accountID), query: nil, authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in let value = try Mastodon.API.decode(type: Mastodon.Entity.Relationship.self, from: data, response: response) return Mastodon.Response.Content(value: value, response: response) } .eraseToAnyPublisher() } } extension Mastodon.API.Account { public enum MuteQueryType { case mute case unmute } public static func mute( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, muteQueryType: MuteQueryType, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { switch muteQueryType { case .mute: return mute(session: session, domain: domain, accountID: accountID, authorization: authorization) case .unmute: return unmute(session: session, domain: domain, accountID: accountID, authorization: authorization) } } } extension Mastodon.API.Account { static func mutekEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL { let pathComponent = "accounts/" + accountID + "/mute" return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) } /// Mute /// /// Mute the given account. Clients should filter statuses and notifications 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/accounts/) /// - Parameters: /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - accountID: id for account /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Relationship` nested in the response public static func mute( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.post( url: mutekEndpointURL(domain: domain, accountID: accountID), query: nil, authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in let value = try Mastodon.API.decode(type: Mastodon.Entity.Relationship.self, from: data, response: response) return Mastodon.Response.Content(value: value, response: response) } .eraseToAnyPublisher() } } extension Mastodon.API.Account { static func unmutekEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL { let pathComponent = "accounts/" + accountID + "/unmute" return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) } /// Unmute /// /// Unmute the given account. /// /// - Since: 0.0.0 /// - Version: 3.3.0 /// # Last Update /// 2021/4/1 /// # Reference /// [Document](https://docs.joinmastodon.org/methods/accounts/) /// - Parameters: /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - accountID: id for account /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Relationship` nested in the response public static func unmute( session: URLSession, domain: String, accountID: Mastodon.Entity.Account.ID, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.post( url: unmutekEndpointURL(domain: domain, accountID: accountID), query: nil, authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in let value = try Mastodon.API.decode(type: Mastodon.Entity.Relationship.self, from: data, response: response) return Mastodon.Response.Content(value: value, response: response) } .eraseToAnyPublisher() } }