diff --git a/docs/events/index.rst b/docs/events/index.rst index 1dfde90073..dad1213804 100644 --- a/docs/events/index.rst +++ b/docs/events/index.rst @@ -365,6 +365,30 @@ SlicingFailed * ``gcode``: the sliced GCODE's filename * ``reason``: the reason for the slicing having failed +SlicingProfileAdded + A new slicing profile was added. + + Payload: + + * ``slicer``: the slicer for which the profile was added + * ``profile``: the profile that was added + +SlicingProfileModified + A new slicing profile was modified. + + Payload: + + * ``slicer``: the slicer for which the profile was modified + * ``profile``: the profile that was modified + +SlicingProfileDeleted + A slicing profile was deleted. + + Payload: + + * ``slicer``: the slicer for which the profile was deleted + * ``profile``: the profile that was deleted + Settings -------- diff --git a/src/octoprint/events.py b/src/octoprint/events.py index 36e488434a..c19a8c8838 100644 --- a/src/octoprint/events.py +++ b/src/octoprint/events.py @@ -86,6 +86,14 @@ class Events(object): SLICING_DONE = "SlicingDone" SLICING_FAILED = "SlicingFailed" SLICING_CANCELLED = "SlicingCancelled" + SLICING_PROFILE_ADDED = "SlicingProfileAdded" + SLICING_PROFILE_MODIFIED = "SlicingProfileModified" + SLICING_PROFILE_DELETED = "SlicingProfileDeleted" + + # Printer Profiles + PRINTER_PROFILE_ADDED = "PrinterProfileAdded" + PRINTER_PROFILE_MODIFIED = "PrinterProfileModified" + PRINTER_PROFILE_DELETED = "PrinterProfileDeleted" # Settings SETTINGS_UPDATED = "SettingsUpdated" diff --git a/src/octoprint/plugins/cura/__init__.py b/src/octoprint/plugins/cura/__init__.py index 095a274b53..a525c0de1c 100644 --- a/src/octoprint/plugins/cura/__init__.py +++ b/src/octoprint/plugins/cura/__init__.py @@ -191,9 +191,6 @@ def get_slicer_profile(self, path): return octoprint.slicing.SlicingProfile(properties["type"], "unknown", profile_dict, display_name=display_name, description=description) def save_slicer_profile(self, path, profile, allow_overwrite=True, overrides=None): - if os.path.exists(path) and not allow_overwrite: - raise octoprint.slicing.ProfileAlreadyExists("cura", profile.name) - new_profile = Profile.merge_profile(profile.data, overrides=overrides) if profile.display_name is not None: diff --git a/src/octoprint/server/api/slicing.py b/src/octoprint/server/api/slicing.py index 7dd80f3bc7..f1dc376389 100644 --- a/src/octoprint/server/api/slicing.py +++ b/src/octoprint/server/api/slicing.py @@ -14,7 +14,7 @@ from octoprint.settings import settings as s, valid_boolean_trues -from octoprint.slicing import UnknownSlicer, SlicerNotConfigured, ProfileAlreadyExists, UnknownProfile +from octoprint.slicing import UnknownSlicer, SlicerNotConfigured, ProfileAlreadyExists, UnknownProfile, CouldNotDeleteProfile @api.route("/slicing", methods=["GET"]) @@ -147,6 +147,8 @@ def slicingDelSlicerProfile(slicer, name): slicingManager.delete_profile(slicer, name) except UnknownSlicer: return make_response("Unknown slicer {slicer}".format(**locals()), 404) + except CouldNotDeleteProfile as e: + return make_response("Could not delete profile {profile} for slicer {slicer}: {cause}".format(profile=name, slicer=slicer, cause=str(e.cause)), 500) return NO_CONTENT diff --git a/src/octoprint/slicing/__init__.py b/src/octoprint/slicing/__init__.py index 448624b9ec..7f40d09e41 100644 --- a/src/octoprint/slicing/__init__.py +++ b/src/octoprint/slicing/__init__.py @@ -407,7 +407,18 @@ def save_profile(self, slicer, name, profile, overrides=None, allow_overwrite=Tr profile.description = description path = self.get_profile_path(slicer, name) + is_overwrite = os.path.exists(path) + + if is_overwrite and not allow_overwrite: + raise ProfileAlreadyExists(slicer, profile.name) + self._save_profile_to_path(slicer, path, profile, overrides=overrides, allow_overwrite=allow_overwrite) + + payload = dict(slicer=slicer, + profile=name) + event = octoprint.events.Events.SLICING_PROFILE_MODIFIED if is_overwrite else octoprint.events.Events.SLICING_PROFILE_ADDED + octoprint.events.eventManager().fire(event, payload) + return profile def _temporary_profile(self, slicer, name=None, overrides=None): @@ -436,6 +447,7 @@ def delete_profile(self, slicer, name): Raises: ~octoprint.slicing.exceptions.UnknownSlicer: The slicer ``slicer`` is unknown. + ~octoprint.slicing.exceptions.CouldNotDeleteProfile: There was an error while deleting the profile. """ if not slicer in self.registered_slicers: @@ -445,10 +457,17 @@ def delete_profile(self, slicer, name): raise ValueError("name must be set") try: - path = self.get_profile_path(slicer, name, must_exist=True) - except UnknownProfile: - return - os.remove(path) + try: + path = self.get_profile_path(slicer, name, must_exist=True) + except UnknownProfile: + return + os.remove(path) + except ProfileException as e: + raise e + except Exception as e: + raise CouldNotDeleteProfile(slicer, name, cause=e) + else: + octoprint.events.eventManager().fire(octoprint.events.Events.SLICING_PROFILE_DELETED, dict(slicer=slicer, profile=name)) def all_profiles(self, slicer, require_configured=False): """ diff --git a/src/octoprint/slicing/exceptions.py b/src/octoprint/slicing/exceptions.py index 8a543e9fa2..7f4b1b6a6b 100644 --- a/src/octoprint/slicing/exceptions.py +++ b/src/octoprint/slicing/exceptions.py @@ -105,3 +105,16 @@ class ProfileAlreadyExists(ProfileException): def __init__(self, slicer, profile, *args, **kwargs): ProfileException.__init__(self, slicer, profile, *args, **kwargs) self.message = "Profile {profile} for slicer {slicer} already exists".format(profile=profile, slicer=slicer) + +class CouldNotDeleteProfile(ProfileException): + """ + Raised if there is an unexpected error trying to delete a known profile. + """ + def __init__(self, slicer, profile, cause=None, *args, **kwargs): + ProfileException.__init__(self, slicer, profile, *args, **kwargs) + + self.cause = cause + if cause: + self.message = "Could not delete profile {profile} for slicer {slicer}: {cause}".format(profile=profile, slicer=slicer, cause=str(cause)) + else: + self.message = "Could not delete profile {profile} for slicer {slicer}".format(profile=profile, slicer=slicer)