From c1760c99409bc8fd32437356db22a4fe597f74fa Mon Sep 17 00:00:00 2001 From: Richard Mitchell Date: Sat, 18 May 2013 17:47:31 +0000 Subject: [PATCH] A very simple API endpoint for loading and printing files direct. This is by default turned off and it "allowed" via the settings From within Slic3r adding a post-processing script .bat containing c:\curl\curl "http://192.168.0.7:5000/api/load?apikey=D96FA6A216CB44F78705D4506689D0EC&print=true" -F file=@%* --- octoprint/server.py | 52 +++++++++++++++++++++++++++-- octoprint/settings.py | 5 +++ octoprint/static/js/ui.js | 10 ++++++ octoprint/templates/settings.jinja2 | 18 ++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/octoprint/server.py b/octoprint/server.py index 3a6249a..692509c 100644 --- a/octoprint/server.py +++ b/octoprint/server.py @@ -22,6 +22,7 @@ import octoprint.users as users SUCCESS = {} BASEURL = "/ajax/" +APIBASEURL = "/api/" app = Flask("octoprint") # Only instantiated by the Server().run() method @@ -272,6 +273,7 @@ def uploadGcodeFile(): filename = gcodeManager.addFile(file) return jsonify(files=gcodeManager.getAllFileData(), filename=filename) + @app.route(BASEURL + "gcodefiles/load", methods=["POST"]) @login_required def loadGcodeFile(): @@ -279,9 +281,9 @@ def loadGcodeFile(): printAfterLoading = False if "print" in request.values.keys() and request.values["print"] in valid_boolean_trues: printAfterLoading = True - filename = gcodeManager.getAbsolutePath(request.values["filename"]) - if filename is not None: - printer.loadGcode(filename, printAfterLoading) + filepath = gcodeManager.getAbsolutePath(request.values["filename"]) + if filepath is not None: + printer.loadGcode(filepath, printAfterLoading) return jsonify(SUCCESS) @app.route(BASEURL + "gcodefiles/delete", methods=["POST"]) @@ -292,6 +294,42 @@ def deleteGcodeFile(): gcodeManager.removeFile(filename) return readGcodeFiles() +#-- very simple api routines +@app.route(APIBASEURL + "load", methods=["POST"]) +@login_required +def apiLoad(): + filename = None + s = settings() + if not s.get(["api", "allow"]): + return jsonify(success=False, message="API calls not enabled") + + if not "apikey" in request.values.keys(): + return jsonify(success=False, message="apikey not present") + + if request.values["apikey"] <> s.get(["api", "key"]): + return jsonify(success=False, message="apikey incorrect" + s.get(["api","key"]) + " " + request.values["apikey"]) + + if "file" in request.files.keys(): + # Perform an upload + file = request.files["file"] + filename = gcodeManager.addFile(file) + if filename is None: + return jsonify(success=False, message="failure loading gcode") + else: + logger = logging.getLogger(__name__) + logger.info("loaded " + filename) + # Immediately perform a loadGcode and possibly print too + printAfterLoading = False + if "print" in request.values.keys() and request.values["print"] in valid_boolean_trues: + printAfterLoading = True + filepath = gcodeManager.getAbsolutePath(filename) + if filepath is not None: + printer.loadGcode(filepath, printAfterLoading) + else: + return jsonify(success=False, message="gcode file not present") + + return jsonify(files=gcodeManager.getAllFileData(), filename=filename) + #~~ timelapse handling @app.route(BASEURL + "timelapse", methods=["GET"]) @@ -361,6 +399,10 @@ def getSettings(): [movementSpeedX, movementSpeedY, movementSpeedZ, movementSpeedE] = s.get(["printerParameters", "movementSpeed", ["x", "y", "z", "e"]]) return jsonify({ + "api": { + "allow": s.getBoolean(["api", "allow"]), + "key": s.get(["api", "key"]) + }, "appearance": { "name": s.get(["appearance", "name"]), "color": s.get(["appearance", "color"]) @@ -404,6 +446,10 @@ def setSettings(): data = request.json s = settings() + if "api" in data.keys(): + if "allow" in data["api"].keys(): s.set(["api", "allow"], data["api"]["allow"]) + if "key" in data["api"].keys(): s.set(["api", "key"], data["api"]["key"], True) + if "appearance" in data.keys(): if "name" in data["appearance"].keys(): s.set(["appearance", "name"], data["appearance"]["name"]) if "color" in data["appearance"].keys(): s.set(["appearance", "color"], data["appearance"]["color"]) diff --git a/octoprint/settings.py b/octoprint/settings.py index 7c385f8..b9bb0b0 100644 --- a/octoprint/settings.py +++ b/octoprint/settings.py @@ -7,6 +7,7 @@ import sys import os import yaml import logging +import uuid APPNAME="OctoPrint" @@ -74,6 +75,10 @@ default_settings = { "enabled": False, "userManager": "octoprint.users.FilebasedUserManager", "userfile": None + }, + "api": { + "allow": False, + "key": ''.join('%02X' % ord(z) for z in uuid.uuid4().bytes) } } diff --git a/octoprint/static/js/ui.js b/octoprint/static/js/ui.js index d2d0882..e793a45 100644 --- a/octoprint/static/js/ui.js +++ b/octoprint/static/js/ui.js @@ -1248,6 +1248,9 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { self.loginState = loginStateViewModel; self.users = usersViewModel; + self.api_allow = ko.observable(undefined); + self.api_key = ko.observable(undefined); + self.appearance_name = ko.observable(undefined); self.appearance_color = ko.observable(undefined); @@ -1295,6 +1298,9 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { } self.fromResponse = function(response) { + self.api_allow(response.api.allow); + self.api_key(response.api.key); + self.appearance_name(response.appearance.name); self.appearance_color(response.appearance.color); @@ -1324,6 +1330,10 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) { self.saveData = function() { var data = { + "api" : { + "allow": self.api_allow(), + "key": self.api_key() + }, "appearance" : { "name": self.appearance_name(), "color": self.appearance_color() diff --git a/octoprint/templates/settings.jinja2 b/octoprint/templates/settings.jinja2 index dc0644a..25feab6 100644 --- a/octoprint/templates/settings.jinja2 +++ b/octoprint/templates/settings.jinja2 @@ -13,6 +13,7 @@
  • Temperature
  • Appearance
  • {% if enableAccessControl %}
  • Users
  • {% endif %} +
  • Api
  • @@ -185,6 +186,23 @@
    +
    +
    +
    +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    {% if enableAccessControl %}