diff --git a/plugins/Toolbox/src/CloudSync/CloudPackageManager.py b/plugins/Toolbox/src/CloudSync/CloudPackageManager.py new file mode 100644 index 0000000000..a724aa316d --- /dev/null +++ b/plugins/Toolbox/src/CloudSync/CloudPackageManager.py @@ -0,0 +1,19 @@ +from cura.CuraApplication import CuraApplication +from plugins.Toolbox.src.CloudApiModel import CloudApiModel +from plugins.Toolbox.src.UltimakerCloudScope import UltimakerCloudScope + + +## Manages Cloud subscriptions. When a package is added to a user's account, the user is 'subscribed' to that package +# Whenever the user logs in on another instance of Cura, these subscriptions can be used to sync the user's plugins +class CloudPackageManager: + + def __init__(self, app: CuraApplication): + self._request_manager = app.getHttpRequestManager() + self._scope = UltimakerCloudScope(app) + + def subscribe(self, package_id: str): + data = "{\"data\": {\"package_id\": \"%s\", \"sdk_version\": \"%s\"}}" % (package_id, CloudApiModel.sdk_version) + self._request_manager.put(url=CloudApiModel.api_url_user_packages, + data=data.encode(), + scope=self._scope + ) diff --git a/plugins/Toolbox/src/CloudSync/LicensePresenter.py b/plugins/Toolbox/src/CloudSync/LicensePresenter.py index 57b9bc5a43..9e77002aa1 100644 --- a/plugins/Toolbox/src/CloudSync/LicensePresenter.py +++ b/plugins/Toolbox/src/CloudSync/LicensePresenter.py @@ -19,7 +19,7 @@ class LicensePresenter(QObject): super().__init__() self._dialog = None # type: Optional[QObject] self._package_manager = app.getPackageManager() # type: PackageManager - # Emits List[Dict[str, str]] containing for example + # Emits List[Dict[str, [Any]] containing for example # [{ "package_id": "BarbarianPlugin", "package_path" : "/tmp/dg345as", "accepted" : True }] self.licenseAnswers = Signal() diff --git a/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py b/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py index 952f3eeb54..507de45f55 100644 --- a/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py +++ b/plugins/Toolbox/src/CloudSync/SyncOrchestrator.py @@ -1,10 +1,13 @@ -from typing import List, Dict +import os +from typing import List, Dict, Any from UM.Extension import Extension from UM.Logger import Logger +from UM.PackageManager import PackageManager from UM.PluginRegistry import PluginRegistry from cura.CuraApplication import CuraApplication from plugins.Toolbox.src.CloudSync.CloudPackageChecker import CloudPackageChecker +from plugins.Toolbox.src.CloudSync.CloudPackageManager import CloudPackageManager from plugins.Toolbox.src.CloudSync.DiscrepanciesPresenter import DiscrepanciesPresenter from plugins.Toolbox.src.CloudSync.DownloadPresenter import DownloadPresenter from plugins.Toolbox.src.CloudSync.LicensePresenter import LicensePresenter @@ -32,6 +35,9 @@ class SyncOrchestrator(Extension): # getPluginId() will return the same value for The toolbox extension and this one self._name = "SyncOrchestrator" + self._package_manager = app.getPackageManager() + self._cloud_package_manager = CloudPackageManager(app) + self._checker = CloudPackageChecker(app) # type: CloudPackageChecker self._checker.discrepancies.connect(self._onDiscrepancies) @@ -61,7 +67,24 @@ class SyncOrchestrator(Extension): self._licensePresenter.present(plugin_path, success_items) # Called when user has accepted / declined all licenses for the downloaded packages - def _onLicenseAnswers(self, answers: Dict[str, bool]): + def _onLicenseAnswers(self, answers: [Dict[str, Any]]): Logger.debug("Got license answers: {}", answers) + for item in answers: + if item["accepted"]: + # install and subscribe packages + if not self._package_manager.installPackage(item["package_path"]): + Logger.error("could not install {}".format(item["package_id"])) + continue + self._cloud_package_manager.subscribe(item["package_id"]) + else: + # todo unsubscribe declined packages + pass + + # delete temp file + os.remove(item["package_path"]) + + + + diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index 681dd7ba72..e3903d0bfd 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -150,12 +150,7 @@ class Toolbox(QObject, Extension): @pyqtSlot(str) def subscribe(self, package_id: str) -> None: - if self._application.getCuraAPI().account.isLoggedIn: - data = "{\"data\": {\"package_id\": \"%s\", \"sdk_version\": \"%s\"}}" % (package_id, self._sdk_version) - self._application.getHttpRequestManager().put(url=CloudApiModel.api_url_user_packages, - data=data.encode(), - scope=self._scope - ) + self._cloud_package_manager.subscribe(package_id) def getLicenseDialogPluginFileLocation(self) -> str: return self._license_dialog_plugin_file_location diff --git a/plugins/Toolbox/src/UltimakerCloudScope.py b/plugins/Toolbox/src/UltimakerCloudScope.py index b5f2983ee8..f7707957e6 100644 --- a/plugins/Toolbox/src/UltimakerCloudScope.py +++ b/plugins/Toolbox/src/UltimakerCloudScope.py @@ -1,5 +1,6 @@ from PyQt5.QtNetwork import QNetworkRequest +from UM.Logger import Logger from UM.TaskManagement.HttpRequestScope import DefaultUserAgentScope from cura.API import Account from cura.CuraApplication import CuraApplication @@ -14,6 +15,10 @@ class UltimakerCloudScope(DefaultUserAgentScope): def request_hook(self, request: QNetworkRequest): super().request_hook(request) token = self._account.accessToken + if not self._account.isLoggedIn or token is None: + Logger.warning("Cannot add authorization to Cloud Api request") + return + header_dict = { "Authorization": "Bearer {}".format(token) }