"Writing" backend methods now protected (need logged in user (or dummy user if access control is disabled) to perform action), most "writing" frontend controls disabled if no logged in (or dummy) user returned from backend.
parent
b27e1ce15e
commit
1febcd671a
|
@ -138,11 +138,13 @@ def connect():
|
||||||
return jsonify(state="Connecting")
|
return jsonify(state="Connecting")
|
||||||
|
|
||||||
@app.route(BASEURL + "control/disconnect", methods=["POST"])
|
@app.route(BASEURL + "control/disconnect", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def disconnect():
|
def disconnect():
|
||||||
printer.disconnect()
|
printer.disconnect()
|
||||||
return jsonify(state="Offline")
|
return jsonify(state="Offline")
|
||||||
|
|
||||||
@app.route(BASEURL + "control/command", methods=["POST"])
|
@app.route(BASEURL + "control/command", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def printerCommand():
|
def printerCommand():
|
||||||
if "application/json" in request.headers["Content-Type"]:
|
if "application/json" in request.headers["Content-Type"]:
|
||||||
data = request.json
|
data = request.json
|
||||||
|
@ -166,21 +168,25 @@ def printerCommand():
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
@app.route(BASEURL + "control/print", methods=["POST"])
|
@app.route(BASEURL + "control/print", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def printGcode():
|
def printGcode():
|
||||||
printer.startPrint()
|
printer.startPrint()
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
@app.route(BASEURL + "control/pause", methods=["POST"])
|
@app.route(BASEURL + "control/pause", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def pausePrint():
|
def pausePrint():
|
||||||
printer.togglePausePrint()
|
printer.togglePausePrint()
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
@app.route(BASEURL + "control/cancel", methods=["POST"])
|
@app.route(BASEURL + "control/cancel", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def cancelPrint():
|
def cancelPrint():
|
||||||
printer.cancelPrint()
|
printer.cancelPrint()
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
@app.route(BASEURL + "control/temperature", methods=["POST"])
|
@app.route(BASEURL + "control/temperature", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def setTargetTemperature():
|
def setTargetTemperature():
|
||||||
if not printer.isOperational():
|
if not printer.isOperational():
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
@ -198,6 +204,7 @@ def setTargetTemperature():
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
@app.route(BASEURL + "control/jog", methods=["POST"])
|
@app.route(BASEURL + "control/jog", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def jog():
|
def jog():
|
||||||
if not printer.isOperational() or printer.isPrinting():
|
if not printer.isOperational() or printer.isPrinting():
|
||||||
# do not jog when a print job is running or we don't have a connection
|
# do not jog when a print job is running or we don't have a connection
|
||||||
|
@ -234,6 +241,7 @@ def getSpeedValues():
|
||||||
return jsonify(feedrate=printer.feedrateState())
|
return jsonify(feedrate=printer.feedrateState())
|
||||||
|
|
||||||
@app.route(BASEURL + "control/speed", methods=["POST"])
|
@app.route(BASEURL + "control/speed", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def speed():
|
def speed():
|
||||||
if not printer.isOperational():
|
if not printer.isOperational():
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
@ -261,6 +269,7 @@ def readGcodeFile(filename):
|
||||||
return send_from_directory(settings().getBaseFolder("uploads"), filename, as_attachment=True)
|
return send_from_directory(settings().getBaseFolder("uploads"), filename, as_attachment=True)
|
||||||
|
|
||||||
@app.route(BASEURL + "gcodefiles/upload", methods=["POST"])
|
@app.route(BASEURL + "gcodefiles/upload", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def uploadGcodeFile():
|
def uploadGcodeFile():
|
||||||
filename = None
|
filename = None
|
||||||
if "gcode_file" in request.files.keys():
|
if "gcode_file" in request.files.keys():
|
||||||
|
@ -269,6 +278,7 @@ def uploadGcodeFile():
|
||||||
return jsonify(files=gcodeManager.getAllFileData(), filename=filename)
|
return jsonify(files=gcodeManager.getAllFileData(), filename=filename)
|
||||||
|
|
||||||
@app.route(BASEURL + "gcodefiles/load", methods=["POST"])
|
@app.route(BASEURL + "gcodefiles/load", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def loadGcodeFile():
|
def loadGcodeFile():
|
||||||
if "filename" in request.values.keys():
|
if "filename" in request.values.keys():
|
||||||
printAfterLoading = False
|
printAfterLoading = False
|
||||||
|
@ -280,6 +290,7 @@ def loadGcodeFile():
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
@app.route(BASEURL + "gcodefiles/delete", methods=["POST"])
|
@app.route(BASEURL + "gcodefiles/delete", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def deleteGcodeFile():
|
def deleteGcodeFile():
|
||||||
if "filename" in request.values.keys():
|
if "filename" in request.values.keys():
|
||||||
filename = request.values["filename"]
|
filename = request.values["filename"]
|
||||||
|
@ -318,6 +329,7 @@ def downloadTimelapse(filename):
|
||||||
return send_from_directory(settings().getBaseFolder("timelapse"), filename, as_attachment=True)
|
return send_from_directory(settings().getBaseFolder("timelapse"), filename, as_attachment=True)
|
||||||
|
|
||||||
@app.route(BASEURL + "timelapse/<filename>", methods=["DELETE"])
|
@app.route(BASEURL + "timelapse/<filename>", methods=["DELETE"])
|
||||||
|
@login_required
|
||||||
def deleteTimelapse(filename):
|
def deleteTimelapse(filename):
|
||||||
if util.isAllowedFile(filename, set(["mpg"])):
|
if util.isAllowedFile(filename, set(["mpg"])):
|
||||||
secure = os.path.join(settings().getBaseFolder("timelapse"), secure_filename(filename))
|
secure = os.path.join(settings().getBaseFolder("timelapse"), secure_filename(filename))
|
||||||
|
@ -326,6 +338,7 @@ def deleteTimelapse(filename):
|
||||||
return getTimelapseData()
|
return getTimelapseData()
|
||||||
|
|
||||||
@app.route(BASEURL + "timelapse/config", methods=["POST"])
|
@app.route(BASEURL + "timelapse/config", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def setTimelapseConfig():
|
def setTimelapseConfig():
|
||||||
if request.values.has_key("type"):
|
if request.values.has_key("type"):
|
||||||
type = request.values["type"]
|
type = request.values["type"]
|
||||||
|
@ -389,6 +402,7 @@ def getSettings():
|
||||||
})
|
})
|
||||||
|
|
||||||
@app.route(BASEURL + "settings", methods=["POST"])
|
@app.route(BASEURL + "settings", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def setSettings():
|
def setSettings():
|
||||||
if "application/json" in request.headers["Content-Type"]:
|
if "application/json" in request.headers["Content-Type"]:
|
||||||
data = request.json
|
data = request.json
|
||||||
|
@ -434,6 +448,7 @@ def setSettings():
|
||||||
#~~ system control
|
#~~ system control
|
||||||
|
|
||||||
@app.route(BASEURL + "system", methods=["POST"])
|
@app.route(BASEURL + "system", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def performSystemAction():
|
def performSystemAction():
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
if request.values.has_key("action"):
|
if request.values.has_key("action"):
|
||||||
|
@ -467,15 +482,14 @@ def login():
|
||||||
|
|
||||||
user = userManager.findUser(username)
|
user = userManager.findUser(username)
|
||||||
if user is not None:
|
if user is not None:
|
||||||
passwordHash = users.UserManager.createPasswordHash(password)
|
if user.check_password(users.UserManager.createPasswordHash(password)):
|
||||||
if passwordHash == user.passwordHash:
|
|
||||||
login_user(user, remember=remember)
|
login_user(user, remember=remember)
|
||||||
return jsonify({"name": user.username, "roles": user.roles})
|
return jsonify({"name": user.get_name(), "user": user.is_user(), "admin": user.is_admin()})
|
||||||
return app.make_response(("User unknown or password incorrect", 401, []))
|
return app.make_response(("User unknown or password incorrect", 401, []))
|
||||||
elif "passive" in request.values.keys():
|
elif "passive" in request.values.keys():
|
||||||
user = current_user
|
user = current_user
|
||||||
if user is not None and not user.is_anonymous():
|
if user is not None and not user.is_anonymous():
|
||||||
return jsonify({"name": user.username, "roles": user.roles})
|
return jsonify({"name": user.get_name(), "user": user.is_user(), "admin": user.is_admin()})
|
||||||
else:
|
else:
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
|
@ -488,8 +502,7 @@ def logout():
|
||||||
def load_user(id):
|
def load_user(id):
|
||||||
if userManager is not None:
|
if userManager is not None:
|
||||||
return userManager.findUser(id)
|
return userManager.findUser(id)
|
||||||
else:
|
return None
|
||||||
return users.DummyUser()
|
|
||||||
|
|
||||||
#~~ startup code
|
#~~ startup code
|
||||||
class Server():
|
class Server():
|
||||||
|
|
|
@ -1,8 +1,80 @@
|
||||||
//~~ View models
|
//~~ View models
|
||||||
|
|
||||||
function ConnectionViewModel() {
|
function LoginStateViewModel() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loggedIn = ko.observable(false);
|
||||||
|
self.username = ko.observable(undefined);
|
||||||
|
self.isAdmin = ko.observable(false);
|
||||||
|
self.isUser = ko.observable(false);
|
||||||
|
|
||||||
|
self.userMenuText = ko.computed(function() {
|
||||||
|
if (self.loggedIn()) {
|
||||||
|
return "\"" + self.username() + "\"";
|
||||||
|
} else {
|
||||||
|
return "Login";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.requestData = function() {
|
||||||
|
$.ajax({
|
||||||
|
url: AJAX_BASEURL + "login",
|
||||||
|
type: "POST",
|
||||||
|
data: {"passive": true},
|
||||||
|
success: self.fromResponse
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fromResponse = function(response) {
|
||||||
|
if (response && response.name) {
|
||||||
|
self.loggedIn(true);
|
||||||
|
self.username(response.name);
|
||||||
|
self.isUser(response.user);
|
||||||
|
self.isAdmin(response.admin);
|
||||||
|
} else {
|
||||||
|
self.loggedIn(false);
|
||||||
|
self.username(undefined);
|
||||||
|
self.isUser(false);
|
||||||
|
self.isAdmin(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.login = function() {
|
||||||
|
var username = $("#login_user").val();
|
||||||
|
var password = $("#login_pass").val();
|
||||||
|
var remember = $("#login_remember").is(":checked");
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: AJAX_BASEURL + "login",
|
||||||
|
type: "POST",
|
||||||
|
data: {"user": username, "pass": password, "remember": remember},
|
||||||
|
success: function(response) {
|
||||||
|
$.pnotify({title: "Login successful", text: "You are now logged in", type: "success"});
|
||||||
|
self.fromResponse(response);
|
||||||
|
},
|
||||||
|
error: function(jqXHR, textStatus, errorThrown) {
|
||||||
|
$.pnotify({title: "Login failed", text: "User unknown or wrong password", type: "error"});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
self.logout = function() {
|
||||||
|
$.ajax({
|
||||||
|
url: AJAX_BASEURL + "logout",
|
||||||
|
type: "POST",
|
||||||
|
success: function(response) {
|
||||||
|
$.pnotify({title: "Logout successful", text: "You are now logged out", type: "success"});
|
||||||
|
self.fromResponse(response);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ConnectionViewModel(loginStateViewModel) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.portOptions = ko.observableArray(undefined);
|
self.portOptions = ko.observableArray(undefined);
|
||||||
self.baudrateOptions = ko.observableArray(undefined);
|
self.baudrateOptions = ko.observableArray(undefined);
|
||||||
self.selectedPort = ko.observable(undefined);
|
self.selectedPort = ko.observable(undefined);
|
||||||
|
@ -107,9 +179,11 @@ function ConnectionViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function PrinterStateViewModel() {
|
function PrinterStateViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.stateString = ko.observable(undefined);
|
self.stateString = ko.observable(undefined);
|
||||||
self.isErrorOrClosed = ko.observable(undefined);
|
self.isErrorOrClosed = ko.observable(undefined);
|
||||||
self.isOperational = ko.observable(undefined);
|
self.isOperational = ko.observable(undefined);
|
||||||
|
@ -238,9 +312,11 @@ function PrinterStateViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function TemperatureViewModel(settingsViewModel) {
|
function TemperatureViewModel(loginStateViewModel, settingsViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.temp = ko.observable(undefined);
|
self.temp = ko.observable(undefined);
|
||||||
self.bedTemp = ko.observable(undefined);
|
self.bedTemp = ko.observable(undefined);
|
||||||
self.targetTemp = ko.observable(undefined);
|
self.targetTemp = ko.observable(undefined);
|
||||||
|
@ -412,9 +488,11 @@ function TemperatureViewModel(settingsViewModel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ControlViewModel() {
|
function ControlViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.isErrorOrClosed = ko.observable(undefined);
|
self.isErrorOrClosed = ko.observable(undefined);
|
||||||
self.isOperational = ko.observable(undefined);
|
self.isOperational = ko.observable(undefined);
|
||||||
self.isPrinting = ko.observable(undefined);
|
self.isPrinting = ko.observable(undefined);
|
||||||
|
@ -567,9 +645,11 @@ function ControlViewModel() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SpeedViewModel() {
|
function SpeedViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.outerWall = ko.observable(undefined);
|
self.outerWall = ko.observable(undefined);
|
||||||
self.innerWall = ko.observable(undefined);
|
self.innerWall = ko.observable(undefined);
|
||||||
self.fill = ko.observable(undefined);
|
self.fill = ko.observable(undefined);
|
||||||
|
@ -625,9 +705,11 @@ function SpeedViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function TerminalViewModel() {
|
function TerminalViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.log = [];
|
self.log = [];
|
||||||
|
|
||||||
self.isErrorOrClosed = ko.observable(undefined);
|
self.isErrorOrClosed = ko.observable(undefined);
|
||||||
|
@ -654,6 +736,7 @@ function TerminalViewModel() {
|
||||||
if (!self.log)
|
if (!self.log)
|
||||||
self.log = []
|
self.log = []
|
||||||
self.log = self.log.concat(data)
|
self.log = self.log.concat(data)
|
||||||
|
self.log = self.log.slice(-300)
|
||||||
self.updateOutput();
|
self.updateOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,9 +773,11 @@ function TerminalViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function GcodeFilesViewModel() {
|
function GcodeFilesViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.isErrorOrClosed = ko.observable(undefined);
|
self.isErrorOrClosed = ko.observable(undefined);
|
||||||
self.isOperational = ko.observable(undefined);
|
self.isOperational = ko.observable(undefined);
|
||||||
self.isPrinting = ko.observable(undefined);
|
self.isPrinting = ko.observable(undefined);
|
||||||
|
@ -824,9 +909,11 @@ function GcodeFilesViewModel() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function TimelapseViewModel() {
|
function TimelapseViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.timelapseType = ko.observable(undefined);
|
self.timelapseType = ko.observable(undefined);
|
||||||
self.timelapseTimedInterval = ko.observable(undefined);
|
self.timelapseTimedInterval = ko.observable(undefined);
|
||||||
|
|
||||||
|
@ -943,9 +1030,11 @@ function TimelapseViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function GcodeViewModel() {
|
function GcodeViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.loadedFilename = undefined;
|
self.loadedFilename = undefined;
|
||||||
self.status = 'idle';
|
self.status = 'idle';
|
||||||
self.enabled = false;
|
self.enabled = false;
|
||||||
|
@ -1006,9 +1095,11 @@ function GcodeViewModel() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SettingsViewModel() {
|
function SettingsViewModel(loginStateViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
|
|
||||||
self.appearance_name = ko.observable(undefined);
|
self.appearance_name = ko.observable(undefined);
|
||||||
self.appearance_color = ko.observable(undefined);
|
self.appearance_color = ko.observable(undefined);
|
||||||
|
|
||||||
|
@ -1135,9 +1226,10 @@ function SettingsViewModel() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function NavigationViewModel(appearanceViewModel, settingsViewModel) {
|
function NavigationViewModel(loginStateViewModel, appearanceViewModel, settingsViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginState = loginStateViewModel;
|
||||||
self.appearance = appearanceViewModel;
|
self.appearance = appearanceViewModel;
|
||||||
self.systemActions = settingsViewModel.system_actions;
|
self.systemActions = settingsViewModel.system_actions;
|
||||||
|
|
||||||
|
@ -1166,9 +1258,10 @@ function NavigationViewModel(appearanceViewModel, settingsViewModel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DataUpdater(connectionViewModel, printerStateViewModel, temperatureViewModel, controlViewModel, speedViewModel, terminalViewModel, gcodeFilesViewModel, timelapseViewModel, gcodeViewModel) {
|
function DataUpdater(loginStateViewModel, connectionViewModel, printerStateViewModel, temperatureViewModel, controlViewModel, speedViewModel, terminalViewModel, gcodeFilesViewModel, timelapseViewModel, gcodeViewModel) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
self.loginStateViewModel = loginStateViewModel;
|
||||||
self.connectionViewModel = connectionViewModel;
|
self.connectionViewModel = connectionViewModel;
|
||||||
self.printerStateViewModel = printerStateViewModel;
|
self.printerStateViewModel = printerStateViewModel;
|
||||||
self.temperatureViewModel = temperatureViewModel;
|
self.temperatureViewModel = temperatureViewModel;
|
||||||
|
@ -1185,6 +1278,7 @@ function DataUpdater(connectionViewModel, printerStateViewModel, temperatureView
|
||||||
$("#offline_overlay").hide();
|
$("#offline_overlay").hide();
|
||||||
self.timelapseViewModel.requestData();
|
self.timelapseViewModel.requestData();
|
||||||
$("#webcam_image").attr("src", CONFIG_WEBCAM_STREAM + "?" + new Date().getTime());
|
$("#webcam_image").attr("src", CONFIG_WEBCAM_STREAM + "?" + new Date().getTime());
|
||||||
|
self.loginStateViewModel.requestData();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self._socket.on("disconnect", function() {
|
self._socket.on("disconnect", function() {
|
||||||
|
@ -1480,20 +1574,22 @@ function AppearanceViewModel(settingsViewModel) {
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
//~~ View models
|
//~~ View models
|
||||||
var connectionViewModel = new ConnectionViewModel();
|
var loginStateViewModel = new LoginStateViewModel();
|
||||||
var printerStateViewModel = new PrinterStateViewModel();
|
var connectionViewModel = new ConnectionViewModel(loginStateViewModel);
|
||||||
var settingsViewModel = new SettingsViewModel();
|
var printerStateViewModel = new PrinterStateViewModel(loginStateViewModel);
|
||||||
|
var settingsViewModel = new SettingsViewModel(loginStateViewModel);
|
||||||
var appearanceViewModel = new AppearanceViewModel(settingsViewModel);
|
var appearanceViewModel = new AppearanceViewModel(settingsViewModel);
|
||||||
var temperatureViewModel = new TemperatureViewModel(settingsViewModel);
|
var temperatureViewModel = new TemperatureViewModel(loginStateViewModel, settingsViewModel);
|
||||||
var controlViewModel = new ControlViewModel();
|
var controlViewModel = new ControlsViewModel(loginStateViewModel);
|
||||||
var speedViewModel = new SpeedViewModel();
|
var speedViewModel = new SpeedViewModel(loginStateViewModel);
|
||||||
var terminalViewModel = new TerminalViewModel();
|
var terminalViewModel = new TerminalViewModel(loginStateViewModel);
|
||||||
var gcodeFilesViewModel = new GcodeFilesViewModel();
|
var gcodeFilesViewModel = new GcodeFilesViewModel(loginStateViewModel);
|
||||||
var timelapseViewModel = new TimelapseViewModel();
|
var timelapseViewModel = new TimelapseViewModel(loginStateViewModel);
|
||||||
var gcodeViewModel = new GcodeViewModel();
|
var gcodeViewModel = new GcodeViewModel(loginStateViewModel);
|
||||||
var navigationViewModel = new NavigationViewModel(appearanceViewModel, settingsViewModel);
|
var navigationViewModel = new NavigationViewModel(loginStateViewModel, appearanceViewModel, settingsViewModel);
|
||||||
|
|
||||||
var dataUpdater = new DataUpdater(
|
var dataUpdater = new DataUpdater(
|
||||||
|
loginStateViewModel,
|
||||||
connectionViewModel,
|
connectionViewModel,
|
||||||
printerStateViewModel,
|
printerStateViewModel,
|
||||||
temperatureViewModel,
|
temperatureViewModel,
|
||||||
|
@ -1505,7 +1601,8 @@ $(function() {
|
||||||
gcodeViewModel
|
gcodeViewModel
|
||||||
);
|
);
|
||||||
|
|
||||||
//work around a stupid iOS6 bug where ajax requests get cached and only work once, as described at http://stackoverflow.com/questions/12506897/is-safari-on-ios-6-caching-ajax-results
|
// work around a stupid iOS6 bug where ajax requests get cached and only work once, as described at
|
||||||
|
// http://stackoverflow.com/questions/12506897/is-safari-on-ios-6-caching-ajax-results
|
||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
headers: { "cache-control": "no-cache" }
|
headers: { "cache-control": "no-cache" }
|
||||||
|
@ -1547,6 +1644,7 @@ $(function() {
|
||||||
})
|
})
|
||||||
$('#tabs a[data-toggle="tab"]').on('shown', function (e) {
|
$('#tabs a[data-toggle="tab"]').on('shown', function (e) {
|
||||||
temperatureViewModel.updatePlot();
|
temperatureViewModel.updatePlot();
|
||||||
|
terminalViewModel.updateOutput();
|
||||||
});
|
});
|
||||||
|
|
||||||
//~~ Speed controls
|
//~~ Speed controls
|
||||||
|
@ -1618,71 +1716,6 @@ $(function() {
|
||||||
//~~ Offline overlay
|
//~~ Offline overlay
|
||||||
$("#offline_overlay_reconnect").click(function() {dataUpdater.reconnect()});
|
$("#offline_overlay_reconnect").click(function() {dataUpdater.reconnect()});
|
||||||
|
|
||||||
//~~ Alert
|
|
||||||
|
|
||||||
/*
|
|
||||||
function displayAlert(text, timeout, type) {
|
|
||||||
var placeholder = $("#alert_placeholder");
|
|
||||||
|
|
||||||
var alertType = "";
|
|
||||||
if (type == "success" || type == "error" || type == "info") {
|
|
||||||
alertType = " alert-" + type;
|
|
||||||
}
|
|
||||||
|
|
||||||
placeholder.append($("<div id='activeAlert' class='alert " + alertType + " fade in' data-alert='alert'><p>" + text + "</p></div>"));
|
|
||||||
placeholder.fadeIn();
|
|
||||||
$("#activeAlert").delay(timeout).fadeOut("slow", function() {$(this).remove(); $("#alert_placeholder").hide();});
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
//~~ Login/logout
|
|
||||||
|
|
||||||
$("#login_button").click(function() {
|
|
||||||
var username = $("#login_user").val();
|
|
||||||
var password = $("#login_pass").val();
|
|
||||||
var remember = $("#login_remember").is(":checked");
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: AJAX_BASEURL + "login",
|
|
||||||
type: "POST",
|
|
||||||
data: {"user": username, "pass": password, "remember": remember},
|
|
||||||
success: function(response) {
|
|
||||||
$.pnotify({title: "Login successful", text: "You are now logged in", type: "success"});
|
|
||||||
$("#login_dropdown_text").text("\"" + response.name + "\"");
|
|
||||||
$("#login_dropdown_loggedout").removeClass("dropdown-menu").addClass("hide");
|
|
||||||
$("#login_dropdown_loggedin").removeClass("hide").addClass("dropdown-menu");
|
|
||||||
},
|
|
||||||
error: function(jqXHR, textStatus, errorThrown) {
|
|
||||||
$.pnotify({title: "Login failed", text: "User unknown or wrong password", type: "error"});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
$("#logout_button").click(function(){
|
|
||||||
$.ajax({
|
|
||||||
url: AJAX_BASEURL + "logout",
|
|
||||||
type: "POST",
|
|
||||||
success: function(response) {
|
|
||||||
$.pnotify({title: "Logout successful", text: "You are now logged out", type: "success"});
|
|
||||||
$("#login_dropdown_text").text("Login");
|
|
||||||
$("#login_dropdown_loggedin").removeClass("dropdown-menu").addClass("hide");
|
|
||||||
$("#login_dropdown_loggedout").removeClass("hide").addClass("dropdown-menu");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: AJAX_BASEURL + "login",
|
|
||||||
type: "POST",
|
|
||||||
data: {"passive": true},
|
|
||||||
success: function(response) {
|
|
||||||
if (response["name"]) {
|
|
||||||
$("#login_dropdown_text").text("\"" + response.name + "\"");
|
|
||||||
$("#login_dropdown_loggedout").removeClass("dropdown-menu").addClass("hide");
|
|
||||||
$("#login_dropdown_loggedin").removeClass("hide").addClass("dropdown-menu");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
//~~ knockout.js bindings
|
//~~ knockout.js bindings
|
||||||
|
|
||||||
ko.bindingHandlers.popover = {
|
ko.bindingHandlers.popover = {
|
||||||
|
@ -1717,14 +1750,15 @@ $(function() {
|
||||||
|
|
||||||
var timelapseElement = document.getElementById("timelapse");
|
var timelapseElement = document.getElementById("timelapse");
|
||||||
if (timelapseElement) {
|
if (timelapseElement) {
|
||||||
ko.applyBindings(timelapseViewModel, document.getElementById("timelapse"));
|
ko.applyBindings(timelapseViewModel, timelapseElement);
|
||||||
}
|
}
|
||||||
var gCodeVisualizerElement = document.getElementById("gcode");
|
var gCodeVisualizerElement = document.getElementById("gcode");
|
||||||
if(gCodeVisualizerElement){
|
if (gCodeVisualizerElement) {
|
||||||
gcodeViewModel.initialize();
|
gcodeViewModel.initialize();
|
||||||
}
|
}
|
||||||
//~~ startup commands
|
//~~ startup commands
|
||||||
|
|
||||||
|
loginStateViewModel.requestData();
|
||||||
connectionViewModel.requestData();
|
connectionViewModel.requestData();
|
||||||
controlViewModel.requestData();
|
controlViewModel.requestData();
|
||||||
gcodeFilesViewModel.requestData();
|
gcodeFilesViewModel.requestData();
|
||||||
|
@ -1745,7 +1779,7 @@ $(function() {
|
||||||
|
|
||||||
$.pnotify.defaults.history = false;
|
$.pnotify.defaults.history = false;
|
||||||
|
|
||||||
// Fix input element click problem
|
// Fix input element click problem on login dialog
|
||||||
$('.dropdown input, .dropdown label').click(function(e) {
|
$('.dropdown input, .dropdown label').click(function(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,9 +33,13 @@
|
||||||
<a class="brand" href="#"><img src="{{ url_for('static', filename='img/tentacle-20x20.png') }}"> <span data-bind="text: appearance.brand">OctoPrint</span></a>
|
<a class="brand" href="#"><img src="{{ url_for('static', filename='img/tentacle-20x20.png') }}"> <span data-bind="text: appearance.brand">OctoPrint</span></a>
|
||||||
<div class="nav-collapse">
|
<div class="nav-collapse">
|
||||||
<ul class="nav pull-right">
|
<ul class="nav pull-right">
|
||||||
<li><a id="navbar_show_settings" class="pull-right" href="#settings_dialog"><i class="icon-wrench"></i> Settings</a></li>
|
<li class="hide" data-bind="css: {hide: !loginState.isAdmin()}">
|
||||||
|
<a id="navbar_show_settings" class="pull-right" href="#settings_dialog">
|
||||||
|
<i class="icon-wrench"></i> Settings
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% if enableSystemMenu %}
|
{% if enableSystemMenu %}
|
||||||
<li class="dropdown">
|
<li class="dropdown hide" data-bind="css: {hide: !loginState.isAdmin()}">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||||
<i class="icon-off"></i> System
|
<i class="icon-off"></i> System
|
||||||
<b class="caret"></b>
|
<b class="caret"></b>
|
||||||
|
@ -48,10 +52,10 @@
|
||||||
{% if enableAccessControl %}
|
{% if enableAccessControl %}
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||||
<i class="icon-user"></i> <span id="login_dropdown_text">Login</span>
|
<i class="icon-user"></i> <span data-bind="text: loginState.userMenuText">Login</span>
|
||||||
<b class="caret"></b>
|
<b class="caret"></b>
|
||||||
</a>
|
</a>
|
||||||
<div id="login_dropdown_loggedout" class="dropdown-menu" style="padding: 15px">
|
<div id="login_dropdown_loggedout" style="padding: 15px" class="dropdown-menu" data-bind="css: {hide: loginState.loggedIn(), 'dropdown-menu': !loginState.loggedIn()}">
|
||||||
<label for="login_user">Username</label>
|
<label for="login_user">Username</label>
|
||||||
<input type="text" id="login_user" placeholder="Username">
|
<input type="text" id="login_user" placeholder="Username">
|
||||||
<label for="login_pass">Password</label>
|
<label for="login_pass">Password</label>
|
||||||
|
@ -59,12 +63,10 @@
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input type="checkbox" id="login_remember"> Remember me
|
<input type="checkbox" id="login_remember"> Remember me
|
||||||
</label>
|
</label>
|
||||||
<button class="btn btn-block btn-primary" id="login_button">Login</button>
|
<button class="btn btn-block btn-primary" id="login_button" data-bind="click: loginState.login">Login</button>
|
||||||
</div>
|
</div>
|
||||||
<ul id="login_dropdown_loggedin" class="hide">
|
<ul id="login_dropdown_loggedin" class="hide" data-bind="css: {hide: !loginState.loggedIn(), 'dropdown-menu': loginState.loggedIn()}">
|
||||||
<li><a href="#">Profile</a></li>
|
<li><a href="#" id="logout_button" data-bind="click: loginState.logout">Logout</a></li>
|
||||||
<li class="divider"></li>
|
|
||||||
<li><a href="#" id="logout_button">Logout</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -82,14 +84,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion-body collapse in" id="connection">
|
<div class="accordion-body collapse in" id="connection">
|
||||||
<div class="accordion-inner">
|
<div class="accordion-inner">
|
||||||
<label for="connection_ports" data-bind="css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed">Serial Port</label>
|
<label for="connection_ports" data-bind="css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed && loginState.isUser">Serial Port</label>
|
||||||
<select id="connection_ports" data-bind="options: portOptions, optionsCaption: 'AUTO', value: selectedPort, css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed"></select>
|
<select id="connection_ports" data-bind="options: portOptions, optionsCaption: 'AUTO', value: selectedPort, css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed && loginState.isUser"></select>
|
||||||
<label for="connection_baudrates" data-bind="css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed">Baudrate</label>
|
<label for="connection_baudrates" data-bind="css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed && loginState.isUser">Baudrate</label>
|
||||||
<select id="connection_baudrates" data-bind="options: baudrateOptions, optionsCaption: 'AUTO', value: selectedBaudrate, css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed"></select>
|
<select id="connection_baudrates" data-bind="options: baudrateOptions, optionsCaption: 'AUTO', value: selectedBaudrate, css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed && loginState.isUser"></select>
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input type="checkbox" id="connection_save" data-bind="checked: saveSettings, css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed"> Save connection settings
|
<input type="checkbox" id="connection_save" data-bind="checked: saveSettings, css: {disabled: !isErrorOrClosed}, enable: isErrorOrClosed && loginState.isUser"> Save connection settings
|
||||||
</label>
|
</label>
|
||||||
<button class="btn btn-block" id="printer_connect" data-bind="click: connect, text: buttonText()">Connect</button>
|
<button class="btn btn-block" id="printer_connect" data-bind="click: connect, text: buttonText(), enable: loginState.isUser">Connect</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -113,9 +115,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row-fluid print-control">
|
<div class="row-fluid print-control">
|
||||||
<button class="btn btn-primary span4" data-bind="click: print, enable: isOperational() && isReady() && !isPrinting(), css: {'btn-danger': isPaused()}" id="job_print"><i class="icon-white" data-bind="css: {'icon-print': !isPaused(), 'icon-undo': isPaused()}"></i> <span data-bind="text: (isPaused() ? 'Restart' : 'Print')">Print</span></button>
|
<button class="btn btn-primary span4" data-bind="click: print, enable: isOperational() && isReady() && !isPrinting() && loginState.isUser(), css: {'btn-danger': isPaused()}" id="job_print"><i class="icon-white" data-bind="css: {'icon-print': !isPaused(), 'icon-undo': isPaused()}"></i> <span data-bind="text: (isPaused() ? 'Restart' : 'Print')">Print</span></button>
|
||||||
<button class="btn span4" id="job_pause" data-bind="click: pause, enable: isPrinting() || isPaused(), css: {active: isPaused()}"><i class="icon-pause"></i> <span>Pause</span></button>
|
<button class="btn span4" id="job_pause" data-bind="click: pause, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser(), css: {active: isPaused()}"><i class="icon-pause"></i> <span>Pause</span></button>
|
||||||
<button class="btn span4" id="job_cancel" data-bind="click: cancel, enable: isPrinting() || isPaused()"><i class="icon-stop"></i> Cancel</button>
|
<button class="btn span4" id="job_cancel" data-bind="click: cancel, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser()"><i class="icon-stop"></i> Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -209,12 +211,12 @@
|
||||||
|
|
||||||
<label for="temp_newTemp">New Target</label>
|
<label for="temp_newTemp">New Target</label>
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
<input type="text" id="temp_newTemp" data-bind="attr: {placeholder: targetTemp}" class="tempInput">
|
<input type="text" id="temp_newTemp" data-bind="attr: {placeholder: targetTemp}, enable: isOperational() && loginState.isUser()" class="tempInput">
|
||||||
<span class="add-on">°C</span>
|
<span class="add-on">°C</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="submit" class="btn" id="temp_newTemp_set">Set</button>
|
<button type="submit" class="btn" id="temp_newTemp_set" data-bind="enable: isOperational() && loginState.isUser()">Set</button>
|
||||||
<button class="btn dropdown-toggle" data-toggle="dropdown">
|
<button class="btn dropdown-toggle" data-toggle="dropdown" data-bind="enable: isOperational() && loginState.isUser()">
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
@ -239,12 +241,12 @@
|
||||||
|
|
||||||
<label for="temp_newBedTemp">New Target</label>
|
<label for="temp_newBedTemp">New Target</label>
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
<input type="text" id="temp_newBedTemp" data-bind="attr: {placeholder: bedTargetTemp}" class="tempInput">
|
<input type="text" id="temp_newBedTemp" data-bind="attr: {placeholder: bedTargetTemp}, enable: isOperational() && loginState.isUser()" class="tempInput">
|
||||||
<span class="add-on">°C</span>
|
<span class="add-on">°C</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="submit" class="btn" id="temp_newBedTemp_set">Set</button>
|
<button type="submit" class="btn" id="temp_newBedTemp_set" data-bind="enable: isOperational() && loginState.isUser()">Set</button>
|
||||||
<button class="btn dropdown-toggle" data-toggle="dropdown">
|
<button class="btn dropdown-toggle" data-toggle="dropdown" data-bind="enable: isOperational() && loginState.isUser()">
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
@ -274,37 +276,37 @@
|
||||||
<div class="jog-panel">
|
<div class="jog-panel">
|
||||||
<h1>X/Y</h1>
|
<h1>X/Y</h1>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('y',1) }"><i class="icon-arrow-up"></i></button>
|
<button class="btn box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('y',1) }"><i class="icon-arrow-up"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn box pull-left" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('x',-1) }"><i class="icon-arrow-left"></i></button>
|
<button class="btn box pull-left" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('x',-1) }"><i class="icon-arrow-left"></i></button>
|
||||||
<button class="btn box pull-left" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendHomeCommand('XY') }"><i class="icon-home"></i></button>
|
<button class="btn box pull-left" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendHomeCommand('XY') }"><i class="icon-home"></i></button>
|
||||||
<button class="btn box pull-left" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('x',1) }"><i class="icon-arrow-right"></i></button>
|
<button class="btn box pull-left" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('x',1) }"><i class="icon-arrow-right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('y',-1) }"><i class="icon-arrow-down"></i></button>
|
<button class="btn box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('y',-1) }"><i class="icon-arrow-down"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Z jogging control panel -->
|
<!-- Z jogging control panel -->
|
||||||
<div class="jog-panel">
|
<div class="jog-panel">
|
||||||
<h1>Z</h1>
|
<h1>Z</h1>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('z',1) }"><i class="icon-arrow-up"></i></button>
|
<button class="btn box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('z',1) }"><i class="icon-arrow-up"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendHomeCommand('Z') }"><i class="icon-home"></i></button>
|
<button class="btn box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendHomeCommand('Z') }"><i class="icon-home"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('z',-1) }"><i class="icon-arrow-down"></i></button>
|
<button class="btn box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('z',-1) }"><i class="icon-arrow-down"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Jog distance -->
|
<!-- Jog distance -->
|
||||||
<div class="distance">
|
<div class="distance">
|
||||||
<div class="btn-group" data-toggle="buttons-radio" id="jog_distance">
|
<div class="btn-group" data-toggle="buttons-radio" id="jog_distance">
|
||||||
<button type="button" class="btn" data-distance="0.1">0.1</button>
|
<button type="button" class="btn" data-distance="0.1" data-bind="enable: loginState.isUser()">0.1</button>
|
||||||
<button type="button" class="btn" data-distance="1">1</button>
|
<button type="button" class="btn" data-distance="1" data-bind="enable: loginState.isUser()">1</button>
|
||||||
<button type="button" class="btn active" data-distance="10">10</button>
|
<button type="button" class="btn active" data-distance="10" data-bind="enable: loginState.isUser()">10</button>
|
||||||
<button type="button" class="btn" data-distance="100">100</button>
|
<button type="button" class="btn" data-distance="100" data-bind="enable: loginState.isUser()">100</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -313,20 +315,20 @@
|
||||||
<h1>E</h1>
|
<h1>E</h1>
|
||||||
<div>
|
<div>
|
||||||
<div class="input-append control-box">
|
<div class="input-append control-box">
|
||||||
<input type="text" class="input-mini text-right" data-bind="value: extrusionAmount, enable: isOperational() && !isPrinting(), attr: {placeholder: 5}">
|
<input type="text" class="input-mini text-right" data-bind="value: extrusionAmount, enable: isOperational() && !isPrinting() && loginState.isUser(), attr: {placeholder: 5}">
|
||||||
<span class="add-on">mm</span>
|
<span class="add-on">mm</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn control-box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendExtrudeCommand() }">Extrude</button>
|
<button class="btn control-box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendExtrudeCommand() }">Extrude</button>
|
||||||
<button class="btn control-box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendRetractCommand() }">Retract</button>
|
<button class="btn control-box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendRetractCommand() }">Retract</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- General control panel -->
|
<!-- General control panel -->
|
||||||
<div class="jog-panel">
|
<div class="jog-panel">
|
||||||
<h1>General</h1>
|
<h1>General</h1>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn control-box" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendCustomCommand({type:'command',command:'M18'}) }"><i class="icon-off"></i> Motors off</button>
|
<button class="btn control-box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendCustomCommand({type:'command',command:'M18'}) }"><i class="icon-off"></i> Motors off</button>
|
||||||
<button class="btn control-box" data-bind="enable: isOperational(), click: function() { $root.sendCustomCommand({type:'command',command:'M106'}) }">Fans on</button>
|
<button class="btn control-box" data-bind="enable: isOperational() && loginState.isUser(), click: function() { $root.sendCustomCommand({type:'command',command:'M106'}) }">Fans on</button>
|
||||||
<button class="btn control-box" data-bind="enable: isOperational(), click: function() { $root.sendCustomCommand({type:'command',command:'M106 S0'}) }">Fans off</button>
|
<button class="btn control-box" data-bind="enable: isOperational() && loginState.isUser(), click: function() { $root.sendCustomCommand({type:'command',command:'M106 S0'}) }">Fans off</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -341,7 +343,7 @@
|
||||||
</script>
|
</script>
|
||||||
<script type="text/html" id="customControls_commandTemplate">
|
<script type="text/html" id="customControls_commandTemplate">
|
||||||
<form class="form-inline">
|
<form class="form-inline">
|
||||||
<button class="btn" data-bind="text: name, enable: $root.isOperational(), click: function() { $root.sendCustomCommand($data) }"></button>
|
<button class="btn" data-bind="text: name, enable: $root.isOperational() && $root.loginState.isUser(), click: function() { $root.sendCustomCommand($data) }"></button>
|
||||||
</form>
|
</form>
|
||||||
</script>
|
</script>
|
||||||
<script type="text/html" id="customControls_parametricCommandTemplate">
|
<script type="text/html" id="customControls_parametricCommandTemplate">
|
||||||
|
@ -350,7 +352,7 @@
|
||||||
<label data-bind="text: name"></label>
|
<label data-bind="text: name"></label>
|
||||||
<input type="text" class="input-small" data-bind="attr: {placeholder: name}, value: value">
|
<input type="text" class="input-small" data-bind="attr: {placeholder: name}, value: value">
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<button class="btn" data-bind="text: name, enable: $root.isOperational(), click: function() { $root.sendCustomCommand($data) }"></button>
|
<button class="btn" data-bind="text: name, enable: $root.isOperational() && $root.loginState.isUser(), click: function() { $root.sendCustomCommand($data) }"></button>
|
||||||
</form>
|
</form>
|
||||||
</script>
|
</script>
|
||||||
<script type="text/html" id="customControls_emptyTemplate"><div></div></script>
|
<script type="text/html" id="customControls_emptyTemplate"><div></div></script>
|
||||||
|
@ -360,30 +362,30 @@
|
||||||
<div class="form-horizontal" style="margin-bottom: 20px">
|
<div class="form-horizontal" style="margin-bottom: 20px">
|
||||||
<label for="speed_outerWall">Outer Wall</label>
|
<label for="speed_outerWall">Outer Wall</label>
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
<input type="text" id="speed_outerWall" class="input-mini" data-bind="enable: isOperational(), attr: {placeholder: outerWall}">
|
<input type="text" id="speed_outerWall" class="input-mini" data-bind="enable: isOperational() && loginState.isUser(), attr: {placeholder: outerWall}">
|
||||||
<span class="add-on">%</span>
|
<span class="add-on">%</span>
|
||||||
<button type="submit" class="btn" id="speed_outerWall_set" data-bind="enable: isOperational()">Set</button>
|
<button type="submit" class="btn" id="speed_outerWall_set" data-bind="enable: isOperational() && loginState.isUser()">Set</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="speed_innerWall">Inner Wall</label>
|
<label for="speed_innerWall">Inner Wall</label>
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
<input type="text" id="speed_innerWall" class="input-mini" data-bind="enable: isOperational(), attr: {placeholder: innerWall}">
|
<input type="text" id="speed_innerWall" class="input-mini" data-bind="enable: isOperational() && loginState.isUser(), attr: {placeholder: innerWall}">
|
||||||
<span class="add-on">%</span>
|
<span class="add-on">%</span>
|
||||||
<button type="submit" class="btn" id="speed_innerWall_set" data-bind="enable: isOperational()">Set</button>
|
<button type="submit" class="btn" id="speed_innerWall_set" data-bind="enable: isOperational() && loginState.isUser()">Set</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="speed_fill">Fill</label>
|
<label for="speed_fill">Fill</label>
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
<input type="text" id="speed_fill" class="input-mini" data-bind="enable: isOperational(), attr: {placeholder: fill}">
|
<input type="text" id="speed_fill" class="input-mini" data-bind="enable: isOperational() && loginState.isUser(), attr: {placeholder: fill}">
|
||||||
<span class="add-on">%</span>
|
<span class="add-on">%</span>
|
||||||
<button type="submit" class="btn" id="speed_fill_set" data-bind="enable: isOperational()">Set</button>
|
<button type="submit" class="btn" id="speed_fill_set" data-bind="enable: isOperational() && loginState.isUser()">Set</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="speed_support">Support</label>
|
<label for="speed_support">Support</label>
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
<input type="text" id="speed_support" class="input-mini" data-bind="enable: isOperational(), attr: {placeholder: support}">
|
<input type="text" id="speed_support" class="input-mini" data-bind="enable: isOperational() && loginState.isUser(), attr: {placeholder: support}">
|
||||||
<span class="add-on">%</span>
|
<span class="add-on">%</span>
|
||||||
<button type="submit" class="btn" id="speed_support_set" data-bind="enable: isOperational()">Set</button>
|
<button type="submit" class="btn" id="speed_support_set" data-bind="enable: isOperational() && loginState.isUser()">Set</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -482,7 +484,7 @@
|
||||||
|
|
||||||
<div class="input-append">
|
<div class="input-append">
|
||||||
<input type="text" id="terminal-command">
|
<input type="text" id="terminal-command">
|
||||||
<button class="btn" type="button" id="terminal-send">Send</button>
|
<button class="btn" type="button" id="terminal-send" data-bind="enable: isOperational() && loginState.isUser()">Send</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if enableTimelapse %}
|
{% if enableTimelapse %}
|
||||||
|
@ -490,7 +492,7 @@
|
||||||
<h1>Timelapse Configuration</h1>
|
<h1>Timelapse Configuration</h1>
|
||||||
|
|
||||||
<label for="webcam_timelapse_mode">Timelapse Mode</label>
|
<label for="webcam_timelapse_mode">Timelapse Mode</label>
|
||||||
<select id="webcam_timelapse_mode" data-bind="value: timelapseType, enable: isOperational() && !isPrinting()">
|
<select id="webcam_timelapse_mode" data-bind="value: timelapseType, enable: isOperational() && !isPrinting() && loginState.isUser()">
|
||||||
<option value="off">Off</option>
|
<option value="off">Off</option>
|
||||||
<option value="zchange">On Z Change</option>
|
<option value="zchange">On Z Change</option>
|
||||||
<option value="timed">Timed</option>
|
<option value="timed">Timed</option>
|
||||||
|
@ -505,7 +507,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button class="btn" data-bind="click: save, enable: isOperational() && !isPrinting()">Save Settings</button>
|
<button class="btn" data-bind="click: save, enable: isOperational() && !isPrinting() && loginState.isUser()">Save Settings</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1>Finished Timelapses</h1>
|
<h1>Finished Timelapses</h1>
|
||||||
|
|
|
@ -150,22 +150,34 @@ class UnknownRole(Exception):
|
||||||
|
|
||||||
class User(UserMixin):
|
class User(UserMixin):
|
||||||
def __init__(self, username, passwordHash, active, roles):
|
def __init__(self, username, passwordHash, active, roles):
|
||||||
self.username = username
|
self._username = username
|
||||||
self.passwordHash = passwordHash
|
self._passwordHash = passwordHash
|
||||||
self.active = active
|
self._active = active
|
||||||
self.roles = roles
|
self._roles = roles
|
||||||
|
|
||||||
|
def check_password(self, passwordHash):
|
||||||
|
return self._passwordHash == passwordHash
|
||||||
|
|
||||||
def get_id(self):
|
def get_id(self):
|
||||||
return self.username
|
return self._username
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self._username
|
||||||
|
|
||||||
def is_active(self):
|
def is_active(self):
|
||||||
return self.active
|
return self._active
|
||||||
|
|
||||||
|
def is_user(self):
|
||||||
|
return "user" in self._roles
|
||||||
|
|
||||||
|
def is_admin(self):
|
||||||
|
return "admin" in self._roles
|
||||||
|
|
||||||
##~~ DummyUser object to use when accessControl is disabled
|
##~~ DummyUser object to use when accessControl is disabled
|
||||||
|
|
||||||
class DummyUser(UserMixin):
|
class DummyUser(User):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.roles = UserManager.valid_roles
|
User.__init__(self, "dummy", "", True, UserManager.valid_roles)
|
||||||
|
|
||||||
def get_id(self):
|
def check_password(self, passwordHash):
|
||||||
return "dummy"
|
return True
|
Loading…
Reference in New Issue