Started work on readding filemanager

This commit is contained in:
xevidos 2020-01-29 00:07:00 -05:00
parent 806dbec3b7
commit c148d140b2
5 changed files with 543 additions and 99 deletions

View file

@ -96,6 +96,17 @@ class Common {
define( "LANGUAGE", "en" ); define( "LANGUAGE", "en" );
} }
if( ! defined( 'UPLOAD_CACHE' ) ) {
if( ! is_dir( sys_get_temp_dir() ) ) {
define( "UPLOAD_CACHE", DATA . "/uploads" );
} else {
define( "UPLOAD_CACHE", rtrim( sys_get_temp_dir(), "/" ) );
}
}
require_once( COMPONENTS . "/permissions/class.permissions.php" ); require_once( COMPONENTS . "/permissions/class.permissions.php" );
require_once( COMPONENTS . "/update/class.update.php" ); require_once( COMPONENTS . "/update/class.update.php" );
require_once( COMPONENTS . "/sql/class.sql.php" ); require_once( COMPONENTS . "/sql/class.sql.php" );

View file

@ -649,6 +649,13 @@ class Filemanager extends Common {
static function recursive_delete( $path, $follow, $keep_parent = false ) { static function recursive_delete( $path, $follow, $keep_parent = false ) {
$response = array(
"status" => "none",
"message" => null,
"keep_parent" => $keep_parent,
);
$status = "none";
if ( is_file( $path ) ) { if ( is_file( $path ) ) {
unlink( $path ); unlink( $path );
@ -657,30 +664,70 @@ class Filemanager extends Common {
$files = array_diff( scandir( $path ), array( '.', '..' ) ); $files = array_diff( scandir( $path ), array( '.', '..' ) );
foreach ( $files as $file ) { foreach ( $files as $file ) {
if ( is_link( $path . "/" . $file ) ) { if( is_link( $path . "/" . $file ) ) {
if ( $follow ) { if( $follow ) {
self::recursive_delete( $path . "/" . $file, $follow, false); $status = self::recursive_delete( $path . "/" . $file, $follow, false );
} }
unlink( $path . "/" . $file ); $status = unlink( $path . "/" . $file );
} elseif ( is_dir( $path . "/" . $file ) ) { } elseif( is_dir( $path . "/" . $file ) ) {
self::recursive_delete( $path . "/" . $file, $follow, false ); $status = self::recursive_delete( $path . "/" . $file, $follow, false );
} else { } else {
unlink( $path . "/" . $file ); $status = unlink( $path . "/" . $file );
} }
} }
if( $keep_parent === false ) { if( $keep_parent === false ) {
rmdir( $path ); $status = rmdir( $path );
return;
} else {
return;
} }
} }
$response["message"] = "Removed $path";
$response["status"] = $status;
return $response;
}
function reverse_recursive_delete( $start, $stop, $files ) {
$response = array(
"status" => "none",
"message" => null,
);
$path_array = explode( "/", $start );
do {
$p = implode( "/", $path_array );
if( is_dir( $p ) && $p !== $stop ) {
if( $files ) {
$this->recursive_delete( $p, true );
} else {
$files = array_diff( scandir( $p ), array( '.', '..' ) );
if( count( $files ) == 0 ) {
$this->recursive_delete( $p, true );
} else {
break;
}
}
} else {
break;
}
array_pop( $path_array );
} while( count( $path_array ) > 1 );
return $response;
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
@ -802,14 +849,13 @@ class Filemanager extends Common {
// UPLOAD (Handles uploads to the specified directory) // UPLOAD (Handles uploads to the specified directory)
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
public function upload( $path, $blob ) { public function upload_blob( $path, $index, $blob ) {
$response = array( $response = array(
"status" => "none", "status" => "none",
"message" => "", "message" => "",
); );
// Check that the path is a directory
if( ! Permissions::has_write( $path ) ) { if( ! Permissions::has_write( $path ) ) {
$response["status"] = "error"; $response["status"] = "error";
@ -822,24 +868,12 @@ class Filemanager extends Common {
$path = WORKSPACE . "/$path"; $path = WORKSPACE . "/$path";
} }
$dirname = dirname( $path ); if( ! is_dir( UPLOAD_CACHE . "$path/" ) ) {
$name = basename( $path );
$blob = @file_get_contents( $_POST["data"] );
$path = $_POST["path"];
$index = $_POST["index"];
$response = array(
"status" => "none",
"message" => "",
);
$tmp = DATA . "tmp/";
if( ! is_dir( $tmp . $path ) ) {
mkdir( $tmp . $path, 0755, true ); mkdir( UPLOAD_CACHE . "$path/", 0755, true );
} }
$handle = fopen( "$tmp$path/$index", "a" ); $handle = fopen( UPLOAD_CACHE . "$path/$index", "a" );
$status = fwrite( $handle, $blob ); $status = fwrite( $handle, $blob );
fclose( $handle ); fclose( $handle );
@ -856,4 +890,70 @@ class Filemanager extends Common {
} }
return $response; return $response;
} }
public function upload_stitch( $path ) {
$response = array(
"status" => "none",
"message" => "",
);
$status = true;
if( ! Permissions::has_write( $path ) ) {
$response["status"] = "error";
$response["message"] = "You do not have access to write to this file.";
return $response;
}
if( ! common::isAbsPath( $path ) ) {
$path = WORKSPACE . "/$path";
}
$cache_path = UPLOAD_CACHE . "$path/";
$dir = dirname( $path );
$name = basename( $path );
if( ! is_dir( $dir ) ) {
mkdir( $dir, 0755, true );
}
$files = scandir( $cache_path );
foreach( $files as $id => $file ) {
if( $file !== "." && $file !== ".." ) {
$data = file_get_contents( $cache_path . $file );
$handle = fopen( $path, "a" );
$status = fwrite( $handle, $data );
fclose( $handle );
unlink( $cache_path . $file );
}
}
$rm_status = $this->reverse_recursive_delete( $cache_path, UPLOAD_CACHE, false );
if( $status === false ) {
$response["status"] = "error";
$response["message"] = "File could not be written to.";
} else {
$response["status"] = "success";
$response["path"] = $path;
$response["bytes"] = $status;
$response["message"] = "$status bytes written to file.";
$response["remove"] = $rm_status;
}
return $response;
}
public function upload_clean_stitches() {
$path = UPLOAD_CACHE;
}
} }

View file

@ -117,7 +117,7 @@
"title": "Delete Contents", "title": "Delete Contents",
"icon": "icon-cancel-circled", "icon": "icon-cancel-circled",
"applies-to": "directory-only", "applies-to": "directory-only",
"onclick": "codiad.filemanager.deleteInnerNode($('#context-menu').attr('data-path'));" "onclick": "codiad.filemanager.delete_children_nodes($('#context-menu').attr('data-path'));"
}, },
{ {
"title": "Break", "title": "Break",

View file

@ -149,7 +149,7 @@ switch( $action ) {
$response = $Filemanager->delete( $path, true ); $response = $Filemanager->delete( $path, true );
break; break;
case 'deleteInner': case 'delete_children':
$response = $Filemanager->delete( $path, true, true ); $response = $Filemanager->delete( $path, true, true );
break; break;
@ -300,7 +300,7 @@ switch( $action ) {
exit( $response ); exit( $response );
break; break;
case 'upload': case 'upload_blob':
if( ! isset( $_POST["data"] ) ) { if( ! isset( $_POST["data"] ) ) {
@ -311,20 +311,34 @@ switch( $action ) {
exit( json_encode( $response ) ); exit( json_encode( $response ) );
} }
if( $_POST["data"] !== "data:" ) { if( ! isset( $_POST["path"] ) ) {
$blob = @file_get_contents( $_POST["data"] );
} else {
$response["status"] = "error"; $response["status"] = "error";
$response["data"] = array( $response["data"] = array(
"error" => "No blob given", "error" => "No path given"
"data" => $_POST["data"],
); );
exit( json_encode( $response ) ); exit( json_encode( $response ) );
} }
$response = $Filemanager->upload( $path, $blob ); if( ! isset( $_POST["index"] ) ) {
$response["status"] = "error";
$response["data"] = array(
"error" => "No index given"
);
exit( json_encode( $response ) );
}
$blob = @file_get_contents( $_POST["data"] );
$path = $_POST["path"];
$index = $_POST["index"];
$response = $Filemanager->upload_blob( $path, $index, $blob );
break;
case 'upload_stitch':
$Filemanager->upload_stitch( $path );
break; break;
default: default:

View file

@ -45,6 +45,7 @@
'bmp', 'bmp',
], ],
}, },
file_reader: null,
files: [], files: [],
node: { node: {
@ -120,7 +121,7 @@
init: async function() { init: async function() {
let _this = this; let _this = codiad.filemanager;
/* Reload the page when saving auto reload preview */ /* Reload the page when saving auto reload preview */
amplify.subscribe( 'settings.save', async function() { amplify.subscribe( 'settings.save', async function() {
@ -153,38 +154,88 @@
$( document ).on( 'dragenter', function( e ) { $( document ).on( 'dragenter', function( e ) {
console.log( e ); let d = e.originalEvent.dataTransfer;
console.log( e.originalEvent.dataTransfer );
if( d ) {
let files = d.files;
let items = d.items;
console.log( 'dragenter', files, items );
_this.upload_overlay_on();
}
}); });
$( '.drop-overlay' ).on( 'drag dragstart dragend dragover dragenter dragleave drop', function( e ) {
$( document ).on( 'drag dragstart dragend dragover dragenter dragleave drop', function( e ) {
//e.preventDefault(); //console.log( 'drag dragstart dragend dragover dragenter dragleave drop', e );
//e.stopPropagation();
console.log( 'drag dragstart dragend dragover dragenter dragleave drop', e );
console.log( e.originalEvent.dataTransfer );
}) })
.on( 'dragover dragenter', function( e ) { .on( 'dragover dragenter', function( e ) {
console.log( 'dragover dragenter', e ); e.preventDefault();
console.log( e.originalEvent.dataTransfer ); e.stopPropagation();
//console.log( 'dragover dragenter', e );
}) })
.on( 'dragleave dragend drop', function( e ) { .on( 'dragleave dragend drop dragdrop', function( e ) {
//$( '.drop-overlay' ).css( 'display', 'none' );
console.log( 'dragleave dragend drop', e );
console.log( e.originalEvent.dataTransfer );
})
.on( 'drop', function( e ) {
//e.preventDefault(); //e.preventDefault();
//e.stopPropagation(); //e.stopPropagation();
//codiad.filemanager.upload_drop( e ); _this.upload_overlay_off();
console.log( 'drop', e ); })
console.log( e.originalEvent.dataTransfer ); .on( 'drop dragdrop', async function( e ) {
e.preventDefault();
e.stopPropagation();
let d = e.originalEvent.dataTransfer;
if( d ) {
let files = [];
let items = [];
let file_list = d.files;
let item_list = d.items;
let total_items = item_list.length;
if( item_list && item_list[0].webkitGetAsEntry ) {
for( let i = 0;i < total_items;i++ ) {
items.push( item_list[i].webkitGetAsEntry() );
}
}
console.log( files, items );
let project = $( '#file-manager a[data-type="root"]' ).attr( 'data-path' );
let path = await _this.open_file_selector( project, {type: "directory"}, 1, {} );
if( items.length ) {
for( let i = items.length;i--; ) {
let j = await _this.upload_load_files( items[i], path );
files = files.concat( j );
}
} else {
files = file_list;
}
for( let i = files.length;i--; ) {
let status = await _this.upload( files[i] );
console.log( status );
}
console.log( 'drop', files, items );
} else {
codiad.message.error( i18n( 'Your browser does not seem to support dragging and dropping files' ) );
}
}); });
$( '.drop-overlay' ).on( 'click', _this.upload_overlay_off );
}, },
archive: function( path ) { archive: function( path ) {
@ -360,39 +411,45 @@
codiad.modal.load( 400, this.dialog, { codiad.modal.load( 400, this.dialog, {
action: 'delete', action: 'delete',
path: path path: path
}); })
$( '#modal-content form' ) .then( function() {
.on( 'submit', function( e ) {
e.preventDefault(); $( '#modal-content form' )
$.get( _this.controller + '?action=delete_children&path=' + encodeURIComponent( path ), function( data ) { .on( 'submit', function( e ) {
let response = codiad.jsend.parse( data ); e.preventDefault();
if( response != 'error' ) { $.get( _this.controller + '?action=delete_children&path=' + encodeURIComponent( path ), function( data ) {
let node = $( '#file-manager a[data-path="' + path + '"]' ); console.log( data );
let parent_path = node.parent().parent().prev().attr( 'data-path' ); let response = codiad.jsend.parse( data );
node.parent( 'li' ).remove(); if( response != 'error' ) {
// Close any active files
$( '#active-files a' ).each( function() {
let curPath = $( this ).attr( 'data-path' ); let node = $( '#file-manager a[data-path="' + path + '"]' );
let parent_path = node.parent().parent().prev().attr( 'data-path' );
console.log( curPath, curPath.indexOf( path ) ); _this.toggle_directory( node, [], [], true );
node.parent( 'li' ).children( 'span' ).remove();
if( path.indexOf( curPath ) == 0 ) { // Close any active files
$( '#active-files a' ).each( function() {
codiad.active.remove( curPath ); let curPath = $( this ).attr( 'data-path' );
}
}); console.log( curPath, curPath.indexOf( path ) );
/* Notify listeners. */ if( path.indexOf( curPath ) == 0 ) {
amplify.publish( 'filemanager.onDelete', {
path: path codiad.active.remove( curPath );
}); }
} });
codiad.modal.unload();
/* Notify listeners. */
amplify.publish( 'filemanager.onDelete', {
path: path
});
}
codiad.modal.unload();
});
}); });
}); });
}, },
@ -592,6 +649,17 @@
return parent.join( '/' ); return parent.join( '/' );
}, },
get_file_reader: function() {
let _this = codiad.filemanager;
if( ! _this.reader ) {
_this.reader = new FileReader();
}
return _this.reader;
},
get_short_name: function( path ) { get_short_name: function( path ) {
return path.split( '/' ).pop(); return path.split( '/' ).pop();
@ -630,11 +698,6 @@
if( node === null ) { if( node === null ) {
node = $( '#file-manager a[data-path="' + path + '"]' ); node = $( '#file-manager a[data-path="' + path + '"]' );
} else if( node == 'create' ) {
node = $( "<a></a>" )
.attr( "data-path", path )
.attr( "data-type", "directory" );
} }
let parentNode = node.parent(); let parentNode = node.parent();
@ -990,7 +1053,7 @@
.then( async function( container ) { .then( async function( container ) {
let _this = codiad.filemanager; let _this = codiad.filemanager;
let div = $( "<div></div>" ); let div = null;
let select = $( '<button class="btn-left">Select</button>' ); let select = $( '<button class="btn-left">Select</button>' );
let cancel = $( '<button class="btn-right">Cancel</button>' ); let cancel = $( '<button class="btn-right">Cancel</button>' );
@ -1007,17 +1070,22 @@
} }
} }
_this.selector_listeners( container, filters, callbacks ); _this.selector_listeners( container, limit, filters, callbacks );
div = $( '#file-manager a[data-path="' + path + '"]' ).parent().parent().parent().clone();
div.attr( "id", "" );
let node = $( div ).find( 'a[data-path="' + path + '"]' );
let result = await _this.index( let result = await _this.index(
path, path,
false, false,
"create", node,
filters, filters,
directory_callbacks, callbacks,
file_callbacks,
); );
console.log( result );
container.html( div ); container.html( div );
container.append( select ); container.append( select );
container.append( cancel ); container.append( cancel );
@ -1036,7 +1104,7 @@
}); });
}); });
}) })
.error( reject ); .catch( reject );
}); });
}, },
@ -1533,7 +1601,7 @@
return index; return index;
}, },
selector_listeners: function( node, filters, callbacks ) { selector_listeners: function( node, limit, filters, callbacks ) {
let _this = codiad.filemanager; let _this = codiad.filemanager;
@ -1659,6 +1727,44 @@
node.removeClass( "loading" ); node.removeClass( "loading" );
}, },
toggle_select_node: function( node, limit = 0 ) {
let _this = codiad.filemanager;
let selected = false;
let path = node.attr( 'data-path' );
let i = 1;
for( i = _this.selected.length;i--; ) {
if( _this.selected[i] == path ) {
selected = true;
break;
}
}
if( limit > 0 && _this.selected.length >= limit ) {
for( i = _this.selected.length;i--; ) {
$( `[data-path='${_this.selected[i]}']` ).css( "background", "" );
}
_this.selected = [];
_this.selected.push( path );
} else {
if( selected ) {
_this.selected.splice( i, 1 );
} else {
_this.selected.push( path );
}
}
console.log( path, _this.selected );
},
unarchive: function( path ) { unarchive: function( path ) {
let _this = this; let _this = this;
@ -1674,7 +1780,220 @@
}); });
}, },
upload: function() {}, upload: function( file ) {
let _this = codiad.filemanager;
let blob_size = 1024*1024*4;
let total_size = file.size;
let upload_status = null;
let total_blobs = 0;
let current = 0;
let index = 0;
console.log( file, file.size );
return new Promise( function( resolve, reject ) {
if( total_size < blob_size ) {
blob_size = total_size;
} else {
total_blobs = ( Math.round( ( total_size / blob_size ) ) );
}
console.log( blob_size, _this.uploads.cache, total_size );
let timeout = setInterval( function() {
if( ( index == total_blobs || current == total_size ) && _this.uploads.cache.length == 0 ) {
_this.upload_stitch( file.path );
clearTimeout( timeout );
resolve( true );
} else if( ( index != total_blobs && current != total_size ) && _this.uploads.cache.length < _this.uploads.max ) {
console.log( "Adding new blob: ", ( index + 1 ) + "/" + total_blobs, current + blob_size + "/" + total_size );
let reader = new FileReader();
let blob = file.slice( current, current + blob_size );
reader.onload = async function( e ) {
current = current + blob_size;
_this.uploads.cache.push({
blob: e.target.result,
path: file.path,
status: "queued",
index: index,
});
index++;
_this.upload_clear_cache();
}
reader.readAsDataURL( blob );
} else {
_this.upload_clear_cache();
}
}, 100 );
});
},
uploads: {
cache: [],
max: 4,
},
upload_blob: function( blob, path, index, o ) {
return new Promise( function( resolve, reject ) {
let _this = codiad.filemanager;
let form = new FormData();
form.append( 'path', path );
form.append( 'index', index );
form.append( 'data', blob );
$.ajax({
type: 'POST',
url: _this.controller + "?action=upload_blob",
data: form,
processData: false,
contentType: false,
success: function( data ) {
console.log( data );
let d = JSON.parse( data );
if( d.status == "success" ) {
o.status = "success";
resolve( data );
} else {
o.status = "error";
reject( data );
}
},
error: function( data ) {
o.status = "error";
reject( data );
},
});
});
},
upload_clear_cache: function() {
let _this = codiad.filemanager;
for( let i = _this.uploads.cache.length;i--; ) {
if( _this.uploads.cache[i].status == "success" ) {
_this.uploads.cache.splice( i, 1 );
} else if( _this.uploads.cache[i].status == "error" ) {
_this.uploads.cache[i].status = "retrying";
_this.upload_blob( _this.uploads.cache[i].blob, _this.uploads.cache[i].path, _this.uploads.cache[i].index, _this.uploads.cache[i] );
} else if( _this.uploads.cache[i].status == "queued" ) {
_this.uploads.cache[i].status = "uploading";
_this.upload_blob( _this.uploads.cache[i].blob, _this.uploads.cache[i].path, _this.uploads.cache[i].index, _this.uploads.cache[i] );
}
}
},
upload_load_files: async function( item, path, files = null ) {
let _this = codiad.filemanager;
if( files === null ) {
files = [];
}
return new Promise( function( resolve, reject ) {
if( item.isFile ) {
// Get file
item.file( function( file ) {
if( ( `${path}` ).charAt( path.length - 1 ) != "/" ) {
path += "/";
}
file.path = path + file.name;
files.push( file );
resolve( files );
});
} else if( item.isDirectory ) {
// Get folder contents
let dirReader = item.createReader();
dirReader.readEntries( async function( entries ) {
if( ( `${path}` ).charAt( path.length - 1 ) != "/" ) {
path += "/";
}
let total = entries.length;
for( let i = 0;i < total; i++ ) {
let children = await _this.upload_load_files( entries[i], path + item.name + "/", files );
files.concat( children );
}
resolve( files );
}, reject );
}
});
},
upload_overlay_off: function() {
$( '.drop-overlay' ).css( 'display', 'none' );
},
upload_overlay_on: function( e ) {
$( '.drop-overlay' ).css( 'display', 'block' );
},
upload_stitch: function( path ) {
let _this = codiad.filemanager;
let form = new FormData();
form.append( 'path', path );
$.ajax({
type: 'POST',
url: _this.controller + "?action=upload_stitch",
data: form,
processData: false,
contentType: false,
success: function( data ) {
console.log( data );
parent = path.split( '/' );
parent.pop();
console.log( path, parent.join( '/' ) );
_this.rescan( parent.join( '/' ) );
},
error: function( data ) {
console.log( data );
},
});
},
upload_to_node: function( path ) { upload_to_node: function( path ) {