diff --git a/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift b/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift index cc135b64..f04f069a 100644 --- a/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift +++ b/Xcodes/AppleAPI/Sources/AppleAPI/Client.swift @@ -126,10 +126,10 @@ public class Client { switch urlResponse.statusCode { case 200..<300: return (data, urlResponse) - case 401: + case 400, 401: throw AuthenticationError.incorrectSecurityCode case let code: - throw AuthenticationError.badStatusCode(code, data, urlResponse) + throw AuthenticationError.badStatusCode(statusCode: code, data: data, response: urlResponse) } } .flatMap { (data, response) -> AnyPublisher in @@ -175,28 +175,36 @@ public enum AuthenticationState: Equatable { public enum AuthenticationError: Swift.Error, LocalizedError, Equatable { case invalidSession case invalidUsernameOrPassword(username: String) - case invalidPhoneNumberIndex(min: Int, max: Int, given: String?) case incorrectSecurityCode case unexpectedSignInResponse(statusCode: Int, message: String?) case appleIDAndPrivacyAcknowledgementRequired case accountUsesTwoStepAuthentication case accountUsesUnknownAuthenticationKind(String?) - case badStatusCode(Int, Data, HTTPURLResponse) + case badStatusCode(statusCode: Int, data: Data, response: HTTPURLResponse) public var errorDescription: String? { switch self { - case .invalidUsernameOrPassword(let username): - return "Invalid username and password combination. Attempted to sign in with username \(username)." + case .invalidSession: + return "Your authentication session is invalid. Try signing in again." + case .invalidUsernameOrPassword: + return "Invalid username and password combination." + case .incorrectSecurityCode: + return "The code that was entered is incorrect." + case let .unexpectedSignInResponse(statusCode, message): + return """ + Received an unexpected sign in response. If you continue to have problems, please submit a bug report in the Help menu and include the following information: + + Status code: \(statusCode) + \(message != nil ? ("Message: " + message!) : "") + """ case .appleIDAndPrivacyAcknowledgementRequired: return "You must sign in to https://appstoreconnect.apple.com and acknowledge the Apple ID & Privacy agreement." - case .invalidPhoneNumberIndex(let min, let max, let given): - return "Not a valid phone number index. Expecting a whole number between \(min)-\(max), but was given \(given ?? "nothing")." case .accountUsesTwoStepAuthentication: - return "Received a response from Apple that indicates this account has two-step authentication enabled. xcodes currently only supports the newer two-factor authentication, though. Please consider upgrading to two-factor authentication, or open an issue on GitHub explaining why this isn't an option for you here: https://github.com/RobotsAndPencils/xcodes/issues/new" + return "Received a response from Apple that indicates this account has two-step authentication enabled. xcodes currently only supports the newer two-factor authentication, though. Please consider upgrading to two-factor authentication, or explain why this isn't an option for you by making a new feature request in the Help menu." case .accountUsesUnknownAuthenticationKind: - return "Received a response from Apple that indicates this account has two-step or two-factor authentication enabled, but xcodes is unsure how to handle this response:" - default: - return String(describing: self) + return "Received a response from Apple that indicates this account has two-step or two-factor authentication enabled, but xcodes is unsure how to handle this response. If you continue to have problems, please submit a bug report in the Help menu." + case let .badStatusCode(statusCode, _, _): + return "Received an unexpected status code: \(statusCode). If you continue to have problems, please submit a bug report in the Help menu." } } } diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index 087bb109..3bf6138c 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -6,6 +6,7 @@ import LegibleError import KeychainAccess import Path import Version +import os.log class AppState: ObservableObject { private let client = AppleAPI.Client() @@ -181,7 +182,7 @@ class AppState: ObservableObject { try? Current.keychain.remove(username) } - // This error message is not user friendly... need to extract some meaningful data in the different cases + Logger.appState.error("Authentication error: \(error.legibleDescription)") self.authError = error case .finished: switch self.authenticationState { diff --git a/Xcodes/Frontend/About/AboutView.swift b/Xcodes/Frontend/About/AboutView.swift index d463f422..a34a8176 100644 --- a/Xcodes/Frontend/About/AboutView.swift +++ b/Xcodes/Frontend/About/AboutView.swift @@ -2,6 +2,7 @@ import SwiftUI struct AboutView: View { let showAcknowledgementsWindow: () -> Void + @SwiftUI.Environment(\.openURL) var openURL: OpenURLAction var body: some View { HStack { @@ -18,7 +19,7 @@ struct AboutView: View { HStack(spacing: 32) { Button(action: { - NSWorkspace.shared.open(URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")!) + openURL(URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")!) }) { Label("GitHub Repo", systemImage: "link") } diff --git a/Xcodes/XcodesApp.swift b/Xcodes/XcodesApp.swift index 85b0569f..4a8ab645 100644 --- a/Xcodes/XcodesApp.swift +++ b/Xcodes/XcodesApp.swift @@ -7,6 +7,7 @@ import SwiftUI struct XcodesApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate @SwiftUI.Environment(\.scenePhase) private var scenePhase: ScenePhase + @SwiftUI.Environment(\.openURL) var openURL: OpenURLAction @StateObject private var appState = AppState() var body: some Scene { @@ -51,6 +52,25 @@ struct XcodesApp: App { } XcodeCommands(appState: appState) + + CommandGroup(replacing: CommandGroupPlacement.help) { + Button("Xcodes GitHub Repo") { + let xcodesRepoURL = URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")! + openURL(xcodesRepoURL) + } + + Divider() + + Button("Report a Bug") { + let bugReportURL = URL(string: "https://github.com/RobotsAndPencils/XcodesApp/issues/new?assignees=&labels=bug&template=bug_report.md&title=")! + openURL(bugReportURL) + } + + Button("Request a New Feature") { + let featureRequestURL = URL(string: "https://github.com/RobotsAndPencils/XcodesApp/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=")! + openURL(featureRequestURL) + } + } } }