Merge pull request #120 from tootsuite/fix/acctLookup
fix: acct lookup support
This commit is contained in:
commit
26116a222e
|
@ -336,6 +336,7 @@ extension MastodonPickServerViewController {
|
||||||
} else {
|
} else {
|
||||||
let mastodonRegisterViewModel = MastodonRegisterViewModel(
|
let mastodonRegisterViewModel = MastodonRegisterViewModel(
|
||||||
domain: server.domain,
|
domain: server.domain,
|
||||||
|
context: self.context,
|
||||||
authenticateInfo: response.authenticateInfo,
|
authenticateInfo: response.authenticateInfo,
|
||||||
instance: response.instance.value,
|
instance: response.instance.value,
|
||||||
applicationToken: response.applicationToken.value
|
applicationToken: response.applicationToken.value
|
||||||
|
|
|
@ -18,6 +18,7 @@ final class MastodonRegisterViewModel {
|
||||||
let authenticateInfo: AuthenticationViewModel.AuthenticateInfo
|
let authenticateInfo: AuthenticationViewModel.AuthenticateInfo
|
||||||
let instance: Mastodon.Entity.Instance
|
let instance: Mastodon.Entity.Instance
|
||||||
let applicationToken: Mastodon.Entity.Token
|
let applicationToken: Mastodon.Entity.Token
|
||||||
|
let context: AppContext
|
||||||
|
|
||||||
let username = CurrentValueSubject<String, Never>("")
|
let username = CurrentValueSubject<String, Never>("")
|
||||||
let displayName = CurrentValueSubject<String, Never>("")
|
let displayName = CurrentValueSubject<String, Never>("")
|
||||||
|
@ -46,11 +47,13 @@ final class MastodonRegisterViewModel {
|
||||||
|
|
||||||
init(
|
init(
|
||||||
domain: String,
|
domain: String,
|
||||||
|
context: AppContext,
|
||||||
authenticateInfo: AuthenticationViewModel.AuthenticateInfo,
|
authenticateInfo: AuthenticationViewModel.AuthenticateInfo,
|
||||||
instance: Mastodon.Entity.Instance,
|
instance: Mastodon.Entity.Instance,
|
||||||
applicationToken: Mastodon.Entity.Token
|
applicationToken: Mastodon.Entity.Token
|
||||||
) {
|
) {
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
|
self.context = context
|
||||||
self.authenticateInfo = authenticateInfo
|
self.authenticateInfo = authenticateInfo
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.applicationToken = applicationToken
|
self.applicationToken = applicationToken
|
||||||
|
@ -78,6 +81,45 @@ final class MastodonRegisterViewModel {
|
||||||
}
|
}
|
||||||
.assign(to: \.value, on: usernameValidateState)
|
.assign(to: \.value, on: usernameValidateState)
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
username
|
||||||
|
.filter { !$0.isEmpty }
|
||||||
|
.debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
|
||||||
|
.removeDuplicates()
|
||||||
|
.compactMap { [weak self] text -> AnyPublisher<Result<Mastodon.Response.Content<Mastodon.Entity.Account>, Error>, Never>? in
|
||||||
|
guard let self = self else { return nil }
|
||||||
|
let query = Mastodon.API.Account.AccountLookupQuery(acct: text)
|
||||||
|
return context.apiService.accountLookup(domain: domain, query: query, authorization: self.applicationAuthorization)
|
||||||
|
.map {
|
||||||
|
response -> Result<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> in
|
||||||
|
Result.success(response)
|
||||||
|
}
|
||||||
|
.catch { error in
|
||||||
|
Just(Result.failure(error))
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
.switchToLatest()
|
||||||
|
.sink { [weak self] result in
|
||||||
|
guard let self = self else { return }
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
let text = L10n.Scene.Register.Error.Reason.taken(L10n.Scene.Register.Error.Item.username)
|
||||||
|
self.usernameErrorPrompt.value = MastodonRegisterViewModel.errorPromptAttributedString(for: text)
|
||||||
|
case .failure:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
usernameValidateState
|
||||||
|
.sink { [weak self] validateState in
|
||||||
|
if validateState == .valid {
|
||||||
|
self?.usernameErrorPrompt.value = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
displayName
|
displayName
|
||||||
.map { displayname in
|
.map { displayname in
|
||||||
guard !displayname.isEmpty else { return .empty }
|
guard !displayname.isEmpty else { return .empty }
|
||||||
|
@ -115,7 +157,8 @@ final class MastodonRegisterViewModel {
|
||||||
let error = error as? Mastodon.API.Error
|
let error = error as? Mastodon.API.Error
|
||||||
let mastodonError = error?.mastodonError
|
let mastodonError = error?.mastodonError
|
||||||
if case let .generic(genericMastodonError) = mastodonError,
|
if case let .generic(genericMastodonError) = mastodonError,
|
||||||
let details = genericMastodonError.details {
|
let details = genericMastodonError.details
|
||||||
|
{
|
||||||
self.usernameErrorPrompt.value = details.usernameErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) }
|
self.usernameErrorPrompt.value = details.usernameErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) }
|
||||||
self.emailErrorPrompt.value = details.emailErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) }
|
self.emailErrorPrompt.value = details.emailErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) }
|
||||||
self.passwordErrorPrompt.value = details.passwordErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) }
|
self.passwordErrorPrompt.value = details.passwordErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) }
|
||||||
|
@ -139,7 +182,7 @@ final class MastodonRegisterViewModel {
|
||||||
|
|
||||||
Publishers.CombineLatest(
|
Publishers.CombineLatest(
|
||||||
publisherOne,
|
publisherOne,
|
||||||
approvalRequired ? reasonValidateState.map {$0 == .valid}.eraseToAnyPublisher() : Just(true).eraseToAnyPublisher()
|
approvalRequired ? reasonValidateState.map { $0 == .valid }.eraseToAnyPublisher() : Just(true).eraseToAnyPublisher()
|
||||||
)
|
)
|
||||||
.map { $0 && $1 }
|
.map { $0 && $1 }
|
||||||
.assign(to: \.value, on: isAllValid)
|
.assign(to: \.value, on: isAllValid)
|
||||||
|
@ -156,7 +199,6 @@ extension MastodonRegisterViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MastodonRegisterViewModel {
|
extension MastodonRegisterViewModel {
|
||||||
|
|
||||||
static func isValidEmail(_ email: String) -> Bool {
|
static func isValidEmail(_ email: String) -> Bool {
|
||||||
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
|
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
|
||||||
|
|
||||||
|
@ -206,5 +248,4 @@ extension MastodonRegisterViewModel {
|
||||||
|
|
||||||
return attributeString
|
return attributeString
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,7 @@ extension MastodonServerRulesViewController {
|
||||||
@objc private func confirmButtonPressed(_ sender: UIButton) {
|
@objc private func confirmButtonPressed(_ sender: UIButton) {
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||||
|
|
||||||
let viewModel = MastodonRegisterViewModel(domain: self.viewModel.domain, authenticateInfo: self.viewModel.authenticateInfo, instance: self.viewModel.instance, applicationToken: self.viewModel.applicationToken)
|
let viewModel = MastodonRegisterViewModel(domain: self.viewModel.domain, context: self.context, authenticateInfo: self.viewModel.authenticateInfo, instance: self.viewModel.instance, applicationToken: self.viewModel.applicationToken)
|
||||||
self.coordinator.present(scene: .mastodonRegister(viewModel: viewModel), from: self, transition: .show)
|
self.coordinator.present(scene: .mastodonRegister(viewModel: viewModel), from: self, transition: .show)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,4 +152,17 @@ extension APIService {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountLookup(
|
||||||
|
domain: String,
|
||||||
|
query: Mastodon.API.Account.AccountLookupQuery,
|
||||||
|
authorization: Mastodon.API.OAuth.Authorization
|
||||||
|
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> {
|
||||||
|
return Mastodon.API.Account.lookupAccount(
|
||||||
|
session: session,
|
||||||
|
domain: domain,
|
||||||
|
query: query,
|
||||||
|
authorization: authorization
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,3 +132,54 @@ extension Mastodon.API.Account {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Mastodon.API.Account {
|
||||||
|
static func accountsLookupEndpointURL(domain: String) -> URL {
|
||||||
|
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("accounts/lookup")
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AccountLookupQuery: GetQuery {
|
||||||
|
|
||||||
|
public var acct: String
|
||||||
|
|
||||||
|
public init(acct: String) {
|
||||||
|
self.acct = acct
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryItems: [URLQueryItem]? {
|
||||||
|
var items: [URLQueryItem] = []
|
||||||
|
items.append(URLQueryItem(name: "acct", value: acct))
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// lookup account by acct.
|
||||||
|
///
|
||||||
|
/// - Version: 3.3.1
|
||||||
|
|
||||||
|
/// - Parameters:
|
||||||
|
/// - session: `URLSession`
|
||||||
|
/// - domain: Mastodon instance domain. e.g. "example.com"
|
||||||
|
/// - query: `AccountInfoQuery` with account query information,
|
||||||
|
/// - authorization: app token
|
||||||
|
/// - Returns: `AnyPublisher` contains `Account` nested in the response
|
||||||
|
public static func lookupAccount(
|
||||||
|
session: URLSession,
|
||||||
|
domain: String,
|
||||||
|
query: AccountLookupQuery,
|
||||||
|
authorization: Mastodon.API.OAuth.Authorization?
|
||||||
|
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> {
|
||||||
|
let request = Mastodon.API.get(
|
||||||
|
url: accountsLookupEndpointURL(domain: domain),
|
||||||
|
query: query,
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue