264 lines
9.8 KiB
Swift
264 lines
9.8 KiB
Swift
//
|
|
// AccountServiceCreateAccount.swift
|
|
// Wallet
|
|
//
|
|
// Created by Saveliy Stavitsky on 12/10/20.
|
|
// Copyright © 2020 List. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Alamofire
|
|
import DeviceCheck
|
|
import WalletNetwork
|
|
|
|
typealias JSON = [String: Any]
|
|
|
|
extension JSON {
|
|
func asData() -> Data? { try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted) }
|
|
}
|
|
|
|
extension AccountOnboarding.Service {
|
|
class CreateAccount {
|
|
|
|
private(set) var usernames: [String] = []
|
|
|
|
private func fetchDeviceToken(completion: @escaping (String?,NSError?) -> Void) {
|
|
guard DCDevice.current.isSupported else { completion(nil, .error(L10n.Error.Device.support));return }
|
|
DCDevice.current.generateToken {
|
|
guard $1 == nil, let data = $0 else { completion(nil, .error(L10n.Error.Device.token));return }
|
|
let result = [
|
|
"deviceType": "ios",
|
|
"payload": [
|
|
"device_token": data.base64EncodedString()
|
|
]
|
|
].asData()?.base64EncodedString()
|
|
DispatchQueue.main.async { completion(result ?? "", nil) }
|
|
}
|
|
}
|
|
|
|
struct CreateRequest: Codable {
|
|
let query: String
|
|
let variables: CreateRequestVariables?
|
|
let operationName: String?
|
|
}
|
|
struct CreateRequestVariables: Codable {
|
|
let publicKey: String
|
|
let username: String
|
|
let payload: String
|
|
}
|
|
|
|
func submitUsername(username: String, publicKey: String, completion: @escaping (Result<String, String>) -> Void) {
|
|
fetchDeviceToken { (token, error) in
|
|
|
|
guard let token = token else {
|
|
completion(.failure(error?.localizedDescription ?? L10n.Common.Error.default))
|
|
return
|
|
}
|
|
|
|
let environment = ApplicationEnvironment.shared().current
|
|
AF.request(
|
|
environment.backend.urlPath,
|
|
method: .post,
|
|
parameters: CreateRequest(
|
|
query: #"""
|
|
mutation createAccount($publicKey:String!, $username:String!, $payload:String!) {
|
|
createAccount(publicKey:$publicKey, username:$username, payload:$payload) {
|
|
account { username }
|
|
errors
|
|
}
|
|
}
|
|
"""#,
|
|
variables: CreateRequestVariables(publicKey: publicKey, username: username, payload: token),
|
|
operationName: "createAccount"),
|
|
encoder: JSONParameterEncoder.default,
|
|
headers: HTTPHeaders(environment.headers)
|
|
).responseDecodable(of: GraphQLResponse<CreateResponseData>.self) { (response) in
|
|
if let username = response.value?.data?.createAccount.account?.username {
|
|
return completion(.success(username))
|
|
} else {
|
|
return completion(.failure(response.value?.data?.createAccount.errors ?? ""))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct CreateResponseData: Decodable {
|
|
let createAccount: CreateData
|
|
}
|
|
private struct CreateData: Decodable {
|
|
let account: Account?
|
|
let errors: String?
|
|
}
|
|
}
|
|
}
|
|
|
|
extension AccountOnboarding.Service.CreateAccount {
|
|
|
|
func fetchUsernames(_ completion: @escaping ([String]) -> Void) {
|
|
|
|
let environment = ApplicationEnvironment.shared().current
|
|
AF.request(
|
|
environment.backend.urlPath,
|
|
method: .post,
|
|
parameters: ["query": "query { accountOrder { accounts { username } } }"],
|
|
encoder: JSONParameterEncoder.default,
|
|
headers: HTTPHeaders(environment.headers)
|
|
).responseDecodable(of: GraphQLResponse<UsernamesResponseData>.self) { (response) in
|
|
completion(response.value?.data?.accountOrder.accounts.map({ $0.username }) ?? [])
|
|
}
|
|
}
|
|
|
|
private struct UsernamesResponseData: Decodable {
|
|
let accountOrder: Order
|
|
}
|
|
private struct Order: Decodable {
|
|
let accounts: [Account]
|
|
}
|
|
private struct Account: Decodable {
|
|
let username: String
|
|
}
|
|
}
|
|
|
|
extension AccountOnboarding.Service.CreateAccount {
|
|
|
|
func checkUsername(username: String) async -> Bool {
|
|
|
|
let record = ApplicationEnvironment.shared().current
|
|
|
|
guard let environment = try? record.networkEnvironment() else { return false }
|
|
let service = AccountService(environment: environment)
|
|
|
|
switch await service.isAvailable(username: username) {
|
|
case .available: return true
|
|
case .alreadyTaken, .system: return false
|
|
}
|
|
}
|
|
}
|
|
|
|
extension AccountOnboarding.Service.CreateAccount {
|
|
|
|
func startWalletPurchase(username: String, publicKey: String, completion: @escaping (Result<String, String>) -> Void) {
|
|
|
|
let environment = ApplicationEnvironment.shared().current
|
|
AF.request(
|
|
environment.backend.urlPath,
|
|
method: .post,
|
|
parameters: CreateRequest(
|
|
query: #"""
|
|
mutation {
|
|
startWalletPurchase(username:"some_username", pubKey:"public_key", device:IOS) {
|
|
tempToken
|
|
errors
|
|
}
|
|
}
|
|
"""#
|
|
.replacingOccurrences(of: "some_username", with: username)
|
|
.replacingOccurrences(of: "public_key", with: publicKey),
|
|
variables: nil,
|
|
operationName: nil),
|
|
encoder: JSONParameterEncoder.default,
|
|
headers: HTTPHeaders(environment.headers)
|
|
)
|
|
.responseDecodable(of: GraphQLResponse<StartWalletPurchaseData>.self) { (response) in
|
|
if let tempToken = response.value?.data?.startWalletPurchase?.tempToken {
|
|
return completion(.success(tempToken))
|
|
} else {
|
|
return completion(.failure(response.value?.data?.startWalletPurchase?.errors
|
|
?? response.value?.errorsDescription ?? ""))
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct StartWalletPurchaseData: Decodable {
|
|
let startWalletPurchase: StartWalletPurchaseResult?
|
|
}
|
|
private struct StartWalletPurchaseResult: Decodable {
|
|
let tempToken: String?
|
|
let errors: String?
|
|
}
|
|
}
|
|
|
|
extension AccountOnboarding.Service.CreateAccount {
|
|
|
|
func verifyPurchase(tempToken: String, token: String, completion: @escaping (Result<Bool, String>) -> Void) {
|
|
|
|
let environment = ApplicationEnvironment.shared().current
|
|
AF.request(
|
|
environment.backend.urlPath,
|
|
method: .post,
|
|
parameters: CreateRequest(
|
|
query: #"""
|
|
query {
|
|
verifyPurchaseToken(tempToken:"temp_token", token:"token_token") {
|
|
errors
|
|
}
|
|
}
|
|
"""#
|
|
.replacingOccurrences(of: "temp_token", with: tempToken)
|
|
.replacingOccurrences(of: "token_token", with: token),
|
|
variables: nil,
|
|
operationName: nil),
|
|
encoder: JSONParameterEncoder.default,
|
|
headers: HTTPHeaders(environment.headers)
|
|
)
|
|
.responseDecodable(of: GraphQLResponse<VerifyPurchaseTokenData>.self) { (response) in
|
|
if let errors = response.value?.data?.verifyPurchaseToken?.errors ?? response.value?.errorsDescription {
|
|
return completion(.failure(errors))
|
|
} else {
|
|
return completion(.success(true))
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct VerifyPurchaseTokenData: Decodable {
|
|
let verifyPurchaseToken: VerifyPurchaseTokenResult?
|
|
}
|
|
private struct VerifyPurchaseTokenResult: Decodable {
|
|
let errors: String?
|
|
}
|
|
}
|
|
|
|
extension AccountOnboarding.Service.CreateAccount {
|
|
|
|
func completePurchase(tempToken: String, token: String, completion: @escaping (Result<Bool, String>) -> Void) {
|
|
|
|
let environment = ApplicationEnvironment.shared().current
|
|
AF.request(
|
|
environment.backend.urlPath,
|
|
method: .post,
|
|
parameters: CreateRequest(
|
|
query: #"""
|
|
mutation {
|
|
completePurchase(tempToken:"temp_token", token:"token_token") {
|
|
errors
|
|
}
|
|
}
|
|
"""#
|
|
.replacingOccurrences(of: "temp_token", with: tempToken)
|
|
.replacingOccurrences(of: "token_token", with: token),
|
|
variables: nil,
|
|
operationName: nil),
|
|
encoder: JSONParameterEncoder.default,
|
|
headers: HTTPHeaders(environment.headers)
|
|
)
|
|
// .responseString(completionHandler: {
|
|
// print(String(data: $0.data!, encoding: .utf8))
|
|
// print(String(data: $0.data!, encoding: .utf8))
|
|
// })
|
|
.responseDecodable(of: GraphQLResponse<CompletePurchaseData>.self) { (response) in
|
|
if let errors = response.value?.data?.completePurchase?.errors ?? response.value?.errorsDescription {
|
|
return completion(.failure(errors))
|
|
} else {
|
|
return completion(.success(true))
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct CompletePurchaseData: Decodable {
|
|
let completePurchase: CompletePurchaseResult?
|
|
}
|
|
private struct CompletePurchaseResult: Decodable {
|
|
let errors: String?
|
|
}
|
|
}
|