// // Account.swift // Pachyderm // // Created by Shadowfacts on 9/8/18. // Copyright © 2018 Shadowfacts. All rights reserved. // import Foundation public class Account: Decodable { public let id: String public let username: String public let acct: String public let displayName: String public let locked: Bool public let createdAt: Date public let followersCount: Int public let followingCount: Int public let statusesCount: Int public let note: String public let url: URL public let avatar: URL public let avatarStatic: URL public let header: URL public let headerStatic: URL public private(set) var emojis: [Emoji] public let moved: Bool? public let movedTo: Account? public let fields: [Field]? public let bot: Bool? public required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decode(String.self, forKey: .id) self.username = try container.decode(String.self, forKey: .username) self.acct = try container.decode(String.self, forKey: .acct) self.displayName = try container.decode(String.self, forKey: .displayName) self.locked = try container.decode(Bool.self, forKey: .locked) self.createdAt = try container.decode(Date.self, forKey: .createdAt) self.followersCount = try container.decode(Int.self, forKey: .followersCount) self.followingCount = try container.decode(Int.self, forKey: .followingCount) self.statusesCount = try container.decode(Int.self, forKey: .statusesCount) self.note = try container.decode(String.self, forKey: .note) self.url = try container.decode(URL.self, forKey: .url) self.avatar = try container.decode(URL.self, forKey: .avatar) self.avatarStatic = try container.decode(URL.self, forKey: .avatarStatic) self.header = try container.decode(URL.self, forKey: .header) self.headerStatic = try container.decode(URL.self, forKey: .url) self.emojis = try container.decode([Emoji].self, forKey: .emojis) self.fields = try? container.decode([Field].self, forKey: .fields) self.bot = try? container.decode(Bool.self, forKey: .bot) if let moved = try? container.decode(Bool.self, forKey: .moved) { self.moved = moved self.movedTo = nil } else if let account = try? container.decode(Account.self, forKey: .moved) { self.moved = true self.movedTo = account } else { self.moved = false self.movedTo = nil } } public static func authorizeFollowRequest(_ account: Account) -> Request { return Request(method: .post, path: "/api/v1/follow_requests/\(account.id)/authorize") } public static func rejectFollowRequest(_ account: Account) -> Request { return Request(method: .post, path: "/api/v1/follow_requests/\(account.id)/reject") } public static func removeFromFollowRequests(_ account: Account) -> Request { return Request(method: .delete, path: "/api/v1/suggestions/\(account.id)") } public static func getFollowers(_ account: Account, range: RequestRange = .default) -> Request<[Account]> { var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(account.id)/followers") request.range = range return request } public static func getFollowing(_ account: Account, range: RequestRange = .default) -> Request<[Account]> { var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(account.id)/following") request.range = range return request } public static func getStatuses(_ accountID: String, range: RequestRange = .default, onlyMedia: Bool? = nil, pinned: Bool? = nil, excludeReplies: Bool? = nil) -> Request<[Status]> { var request = Request<[Status]>(method: .get, path: "/api/v1/accounts/\(accountID)/statuses", queryParameters: [ "only_media" => onlyMedia, "pinned" => pinned, "exclude_replies" => excludeReplies ]) request.range = range return request } public static func follow(_ accountID: String) -> Request { return Request(method: .post, path: "/api/v1/accounts/\(accountID)/follow") } public static func unfollow(_ accountID: String) -> Request { return Request(method: .post, path: "/api/v1/accounts/\(accountID)/unfollow") } public static func block(_ account: Account) -> Request { return Request(method: .post, path: "/api/v1/accounts/\(account.id)/block") } public static func unblock(_ account: Account) -> Request { return Request(method: .post, path: "/api/v1/accounts/\(account.id)/unblock") } public static func mute(_ account: Account, notifications: Bool? = nil) -> Request { return Request(method: .post, path: "/api/v1/accounts/\(account.id)/mute", body: .parameters([ "notifications" => notifications ])) } public static func unmute(_ account: Account) -> Request { return Request(method: .post, path: "/api/v1/accounts/\(account.id)/unmute") } public static func getLists(_ account: Account) -> Request<[List]> { return Request<[List]>(method: .get, path: "/api/v1/accounts/\(account.id)/lists") } private enum CodingKeys: String, CodingKey { case id case username case acct case displayName = "display_name" case locked case createdAt = "created_at" case followersCount = "followers_count" case followingCount = "following_count" case statusesCount = "statuses_count" case note case url case avatar case avatarStatic = "avatar_static" case header case headerStatic = "header_static" case emojis case moved case fields case bot } } extension Account: CustomDebugStringConvertible { public var debugDescription: String { return "Account(\(id), \(acct))" } } extension Account { public struct Field: Codable { public let name: String public let value: String } }