forked from cory/tildefriends
		
	Fiddled with saving and loading so that admin users can push and pull to parent apps.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3806 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		
							
								
								
									
										15
									
								
								core/app.js
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								core/app.js
									
									
									
									
									
								
							| @@ -64,6 +64,7 @@ function socket(request, response, client) { | |||||||
| 				var packageName; | 				var packageName; | ||||||
| 				var blobId; | 				var blobId; | ||||||
| 				var match; | 				var match; | ||||||
|  | 				var parentApp; | ||||||
| 				if (match = /^\/([&%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(message.path)) { | 				if (match = /^\/([&%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(message.path)) { | ||||||
| 					blobId = match[1]; | 					blobId = match[1]; | ||||||
| 				} else if (match = /^\/\~([^\/]+)\/([^\/]+)\/$/.exec(message.path)) { | 				} else if (match = /^\/\~([^\/]+)\/([^\/]+)\/$/.exec(message.path)) { | ||||||
| @@ -74,8 +75,20 @@ function socket(request, response, client) { | |||||||
| 						response.send(JSON.stringify({action: "error", error: message.path + ' not found'}), 0x1); | 						response.send(JSON.stringify({action: "error", error: message.path + ' not found'}), 0x1); | ||||||
| 						return; | 						return; | ||||||
| 					} | 					} | ||||||
|  | 					if (user != 'core') { | ||||||
|  | 						var coreId = await new Database('core').get('path:' + path); | ||||||
|  | 						parentApp = { | ||||||
|  | 							path: '/~core/' + path + '/', | ||||||
|  | 							id: coreId, | ||||||
|  | 						}; | ||||||
| 					} | 					} | ||||||
| 				response.send(JSON.stringify({action: "session", credentials: credentials}), 0x1); | 				} | ||||||
|  | 				response.send(JSON.stringify({ | ||||||
|  | 					action: "session", | ||||||
|  | 					credentials: credentials, | ||||||
|  | 					parentApp: parentApp, | ||||||
|  | 					id: blobId, | ||||||
|  | 				}), 0x1); | ||||||
|  |  | ||||||
| 				options.api = message.api || []; | 				options.api = message.api || []; | ||||||
| 				options.credentials = credentials; | 				options.credentials = credentials; | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ var gApp = {files: {}}; | |||||||
| var gEditor; | var gEditor; | ||||||
| var gSplit; | var gSplit; | ||||||
| var gGraphs = {}; | var gGraphs = {}; | ||||||
|  | var gParentApp; | ||||||
|  |  | ||||||
| var kErrorColor = "#dc322f"; | var kErrorColor = "#dc322f"; | ||||||
| var kStatusColor = "#fff"; | var kStatusColor = "#fff"; | ||||||
| @@ -164,6 +165,7 @@ function guessMode(name) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function loadFile(name, id) { | function loadFile(name, id) { | ||||||
|  | 	return new Promise(function(resolve, reject) { | ||||||
| 		var request = new XMLHttpRequest(); | 		var request = new XMLHttpRequest(); | ||||||
| 		request.addEventListener("loadend", function() { | 		request.addEventListener("loadend", function() { | ||||||
| 			if (request.status == 200) { | 			if (request.status == 200) { | ||||||
| @@ -171,26 +173,34 @@ function loadFile(name, id) { | |||||||
| 				if (!Object.values(gFiles).some(x => !x.doc)) { | 				if (!Object.values(gFiles).some(x => !x.doc)) { | ||||||
| 					document.getElementById("editPane").style.display = 'flex'; | 					document.getElementById("editPane").style.display = 'flex'; | ||||||
| 					openFile(Object.keys(gFiles).sort()[0]); | 					openFile(Object.keys(gFiles).sort()[0]); | ||||||
|  | 					resolve(); | ||||||
| 				} | 				} | ||||||
|  | 			} else { | ||||||
|  | 				reject('Error loading source.'); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 		request.addEventListener("error", function() { | 		request.addEventListener("error", function() { | ||||||
| 			alert("Error loading source."); | 			alert("Error loading source."); | ||||||
| 			closeEditor(); | 			closeEditor(); | ||||||
|  | 			reject('Error loading source.'); | ||||||
| 		}); | 		}); | ||||||
| 		request.addEventListener("timeout", function() { | 		request.addEventListener("timeout", function() { | ||||||
| 			alert("Timed out loading source."); | 			alert("Timed out loading source."); | ||||||
| 			closeEditor(); | 			closeEditor(); | ||||||
|  | 			reject('Timed out loading source.'); | ||||||
| 		}); | 		}); | ||||||
| 		request.addEventListener("abort", function() { | 		request.addEventListener("abort", function() { | ||||||
| 			alert("Loading source aborted."); | 			alert("Loading source aborted."); | ||||||
| 			closeEditor(); | 			closeEditor(); | ||||||
|  | 			reject('Loading source aborted.'); | ||||||
| 		}); | 		}); | ||||||
| 		request.open("GET", "/" + id + "/view"); | 		request.open("GET", "/" + id + "/view"); | ||||||
| 		request.send(); | 		request.send(); | ||||||
|  | 	}); | ||||||
| } | } | ||||||
|  |  | ||||||
| function load() { | function load(path) { | ||||||
|  | 	return new Promise(function(resolve, reject) { | ||||||
| 		var request = new XMLHttpRequest(); | 		var request = new XMLHttpRequest(); | ||||||
| 		request.addEventListener("loadend", function() { | 		request.addEventListener("loadend", function() { | ||||||
| 			if (request.status == 200 || request.status == 404) { | 			if (request.status == 200 || request.status == 404) { | ||||||
| @@ -210,6 +220,7 @@ function load() { | |||||||
| 				gFiles = {}; | 				gFiles = {}; | ||||||
| 				var text; | 				var text; | ||||||
| 				var isApp = false; | 				var isApp = false; | ||||||
|  | 				var promises = []; | ||||||
| 				if (request.status == 200) { | 				if (request.status == 200) { | ||||||
| 					text = request.responseText; | 					text = request.responseText; | ||||||
| 					try { | 					try { | ||||||
| @@ -218,7 +229,7 @@ function load() { | |||||||
| 							isApp = true; | 							isApp = true; | ||||||
| 							Object.keys(json['files']).forEach(function(name) { | 							Object.keys(json['files']).forEach(function(name) { | ||||||
| 								gFiles[name] = {}; | 								gFiles[name] = {}; | ||||||
| 							loadFile(name, json['files'][name]); | 								promises.push(loadFile(name, json['files'][name])); | ||||||
| 							}); | 							}); | ||||||
| 							if (Object.keys(json['files']).length == 0) { | 							if (Object.keys(json['files']).length == 0) { | ||||||
| 								document.getElementById("editPane").style.display = 'flex'; | 								document.getElementById("editPane").style.display = 'flex'; | ||||||
| @@ -227,6 +238,8 @@ function load() { | |||||||
| 						} | 						} | ||||||
| 					} catch { | 					} catch { | ||||||
| 					} | 					} | ||||||
|  | 				} else { | ||||||
|  | 					reject('Load failed.'); | ||||||
| 				} | 				} | ||||||
| 				if (!isApp) { | 				if (!isApp) { | ||||||
| 					document.getElementById("editPane").style.display = 'flex'; | 					document.getElementById("editPane").style.display = 'flex'; | ||||||
| @@ -239,22 +252,27 @@ function load() { | |||||||
| 					}; | 					}; | ||||||
| 					openFile(gCurrentFile); | 					openFile(gCurrentFile); | ||||||
| 				} | 				} | ||||||
|  | 				Promise.all(promises).then(resolve).catch(reject); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 		request.addEventListener("error", function() { | 		request.addEventListener("error", function() { | ||||||
| 			alert("Error loading source."); | 			alert("Error loading source."); | ||||||
| 			closeEditor(); | 			closeEditor(); | ||||||
|  | 			reject('Error loading source.'); | ||||||
| 		}); | 		}); | ||||||
| 		request.addEventListener("timeout", function() { | 		request.addEventListener("timeout", function() { | ||||||
| 			alert("Timed out loading source."); | 			alert("Timed out loading source."); | ||||||
| 			closeEditor(); | 			closeEditor(); | ||||||
|  | 			reject('Timed out loading source.'); | ||||||
| 		}); | 		}); | ||||||
| 		request.addEventListener("abort", function() { | 		request.addEventListener("abort", function() { | ||||||
| 			alert("Loading source aborted."); | 			alert("Loading source aborted."); | ||||||
| 			closeEditor(); | 			closeEditor(); | ||||||
|  | 			reject('Loading source aborted.'); | ||||||
| 		}); | 		}); | ||||||
| 	request.open("GET", url() + "view"); | 		request.open("GET", (path || url()) + "view"); | ||||||
| 		request.send(); | 		request.send(); | ||||||
|  | 	}); | ||||||
| } | } | ||||||
|  |  | ||||||
| function closeStats() { | function closeStats() { | ||||||
| @@ -277,22 +295,34 @@ function explodePath() { | |||||||
| 	return /^\/~([^\/]+)\/([^\/]+)(.*)/.exec(window.location.pathname); | 	return /^\/~([^\/]+)\/([^\/]+)(.*)/.exec(window.location.pathname); | ||||||
| } | } | ||||||
|  |  | ||||||
| function save() { | function save(save_to) { | ||||||
| 	document.getElementById("save").disabled = true; | 	document.getElementById("save").disabled = true; | ||||||
|  | 	document.getElementById("push_to_parent").disabled = true; | ||||||
|  | 	document.getElementById("pull_from_parent").disabled = true; | ||||||
| 	if (gCurrentFile) { | 	if (gCurrentFile) { | ||||||
| 		gFiles[gCurrentFile].doc = gEditor.getDoc(); | 		gFiles[gCurrentFile].doc = gEditor.getDoc(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var run = document.getElementById("run").checked; |  | ||||||
|  |  | ||||||
| 	var appFinished = function(success) { | 	var appFinished = function(success) { | ||||||
| 		document.getElementById("save").disabled = false; | 		document.getElementById("save").disabled = false; | ||||||
|  | 		document.getElementById("push_to_parent").disabled = false; | ||||||
|  | 		document.getElementById("pull_from_parent").disabled = false; | ||||||
| 		Object.values(gFiles).forEach(function(file) { | 		Object.values(gFiles).forEach(function(file) { | ||||||
| 			file.generation = file.doc.changeGeneration(); | 			file.generation = file.doc.changeGeneration(); | ||||||
| 		}); | 		}); | ||||||
| 		updateFiles(); | 		updateFiles(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	var save_path = save_to; | ||||||
|  | 	if (!save_to) { | ||||||
|  | 		var name = document.getElementById("name"); | ||||||
|  | 		if (name && name.value) { | ||||||
|  | 			save_path = name.value; | ||||||
|  | 		} else { | ||||||
|  | 			save_path = url(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	var always = function() { | 	var always = function() { | ||||||
| 		var anyUnfinished = Object.values(gFiles).some(x => x.request); | 		var anyUnfinished = Object.values(gFiles).some(x => x.request); | ||||||
| 		var anyUnsaved = Object.values(gFiles).some(x => !x.doc.isClean(x.generation) && !x.id); | 		var anyUnsaved = Object.values(gFiles).some(x => !x.doc.isClean(x.generation) && !x.id); | ||||||
| @@ -312,15 +342,10 @@ function save() { | |||||||
| 			}); | 			}); | ||||||
| 			request.addEventListener("loadend", function() { | 			request.addEventListener("loadend", function() { | ||||||
| 				if (request.status == 200) { | 				if (request.status == 200) { | ||||||
| 					var latest = document.getElementById('latest'); | 					if (save_path != window.location.pathname) { | ||||||
| 					latest.href = request.responseText; | 						alert('Saved to ' + save_path + '.'); | ||||||
| 					latest.style.visibility = request.responseText != window.location.path ? 'visible' : 'hidden'; |  | ||||||
| 					if (run) { |  | ||||||
| 						if (request.responseText) { |  | ||||||
| 							reconnect(request.responseText); |  | ||||||
| 					} else { | 					} else { | ||||||
| 							reconnect(window.location.path); | 						reconnect(save_path); | ||||||
| 						} |  | ||||||
| 					} | 					} | ||||||
| 					appFinished(true); | 					appFinished(true); | ||||||
| 				} else { | 				} else { | ||||||
| @@ -337,14 +362,7 @@ function save() { | |||||||
| 				appFinished(false); | 				appFinished(false); | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
| 			var saveTo = null; | 			request.open("POST", save_path + 'save', true); | ||||||
| 			var name = document.getElementById("name"); |  | ||||||
| 			if (name && name.value) { |  | ||||||
| 				saveTo = name.value + "save"; |  | ||||||
| 			} else { |  | ||||||
| 				saveTo = url() + "save"; |  | ||||||
| 			} |  | ||||||
| 			request.open("POST", saveTo, true); |  | ||||||
| 			request.setRequestHeader("Content-Type", "text/json"); | 			request.setRequestHeader("Content-Type", "text/json"); | ||||||
| 			request.send(JSON.stringify(app)); | 			request.send(JSON.stringify(app)); | ||||||
| 		} else if (!anyUnfinished) { | 		} else if (!anyUnfinished) { | ||||||
| @@ -399,6 +417,14 @@ function save() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function pullFromParent() { | ||||||
|  | 	load(gParentApp ? gParentApp.path : null).then(x => save()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function pushToParent() { | ||||||
|  | 	save(gParentApp ? gParentApp.path : null); | ||||||
|  | } | ||||||
|  |  | ||||||
| function url() { | function url() { | ||||||
| 	var hash = window.location.href.indexOf('#'); | 	var hash = window.location.href.indexOf('#'); | ||||||
| 	var question = window.location.href.indexOf('?'); | 	var question = window.location.href.indexOf('?'); | ||||||
| @@ -422,7 +448,11 @@ function receive(message) { | |||||||
| 	if (message && message.action == "session") { | 	if (message && message.action == "session") { | ||||||
| 		setStatusMessage("...Executing...", kStatusColor, true); | 		setStatusMessage("...Executing...", kStatusColor, true); | ||||||
| 		gCredentials = message.credentials; | 		gCredentials = message.credentials; | ||||||
|  | 		gParentApp = message.parentApp; | ||||||
| 		updateLogin(); | 		updateLogin(); | ||||||
|  | 		var parent_enabled = message.parentApp; | ||||||
|  | 		document.getElementById('push_to_parent').style.display = parent_enabled ? 'inline-block' : 'none'; | ||||||
|  | 		document.getElementById('pull_from_parent').style.display = parent_enabled ? 'inline-block' : 'none'; | ||||||
| 	} else if (message && message.action == "ready") { | 	} else if (message && message.action == "ready") { | ||||||
| 		setStatusMessage(null); | 		setStatusMessage(null); | ||||||
| 		if (window.location.hash) { | 		if (window.location.hash) { | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								core/core.js
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								core/core.js
									
									
									
									
									
								
							| @@ -479,11 +479,9 @@ async function blobHandler(request, response, blobId, uri) { | |||||||
| 				var user = match[1]; | 				var user = match[1]; | ||||||
| 				var app = match[2]; | 				var app = match[2]; | ||||||
| 				var credentials = auth.query(request.headers); | 				var credentials = auth.query(request.headers); | ||||||
| 				if (!credentials || !credentials.session || credentials.session.name != user) { | 				if (credentials && credentials.session && | ||||||
| 					response.writeHead(401, {"Content-Type": "text/plain; charset=utf-8"}); | 					(credentials.session.name == user || | ||||||
| 					response.end("401 Unauthorized"); | 					(credentials.permissions.administration && user == 'core'))) { | ||||||
| 					return; |  | ||||||
| 				} |  | ||||||
| 					var database = new Database(user); | 					var database = new Database(user); | ||||||
| 					var apps = new Set(); | 					var apps = new Set(); | ||||||
| 					try { | 					try { | ||||||
| @@ -495,6 +493,11 @@ async function blobHandler(request, response, blobId, uri) { | |||||||
| 						database.set('apps', JSON.stringify([...apps])); | 						database.set('apps', JSON.stringify([...apps])); | ||||||
| 					} | 					} | ||||||
| 					database.set('path:' + app, newBlobId); | 					database.set('path:' + app, newBlobId); | ||||||
|  | 				} else { | ||||||
|  | 					response.writeHead(401, {"Content-Type": "text/plain; charset=utf-8"}); | ||||||
|  | 					response.end("401 Unauthorized"); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			response.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"}); | 			response.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"}); | ||||||
| @@ -594,7 +597,7 @@ loadSettings().then(function() { | |||||||
| 			return staticFileHandler(request, response, null, match[1]); | 			return staticFileHandler(request, response, null, match[1]); | ||||||
| 		} else if (match = /^\/perfetto\/([\.\w-/]*)$/.exec(request.uri)) { | 		} else if (match = /^\/perfetto\/([\.\w-/]*)$/.exec(request.uri)) { | ||||||
| 			return perfettoHandler(request, response, match[1]); | 			return perfettoHandler(request, response, match[1]); | ||||||
| 		} else if (match = /^(.*)(\/save)$/.exec(request.uri)) { | 		} else if (match = /^(.*)(\/save?)$/.exec(request.uri)) { | ||||||
| 			return blobHandler(request, response, match[1], match[2]); | 			return blobHandler(request, response, match[1], match[2]); | ||||||
| 		} else if (match = /^\/trace$/.exec(request.uri)) { | 		} else if (match = /^\/trace$/.exec(request.uri)) { | ||||||
| 			var data = trace(); | 			var data = trace(); | ||||||
|   | |||||||
| @@ -31,9 +31,9 @@ | |||||||
| 					<input type="button" id="closeEditor" name="closeEditor" value="Close" onclick="closeEditor()"> | 					<input type="button" id="closeEditor" name="closeEditor" value="Close" onclick="closeEditor()"> | ||||||
| 					<input type="button" id="save" name="save" value="Save" onclick="save()"> | 					<input type="button" id="save" name="save" value="Save" onclick="save()"> | ||||||
| 					<input type="text" id="name" name="name"></input> | 					<input type="text" id="name" name="name"></input> | ||||||
| 					<input type="checkbox" id="run" name="run" checked><label for="run">Restart after save</label> | 					<input type="button" id="push_to_parent" value="Push to Parent" onclick="pushToParent()"> | ||||||
|  | 					<input type="button" id="pull_from_parent" value="Pull from Parent" onclick="pullFromParent()"> | ||||||
| 					<input type="button" id="revert" name="revert" value="Revert to Saved" onclick="revert()"> | 					<input type="button" id="revert" name="revert" value="Revert to Saved" onclick="revert()"> | ||||||
| 					<a id="latest" href="">Latest</a> |  | ||||||
| 				</div> | 				</div> | ||||||
| 				<div class="hbox" style="height: 100%"> | 				<div class="hbox" style="height: 100%"> | ||||||
| 					<div id="filesPane"> | 					<div id="filesPane"> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user