Shell: Add file system browser to retrieve arbitrary files
This commit is contained in:

committed by
Sebastian Serth

parent
60078701f5
commit
58548555a5
@ -2,17 +2,17 @@ $(document).on('turbolinks:load', function () {
|
||||
const ENTER_KEY_CODE = 13;
|
||||
|
||||
const clearOutput = function () {
|
||||
$('#output').html('');
|
||||
log.html('');
|
||||
};
|
||||
|
||||
const executeCommand = function (command) {
|
||||
$.ajax({
|
||||
data: {
|
||||
command: command,
|
||||
sudo: $('#sudo').is(':checked')
|
||||
sudo: sudo.is(':checked')
|
||||
},
|
||||
method: 'POST',
|
||||
url: $('#shell').data('url')
|
||||
url: Routes.execute_command_execution_environment_path(id)
|
||||
}).done(handleResponse);
|
||||
};
|
||||
|
||||
@ -46,7 +46,7 @@ $(document).on('turbolinks:load', function () {
|
||||
em.text(command);
|
||||
const p = $('<p>');
|
||||
p.append(em)
|
||||
$('#output').append(p);
|
||||
log.append(p);
|
||||
};
|
||||
|
||||
const printOutput = function (output) {
|
||||
@ -55,22 +55,21 @@ $(document).on('turbolinks:load', function () {
|
||||
const element = $('<p>');
|
||||
element.addClass('text-success');
|
||||
element.text(output.stdout);
|
||||
$('#output').append(element);
|
||||
log.append(element);
|
||||
}
|
||||
|
||||
if (output.stderr) {
|
||||
const element = $('<p>');
|
||||
element.addClass('text-warning');
|
||||
element.text(output.stderr);
|
||||
$('#output').append(element);
|
||||
log.append(element);
|
||||
}
|
||||
|
||||
if (!output.stdout && !output.stderr) {
|
||||
const element = $('<p>');
|
||||
element.addClass('text-muted');
|
||||
const output = $('#output');
|
||||
element.text(output.data('message-no-output'));
|
||||
output.append(element);
|
||||
element.text(log.data('message-no-output'));
|
||||
log.append(element);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -79,26 +78,99 @@ $(document).on('turbolinks:load', function () {
|
||||
const element = $('<p>');
|
||||
element.addClass('text-danger');
|
||||
element.text($('#shell').data('message-timeout'));
|
||||
$('#output').append(element);
|
||||
log.append(element);
|
||||
};
|
||||
|
||||
const printOutOfMemory = function (output) {
|
||||
const element = $('<p>');
|
||||
element.addClass('text-danger');
|
||||
element.text($('#shell').data('message-out-of-memory'));
|
||||
$('#output').append(element);
|
||||
log.append(element);
|
||||
};
|
||||
|
||||
if ($('#shell').isPresent()) {
|
||||
const command = $('#command')
|
||||
command.focus();
|
||||
command.on('keypress', handleKeyPress);
|
||||
const retrieveFiles = function () {
|
||||
let fileTree = $('#download-file-tree');
|
||||
|
||||
const sudo = $('#sudo');
|
||||
sudo.on('change', function () {
|
||||
sudo.parent().toggleClass('text-muted')
|
||||
command.focus();
|
||||
});
|
||||
// Get current instance of the jstree if available and refresh the existing one.
|
||||
// Otherwise, initialize a new one.
|
||||
if (fileTree.jstree(true)) {
|
||||
return fileTree.jstree('refresh');
|
||||
} else {
|
||||
fileTree.removeClass('my-3 justify-content-center');
|
||||
fileTree.jstree({
|
||||
'core': {
|
||||
'data': {
|
||||
'url': function (node) {
|
||||
const params = {sudo: sudo.is(':checked')};
|
||||
return Routes.list_files_in_execution_environment_path(id, params);
|
||||
},
|
||||
'data': function (node) {
|
||||
return {'path': getPath(fileTree.jstree(), node)|| '/'};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
fileTree.on('select_node.jstree', function (node, selected, _event) {
|
||||
// We never want a node to be selected permanently, so we deselect it immediately.
|
||||
selected.instance.deselect_all();
|
||||
|
||||
const path = getPath(selected.instance, selected.node)
|
||||
const params = {sudo: sudo.is(':checked')};
|
||||
const downloadPath = Routes.download_file_from_execution_environment_path(id, path, params);
|
||||
|
||||
// Now we download the file if allowed.
|
||||
if (selected.node.original.icon.split(" ").some(function (icon) {
|
||||
return ['fa-lock', 'fa-folder'].includes(icon);
|
||||
})) {
|
||||
$.flash.danger({
|
||||
icon: ['fa-solid', 'fa-shield-halved'],
|
||||
text: I18n.t('execution_environments.shell.file_tree.permission_denied')
|
||||
});
|
||||
} else {
|
||||
window.location = downloadPath;
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
const getPath = function (jstree, node) {
|
||||
if (node.id === '#') {
|
||||
// Root node
|
||||
return '/'
|
||||
}
|
||||
|
||||
// We build the path to the file by concatenating the paths of all parent nodes.
|
||||
let file_path = node.parents.reverse().map(function (id) {
|
||||
return jstree.get_text(id);
|
||||
}).filter(function (text) {
|
||||
return text !== false;
|
||||
}).join('/');
|
||||
|
||||
return `${node.parent !== '#' ? '/' : ''}${file_path}${node.original.path}`;
|
||||
}
|
||||
|
||||
const shell = $('#shell');
|
||||
|
||||
if (!shell.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const command = $('#command')
|
||||
command.focus();
|
||||
command.on('keypress', handleKeyPress);
|
||||
|
||||
const id = shell.data('id');
|
||||
const log = $('#output');
|
||||
|
||||
const sudo = $('#sudo');
|
||||
sudo.on('change', function () {
|
||||
sudo.parent().toggleClass('text-muted')
|
||||
command.focus();
|
||||
});
|
||||
$('#reload-files').on('click', function () {
|
||||
new bootstrap.Collapse('#collapse_files', 'show');
|
||||
retrieveFiles();
|
||||
});
|
||||
$('#reload-now-link').on('click', retrieveFiles);
|
||||
})
|
||||
;
|
||||
|
Reference in New Issue
Block a user