diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py index d6c20d387b..3ede206d45 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py @@ -9,10 +9,13 @@ from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply from UM.Logger import Logger from cura.API import Account from cura.NetworkClient import NetworkClient -from plugins.UM3NetworkPrinting.src.Models import BaseModel -from plugins.UM3NetworkPrinting.src.Cloud.Models import ( - CloudCluster, CloudErrorObject, CloudClusterStatus, CloudJobUploadRequest, CloudPrintResponse, CloudJobResponse -) +from ..Models import BaseModel +from .Models.CloudCluster import CloudCluster +from .Models.CloudErrorObject import CloudErrorObject +from .Models.CloudClusterStatus import CloudClusterStatus +from .Models.CloudJobUploadRequest import CloudJobUploadRequest +from .Models.CloudPrintResponse import CloudPrintResponse +from .Models.CloudJobResponse import CloudJobResponse ## The cloud API client is responsible for handling the requests and responses from the cloud. diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py index 91f5721aa6..c6397fc41f 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py @@ -2,9 +2,9 @@ # Cura is released under the terms of the LGPLv3 or higher. import os from time import time -from typing import List, Optional, Dict, Set +from typing import Dict, List, Optional, Set -from PyQt5.QtCore import QObject, pyqtSignal, QUrl, pyqtProperty, pyqtSlot +from PyQt5.QtCore import QObject, QUrl, pyqtProperty, pyqtSignal, pyqtSlot from UM import i18nCatalog from UM.FileHandler.FileHandler import FileHandler @@ -12,18 +12,19 @@ from UM.Logger import Logger from UM.Message import Message from UM.Scene.SceneNode import SceneNode from cura.CuraApplication import CuraApplication -from cura.PrinterOutput.PrinterOutputController import PrinterOutputController -from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState, NetworkedPrinterOutputDevice +from cura.PrinterOutput.PrinterOutputController import PrinterOutputController from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel -from plugins.UM3NetworkPrinting.src.Cloud.CloudApiClient import CloudApiClient -from plugins.UM3NetworkPrinting.src.MeshFormatHandler import MeshFormatHandler -from plugins.UM3NetworkPrinting.src.UM3PrintJobOutputModel import UM3PrintJobOutputModel -from .Models import ( - CloudClusterPrinter, CloudClusterPrintJob, CloudJobUploadRequest, CloudJobResponse, CloudClusterStatus, - CloudClusterPrinterConfigurationMaterial, CloudErrorObject, - CloudPrintResponse -) +from ..MeshFormatHandler import MeshFormatHandler +from ..UM3PrintJobOutputModel import UM3PrintJobOutputModel +from .CloudApiClient import CloudApiClient +from .Models.CloudErrorObject import CloudErrorObject +from .Models.CloudClusterStatus import CloudClusterStatus +from .Models.CloudJobUploadRequest import CloudJobUploadRequest +from .Models.CloudPrintResponse import CloudPrintResponse +from .Models.CloudJobResponse import CloudJobResponse +from .Models.CloudClusterPrinter import CloudClusterPrinter +from .Models.CloudClusterPrintJob import CloudClusterPrintJob ## Class that contains all the translations for this module. @@ -180,80 +181,23 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice): remote_printers = {p.uuid: p for p in printers} # type: Dict[str, CloudClusterPrinter] current_printers = {p.key: p for p in self._printers} # type: Dict[str, PrinterOutputModel] - removed_printer_ids = set(current_printers).difference(remote_printers) - new_printer_ids = set(remote_printers).difference(current_printers) - updated_printer_ids = set(current_printers).intersection(remote_printers) + remote_printer_ids = set(remote_printers) # type: Set[str] + current_printer_ids = set(current_printers) # type: Set[str] - for printer_guid in removed_printer_ids: - self._printers.remove(current_printers[printer_guid]) + for removed_printer_id in current_printer_ids.difference(remote_printer_ids): + removed_printer = current_printers[removed_printer_id] + self._printers.remove(removed_printer) - for printer_guid in new_printer_ids: - self._addPrinter(remote_printers[printer_guid]) + for new_printer_id in remote_printer_ids.difference(current_printer_ids): + new_printer = remote_printers[new_printer_id] + controller = PrinterOutputController(self) + self._printers.append(new_printer.createOutputModel(controller)) - for printer_guid in updated_printer_ids: - self._updatePrinter(current_printers[printer_guid], remote_printers[printer_guid]) + for updated_printer_guid in current_printer_ids.intersection(remote_printer_ids): + remote_printers[updated_printer_guid].updateOutputModel(current_printers[updated_printer_guid]) self.clusterPrintersChanged.emit() - def _addPrinter(self, printer: CloudClusterPrinter) -> None: - model = PrinterOutputModel( - PrinterOutputController(self), len(printer.configuration), firmware_version = printer.firmware_version - ) - self._printers.append(model) - self._updatePrinter(model, printer) - - def _updatePrinter(self, model: PrinterOutputModel, printer: CloudClusterPrinter) -> None: - model.updateKey(printer.uuid) - model.updateName(printer.friendly_name) - model.updateType(printer.machine_variant) - model.updateState(printer.status if printer.enabled else "disabled") - - for index in range(0, len(printer.configuration)): - try: - extruder = model.extruders[index] - extruder_data = printer.configuration[index] - except IndexError: - break - - extruder.updateHotendID(extruder_data.print_core_id) - - if extruder.activeMaterial is None or extruder.activeMaterial.guid != extruder_data.material.guid: - material = self._createMaterialOutputModel(extruder_data.material) - extruder.updateActiveMaterial(material) - - @staticmethod - def _createMaterialOutputModel(material: CloudClusterPrinterConfigurationMaterial) -> MaterialOutputModel: - material_manager = CuraApplication.getInstance().getMaterialManager() - material_group_list = material_manager.getMaterialGroupListByGUID(material.guid) or [] - - # Sort the material groups by "is_read_only = True" first, and then the name alphabetically. - read_only_material_group_list = list(filter(lambda x: x.is_read_only, material_group_list)) - non_read_only_material_group_list = list(filter(lambda x: not x.is_read_only, material_group_list)) - material_group = None - if read_only_material_group_list: - read_only_material_group_list = sorted(read_only_material_group_list, key = lambda x: x.name) - material_group = read_only_material_group_list[0] - elif non_read_only_material_group_list: - non_read_only_material_group_list = sorted(non_read_only_material_group_list, key = lambda x: x.name) - material_group = non_read_only_material_group_list[0] - - if material_group: - container = material_group.root_material_node.getContainer() - color = container.getMetaDataEntry("color_code") - brand = container.getMetaDataEntry("brand") - material_type = container.getMetaDataEntry("material") - name = container.getName() - else: - Logger.log("w", "Unable to find material with guid {guid}. Using data as provided by cluster" - .format(guid = material.guid)) - color = material.color - brand = material.brand - material_type = material.material - name = "Empty" if material.material == "empty" else "Unknown" - - return MaterialOutputModel(guid = material.guid, type = material_type, brand = brand, color = color, - name = name) - def _updatePrintJobs(self, jobs: List[CloudClusterPrintJob]) -> None: remote_jobs = {j.uuid: j for j in jobs} # type: Dict[str, CloudClusterPrintJob] current_jobs = {j.key: j for j in self._print_jobs} # type: Dict[str, UM3PrintJobOutputModel] @@ -264,11 +208,11 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice): for removed_job_id in current_job_ids.difference(remote_job_ids): self._print_jobs.remove(current_jobs[removed_job_id]) - for new_job_id in remote_job_ids.difference(current_jobs): + for new_job_id in remote_job_ids.difference(current_job_ids): self._addPrintJob(remote_jobs[new_job_id]) for updated_job_id in current_job_ids.intersection(remote_job_ids): - self._updateUM3PrintJobOutputModel(current_jobs[updated_job_id], remote_jobs[updated_job_id]) + remote_jobs[updated_job_id].updateOutputModel(current_jobs[updated_job_id]) # We only have to update when jobs are added or removed # updated jobs push their changes via their output model @@ -282,16 +226,7 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice): return Logger.log("w", "Missing printer %s for job %s in %s", job.printer_uuid, job.uuid, [p.key for p in self._printers]) - model = UM3PrintJobOutputModel(printer.getController(), job.uuid, job.name) - model.updateAssignedPrinter(printer) - self._print_jobs.append(model) - - @staticmethod - def _updateUM3PrintJobOutputModel(model: UM3PrintJobOutputModel, job: CloudClusterPrintJob) -> None: - model.updateTimeTotal(job.time_total) - model.updateTimeElapsed(job.time_elapsed) - model.updateOwner(job.owner) - model.updateState(job.status) + self._print_jobs.append(job.createOutputModel(printer)) def _onPrintJobCreated(self, mesh: bytes, job_response: CloudJobResponse) -> None: self._api.uploadMesh(job_response, mesh, self._onPrintJobUploaded, self._updateUploadProgress, diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index 0fbeeb82b6..51c7f49074 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -8,9 +8,10 @@ from UM import i18nCatalog from UM.Logger import Logger from UM.Message import Message from cura.CuraApplication import CuraApplication -from plugins.UM3NetworkPrinting.src.Cloud.CloudApiClient import CloudApiClient +from .CloudApiClient import CloudApiClient from .CloudOutputDevice import CloudOutputDevice -from .Models import CloudCluster, CloudErrorObject +from .Models.CloudCluster import CloudCluster +from .Models.CloudErrorObject import CloudErrorObject ## The cloud output device manager is responsible for using the Ultimaker Cloud APIs to manage remote clusters. diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models.py b/plugins/UM3NetworkPrinting/src/Cloud/Models.py deleted file mode 100644 index 27ff7df604..0000000000 --- a/plugins/UM3NetworkPrinting/src/Cloud/Models.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright (c) 2018 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. -from typing import List, Dict - -from ..Models import BaseModel - - -## Class representing errors generated by the cloud servers, according to the json-api standard. -class CloudErrorObject(BaseModel): - def __init__(self, **kwargs): - self.id = None # type: str - self.code = None # type: str - self.http_status = None # type: str - self.title = None # type: str - self.detail = None # type: str - self.meta = None # type: Dict[str, any] - super().__init__(**kwargs) - - -## Class representing a cloud connected cluster. -class CloudCluster(BaseModel): - def __init__(self, **kwargs): - self.cluster_id = None # type: str - self.host_guid = None # type: str - self.host_name = None # type: str - self.host_version = None # type: str - self.status = None # type: str - self.is_online = None # type: bool - super().__init__(**kwargs) - - def validate(self): - if not self.cluster_id: - raise ValueError("cluster_id is required on CloudCluster") - - -## Class representing a cloud cluster printer configuration -class CloudClusterPrinterConfigurationMaterial(BaseModel): - def __init__(self, **kwargs): - self.guid = None # type: str - self.brand = None # type: str - self.color = None # type: str - self.material = None # type: str - super().__init__(**kwargs) - - -## Class representing a cloud cluster printer configuration -class CloudClusterPrinterConfiguration(BaseModel): - def __init__(self, **kwargs): - self.extruder_index = None # type: str - self.material = None # type: CloudClusterPrinterConfigurationMaterial - self.nozzle_diameter = None # type: str - self.print_core_id = None # type: str - super().__init__(**kwargs) - - if isinstance(self.material, dict): - self.material = CloudClusterPrinterConfigurationMaterial(**self.material) - - -## Class representing a cluster printer -class CloudClusterPrinter(BaseModel): - def __init__(self, **kwargs): - self.configuration = [] # type: List[CloudClusterPrinterConfiguration] - self.enabled = None # type: str - self.firmware_version = None # type: str - self.friendly_name = None # type: str - self.ip_address = None # type: str - self.machine_variant = None # type: str - self.status = None # type: str - self.unique_name = None # type: str - self.uuid = None # type: str - super().__init__(**kwargs) - - self.configuration = [CloudClusterPrinterConfiguration(**c) - if isinstance(c, dict) else c for c in self.configuration] - - -## Class representing a cloud cluster print job constraint -class CloudClusterPrintJobConstraint(BaseModel): - def __init__(self, **kwargs): - self.require_printer_name = None # type: str - super().__init__(**kwargs) - - -## Class representing a print job -class CloudClusterPrintJob(BaseModel): - def __init__(self, **kwargs): - self.assigned_to = None # type: str - self.configuration = [] # type: List[CloudClusterPrinterConfiguration] - self.constraints = [] # type: List[CloudClusterPrintJobConstraint] - self.created_at = None # type: str - self.force = None # type: str - self.last_seen = None # type: str - self.machine_variant = None # type: str - self.name = None # type: str - self.network_error_count = None # type: int - self.owner = None # type: str - self.printer_uuid = None # type: str - self.started = None # type: str - self.status = None # type: str - self.time_elapsed = None # type: str - self.time_total = None # type: str - self.uuid = None # type: str - super().__init__(**kwargs) - self.printers = [CloudClusterPrinterConfiguration(**c) if isinstance(c, dict) else c - for c in self.configuration] - self.printers = [CloudClusterPrintJobConstraint(**p) if isinstance(p, dict) else p - for p in self.constraints] - - -# Model that represents the status of the cluster for the cloud -class CloudClusterStatus(BaseModel): - def __init__(self, **kwargs): - # a list of the printers - self.printers = [] # type: List[CloudClusterPrinter] - # a list of the print jobs - self.print_jobs = [] # type: List[CloudClusterPrintJob] - - super().__init__(**kwargs) - - # converting any dictionaries into models - self.printers = [CloudClusterPrinter(**p) if isinstance(p, dict) else p for p in self.printers] - self.print_jobs = [CloudClusterPrintJob(**j) if isinstance(j, dict) else j for j in self.print_jobs] - - -# Model that represents the request to upload a print job to the cloud -class CloudJobUploadRequest(BaseModel): - def __init__(self, **kwargs): - self.file_size = None # type: int - self.job_name = None # type: str - self.content_type = None # type: str - super().__init__(**kwargs) - - -# Model that represents the response received from the cloud after requesting to upload a print job -class CloudJobResponse(BaseModel): - def __init__(self, **kwargs): - self.download_url = None # type: str - self.job_id = None # type: str - self.job_name = None # type: str - self.slicing_details = None # type: str - self.status = None # type: str - self.upload_url = None # type: str - self.content_type = None # type: str - super().__init__(**kwargs) - - -# Model that represents the responses received from the cloud after requesting a job to be printed. -class CloudPrintResponse(BaseModel): - def __init__(self, **kwargs): - self.cluster_job_id = None # type: str - self.job_id = None # type: str - self.status = None # type: str - super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudCluster.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudCluster.py new file mode 100644 index 0000000000..dd1e2e85bf --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudCluster.py @@ -0,0 +1,21 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from ...Models import BaseModel + + +## Class representing a cloud connected cluster. +class CloudCluster(BaseModel): + def __init__(self, **kwargs): + self.cluster_id = None # type: str + self.host_guid = None # type: str + self.host_name = None # type: str + self.host_version = None # type: str + self.status = None # type: str + self.is_online = None # type: bool + super().__init__(**kwargs) + + # Validates the model, raising an exception if the model is invalid. + def validate(self) -> None: + super().validate() + if not self.cluster_id: + raise ValueError("cluster_id is required on CloudCluster") diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJob.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJob.py new file mode 100644 index 0000000000..e2e3787435 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJob.py @@ -0,0 +1,52 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import List + +from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel +from .CloudClusterPrinterConfiguration import CloudClusterPrinterConfiguration +from .CloudClusterPrintJobConstraint import CloudClusterPrintJobConstraint +from ...Models import BaseModel + + +## Class representing a print job +from plugins.UM3NetworkPrinting.src.UM3PrintJobOutputModel import UM3PrintJobOutputModel + + +class CloudClusterPrintJob(BaseModel): + def __init__(self, **kwargs) -> None: + self.assigned_to = None # type: str + self.configuration = [] # type: List[CloudClusterPrinterConfiguration] + self.constraints = [] # type: List[CloudClusterPrintJobConstraint] + self.created_at = None # type: str + self.force = None # type: str + self.last_seen = None # type: str + self.machine_variant = None # type: str + self.name = None # type: str + self.network_error_count = None # type: int + self.owner = None # type: str + self.printer_uuid = None # type: str + self.started = None # type: str + self.status = None # type: str + self.time_elapsed = None # type: str + self.time_total = None # type: str + self.uuid = None # type: str + super().__init__(**kwargs) + self.printers = [CloudClusterPrinterConfiguration(**c) if isinstance(c, dict) else c + for c in self.configuration] + self.printers = [CloudClusterPrintJobConstraint(**p) if isinstance(p, dict) else p + for p in self.constraints] + + ## Creates an UM3 print job output model based on this cloud cluster print job. + # \param printer: The output model of the printer + def createOutputModel(self, printer: PrinterOutputModel) -> UM3PrintJobOutputModel: + model = UM3PrintJobOutputModel(printer.getController(), self.uuid, self.name) + model.updateAssignedPrinter(printer) + return model + + ## Updates an UM3 print job output model based on this cloud cluster print job. + # \param model: The model to update. + def updateOutputModel(self, model: UM3PrintJobOutputModel) -> None: + model.updateTimeTotal(self.time_total) + model.updateTimeElapsed(self.time_elapsed) + model.updateOwner(self.owner) + model.updateState(self.status) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConstraint.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConstraint.py new file mode 100644 index 0000000000..884ff8f0c2 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConstraint.py @@ -0,0 +1,10 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from ...Models import BaseModel + + +## Class representing a cloud cluster print job constraint +class CloudClusterPrintJobConstraint(BaseModel): + def __init__(self, **kwargs) -> None: + self.require_printer_name = None # type: str + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinter.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinter.py new file mode 100644 index 0000000000..dd65dffa26 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinter.py @@ -0,0 +1,44 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import List + +from cura.PrinterOutput.PrinterOutputController import PrinterOutputController +from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel +from .CloudClusterPrinterConfiguration import CloudClusterPrinterConfiguration +from ...Models import BaseModel + + +## Class representing a cluster printer +class CloudClusterPrinter(BaseModel): + def __init__(self, **kwargs) -> None: + self.configuration = [] # type: List[CloudClusterPrinterConfiguration] + self.enabled = None # type: str + self.firmware_version = None # type: str + self.friendly_name = None # type: str + self.ip_address = None # type: str + self.machine_variant = None # type: str + self.status = None # type: str + self.unique_name = None # type: str + self.uuid = None # type: str + super().__init__(**kwargs) + + self.configuration = [CloudClusterPrinterConfiguration(**c) + if isinstance(c, dict) else c for c in self.configuration] + + ## Creates a new output model. + # \param controller - The controller of the model. + def createOutputModel(self, controller: PrinterOutputController) -> PrinterOutputModel: + model = PrinterOutputModel(controller, len(self.configuration), firmware_version = self.firmware_version) + self.updateOutputModel(model) + return model + + ## Updates the given output model. + # \param model - The output model to update. + def updateOutputModel(self, model: PrinterOutputModel) -> None: + model.updateKey(self.uuid) + model.updateName(self.friendly_name) + model.updateType(self.machine_variant) + model.updateState(self.status if self.enabled else "disabled") + + for configuration, extruder in zip(self.configuration, model.extruders): + configuration.updateOutputModel(extruder) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfiguration.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfiguration.py new file mode 100644 index 0000000000..be92549015 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfiguration.py @@ -0,0 +1,27 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel +from .CloudClusterPrinterConfigurationMaterial import CloudClusterPrinterConfigurationMaterial +from ...Models import BaseModel + + +## Class representing a cloud cluster printer configuration +class CloudClusterPrinterConfiguration(BaseModel): + def __init__(self, **kwargs) -> None: + self.extruder_index = None # type: str + self.material = None # type: CloudClusterPrinterConfigurationMaterial + self.nozzle_diameter = None # type: str + self.print_core_id = None # type: str + super().__init__(**kwargs) + + if isinstance(self.material, dict): + self.material = CloudClusterPrinterConfigurationMaterial(**self.material) + + ## Updates the given output model. + # \param model - The output model to update. + def updateOutputModel(self, model: ExtruderOutputModel) -> None: + model.updateHotendID(self.print_core_id) + + if model.activeMaterial is None or model.activeMaterial.guid != self.material.guid: + material = self.material.createOutputModel() + model.updateActiveMaterial(material) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfigurationMaterial.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfigurationMaterial.py new file mode 100644 index 0000000000..8023784925 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfigurationMaterial.py @@ -0,0 +1,46 @@ +from UM.Logger import Logger +from cura.CuraApplication import CuraApplication +from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel +from ...Models import BaseModel + + +## Class representing a cloud cluster printer configuration +class CloudClusterPrinterConfigurationMaterial(BaseModel): + def __init__(self, **kwargs) -> None: + self.guid = None # type: str + self.brand = None # type: str + self.color = None # type: str + self.material = None # type: str + super().__init__(**kwargs) + + ## Creates a material output model based on this cloud printer material. + def createOutputModel(self) -> MaterialOutputModel: + material_manager = CuraApplication.getInstance().getMaterialManager() + material_group_list = material_manager.getMaterialGroupListByGUID(self.guid) or [] + + # Sort the material groups by "is_read_only = True" first, and then the name alphabetically. + read_only_material_group_list = list(filter(lambda x: x.is_read_only, material_group_list)) + non_read_only_material_group_list = list(filter(lambda x: not x.is_read_only, material_group_list)) + material_group = None + if read_only_material_group_list: + read_only_material_group_list = sorted(read_only_material_group_list, key = lambda x: x.name) + material_group = read_only_material_group_list[0] + elif non_read_only_material_group_list: + non_read_only_material_group_list = sorted(non_read_only_material_group_list, key = lambda x: x.name) + material_group = non_read_only_material_group_list[0] + + if material_group: + container = material_group.root_material_node.getContainer() + color = container.getMetaDataEntry("color_code") + brand = container.getMetaDataEntry("brand") + material_type = container.getMetaDataEntry("material") + name = container.getName() + else: + Logger.log("w", "Unable to find material with guid {guid}. Using data as provided by cluster" + .format(guid = self.guid)) + color = self.color + brand = self.brand + material_type = self.material + name = "Empty" if self.material == "empty" else "Unknown" + + return MaterialOutputModel(guid = self.guid, type = material_type, brand = brand, color = color, name = name) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterStatus.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterStatus.py new file mode 100644 index 0000000000..a44b665973 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterStatus.py @@ -0,0 +1,22 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import List + +from .CloudClusterPrinter import CloudClusterPrinter +from .CloudClusterPrintJob import CloudClusterPrintJob +from ...Models import BaseModel + + +# Model that represents the status of the cluster for the cloud +class CloudClusterStatus(BaseModel): + def __init__(self, **kwargs) -> None: + # a list of the printers + self.printers = [] # type: List[CloudClusterPrinter] + # a list of the print jobs + self.print_jobs = [] # type: List[CloudClusterPrintJob] + + super().__init__(**kwargs) + + # converting any dictionaries into models + self.printers = [CloudClusterPrinter(**p) if isinstance(p, dict) else p for p in self.printers] + self.print_jobs = [CloudClusterPrintJob(**j) if isinstance(j, dict) else j for j in self.print_jobs] diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudErrorObject.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudErrorObject.py new file mode 100644 index 0000000000..813ef957e4 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudErrorObject.py @@ -0,0 +1,17 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Dict + +from ...Models import BaseModel + + +## Class representing errors generated by the cloud servers, according to the json-api standard. +class CloudErrorObject(BaseModel): + def __init__(self, **kwargs) -> None: + self.id = None # type: str + self.code = None # type: str + self.http_status = None # type: str + self.title = None # type: str + self.detail = None # type: str + self.meta = None # type: Dict[str, any] + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudJobResponse.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudJobResponse.py new file mode 100644 index 0000000000..0b611dd2d3 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudJobResponse.py @@ -0,0 +1,16 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from ...Models import BaseModel + + +# Model that represents the response received from the cloud after requesting to upload a print job +class CloudJobResponse(BaseModel): + def __init__(self, **kwargs) -> None: + self.download_url = None # type: str + self.job_id = None # type: str + self.job_name = None # type: str + self.slicing_details = None # type: str + self.status = None # type: str + self.upload_url = None # type: str + self.content_type = None # type: str + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudJobUploadRequest.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudJobUploadRequest.py new file mode 100644 index 0000000000..3e038b343e --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudJobUploadRequest.py @@ -0,0 +1,12 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from ...Models import BaseModel + + +# Model that represents the request to upload a print job to the cloud +class CloudJobUploadRequest(BaseModel): + def __init__(self, **kwargs) -> None: + self.file_size = None # type: int + self.job_name = None # type: str + self.content_type = None # type: str + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintResponse.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintResponse.py new file mode 100644 index 0000000000..ff05ad5b19 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintResponse.py @@ -0,0 +1,12 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from ...Models import BaseModel + + +# Model that represents the responses received from the cloud after requesting a job to be printed. +class CloudPrintResponse(BaseModel): + def __init__(self, **kwargs) -> None: + self.cluster_job_id = None # type: str + self.job_id = None # type: str + self.status = None # type: str + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/__init__.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/__init__.py new file mode 100644 index 0000000000..f3f6970c54 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py index 64ac613723..aa8be9ecd9 100644 --- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py @@ -25,11 +25,11 @@ from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationM from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState, NetworkedPrinterOutputDevice from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel -from plugins.UM3NetworkPrinting.src.MeshFormatHandler import MeshFormatHandler from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController -from .SendMaterialJob import SendMaterialJob from .ConfigurationChangeModel import ConfigurationChangeModel +from .MeshFormatHandler import MeshFormatHandler +from .SendMaterialJob import SendMaterialJob from .UM3PrintJobOutputModel import UM3PrintJobOutputModel from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply diff --git a/plugins/UM3NetworkPrinting/src/Models.py b/plugins/UM3NetworkPrinting/src/Models.py index 2bcac70766..c5b9b16665 100644 --- a/plugins/UM3NetworkPrinting/src/Models.py +++ b/plugins/UM3NetworkPrinting/src/Models.py @@ -8,6 +8,7 @@ class BaseModel: self.__dict__.update(kwargs) self.validate() + # Validates the model, raising an exception if the model is invalid. def validate(self) -> None: pass @@ -34,7 +35,9 @@ class LocalMaterial(BaseModel): self.version = version # type: int super().__init__(**kwargs) + # def validate(self) -> None: + super().validate() if not self.GUID: raise ValueError("guid is required on LocalMaterial") if not self.version: diff --git a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py index b669eb192a..e3ec9faeaf 100644 --- a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py @@ -10,7 +10,7 @@ from PyQt5.QtCore import QByteArray from UM.MimeTypeDatabase import MimeType from UM.Application import Application -from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob +from ..src.SendMaterialJob import SendMaterialJob @patch("builtins.open", lambda _, __: io.StringIO(""))