def on_api_get(self, request): from flask import jsonify from octoprint.server import fileManager import octoprint.filemanager import octoprint.filemanager.util import octoprint.filemanager.storage from octoprint.filemanager import FileDestinations req_path = "/" if request.args.get('path'): req_path = request.args.get('path') if fileManager.folder_exists(FileDestinations.LOCAL, req_path): files = fileManager.list_files(path=req_path, filter=None, recursive=False) tmp_f = [] tmp_d = [] if req_path != "/": tmp_d = [".."] for f in files["local"]: if files["local"][f]["type"] == "folder": tmp_d.append(files["local"][f]["name"]) if files["local"][f]["type"] == "machinecode": n = files["local"][f]["name"] succ = "n/a" if "history" in files["local"][f]: history = files["local"][f]["history"] last = None for entry in history: if not last or ("timestamp" in entry and "timestamp" in last and entry["timestamp"] > last["timestamp"]): last = entry if last: if last["success"]: succ = "succ" else: succ = "err" tmp_f.append([n, succ]) result = dict() result["path"] = req_path result["files"] = sorted(tmp_f, key=lambda s: s[0].lower()) result["directories"] = sorted(tmp_d, key=lambda s: s.lower()) return jsonify(result) return None
def gcodeFileCommand(filename, target): if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]: return make_response("Unknown target: %s" % target, 404) # valid file commands, dict mapping command name to mandatory parameters valid_commands = { "select": [], "slice": [], "copy": ["destination"], "move": ["destination"] } command, data, response = get_json_command_from_request(request, valid_commands) if response is not None: return response if command == "select": if not _verifyFileExists(target, filename): return make_response("File not found on '%s': %s" % (target, filename), 404) # selects/loads a file if not octoprint.filemanager.valid_file_type(filename, type="machinecode"): return make_response("Cannot select {filename} for printing, not a machinecode file".format(**locals()), 415) printAfterLoading = False if "print" in data.keys() and data["print"] in valid_boolean_trues: if not printer.is_operational(): return make_response("Printer is not operational, cannot directly start printing", 409) printAfterLoading = True sd = False if target == FileDestinations.SDCARD: filenameToSelect = filename sd = True else: filenameToSelect = fileManager.path_on_disk(target, filename) printer.select_file(filenameToSelect, sd, printAfterLoading) elif command == "slice": if not _verifyFileExists(target, filename): return make_response("File not found on '%s': %s" % (target, filename), 404) try: if "slicer" in data: slicer = data["slicer"] del data["slicer"] slicer_instance = slicingManager.get_slicer(slicer) elif "cura" in slicingManager.registered_slicers: slicer = "cura" slicer_instance = slicingManager.get_slicer("cura") else: return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415) except octoprint.slicing.UnknownSlicer as e: return make_response("Slicer {slicer} is not available".format(slicer=e.slicer), 400) if not any([octoprint.filemanager.valid_file_type(filename, type=source_file_type) for source_file_type in slicer_instance.get_slicer_properties().get("source_file_types", ["model"])]): return make_response("Cannot slice {filename}, not a model file".format(**locals()), 415) if slicer_instance.get_slicer_properties().get("same_device", True) and (printer.is_printing() or printer.is_paused()): # slicer runs on same device as OctoPrint, slicing while printing is hence disabled return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409) if "destination" in data and data["destination"]: destination = data["destination"] del data["destination"] elif "gcode" in data and data["gcode"]: destination = data["gcode"] del data["gcode"] else: import os name, _ = os.path.splitext(filename) destination = name + "." + slicer_instance.get_slicer_properties().get("destination_extensions", ["gco", "gcode", "g"])[0] full_path = destination if "path" in data and data["path"]: full_path = fileManager.join_path(target, data["path"], destination) else: path, _ = fileManager.split_path(target, filename) if path: full_path = fileManager.join_path(target, path, destination) # prohibit overwriting the file that is currently being printed currentOrigin, currentFilename = _getCurrentFile() if currentFilename == full_path and currentOrigin == target and (printer.is_printing() or printer.is_paused()): make_response("Trying to slice into file that is currently being printed: %s" % full_path, 409) if "profile" in data.keys() and data["profile"]: profile = data["profile"] del data["profile"] else: profile = None if "printerProfile" in data.keys() and data["printerProfile"]: printerProfile = data["printerProfile"] del data["printerProfile"] else: printerProfile = None if "position" in data.keys() and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]: position = data["position"] del data["position"] else: position = None select_after_slicing = False if "select" in data.keys() and data["select"] in valid_boolean_trues: if not printer.is_operational(): return make_response("Printer is not operational, cannot directly select for printing", 409) select_after_slicing = True print_after_slicing = False if "print" in data.keys() and data["print"] in valid_boolean_trues: if not printer.is_operational(): return make_response("Printer is not operational, cannot directly start printing", 409) select_after_slicing = print_after_slicing = True override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None] overrides = dict() for key in override_keys: overrides[key[len("profile."):]] = data[key] def slicing_done(target, path, select_after_slicing, print_after_slicing): if select_after_slicing or print_after_slicing: sd = False if target == FileDestinations.SDCARD: filenameToSelect = path sd = True else: filenameToSelect = fileManager.path_on_disk(target, path) printer.select_file(filenameToSelect, sd, print_after_slicing) try: fileManager.slice(slicer, target, filename, target, full_path, profile=profile, printer_profile_id=printerProfile, position=position, overrides=overrides, callback=slicing_done, callback_args=(target, full_path, select_after_slicing, print_after_slicing)) except octoprint.slicing.UnknownProfile: return make_response("Profile {profile} doesn't exist".format(**locals()), 400) files = {} location = url_for(".readGcodeFile", target=target, filename=full_path, _external=True) result = { "name": destination, "path": full_path, "origin": FileDestinations.LOCAL, "refs": { "resource": location, "download": url_for("index", _external=True) + "downloads/files/" + target + "/" + full_path } } r = make_response(jsonify(result), 202) r.headers["Location"] = location return r elif command == "copy" or command == "move": # Copy and move are only possible on local storage if not target in [FileDestinations.LOCAL]: return make_response("Unsupported target for {}: {}".format(command, target), 400) if not _verifyFileExists(target, filename) and not _verifyFolderExists(target, filename): return make_response("File or folder not found on {}: {}".format(target, filename), 404) path, name = fileManager.split_path(target, filename) destination = data["destination"] if _verifyFolderExists(target, destination): # destination is an existing folder, we'll assume we are supposed to move filename to this # folder under the same name destination = fileManager.join_path(target, destination, name) if _verifyFileExists(target, destination) or _verifyFolderExists(target, destination): return make_response("File or folder does already exist on {}: {}".format(target, destination), 409) is_file = fileManager.file_exists(target, filename) is_folder = fileManager.folder_exists(target, filename) if not (is_file or is_folder): return make_response("{} on {} is neither file or folder, can't {}".format(filename, target, command), 400) if command == "copy": if is_file: fileManager.copy_file(target, filename, destination) else: fileManager.copy_folder(target, filename, destination) elif command == "move": if _isBusy(target, filename): return make_response("Trying to move a file or folder that is currently in use: {}".format(filename), 409) # deselect the file if it's currently selected currentOrigin, currentFilename = _getCurrentFile() if currentFilename is not None and filename == currentFilename: printer.unselect_file() if is_file: fileManager.move_file(target, filename, destination) else: fileManager.move_folder(target, filename, destination) location = url_for(".readGcodeFile", target=target, filename=destination, _external=True) result = { "name": name, "path": destination, "origin": FileDestinations.LOCAL, "refs": { "resource": location } } if is_file: result["refs"]["download"] = url_for("index", _external=True) + "downloads/files/" + target + "/" + destination r = make_response(jsonify(result), 201) r.headers["Location"] = location return r return NO_CONTENT
def _verifyFolderExists(origin, foldername): if origin == FileDestinations.SDCARD: return False else: return fileManager.folder_exists(origin, foldername)
def gcodeFileCommand(filename, target): if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]: return make_response("Unknown target: %s" % target, 404) # valid file commands, dict mapping command name to mandatory parameters valid_commands = { "select": [], "slice": [], "analyse": [], "copy": ["destination"], "move": ["destination"] } command, data, response = get_json_command_from_request(request, valid_commands) if response is not None: return response user = current_user.get_name() if command == "select": if not _verifyFileExists(target, filename): return make_response("File not found on '%s': %s" % (target, filename), 404) # selects/loads a file if not octoprint.filemanager.valid_file_type(filename, type="machinecode"): return make_response("Cannot select {filename} for printing, not a machinecode file".format(**locals()), 415) printAfterLoading = False if "print" in data.keys() and data["print"] in valid_boolean_trues: if not printer.is_operational(): return make_response("Printer is not operational, cannot directly start printing", 409) printAfterLoading = True sd = False if target == FileDestinations.SDCARD: filenameToSelect = filename sd = True else: filenameToSelect = fileManager.path_on_disk(target, filename) printer.select_file(filenameToSelect, sd, printAfterLoading, user) elif command == "slice": if not _verifyFileExists(target, filename): return make_response("File not found on '%s': %s" % (target, filename), 404) try: if "slicer" in data: slicer = data["slicer"] del data["slicer"] slicer_instance = slicingManager.get_slicer(slicer) elif "cura" in slicingManager.registered_slicers: slicer = "cura" slicer_instance = slicingManager.get_slicer("cura") else: return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415) except octoprint.slicing.UnknownSlicer as e: return make_response("Slicer {slicer} is not available".format(slicer=e.slicer), 400) if not any([octoprint.filemanager.valid_file_type(filename, type=source_file_type) for source_file_type in slicer_instance.get_slicer_properties().get("source_file_types", ["model"])]): return make_response("Cannot slice {filename}, not a model file".format(**locals()), 415) if slicer_instance.get_slicer_properties().get("same_device", True) and (printer.is_printing() or printer.is_paused()): # slicer runs on same device as OctoPrint, slicing while printing is hence disabled return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409) if "destination" in data and data["destination"]: destination = data["destination"] del data["destination"] elif "gcode" in data and data["gcode"]: destination = data["gcode"] del data["gcode"] else: import os name, _ = os.path.splitext(filename) destination = name + "." + slicer_instance.get_slicer_properties().get("destination_extensions", ["gco", "gcode", "g"])[0] full_path = destination if "path" in data and data["path"]: full_path = fileManager.join_path(target, data["path"], destination) else: path, _ = fileManager.split_path(target, filename) if path: full_path = fileManager.join_path(target, path, destination) canon_path, canon_name = fileManager.canonicalize(target, full_path) sanitized_name = fileManager.sanitize_name(target, canon_name) if canon_path: full_path = fileManager.join_path(target, canon_path, sanitized_name) else: full_path = sanitized_name # prohibit overwriting the file that is currently being printed currentOrigin, currentFilename = _getCurrentFile() if currentFilename == full_path and currentOrigin == target and (printer.is_printing() or printer.is_paused()): make_response("Trying to slice into file that is currently being printed: %s" % full_path, 409) if "profile" in data.keys() and data["profile"]: profile = data["profile"] del data["profile"] else: profile = None if "printerProfile" in data.keys() and data["printerProfile"]: printerProfile = data["printerProfile"] del data["printerProfile"] else: printerProfile = None if "position" in data.keys() and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]: position = data["position"] del data["position"] else: position = None select_after_slicing = False if "select" in data.keys() and data["select"] in valid_boolean_trues: if not printer.is_operational(): return make_response("Printer is not operational, cannot directly select for printing", 409) select_after_slicing = True print_after_slicing = False if "print" in data.keys() and data["print"] in valid_boolean_trues: if not printer.is_operational(): return make_response("Printer is not operational, cannot directly start printing", 409) select_after_slicing = print_after_slicing = True override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None] overrides = dict() for key in override_keys: overrides[key[len("profile."):]] = data[key] def slicing_done(target, path, select_after_slicing, print_after_slicing): if select_after_slicing or print_after_slicing: sd = False if target == FileDestinations.SDCARD: filenameToSelect = path sd = True else: filenameToSelect = fileManager.path_on_disk(target, path) printer.select_file(filenameToSelect, sd, print_after_slicing, user) try: fileManager.slice(slicer, target, filename, target, full_path, profile=profile, printer_profile_id=printerProfile, position=position, overrides=overrides, display=canon_name, callback=slicing_done, callback_args=(target, full_path, select_after_slicing, print_after_slicing)) except octoprint.slicing.UnknownProfile: return make_response("Profile {profile} doesn't exist".format(**locals()), 400) files = {} location = url_for(".readGcodeFile", target=target, filename=full_path, _external=True) result = { "name": sanitized_name, "path": full_path, "display": canon_name, "origin": FileDestinations.LOCAL, "refs": { "resource": location, "download": url_for("index", _external=True) + "downloads/files/" + target + "/" + full_path } } r = make_response(jsonify(result), 202) r.headers["Location"] = location return r elif command == "analyse": if not _verifyFileExists(target, filename): return make_response("File not found on '%s': %s" % (target, filename), 404) printer_profile = None if "printerProfile" in data and data["printerProfile"]: printer_profile = data["printerProfile"] if not fileManager.analyse(target, filename, printer_profile_id=printer_profile): return make_response("No analysis possible for {} on {}".format(filename, target), 400) elif command == "copy" or command == "move": # Copy and move are only possible on local storage if not target in [FileDestinations.LOCAL]: return make_response("Unsupported target for {}: {}".format(command, target), 400) if not _verifyFileExists(target, filename) and not _verifyFolderExists(target, filename): return make_response("File or folder not found on {}: {}".format(target, filename), 404) path, name = fileManager.split_path(target, filename) destination = data["destination"] dst_path, dst_name = fileManager.split_path(target, destination) sanitized_destination = fileManager.join_path(target, dst_path, fileManager.sanitize_name(target, dst_name)) if _verifyFolderExists(target, destination) and sanitized_destination != filename: # destination is an existing folder and not ourselves (= display rename), we'll assume we are supposed # to move filename to this folder under the same name destination = fileManager.join_path(target, destination, name) is_file = fileManager.file_exists(target, filename) is_folder = fileManager.folder_exists(target, filename) if not (is_file or is_folder): return make_response("{} on {} is neither file or folder, can't {}".format(filename, target, command), 400) if command == "copy": # destination already there? error... if _verifyFileExists(target, destination) or _verifyFolderExists(target, destination): return make_response("File or folder does already exist on {}: {}".format(target, destination), 409) if is_file: fileManager.copy_file(target, filename, destination) else: fileManager.copy_folder(target, filename, destination) elif command == "move": if _isBusy(target, filename): return make_response("Trying to move a file or folder that is currently in use: {}".format(filename), 409) # destination already there AND not ourselves (= display rename)? error... if (_verifyFileExists(target, destination) or _verifyFolderExists(target, destination)) \ and sanitized_destination != filename: return make_response("File or folder does already exist on {}: {}".format(target, destination), 409) # deselect the file if it's currently selected currentOrigin, currentFilename = _getCurrentFile() if currentFilename is not None and filename == currentFilename: printer.unselect_file() if is_file: fileManager.move_file(target, filename, destination) else: fileManager.move_folder(target, filename, destination) location = url_for(".readGcodeFile", target=target, filename=destination, _external=True) result = { "name": name, "path": destination, "origin": FileDestinations.LOCAL, "refs": { "resource": location } } if is_file: result["refs"]["download"] = url_for("index", _external=True) + "downloads/files/" + target + "/" + destination r = make_response(jsonify(result), 201) r.headers["Location"] = location return r return NO_CONTENT
def gcodeFileCommand(filename, target): if target not in [FileDestinations.LOCAL, FileDestinations.SDCARD]: abort(404) if not _validate(target, filename): abort(404) # valid file commands, dict mapping command name to mandatory parameters valid_commands = { "select": [], "unselect": [], "slice": [], "analyse": [], "copy": ["destination"], "move": ["destination"], } command, data, response = get_json_command_from_request( request, valid_commands) if response is not None: return response user = current_user.get_name() if command == "select": with Permissions.FILES_SELECT.require(403): if not _verifyFileExists(target, filename): abort(404) # selects/loads a file if not octoprint.filemanager.valid_file_type(filename, type="machinecode"): abort( 415, description= "Cannot select file for printing, not a machinecode file", ) if not printer.is_ready(): abort( 409, description= "Printer is already printing, cannot select a new file", ) printAfterLoading = False if "print" in data and data["print"] in valid_boolean_trues: with Permissions.PRINT.require(403): if not printer.is_operational(): abort( 409, description= "Printer is not operational, cannot directly start printing", ) printAfterLoading = True sd = False if target == FileDestinations.SDCARD: filenameToSelect = filename sd = True else: filenameToSelect = fileManager.path_on_disk(target, filename) printer.select_file(filenameToSelect, sd, printAfterLoading, user) elif command == "unselect": with Permissions.FILES_SELECT.require(403): if not printer.is_ready(): return make_response( "Printer is already printing, cannot unselect current file", 409) _, currentFilename = _getCurrentFile() if currentFilename is None: return make_response( "Cannot unselect current file when there is no file selected", 409) if filename != currentFilename and filename != "current": return make_response( "Only the currently selected file can be unselected", 400) printer.unselect_file() elif command == "slice": with Permissions.SLICE.require(403): if not _verifyFileExists(target, filename): abort(404) try: if "slicer" in data: slicer = data["slicer"] del data["slicer"] slicer_instance = slicingManager.get_slicer(slicer) elif "cura" in slicingManager.registered_slicers: slicer = "cura" slicer_instance = slicingManager.get_slicer("cura") else: abort(415, description="Cannot slice file, no slicer available") except octoprint.slicing.UnknownSlicer: abort(404) if not any([ octoprint.filemanager.valid_file_type( filename, type=source_file_type) for source_file_type in slicer_instance. get_slicer_properties().get("source_file_types", ["model"]) ]): abort(415, description="Cannot slice file, not a model file") cores = psutil.cpu_count() if (slicer_instance.get_slicer_properties().get( "same_device", True) and (printer.is_printing() or printer.is_paused()) and (cores is None or cores < 2)): # slicer runs on same device as OctoPrint, slicing while printing is hence disabled abort( 409, description= "Cannot slice on this slicer while printing on single core systems or systems of unknown core count due to performance reasons", ) if "destination" in data and data["destination"]: destination = data["destination"] del data["destination"] elif "gcode" in data and data["gcode"]: destination = data["gcode"] del data["gcode"] else: import os name, _ = os.path.splitext(filename) destination = ( name + "." + slicer_instance.get_slicer_properties().get( "destination_extensions", ["gco", "gcode", "g"])[0]) full_path = destination if "path" in data and data["path"]: full_path = fileManager.join_path(target, data["path"], destination) else: path, _ = fileManager.split_path(target, filename) if path: full_path = fileManager.join_path(target, path, destination) canon_path, canon_name = fileManager.canonicalize( target, full_path) sanitized_name = fileManager.sanitize_name(target, canon_name) if canon_path: full_path = fileManager.join_path(target, canon_path, sanitized_name) else: full_path = sanitized_name # prohibit overwriting the file that is currently being printed currentOrigin, currentFilename = _getCurrentFile() if (currentFilename == full_path and currentOrigin == target and (printer.is_printing() or printer.is_paused())): abort( 409, description= "Trying to slice into file that is currently being printed", ) if "profile" in data and data["profile"]: profile = data["profile"] del data["profile"] else: profile = None if "printerProfile" in data and data["printerProfile"]: printerProfile = data["printerProfile"] del data["printerProfile"] else: printerProfile = None if ("position" in data and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]): position = data["position"] del data["position"] else: position = None select_after_slicing = False if "select" in data and data["select"] in valid_boolean_trues: if not printer.is_operational(): abort( 409, description= "Printer is not operational, cannot directly select for printing", ) select_after_slicing = True print_after_slicing = False if "print" in data and data["print"] in valid_boolean_trues: if not printer.is_operational(): abort( 409, description= "Printer is not operational, cannot directly start printing", ) select_after_slicing = print_after_slicing = True override_keys = [ k for k in data if k.startswith("profile.") and data[k] is not None ] overrides = {} for key in override_keys: overrides[key[len("profile."):]] = data[key] def slicing_done(target, path, select_after_slicing, print_after_slicing): if select_after_slicing or print_after_slicing: sd = False if target == FileDestinations.SDCARD: filenameToSelect = path sd = True else: filenameToSelect = fileManager.path_on_disk( target, path) printer.select_file(filenameToSelect, sd, print_after_slicing, user) try: fileManager.slice( slicer, target, filename, target, full_path, profile=profile, printer_profile_id=printerProfile, position=position, overrides=overrides, display=canon_name, callback=slicing_done, callback_args=( target, full_path, select_after_slicing, print_after_slicing, ), ) except octoprint.slicing.UnknownProfile: abort(404, description="Unknown profile") location = url_for(".readGcodeFile", target=target, filename=full_path, _external=True) result = { "name": destination, "path": full_path, "display": canon_name, "origin": FileDestinations.LOCAL, "refs": { "resource": location, "download": url_for("index", _external=True) + "downloads/files/" + target + "/" + full_path, }, } r = make_response(jsonify(result), 202) r.headers["Location"] = location return r elif command == "analyse": with Permissions.FILES_UPLOAD.require(403): if not _verifyFileExists(target, filename): abort(404) printer_profile = None if "printerProfile" in data and data["printerProfile"]: printer_profile = data["printerProfile"] if not fileManager.analyse( target, filename, printer_profile_id=printer_profile): abort(400, description="No analysis possible") elif command == "copy" or command == "move": with Permissions.FILES_UPLOAD.require(403): # Copy and move are only possible on local storage if target not in [FileDestinations.LOCAL]: abort(400, description="Unsupported target for {}".format(command)) if not _verifyFileExists(target, filename) and not _verifyFolderExists( target, filename): abort(404) path, name = fileManager.split_path(target, filename) destination = data["destination"] dst_path, dst_name = fileManager.split_path(target, destination) sanitized_destination = fileManager.join_path( target, dst_path, fileManager.sanitize_name(target, dst_name)) # Check for exception thrown by _verifyFolderExists, if outside the root directory try: if (_verifyFolderExists(target, destination) and sanitized_destination != filename): # destination is an existing folder and not ourselves (= display rename), we'll assume we are supposed # to move filename to this folder under the same name destination = fileManager.join_path( target, destination, name) if _verifyFileExists(target, destination) or _verifyFolderExists( target, destination): abort(409, description="File or folder does already exist") except Exception: abort(409, description= "Exception thrown by storage, bad folder/file name?") is_file = fileManager.file_exists(target, filename) is_folder = fileManager.folder_exists(target, filename) if not (is_file or is_folder): abort(400, description="Neither file nor folder, can't {}".format( command)) if command == "copy": # destination already there? error... if _verifyFileExists(target, destination) or _verifyFolderExists( target, destination): abort(409, description="File or folder does already exist") if is_file: fileManager.copy_file(target, filename, destination) else: fileManager.copy_folder(target, filename, destination) elif command == "move": with Permissions.FILES_DELETE.require(403): if _isBusy(target, filename): abort( 409, description= "Trying to move a file or folder that is currently in use", ) # destination already there AND not ourselves (= display rename)? error... if (_verifyFileExists(target, destination) or _verifyFolderExists(target, destination) ) and sanitized_destination != filename: abort(409, description="File or folder does already exist") # deselect the file if it's currently selected currentOrigin, currentFilename = _getCurrentFile() if currentFilename is not None and filename == currentFilename: printer.unselect_file() if is_file: fileManager.move_file(target, filename, destination) else: fileManager.move_folder(target, filename, destination) location = url_for(".readGcodeFile", target=target, filename=destination, _external=True) result = { "name": name, "path": destination, "origin": FileDestinations.LOCAL, "refs": { "resource": location }, } if is_file: result["refs"]["download"] = ( url_for("index", _external=True) + "downloads/files/" + target + "/" + destination) r = make_response(jsonify(result), 201) r.headers["Location"] = location return r return NO_CONTENT