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:
parent
ec5d7c1a01
commit
0278aceb62
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;
|
||||||
|
232
core/client.js
232
core/client.js
@ -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,97 +165,114 @@ function guessMode(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadFile(name, id) {
|
function loadFile(name, id) {
|
||||||
var request = new XMLHttpRequest();
|
return new Promise(function(resolve, reject) {
|
||||||
request.addEventListener("loadend", function() {
|
var request = new XMLHttpRequest();
|
||||||
if (request.status == 200) {
|
request.addEventListener("loadend", function() {
|
||||||
gFiles[name].doc = new CodeMirror.Doc(request.responseText, guessMode(name));
|
if (request.status == 200) {
|
||||||
if (!Object.values(gFiles).some(x => !x.doc)) {
|
gFiles[name].doc = new CodeMirror.Doc(request.responseText, guessMode(name));
|
||||||
document.getElementById("editPane").style.display = 'flex';
|
if (!Object.values(gFiles).some(x => !x.doc)) {
|
||||||
openFile(Object.keys(gFiles).sort()[0]);
|
document.getElementById("editPane").style.display = 'flex';
|
||||||
|
openFile(Object.keys(gFiles).sort()[0]);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject('Error loading source.');
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
request.addEventListener("error", function() {
|
||||||
|
alert("Error loading source.");
|
||||||
|
closeEditor();
|
||||||
|
reject('Error loading source.');
|
||||||
|
});
|
||||||
|
request.addEventListener("timeout", function() {
|
||||||
|
alert("Timed out loading source.");
|
||||||
|
closeEditor();
|
||||||
|
reject('Timed out loading source.');
|
||||||
|
});
|
||||||
|
request.addEventListener("abort", function() {
|
||||||
|
alert("Loading source aborted.");
|
||||||
|
closeEditor();
|
||||||
|
reject('Loading source aborted.');
|
||||||
|
});
|
||||||
|
request.open("GET", "/" + id + "/view");
|
||||||
|
request.send();
|
||||||
});
|
});
|
||||||
request.addEventListener("error", function() {
|
|
||||||
alert("Error loading source.");
|
|
||||||
closeEditor();
|
|
||||||
});
|
|
||||||
request.addEventListener("timeout", function() {
|
|
||||||
alert("Timed out loading source.");
|
|
||||||
closeEditor();
|
|
||||||
});
|
|
||||||
request.addEventListener("abort", function() {
|
|
||||||
alert("Loading source aborted.");
|
|
||||||
closeEditor();
|
|
||||||
});
|
|
||||||
request.open("GET", "/" + id + "/view");
|
|
||||||
request.send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function load() {
|
function load(path) {
|
||||||
var request = new XMLHttpRequest();
|
return new Promise(function(resolve, reject) {
|
||||||
request.addEventListener("loadend", function() {
|
var request = new XMLHttpRequest();
|
||||||
if (request.status == 200 || request.status == 404) {
|
request.addEventListener("loadend", function() {
|
||||||
if (!gEditor) {
|
if (request.status == 200 || request.status == 404) {
|
||||||
gEditor = CodeMirror.fromTextArea(document.getElementById("editor"), {
|
if (!gEditor) {
|
||||||
'theme': 'base16-dark',
|
gEditor = CodeMirror.fromTextArea(document.getElementById("editor"), {
|
||||||
'lineNumbers': true,
|
'theme': 'base16-dark',
|
||||||
'tabSize': 4,
|
'lineNumbers': true,
|
||||||
'indentUnit': 4,
|
'tabSize': 4,
|
||||||
'indentWithTabs': true,
|
'indentUnit': 4,
|
||||||
'showTrailingSpace': true,
|
'indentWithTabs': true,
|
||||||
});
|
'showTrailingSpace': true,
|
||||||
gEditor.on('changes', function() {
|
});
|
||||||
updateFiles();
|
gEditor.on('changes', function() {
|
||||||
});
|
updateFiles();
|
||||||
}
|
});
|
||||||
gFiles = {};
|
}
|
||||||
var text;
|
gFiles = {};
|
||||||
var isApp = false;
|
var text;
|
||||||
if (request.status == 200) {
|
var isApp = false;
|
||||||
text = request.responseText;
|
var promises = [];
|
||||||
try {
|
if (request.status == 200) {
|
||||||
var json = JSON.parse(text);
|
text = request.responseText;
|
||||||
if (json && json['type'] == 'tildefriends-app') {
|
try {
|
||||||
isApp = true;
|
var json = JSON.parse(text);
|
||||||
Object.keys(json['files']).forEach(function(name) {
|
if (json && json['type'] == 'tildefriends-app') {
|
||||||
gFiles[name] = {};
|
isApp = true;
|
||||||
loadFile(name, json['files'][name]);
|
Object.keys(json['files']).forEach(function(name) {
|
||||||
});
|
gFiles[name] = {};
|
||||||
if (Object.keys(json['files']).length == 0) {
|
promises.push(loadFile(name, json['files'][name]));
|
||||||
document.getElementById("editPane").style.display = 'flex';
|
});
|
||||||
|
if (Object.keys(json['files']).length == 0) {
|
||||||
|
document.getElementById("editPane").style.display = 'flex';
|
||||||
|
}
|
||||||
|
gApp = JSON.parse(text);
|
||||||
}
|
}
|
||||||
gApp = JSON.parse(text);
|
} catch {
|
||||||
}
|
}
|
||||||
} catch {
|
} else {
|
||||||
|
reject('Load failed.');
|
||||||
}
|
}
|
||||||
}
|
if (!isApp) {
|
||||||
if (!isApp) {
|
document.getElementById("editPane").style.display = 'flex';
|
||||||
document.getElementById("editPane").style.display = 'flex';
|
if (!text) {
|
||||||
if (!text) {
|
text = '// New script.\n';
|
||||||
text = '// New script.\n';
|
}
|
||||||
|
gCurrentFile = 'app.js';
|
||||||
|
gFiles[gCurrentFile] = {
|
||||||
|
doc: new CodeMirror.Doc(text, guessMode(gCurrentFile)),
|
||||||
|
};
|
||||||
|
openFile(gCurrentFile);
|
||||||
}
|
}
|
||||||
gCurrentFile = 'app.js';
|
Promise.all(promises).then(resolve).catch(reject);
|
||||||
gFiles[gCurrentFile] = {
|
|
||||||
doc: new CodeMirror.Doc(text, guessMode(gCurrentFile)),
|
|
||||||
};
|
|
||||||
openFile(gCurrentFile);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
request.addEventListener("error", function() {
|
||||||
|
alert("Error loading source.");
|
||||||
|
closeEditor();
|
||||||
|
reject('Error loading source.');
|
||||||
|
});
|
||||||
|
request.addEventListener("timeout", function() {
|
||||||
|
alert("Timed out loading source.");
|
||||||
|
closeEditor();
|
||||||
|
reject('Timed out loading source.');
|
||||||
|
});
|
||||||
|
request.addEventListener("abort", function() {
|
||||||
|
alert("Loading source aborted.");
|
||||||
|
closeEditor();
|
||||||
|
reject('Loading source aborted.');
|
||||||
|
});
|
||||||
|
request.open("GET", (path || url()) + "view");
|
||||||
|
request.send();
|
||||||
});
|
});
|
||||||
request.addEventListener("error", function() {
|
|
||||||
alert("Error loading source.");
|
|
||||||
closeEditor();
|
|
||||||
});
|
|
||||||
request.addEventListener("timeout", function() {
|
|
||||||
alert("Timed out loading source.");
|
|
||||||
closeEditor();
|
|
||||||
});
|
|
||||||
request.addEventListener("abort", function() {
|
|
||||||
alert("Loading source aborted.");
|
|
||||||
closeEditor();
|
|
||||||
});
|
|
||||||
request.open("GET", url() + "view");
|
|
||||||
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';
|
} else {
|
||||||
if (run) {
|
reconnect(save_path);
|
||||||
if (request.responseText) {
|
|
||||||
reconnect(request.responseText);
|
|
||||||
} else {
|
|
||||||
reconnect(window.location.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) {
|
||||||
|
29
core/core.js
29
core/core.js
@ -479,22 +479,25 @@ 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 &&
|
||||||
|
(credentials.session.name == user ||
|
||||||
|
(credentials.permissions.administration && user == 'core'))) {
|
||||||
|
var database = new Database(user);
|
||||||
|
var apps = new Set();
|
||||||
|
try {
|
||||||
|
apps = new Set(JSON.parse(database.get('apps')));
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
if (!apps.has(app)) {
|
||||||
|
apps.add(app);
|
||||||
|
database.set('apps', JSON.stringify([...apps]));
|
||||||
|
}
|
||||||
|
database.set('path:' + app, newBlobId);
|
||||||
|
} else {
|
||||||
response.writeHead(401, {"Content-Type": "text/plain; charset=utf-8"});
|
response.writeHead(401, {"Content-Type": "text/plain; charset=utf-8"});
|
||||||
response.end("401 Unauthorized");
|
response.end("401 Unauthorized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var database = new Database(user);
|
|
||||||
var apps = new Set();
|
|
||||||
try {
|
|
||||||
apps = new Set(JSON.parse(database.get('apps')));
|
|
||||||
} catch {
|
|
||||||
}
|
|
||||||
if (!apps.has(app)) {
|
|
||||||
apps.add(app);
|
|
||||||
database.set('apps', JSON.stringify([...apps]));
|
|
||||||
}
|
|
||||||
database.set('path:' + app, newBlobId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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">
|
||||||
|
Loading…
Reference in New Issue
Block a user