diff --git a/Box42/Menubar/MenubarViewController.swift b/Box42/Menubar/MenubarViewController.swift index 56f60e5..495d7df 100644 --- a/Box42/Menubar/MenubarViewController.swift +++ b/Box42/Menubar/MenubarViewController.swift @@ -9,7 +9,7 @@ import Foundation import AppKit class MenubarViewController: NSViewController { - var popover = NSPopover() + var popover: NSPopover! = NSPopover() var statusBarVM = StatusBarViewModel() lazy var eventMonitor: EventMonitor = self.setupEventMonitor() var boxWindowController: BoxWindowController? diff --git a/Box42/QuickSlot/Model/QuickSlotButtonModel.swift b/Box42/QuickSlot/Model/QuickSlotButtonModel.swift index b965db8..9a55e20 100644 --- a/Box42/QuickSlot/Model/QuickSlotButtonModel.swift +++ b/Box42/QuickSlot/Model/QuickSlotButtonModel.swift @@ -8,7 +8,7 @@ import Foundation // Model -struct QuickSlotButtonModel { +struct QuickSlotButtonModel: Codable { let id: UUID var title: String var path: String? diff --git a/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift b/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift index c5d60bc..b1b31be 100644 --- a/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift +++ b/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift @@ -41,7 +41,9 @@ class QuickSlotButtonCollectionViewController: NSViewController { func initializeCombine() { viewModel.$buttons .sink { [weak self] _ in - self?.quickSlotButtonCollectionView.reloadData() + DispatchQueue.main.async { + self?.quickSlotButtonCollectionView.reloadData() + } } .store(in: &cancellables) } diff --git a/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift b/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift index d636599..568168d 100644 --- a/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift +++ b/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift @@ -13,7 +13,8 @@ class QuickSlotViewModel { @Published var buttons: [QuickSlotButtonModel] = [] private init() { - let button1 = QuickSlotButtonModel(title: QuickSlotUI.title.clean, + let button1 = QuickSlotButtonModel(id: UUID(uuidString: "550e8400-e29b-41d4-a716-446655440000")!, + title: QuickSlotUI.title.clean, path: Bundle.main.path(forResource: "cleanCache", ofType: "sh")) let button2 = QuickSlotButtonModel(title: QuickSlotUI.title.preferences) let button3 = QuickSlotButtonModel(title: QuickSlotUI.title.scripts) diff --git a/Box42/Resources/AppDelegate.swift b/Box42/Resources/AppDelegate.swift index d674746..7d2ae45 100644 --- a/Box42/Resources/AppDelegate.swift +++ b/Box42/Resources/AppDelegate.swift @@ -31,8 +31,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { WebViewManager.shared.getCookie() API.getUserProfile(WebViewManager.shared.getCookieWebKit) _ = QuickSlotViewModel.shared - API.getUserMeScripts(WebViewManager.shared.getCookieWebKit) - _ = ScriptViewModel.shared + _ = ScriptViewModel.shared // 초기화와 동시에 } func applicationWillTerminate(_ aNotification: Notification) { diff --git a/Box42/Scripts/Controller/ScriptsViewController.swift b/Box42/Scripts/Controller/ScriptsViewController.swift index e86f46d..ff06ef2 100644 --- a/Box42/Scripts/Controller/ScriptsViewController.swift +++ b/Box42/Scripts/Controller/ScriptsViewController.swift @@ -10,7 +10,7 @@ import Foundation class ScriptsViewController: NSViewController { var scriptsTableView: ScriptsTableView? - var viewModel: ScriptViewModel? = ScriptViewModel() { + var viewModel: ScriptViewModel? = ScriptViewModel.shared { didSet { scriptsTableView?.viewModel = viewModel } diff --git a/Box42/Scripts/Model/Scripts.swift b/Box42/Scripts/Model/Scripts.swift index a83a5c4..40d59fa 100644 --- a/Box42/Scripts/Model/Scripts.swift +++ b/Box42/Scripts/Model/Scripts.swift @@ -12,17 +12,19 @@ struct Scripts: Codable { } struct Script: Codable { - var id: UUID + var id: UUID? var name: String var description: String var path: String - var savedId: Int + var savedId: Int? + var userUuid: String? - init(name: String, description: String, path: String, savedId: Int) { - self.id = UUID() + init(id: UUID = UUID(), name: String, description: String, path: String, savedId: Int, userUuid: String?) { + self.id = id self.name = name self.description = description self.path = path self.savedId = savedId + self.userUuid = userUuid } } diff --git a/Box42/Scripts/View/Table/ScriptsTableView.swift b/Box42/Scripts/View/Table/ScriptsTableView.swift index 2d77ef0..ccb1343 100644 --- a/Box42/Scripts/View/Table/ScriptsTableView.swift +++ b/Box42/Scripts/View/Table/ScriptsTableView.swift @@ -12,14 +12,17 @@ import Combine class ScriptsTableView: NSTableView { var viewModel: ScriptViewModel? { didSet { + print("ViewModel has been set.") setupBindings() } } - + var cancellables: Set = [] private func setupBindings() { - viewModel?.$scripts.sink(receiveValue: { [weak self] _ in + print("Setting up bindings...") // 디버깅 로그 + viewModel?.$scripts.sink(receiveValue: { [weak self] newScripts in + print("Received new scripts: \(newScripts)") // 디버깅 로그 DispatchQueue.main.async { self?.reloadData() } diff --git a/Box42/Scripts/ViewModel/ScriptsViewModel.swift b/Box42/Scripts/ViewModel/ScriptsViewModel.swift index d81c86e..04a0a37 100644 --- a/Box42/Scripts/ViewModel/ScriptsViewModel.swift +++ b/Box42/Scripts/ViewModel/ScriptsViewModel.swift @@ -13,32 +13,33 @@ class ScriptViewModel: NSObject { @Published var scripts: [Script] = [] - override init() { + private override init() { self.scripts = [ Script(name: "cleanCache", description: "Cleaning cache", - path: Bundle.main.path(forResource: "cleanCache", ofType: "sh") ?? "", savedId: -1 ), - Script(name: "brewInGoinfre", - description: "Brew download in goinfre", - path: Bundle.main.path(forResource: "brewInGoinfre", ofType: "sh") ?? "", savedId: -1), - Script(name: "exportMacOSInfo", - description: "export setting MacOS Info", - path: Bundle.main.path(forResource: "exportMacOSInfo", ofType: "sh") ?? "", savedId: -1 ), - Script(name: "importMacOSInfo", - description: "import MacOS Info", - path: Bundle.main.path(forResource: "importMacOSInfo", ofType: "sh") ?? "", savedId: -1), - Script(name: "key Mapping", - description: "key Mapping", - path: Bundle.main.path(forResource: "keyMapping", ofType: "sh") ?? "", savedId: -1 ), - Script(name: "nodeInstall", - description: "node Install", - path: Bundle.main.path(forResource: "nodeInstall", ofType: "sh") ?? "", savedId: -1) + path: Bundle.main.path(forResource: "cleanCache", ofType: "sh") ?? "", savedId: -1 , userUuid: nil), +// Script(name: "brewInGoinfre", +// description: "Brew download in goinfre", +// path: Bundle.main.path(forResource: "brewInGoinfre", ofType: "sh") ?? "", savedId: -1, userUuid: nil), +// Script(name: "exportMacOSInfo", +// description: "export setting MacOS Info", +// path: Bundle.main.path(forResource: "exportMacOSInfo", ofType: "sh") ?? "", savedId: -1, userUuid: nil), +// Script(name: "importMacOSInfo", +// description: "import MacOS Info", +// path: Bundle.main.path(forResource: "importMacOSInfo", ofType: "sh") ?? "", savedId: -1, userUuid: nil), +// Script(name: "key Mapping", +// description: "key Mapping", +// path: Bundle.main.path(forResource: "keyMapping", ofType: "sh") ?? "", savedId: -1, userUuid: nil), +// Script(name: "nodeInstall", +// description: "node Install", +// path: Bundle.main.path(forResource: "nodeInstall", ofType: "sh") ?? "", savedId: -1, userUuid: nil) ] + API.initializeUserMeScripts(WebViewManager.shared.getCookieWebKit) } // Create - func addScript(name: String, description: String, path: String) { - let newScript = Script(name: name, description: description, path: path, savedId: -1) + func addScript(id: UUID = UUID(), name: String, description: String, path: String, savedId: Int, userUuid: String) { + let newScript = Script(id: UUID(), name: name, description: description, path: path, savedId: savedId, userUuid: userUuid) scripts.append(newScript) } @@ -61,16 +62,30 @@ class ScriptViewModel: NSObject { // Delete func deleteScript(id: UUID) { - // delete 요청 보내야함 보내고 성공하면 지우기 - scripts.removeAll(where: { $0.id == id }) - QuickSlotViewModel.shared.removeButton(id) + if let script = scripts.first(where: { $0.id == id }) { + API.deleteUserMeScripts(WebViewManager.shared.getCookieWebKit, savedId: script.savedId!) { result in + switch result { + case .success(_): + self.scripts.removeAll(where: { $0.id == id }) + QuickSlotViewModel.shared.removeButton(id) + + case .failure(let error): + print("Failed to delete script: \(error)") + } + } + } } - // 새로운 스크립트 배열로 교체하는 메서드 + // 새로운 스크립트 배열로 교체하는 메소드 func replaceScripts(with newScripts: [Script]) { self.scripts = newScripts } + // VM class 시작시 최초 1회 실행되는 메소드 + func setupScripts(with newScripts: [Script]) { + self.scripts += newScripts + } + // 스크립트안에서 해당하는 스크립트를 찾아서 quickslotVM에 추가 func quickSlotScript(id: UUID) { if let index = scripts.firstIndex(where: { $0.id == id }) { diff --git a/Box42/Shared/API/API.swift b/Box42/Shared/API/API.swift index f9cb069..5d709ef 100644 --- a/Box42/Shared/API/API.swift +++ b/Box42/Shared/API/API.swift @@ -26,9 +26,17 @@ class API { return } + let jsonString = String(data: data, encoding: .utf8) + print("Received JSON string:\n\(jsonString ?? "")") + do { + if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { + print("Received data:\n\(json)") + } + let decodedData = try JSONDecoder().decode(type, from: data) completion(.success(decodedData)) + } catch let jsonError { completion(.failure(jsonError)) } @@ -54,10 +62,9 @@ class API { completion(.failure(NSError(domain: "InvalidStatusCode", code: httpResponse.statusCode, userInfo: nil))) return } - completion(.success(data)) } task.resume() } - + } diff --git a/Box42/Shared/API/DeleteUserMeScript.swift b/Box42/Shared/API/DeleteUserMeScript.swift index abfc1e1..dc77f5c 100644 --- a/Box42/Shared/API/DeleteUserMeScript.swift +++ b/Box42/Shared/API/DeleteUserMeScript.swift @@ -5,4 +5,20 @@ // Created by Chanhee Kim on 9/2/23. // -import Foundation +import WebKit + +extension API { + // MARK: - Scripts DELETE: https://api.42box.kr/user-service/users/me/scripts/{savedId} + static func deleteUserMeScripts(_ webView: WKWebView, savedId: Int, completion: @escaping (Result) -> Void) { + let url = "https://api.42box.kr/user-service/users/me/scripts/\(savedId)" + + deleteDataFromAPI(withURL: url) { (result: Result) in + switch result { + case .success(_): + completion(.success(())) + case .failure(let error): + completion(.failure(error)) + } + } + } +} diff --git a/Box42/Shared/API/GetUserMeScripts.swift b/Box42/Shared/API/GetUserMeScripts.swift index 7fa7d15..cd09521 100644 --- a/Box42/Shared/API/GetUserMeScripts.swift +++ b/Box42/Shared/API/GetUserMeScripts.swift @@ -8,7 +8,7 @@ import WebKit extension API { - // MARK: - Scripts GET: https://api.42box.site/user-service/users/me/scripts + // MARK: - Scripts GET: https://api.42box.kr/user-service/users/me/scripts // result : scripts.shared 저장 static func getUserMeScripts(_ webView: WKWebView) { @@ -18,7 +18,7 @@ extension API { cookieStorage.setCookie(cookie) } - fetchDataFromAPI(withURL: "https://api.42box.site/user-service/users/me/scripts", forType: [Script].self) { (result: Result<[Script], Error>) in + fetchDataFromAPI(withURL: "https://api.42box.kr/user-service/users/me/scripts", forType: [Script].self) { (result: Result<[Script], Error>) in switch result { case .success(let scripts): print(">> MacOS Get :", scripts) @@ -31,4 +31,26 @@ extension API { } } } + + static func initializeUserMeScripts(_ webView: WKWebView) { + webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in + let cookieStorage = HTTPCookieStorage.shared + for cookie in cookies { + cookieStorage.setCookie(cookie) + } + + fetchDataFromAPI(withURL: "https://api.42box.kr/user-service/users/me/scripts", forType: [Script].self) { (result: Result<[Script], Error>) in + switch result { + case .success(let scripts): + print(">> MacOS Get :", scripts) + DispatchQueue.main.async { + ScriptViewModel.shared.setupScripts(with: scripts) + } + case .failure(let error): + print("Error: \(error)") + } + } + } + } + } diff --git a/Box42/Shared/API/GetUserProfile.swift b/Box42/Shared/API/GetUserProfile.swift index 1815669..f029f45 100644 --- a/Box42/Shared/API/GetUserProfile.swift +++ b/Box42/Shared/API/GetUserProfile.swift @@ -8,7 +8,7 @@ import WebKit extension API { - // MARK: - 유저 정보 (Back) GET: https://api.42box.site/user-service/users/me + // MARK: - 유저 정보 (Back) GET: https://api.42box.kr/user-service/users/me // result : 성공 UserProfile.shared 저장 static func getUserProfile(_ webView: WKWebView) { @@ -18,7 +18,7 @@ extension API { cookieStorage.setCookie(cookie) } - fetchDataFromAPI(withURL: "https://api.42box.site/user-service/users/me", forType: UserProfile.self) { (result: Result) in + fetchDataFromAPI(withURL: "https://api.42box.kr/user-service/users/me", forType: UserProfile.self) { (result: Result) in switch result { case .success(let userProfile): print(">> MacOS Get :", userProfile) @@ -30,40 +30,3 @@ extension API { } } } - -//static func getUserProfile(_ webView: WKWebView) { -// webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in -// let cookieStorage = HTTPCookieStorage.shared -// -// for cookie in cookies { -//// print("\(cookie.name) = \(cookie.value)") -// cookieStorage.setCookie(cookie) -// } -// -// var request = URLRequest(url: URL(string: "https://api.42box.site/user-service/users/me")!) -// request.httpShouldHandleCookies = true -// let task = URLSession.shared.dataTask(with: request) { (data, response, error) in -// if let error = error { -// print("Error: \(error)") -// return -// } -// -// guard let data = data else { -// print("No data received.") -// return -// } -// -// do { -// let userProfile = try JSONDecoder().decode(UserProfile.self, from: data) -// -// print(">> MacOS Get :", userProfile ) -// UserManager.shared.updateUserProfile(newProfile: userProfile) -// -// } catch let jsonError { -// print("JSON Parsing Error: \(jsonError)") -// } -// } -// task.resume() -// } -//} -// diff --git a/Box42/Shared/User/UserProfile.swift b/Box42/Shared/User/UserProfile.swift index 839b5c7..ce4e8a8 100644 --- a/Box42/Shared/User/UserProfile.swift +++ b/Box42/Shared/User/UserProfile.swift @@ -5,6 +5,8 @@ // Created by Chanhee Kim on 8/28/23. // +import AppKit + struct UserProfile: Codable { let uuid: String let nickname: String @@ -14,6 +16,7 @@ struct UserProfile: Codable { let statusMessage: String let profileImageUrl: String let profileImagePath: String + let quickSlotList: [QuickSlotButtonModel] } struct URLItem: Codable { @@ -42,7 +45,9 @@ extension UserProfile { URLItem(name: "42gg", url: "https://42gg.kr/")], statusMessage: "hello 42Box!", profileImageUrl: "https://42box.kr/user_profile_image/a52671f9-fca9-43ad-b0c0-1c5360831cf2.png", - profileImagePath: "user_profile_image/a52671f9-fca9-43ad-b0c0-1c5360831cf2.png" + profileImagePath: "user_profile_image/a52671f9-fca9-43ad-b0c0-1c5360831cf2.png", + quickSlotList: [ QuickSlotButtonModel(id: UUID(uuidString: "550e8400-e29b-41d4-a716-446655440000")!, title: "cleanCache", path: Bundle.main.path(forResource: "cleanCache", ofType: "sh")), + ] ) } } diff --git a/Box42/WebView/Model/WebViewUI.swift b/Box42/WebView/Model/WebViewUI.swift index b3d5582..d5e4a63 100644 --- a/Box42/WebView/Model/WebViewUI.swift +++ b/Box42/WebView/Model/WebViewUI.swift @@ -9,9 +9,10 @@ import Foundation enum WebViewUI { enum transfer { - static let download = "download" + static let downloadScript = "downloadScript" + static let executeScript = "executeScript" + static let deleteScript = "deleteScript" static let icon = "icon" static let userProfile = "userProfile" - static let script = "script" } } diff --git a/Box42/WebView/WebView.swift b/Box42/WebView/WebView.swift index 80b8b3b..8521d2a 100644 --- a/Box42/WebView/WebView.swift +++ b/Box42/WebView/WebView.swift @@ -21,10 +21,11 @@ class WebView: WKWebView, WKScriptMessageHandler { configuration.userContentController = contentController super.init(frame: .zero, configuration: configuration) - contentController.add(self, name: WebViewUI.transfer.download) + contentController.add(self, name: WebViewUI.transfer.deleteScript) + contentController.add(self, name: WebViewUI.transfer.executeScript) + contentController.add(self, name: WebViewUI.transfer.downloadScript) contentController.add(self, name: WebViewUI.transfer.icon) contentController.add(self, name: WebViewUI.transfer.userProfile) - contentController.add(self, name: WebViewUI.transfer.script) self.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true self.configuration.preferences.javaScriptEnabled = true @@ -41,15 +42,12 @@ class WebView: WKWebView, WKScriptMessageHandler { // MARK: - Front Client 통신 extension WebView { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - // 스크립트 다운로드 - if message.name == WebViewUI.transfer.download, let downloadURLString = message.body as? String { - ScriptsFileManager.downloadFile(from: downloadURLString) - } + // 아이콘 정보 PUT: if message.name == WebViewUI.transfer.icon, let imgIconString = message.body as? String { icon.buttonImageChange(imgIconString) } - // 유저 정보 (Front)GET: https://api.42box.site/user-service/users/me + // 유저 정보 (Front)GET: https://api.42box.kr/user-service/users/me if message.name == WebViewUI.transfer.userProfile, let userProfileString = message.body as? String { let userProfileJson = userProfileString.data(using: .utf8) @@ -65,20 +63,58 @@ extension WebView { print("JSON decoding failed: \(error)") } } - - if message.name == WebViewUI.transfer.script, let scriptString = message.body as? String { - let scriptJson = scriptString.data(using: .utf8) + // 스크립트 다운로드 + if message.name == WebViewUI.transfer.downloadScript, let downloadScriptString = message.body as? String { + let scriptJson = downloadScriptString.data(using: .utf8) + print(String(data: scriptJson!, encoding: .utf8) ?? "Invalid JSON data") do { let decoder = JSONDecoder() - let downScript = try decoder.decode(Script.self, from: scriptJson!) - print(downScript) + let downloadString = try decoder.decode(Script.self, from: scriptJson!) + ScriptViewModel.shared.addScript(id: UUID(), name: downloadString.name, description: downloadString.description, path: downloadString.path, savedId: Int(downloadString.savedId ?? 0), userUuid: downloadString.userUuid!) + print(downloadString) } catch { print("JSON decoding failed: \(error)") } } + + // 스크립트 실행 + if message.name == WebViewUI.transfer.executeScript, let executeScriptString = message.body as? String { + let scriptJson = executeScriptString.data(using: .utf8) + print(String(data: scriptJson!, encoding: .utf8) ?? "Invalid JSON data") + + do { + let decoder = JSONDecoder() + let executeScript = try decoder.decode(Script.self, from: scriptJson!) + print(String(data: scriptJson!, encoding: .utf8) ?? "Invalid JSON data") + + print(executeScript) + + ScriptsFileManager.downloadFile(from: "https://42box.kr/" + executeScript.path) + } catch { + print("JSON decoding failed: \(error)") + } + } + + // 스크립트 삭제 + if message.name == WebViewUI.transfer.deleteScript, let deleteScriptString = message.body as? String { + let scriptJson = deleteScriptString.data(using: .utf8) + print(String(data: scriptJson!, encoding: .utf8) ?? "Invalid JSON data") + + do { + let decoder = JSONDecoder() + let deleteScript = try decoder.decode(Script.self, from: scriptJson!) + print(String(data: scriptJson!, encoding: .utf8) ?? "Invalid JSON data") + + print(deleteScript) + + ScriptViewModel.shared.deleteScript(id: deleteScript.id!) + } catch { + print("JSON decoding failed: \(error)") + } + } } } diff --git a/Box42/WebView/WebViewManager.swift b/Box42/WebView/WebViewManager.swift index 18f0905..088c310 100644 --- a/Box42/WebView/WebViewManager.swift +++ b/Box42/WebView/WebViewManager.swift @@ -40,7 +40,7 @@ class WebViewManager: NSObject { } func getCookie() { - if let url = URL(string: "https://api.42box.site") { + if let url = URL(string: "https://api.42box.kr") { let request = URLRequest(url: url) getCookieWebKit.load(request) }