diff --git a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme b/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme index 8642ae0..b0a4d86 100644 --- a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme +++ b/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme @@ -91,7 +91,7 @@ + isEnabled = "YES"> String { diff --git a/phpmon/Domain/DomainList/AddProxyVC.swift b/phpmon/Domain/DomainList/AddProxyVC.swift index f2363e0..6d0fe81 100644 --- a/phpmon/Domain/DomainList/AddProxyVC.swift +++ b/phpmon/Domain/DomainList/AddProxyVC.swift @@ -72,6 +72,7 @@ class AddProxyVC: NSViewController, NSTextFieldDelegate { App.shared.domainListWindowController?.contentVC.setUIBusy() Task { // Ensure we proxy the site asynchronously and reload UI on main thread again + #warning("Creating a proxy should happen via the ValetInteractor") await Shell.quiet("\(Paths.valet) proxy \(domain) \(proxyName)\(secure)") await Actions.restartNginx() diff --git a/phpmon/Domain/DomainList/AddSiteVC.swift b/phpmon/Domain/DomainList/AddSiteVC.swift index 17fd285..b4f5f71 100644 --- a/phpmon/Domain/DomainList/AddSiteVC.swift +++ b/phpmon/Domain/DomainList/AddSiteVC.swift @@ -71,6 +71,7 @@ class AddSiteVC: NSViewController, NSTextFieldDelegate { // Adding `valet links` is a workaround for Valet malforming the config.json file // TODO: I will have to investigate and report this behaviour if possible + #warning("Linking a site should happen via the ValetInteractor") Task { await Shell.quiet("cd '\(path)' && \(Paths.valet) link '\(name)' && valet links") } dismissView(outcome: .OK) diff --git a/phpmon/Domain/DomainList/DomainListVC+Actions.swift b/phpmon/Domain/DomainList/DomainListVC+Actions.swift index 389f538..2552e1c 100644 --- a/phpmon/Domain/DomainList/DomainListVC+Actions.swift +++ b/phpmon/Domain/DomainList/DomainListVC+Actions.swift @@ -68,7 +68,7 @@ extension DomainListVC { @objc func toggleSecure() { if selected is ValetSite { - Task { toggleSecureForSite() } + Task { await toggleSecureForSite() } } else { Task { await toggleSecureForProxy() } } @@ -78,74 +78,33 @@ extension DomainListVC { guard let proxy = selectedProxy else { return } do { - // Toggle secure + // Recreate proxy as secure or unsecured proxy try await proxy.toggleSecure() - // Send a notification about the new status (if applicable) - LocalNotification.send( - title: "domain_list.alerts_status_changed.title".localized, - subtitle: "domain_list.alerts_status_changed.desc" - .localized( - // 1. The domain that was secured is listed - "\(proxy.domain).\(Valet.shared.config.tld)", - // 2. What the domain is is listed (secure / unsecure) - proxy.secured - ? "domain_list.alerts_status_secure".localized - : "domain_list.alerts_status_secure".localized - ), - preference: .notifyAboutSecureToggle - ) - + self.notifyAboutModifiedSecureStatus(domain: proxy.domain, secured: proxy.secured) // Reload the UI (do this last so we don't invalidate the proxy) self.reloadSelectedRow() } catch { + // Notify the user about a failed command let error = error as! ValetInteractionError - - BetterAlert() - .withInformation( - title: "domain_list.alerts_status_not_changed.title".localized, - subtitle: "domain_list.alerts_status_not_changed.desc".localized(error.command) - ) - .withPrimary(text: "OK") - .show() + self.notifyAboutFailedSecureStatus(command: error.command) } } - func toggleSecureForSite() { - let rowToReload = tableView.selectedRow - let originalSecureStatus = selectedSite!.secured - let action = selectedSite!.secured ? "unsecure" : "secure" - let selectedSite = selectedSite! - let command = "cd '\(selectedSite.absolutePath)' && sudo \(Paths.valet) \(action) && exit;" + func toggleSecureForSite() async { + guard let site = selectedSite else { return } - waitAndExecute { - await Shell.quiet(command) - } completion: { [self] in - selectedSite.determineSecured() - if selectedSite.secured == originalSecureStatus { - BetterAlert() - .withInformation( - title: "domain_list.alerts_status_not_changed.title".localized, - subtitle: "domain_list.alerts_status_not_changed.desc".localized(command) - ) - .withPrimary(text: "OK") - .show() - } else { - let newState = selectedSite.secured ? "secured" : "unsecured" - LocalNotification.send( - title: "domain_list.alerts_status_changed.title".localized, - subtitle: "domain_list.alerts_status_changed.desc" - .localized( - "\(selectedSite.name).\(Valet.shared.config.tld)", - newState - ), - preference: .notifyAboutSecureToggle - ) - } - - tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0, 1, 2, 3, 4]) - tableView.deselectRow(rowToReload) - tableView.selectRowIndexes([rowToReload], byExtendingSelection: true) + do { + // Instruct Valet to secure or unsecure a site + try await site.toggleSecure() + // Send a notification about the new status (if applicable) + self.notifyAboutModifiedSecureStatus(domain: site.name, secured: site.secured) + // Reload the UI (do this last so we don't invalidate the proxy) + self.reloadSelectedRow() + } catch { + // Notify the user about a failed command + let error = error as! ValetInteractionError + self.notifyAboutFailedSecureStatus(command: error.command) } } @@ -223,4 +182,32 @@ extension DomainListVC { } ) } + + // MARK: - Alerts & Modals + + private func notifyAboutModifiedSecureStatus(domain: String, secured: Bool) { + LocalNotification.send( + title: "domain_list.alerts_status_changed.title".localized, + subtitle: "domain_list.alerts_status_changed.desc" + .localized( + // 1. The domain that was secured is listed + "\(domain).\(Valet.shared.config.tld)", + // 2. What the domain is is listed (secure / unsecure) + secured + ? "domain_list.alerts_status_secure".localized + : "domain_list.alerts_status_unsecure".localized + ), + preference: .notifyAboutSecureToggle + ) + } + + private func notifyAboutFailedSecureStatus(command: String) { + BetterAlert() + .withInformation( + title: "domain_list.alerts_status_not_changed.title".localized, + subtitle: "domain_list.alerts_status_not_changed.desc".localized(command) + ) + .withPrimary(text: "OK") + .show() + } } diff --git a/phpmon/Domain/Integrations/Valet/Domains/ValetInteractor.swift b/phpmon/Domain/Integrations/Valet/Domains/ValetInteractor.swift index 318b942..0e9722d 100644 --- a/phpmon/Domain/Integrations/Valet/Domains/ValetInteractor.swift +++ b/phpmon/Domain/Integrations/Valet/Domains/ValetInteractor.swift @@ -15,11 +15,31 @@ struct ValetInteractionError: Error { #warning("ValetInteractor needs to be implemented and used") class ValetInteractor { - public static func toggleSecure(site: ValetSite) async throws { - // TODO + static var shared = ValetInteractor() + + public static func useFake() { + ValetInteractor.shared = FakeValetInteractor() } - public static func toggleSecure(proxy: ValetProxy) async throws { + public func toggleSecure(site: ValetSite) async throws { + // Keep track of the original status (secure or not?) + let originalSecureStatus = site.secured + + // Keep track of the command we wish to run + let action = site.secured ? "unsecure" : "secure" + let command = "cd '\(site.absolutePath)' && sudo \(Paths.valet) \(action) && exit;" + + // Run the command + await Shell.quiet(command) + + // Check if the secured status has actually changed + site.determineSecured() + if site.secured == originalSecureStatus { + throw ValetInteractionError(command: command) + } + } + + public func toggleSecure(proxy: ValetProxy) async throws { // Keep track of the original status (secure or not?) let originalSecureStatus = proxy.secured @@ -33,6 +53,7 @@ class ValetInteractor { : "\(Paths.valet) proxy \(proxy.domain) \(proxy.target) --secure" ] + // Run the commands for command in commands { await Shell.quiet(command) } @@ -49,15 +70,29 @@ class ValetInteractor { await Actions.restartNginx() } - public static func isolate(site: ValetSite, version: PhpVersionNumber) async throws { + public func isolate(site: ValetSite, version: PhpVersionNumber) async throws { // TODO } - public static func unlink(site: ValetSite) async throws { + public func unlink(site: ValetSite) async throws { // TODO } - public static func remove(proxy: ValetProxy) async throws { + public func remove(proxy: ValetProxy) async throws { await Shell.quiet("valet unproxy '\(proxy.domain)'") } } + +class FakeValetInteractor: ValetInteractor { + override func toggleSecure(proxy: ValetProxy) async throws { + proxy.secured = !proxy.secured + } + + override func toggleSecure(site: ValetSite) async throws { + site.secured = !site.secured + } + + override func remove(proxy: ValetProxy) async throws { + fatalError("This should remove the proxy") + } +} diff --git a/phpmon/Domain/Integrations/Valet/Proxies/ValetProxy.swift b/phpmon/Domain/Integrations/Valet/Proxies/ValetProxy.swift index ce118e1..23d5cf0 100644 --- a/phpmon/Domain/Integrations/Valet/Proxies/ValetProxy.swift +++ b/phpmon/Domain/Integrations/Valet/Proxies/ValetProxy.swift @@ -58,10 +58,10 @@ class ValetProxy: ValetListable { } func toggleSecure() async throws { - try await ValetInteractor.toggleSecure(proxy: self) + try await ValetInteractor.shared.toggleSecure(proxy: self) } func remove() async { - try! await ValetInteractor.remove(proxy: self) + try! await ValetInteractor.shared.remove(proxy: self) } } diff --git a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift index 86ddb88..b88863e 100644 --- a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift +++ b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift @@ -266,14 +266,14 @@ class ValetSite: ValetListable { // MARK: - Interactions func toggleSecure() async throws { - try await ValetInteractor.toggleSecure(site: self) + try await ValetInteractor.shared.toggleSecure(site: self) } func isolate(version: PhpVersionNumber) async throws { - try await ValetInteractor.isolate(site: self, version: version) + try await ValetInteractor.shared.isolate(site: self, version: version) } func unlink() async throws { - try await ValetInteractor.unlink(site: self) + try await ValetInteractor.shared.unlink(site: self) } }