diff --git a/apps/files/admin.php b/apps/files/admin.php
index f747f8645f6..02c3147dba5 100644
--- a/apps/files/admin.php
+++ b/apps/files/admin.php
@@ -21,10 +21,6 @@
*
*/
-
-// Init owncloud
-
-
OCP\User::checkAdminUser();
$htaccessWorking=(getenv('htaccessWorking')=='true');
diff --git a/apps/files/ajax/autocomplete.php b/apps/files/ajax/autocomplete.php
deleted file mode 100644
index b32ba7c3d5b..00000000000
--- a/apps/files/ajax/autocomplete.php
+++ /dev/null
@@ -1,54 +0,0 @@
-$item, 'label'=>$item, 'name'=>$item);
- }
- }
- }
- }
- }
-}
-OCP\JSON::encodedPrint($files);
diff --git a/apps/files/ajax/delete.php b/apps/files/ajax/delete.php
index 6532b76df21..da7e9d6b2aa 100644
--- a/apps/files/ajax/delete.php
+++ b/apps/files/ajax/delete.php
@@ -12,17 +12,22 @@ $files = isset($_POST["file"]) ? stripslashes($_POST["file"]) : stripslashes($_P
$files = json_decode($files);
$filesWithError = '';
+
$success = true;
+
//Now delete
-foreach($files as $file) {
- if( !OC_Files::delete( $dir, $file )) {
+foreach ($files as $file) {
+ if (($dir === '' && $file === 'Shared') || !\OC\Files\Filesystem::unlink($dir . '/' . $file)) {
$filesWithError .= $file . "\n";
$success = false;
}
}
-if($success) {
- OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $files )));
+// get array with updated storage stats (e.g. max file size) after upload
+$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
+
+if ($success) {
+ OCP\JSON::success(array("data" => array_merge(array("dir" => $dir, "files" => $files), $storageStats)));
} else {
- OCP\JSON::error(array("data" => array( "message" => "Could not delete:\n" . $filesWithError )));
+ OCP\JSON::error(array("data" => array_merge(array("message" => "Could not delete:\n" . $filesWithError), $storageStats)));
}
diff --git a/apps/files/ajax/getstoragestats.php b/apps/files/ajax/getstoragestats.php
new file mode 100644
index 00000000000..7a2b642a9bd
--- /dev/null
+++ b/apps/files/ajax/getstoragestats.php
@@ -0,0 +1,9 @@
+ \OCA\files\lib\Helper::buildFileStorageStatistics('/')));
diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php
index cade7e872b3..878e4cb2159 100644
--- a/apps/files/ajax/list.php
+++ b/apps/files/ajax/list.php
@@ -32,7 +32,7 @@ if($doBreadcrumb) {
// make filelist
$files = array();
-foreach( OC_Files::getdirectorycontent( $dir ) as $i ) {
+foreach( \OC\Files\Filesystem::getDirectoryContent( $dir ) as $i ) {
$i["date"] = OCP\Util::formatDate($i["mtime"] );
$files[] = $i;
}
diff --git a/apps/files/ajax/move.php b/apps/files/ajax/move.php
index 4ebc3f42d9f..78ed218c136 100644
--- a/apps/files/ajax/move.php
+++ b/apps/files/ajax/move.php
@@ -7,19 +7,23 @@ OCP\JSON::checkLoggedIn();
OCP\JSON::callCheck();
// Get data
-$dir = stripslashes($_GET["dir"]);
-$file = stripslashes($_GET["file"]);
-$target = stripslashes(rawurldecode($_GET["target"]));
+$dir = stripslashes($_POST["dir"]);
+$file = stripslashes($_POST["file"]);
+$target = stripslashes(rawurldecode($_POST["target"]));
-$l=OC_L10N::get('files');
-
-if(OC_Filesystem::file_exists($target . '/' . $file)) {
- OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s - File with this name already exists", array($file)) )));
+if(\OC\Files\Filesystem::file_exists($target . '/' . $file)) {
+ OCP\JSON::error(array("data" => array( "message" => "Could not move $file - File with this name already exists" )));
exit;
}
-if(OC_Files::move($dir, $file, $target, $file)) {
- OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file )));
-} else {
- OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
+if ($dir != '' || $file != 'Shared') {
+ $targetFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file);
+ $sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file);
+ if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) {
+ OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file )));
+ } else {
+ OCP\JSON::error(array("data" => array( "message" => "Could not move $file" )));
+ }
+}else{
+ OCP\JSON::error(array("data" => array( "message" => "Could not move $file" )));
}
diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php
index 2bac9bb20ba..38714f34a63 100644
--- a/apps/files/ajax/newfile.php
+++ b/apps/files/ajax/newfile.php
@@ -63,13 +63,12 @@ if($source) {
$ctx = stream_context_create(null, array('notification' =>'progress'));
$sourceStream=fopen($source, 'rb', false, $ctx);
$target=$dir.'/'.$filename;
- $result=OC_Filesystem::file_put_contents($target, $sourceStream);
+ $result=\OC\Files\Filesystem::file_put_contents($target, $sourceStream);
if($result) {
- $target = OC_Filesystem::normalizePath($target);
- $meta = OC_FileCache::get($target);
+ $meta = \OC\Files\Filesystem::getFileInfo($target);
$mime=$meta['mimetype'];
- $id = OC_FileCache::getId($target);
- $eventSource->send('success', array('mime'=>$mime, 'size'=>OC_Filesystem::filesize($target), 'id' => $id));
+ $id = $meta['fileid'];
+ $eventSource->send('success', array('mime'=>$mime, 'size'=>\OC\Files\Filesystem::filesize($target), 'id' => $id));
} else {
$eventSource->send('error', "Error while downloading ".$source. ' to '.$target);
}
@@ -77,15 +76,15 @@ if($source) {
exit();
} else {
if($content) {
- if(OC_Filesystem::file_put_contents($dir.'/'.$filename, $content)) {
- $meta = OC_FileCache::get($dir.'/'.$filename);
- $id = OC_FileCache::getId($dir.'/'.$filename);
+ if(\OC\Files\Filesystem::file_put_contents($dir.'/'.$filename, $content)) {
+ $meta = \OC\Files\Filesystem::getFileInfo($dir.'/'.$filename);
+ $id = $meta['fileid'];
OCP\JSON::success(array("data" => array('content'=>$content, 'id' => $id)));
exit();
}
- }elseif(OC_Files::newFile($dir, $filename, 'file')) {
- $meta = OC_FileCache::get($dir.'/'.$filename);
- $id = OC_FileCache::getId($dir.'/'.$filename);
+ }elseif(\OC\Files\Filesystem::touch($dir . '/' . $filename)) {
+ $meta = \OC\Files\Filesystem::getFileInfo($dir.'/'.$filename);
+ $id = $meta['fileid'];
OCP\JSON::success(array("data" => array('content'=>$content, 'id' => $id)));
exit();
}
diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php
index 0f1f2f14eb0..e26e1238bc6 100644
--- a/apps/files/ajax/newfolder.php
+++ b/apps/files/ajax/newfolder.php
@@ -19,13 +19,14 @@ if(strpos($foldername, '/')!==false) {
exit();
}
-if(OC_Files::newFile($dir, stripslashes($foldername), 'dir')) {
+if(\OC\Files\Filesystem::mkdir($dir . '/' . stripslashes($foldername))) {
if ( $dir != '/') {
$path = $dir.'/'.$foldername;
} else {
$path = '/'.$foldername;
}
- $id = OC_FileCache::getId($path);
+ $meta = \OC\Files\Filesystem::getFileInfo($path);
+ $id = $meta['fileid'];
OCP\JSON::success(array("data" => array('id'=>$id)));
exit();
}
diff --git a/apps/files/ajax/rawlist.php b/apps/files/ajax/rawlist.php
index e0aa0bdac52..1cd2944483c 100644
--- a/apps/files/ajax/rawlist.php
+++ b/apps/files/ajax/rawlist.php
@@ -15,7 +15,7 @@ $mimetype = isset($_GET['mimetype']) ? $_GET['mimetype'] : '';
// make filelist
$files = array();
-foreach( OC_Files::getdirectorycontent( $dir, $mimetype ) as $i ) {
+foreach( \OC\Files\Filesystem::getDirectoryContent( $dir, $mimetype ) as $i ) {
$i["date"] = OCP\Util::formatDate($i["mtime"] );
$i['mimetype_icon'] = $i['type'] == 'dir' ? \mimetype_icon('dir'): \mimetype_icon($i['mimetype']);
$files[] = $i;
diff --git a/apps/files/ajax/rename.php b/apps/files/ajax/rename.php
index 89b4d4bba73..970aaa638da 100644
--- a/apps/files/ajax/rename.php
+++ b/apps/files/ajax/rename.php
@@ -11,10 +11,14 @@ $dir = stripslashes($_GET["dir"]);
$file = stripslashes($_GET["file"]);
$newname = stripslashes($_GET["newname"]);
-// Delete
-if( $newname !== '.' and OC_Files::move( $dir, $file, $dir, $newname )) {
- OCP\JSON::success(array("data" => array( "dir" => $dir, "file" => $file, "newname" => $newname )));
-} else {
- $l=OC_L10N::get('files');
- OCP\JSON::error(array("data" => array( "message" => $l->t("Unable to rename file") )));
+if ( $newname !== '.' and ($dir != '' || $file != 'Shared') and $newname !== '.') {
+ $targetFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $newname);
+ $sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file);
+ if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) {
+ OCP\JSON::success(array("data" => array( "dir" => $dir, "file" => $file, "newname" => $newname )));
+ } else {
+ OCP\JSON::error(array("data" => array( "message" => "Unable to rename file" )));
+ }
+}else{
+ OCP\JSON::error(array("data" => array( "message" => "Unable to rename file" )));
}
diff --git a/apps/files/ajax/scan.php b/apps/files/ajax/scan.php
index a819578e309..391b98608bd 100644
--- a/apps/files/ajax/scan.php
+++ b/apps/files/ajax/scan.php
@@ -1,44 +1,71 @@
getAbsolutePath($dir);
+
+$mountPoints = \OC\Files\Filesystem::getMountPoints($absolutePath);
+$mountPoints[] = \OC\Files\Filesystem::getMountPoint($absolutePath);
+$mountPoints = array_reverse($mountPoints); //start with the mount point of $dir
+
+foreach ($mountPoints as $mountPoint) {
+ $storage = \OC\Files\Filesystem::getStorage($mountPoint);
+ if ($storage) {
+ ScanListener::$mountPoints[$storage->getId()] = $mountPoint;
+ $scanner = $storage->getScanner();
+ if ($force) {
+ $scanner->scan('');
+ } else {
+ $scanner->backgroundScan();
}
-
- OC_FileCache::scan($dir, $eventSource);
- OC_FileCache::clean();
- OCP\DB::commit();
- $eventSource->send('success', true);
- } else {
- OCP\JSON::success(array('data'=>array('done'=>true)));
- exit;
- }
-} else {
- if($checkOnly) {
- OCP\JSON::success(array('data'=>array('done'=>false)));
- exit;
- }
- if(isset($eventSource)) {
- $eventSource->send('success', false);
- } else {
- exit;
}
}
+
+$eventSource->send('done', ScanListener::$fileCount);
$eventSource->close();
+
+class ScanListener {
+
+ static public $fileCount = 0;
+ static public $lastCount = 0;
+
+ /**
+ * @var \OC\Files\View $view
+ */
+ static public $view;
+
+ /**
+ * @var array $mountPoints map storage ids to mountpoints
+ */
+ static public $mountPoints = array();
+
+ /**
+ * @var \OC_EventSource event source to pass events to
+ */
+ static public $eventSource;
+
+ static function folder($params) {
+ $internalPath = $params['path'];
+ $mountPoint = self::$mountPoints[$params['storage']];
+ $path = self::$view->getRelativePath($mountPoint . $internalPath);
+ self::$eventSource->send('folder', $path);
+ }
+
+ static function file() {
+ self::$fileCount++;
+ if (self::$fileCount > self::$lastCount + 20) { //send a count update every 20 files
+ self::$lastCount = self::$fileCount;
+ self::$eventSource->send('count', self::$fileCount);
+ }
+ }
+}
diff --git a/apps/files/ajax/upgrade.php b/apps/files/ajax/upgrade.php
new file mode 100644
index 00000000000..7237b02c0b0
--- /dev/null
+++ b/apps/files/ajax/upgrade.php
@@ -0,0 +1,44 @@
+hasItems()) {
+ OC_Hook::connect('\OC\Files\Cache\Upgrade', 'migrate_path', $listener, 'upgradePath');
+
+ OC_DB::beginTransaction();
+ $upgrade = new \OC\Files\Cache\Upgrade($legacy);
+ $count = $legacy->getCount();
+ $eventSource->send('total', $count);
+ $upgrade->upgradePath('/' . $user . '/files');
+ OC_DB::commit();
+}
+\OC\Files\Cache\Upgrade::upgradeDone($user);
+$eventSource->send('done', true);
+$eventSource->close();
+
+class UpgradeListener {
+ /**
+ * @var OC_EventSource $eventSource
+ */
+ private $eventSource;
+
+ private $count = 0;
+ private $lastSend = 0;
+
+ public function __construct($eventSource) {
+ $this->eventSource = $eventSource;
+ }
+
+ public function upgradePath($path) {
+ $this->count++;
+ if ($this->count > ($this->lastSend + 5)) {
+ $this->lastSend = $this->count;
+ $this->eventSource->send('count', $this->count);
+ }
+ }
+}
diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index 2a2d935da6c..9ecc1a6c2f4 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -8,65 +8,78 @@ OCP\JSON::setContentTypeHeader('text/plain');
OCP\JSON::checkLoggedIn();
OCP\JSON::callCheck();
-$l=OC_L10N::get('files');
+$l = OC_L10N::get('files');
+
+// get array with current storage stats (e.g. max file size)
+$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
if (!isset($_FILES['files'])) {
- OCP\JSON::error(array('data' => array( 'message' => $l->t( 'No file was uploaded. Unknown error' ))));
+ OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('No file was uploaded. Unknown error')), $storageStats)));
exit();
}
foreach ($_FILES['files']['error'] as $error) {
if ($error != 0) {
$errors = array(
- UPLOAD_ERR_OK=>$l->t('There is no error, the file uploaded with success'),
- UPLOAD_ERR_INI_SIZE=>$l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ')
- .ini_get('upload_max_filesize'),
- UPLOAD_ERR_FORM_SIZE=>$l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified'
- .' in the HTML form'),
- UPLOAD_ERR_PARTIAL=>$l->t('The uploaded file was only partially uploaded'),
- UPLOAD_ERR_NO_FILE=>$l->t('No file was uploaded'),
- UPLOAD_ERR_NO_TMP_DIR=>$l->t('Missing a temporary folder'),
- UPLOAD_ERR_CANT_WRITE=>$l->t('Failed to write to disk'),
+ UPLOAD_ERR_OK => $l->t('There is no error, the file uploaded with success'),
+ UPLOAD_ERR_INI_SIZE => $l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ')
+ . ini_get('upload_max_filesize'),
+ UPLOAD_ERR_FORM_SIZE => $l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified'
+ . ' in the HTML form'),
+ UPLOAD_ERR_PARTIAL => $l->t('The uploaded file was only partially uploaded'),
+ UPLOAD_ERR_NO_FILE => $l->t('No file was uploaded'),
+ UPLOAD_ERR_NO_TMP_DIR => $l->t('Missing a temporary folder'),
+ UPLOAD_ERR_CANT_WRITE => $l->t('Failed to write to disk'),
);
- OCP\JSON::error(array('data' => array( 'message' => $errors[$error] )));
+ OCP\JSON::error(array('data' => array_merge(array('message' => $errors[$error]), $storageStats)));
exit();
}
}
-$files=$_FILES['files'];
+$files = $_FILES['files'];
$dir = $_POST['dir'];
-$error='';
+$error = '';
-$totalSize=0;
-foreach($files['size'] as $size) {
- $totalSize+=$size;
+$maxUploadFilesize = OCP\Util::maxUploadFilesize($dir);
+$maxHumanFilesize = OCP\Util::humanFileSize($maxUploadFilesize);
+
+$totalSize = 0;
+foreach ($files['size'] as $size) {
+ $totalSize += $size;
}
-if($totalSize>OC_Filesystem::free_space($dir)) {
- OCP\JSON::error(array('data' => array( 'message' => $l->t( 'Not enough space available' ))));
+if ($totalSize > \OC\Files\Filesystem::free_space($dir)) {
+ OCP\JSON::error(array('data' => array('message' => $l->t('Not enough space available'),
+ 'uploadMaxFilesize' => $maxUploadFilesize,
+ 'maxHumanFilesize' => $maxHumanFilesize)));
exit();
}
-$result=array();
-if(strpos($dir, '..') === false) {
- $fileCount=count($files['name']);
- for($i=0;$i<$fileCount;$i++) {
+$result = array();
+if (strpos($dir, '..') === false) {
+ $fileCount = count($files['name']);
+ for ($i = 0; $i < $fileCount; $i++) {
$target = OCP\Files::buildNotExistingFileName(stripslashes($dir), $files['name'][$i]);
// $path needs to be normalized - this failed within drag'n'drop upload to a sub-folder
- $target = OC_Filesystem::normalizePath($target);
- if(is_uploaded_file($files['tmp_name'][$i]) and OC_Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) {
- $meta = OC_FileCache::get($target);
- $id = OC_FileCache::getId($target);
- $result[]=array( 'status' => 'success',
- 'mime'=>$meta['mimetype'],
- 'size'=>$meta['size'],
- 'id'=>$id,
- 'name'=>basename($target));
+ $target = \OC\Files\Filesystem::normalizePath($target);
+ if (is_uploaded_file($files['tmp_name'][$i]) and \OC\Files\Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) {
+ $meta = \OC\Files\Filesystem::getFileInfo($target);
+ // updated max file size after upload
+ $storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
+
+ $result[] = array('status' => 'success',
+ 'mime' => $meta['mimetype'],
+ 'size' => $meta['size'],
+ 'id' => $meta['fileid'],
+ 'name' => basename($target),
+ 'uploadMaxFilesize' => $maxUploadFilesize,
+ 'maxHumanFilesize' => $maxHumanFilesize
+ );
}
}
OCP\JSON::encodedPrint($result);
exit();
} else {
- $error=$l->t( 'Invalid directory.' );
+ $error = $l->t('Invalid directory.');
}
-OCP\JSON::error(array('data' => array('message' => $error )));
+OCP\JSON::error(array('data' => array_merge(array('message' => $error), $storageStats)));
diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php
index 108f02930e2..ab2f3b01a29 100644
--- a/apps/files/appinfo/app.php
+++ b/apps/files/appinfo/app.php
@@ -1,5 +1,5 @@
basename($file),
);
diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml
index 0a1b196b06f..7c82c839dab 100644
--- a/apps/files/appinfo/info.xml
+++ b/apps/files/appinfo/info.xml
@@ -5,7 +5,7 @@
';
+ deleteAction[0].outerHTML = newHTML;
+ }
// Finish any existing actions
if (FileList.lastAction) {
FileList.lastAction();
}
- FileList.prepareDeletion(files);
-
- if (!FileList.useUndo) {
- FileList.lastAction();
- } else {
- // NOTE: Temporary fix to change the text to unshared for files in root of Shared folder
- if ($('#dir').val() == '/Shared') {
- $('#notification').html(t('files', 'unshared {files}', {'files': escapeHTML(files)})+''+t('files', 'undo')+'');
- } else {
- $('#notification').html(t('files', 'deleted {files}', {'files': escapeHTML(files)})+''+t('files', 'undo')+'');
- }
- $('#notification').fadeIn();
- }
- },
- finishDelete:function(ready,sync){
- if(!FileList.deleteCanceled && FileList.deleteFiles){
- var fileNames=JSON.stringify(FileList.deleteFiles);
- $.ajax({
- url: OC.filePath('files', 'ajax', 'delete.php'),
- async:!sync,
- type:'post',
- data: {dir:$('#dir').val(),files:fileNames},
- complete: function(data){
- boolOperationFinished(data, function(){
- $('#notification').fadeOut('400');
- $.each(FileList.deleteFiles,function(index,file){
- FileList.remove(file);
+ var fileNames = JSON.stringify(files);
+ $.post(OC.filePath('files', 'ajax', 'delete.php'),
+ {dir:$('#dir').val(),files:fileNames},
+ function(result){
+ if (result.status == 'success') {
+ $.each(files,function(index,file){
+ var files = $('tr').filterAttr('data-file',file);
+ files.hide();
+ files.find('input[type="checkbox"]').removeAttr('checked');
+ files.removeClass('selected');
});
- FileList.deleteCanceled=true;
- FileList.deleteFiles=null;
- FileList.lastAction = null;
- if(ready){
- ready();
- }
- });
- }
- });
- }
- },
- prepareDeletion:function(files){
- if(files.substr){
- files=[files];
- }
- $.each(files,function(index,file){
- var files = $('tr').filterAttr('data-file',file);
- files.hide();
- files.find('input[type="checkbox"]').removeAttr('checked');
- files.removeClass('selected');
- });
- procesSelection();
- FileList.deleteCanceled=false;
- FileList.deleteFiles=files;
- FileList.lastAction = function() {
- FileList.finishDelete(null, true);
- };
+ procesSelection();
+ } else {
+ $.each(files,function(index,file) {
+ var deleteAction = $('tr').filterAttr('data-file',file).children("td.date").children(".move2trash");
+ deleteAction[0].outerHTML = oldHTML;
+ });
+ }
+ });
}
};
@@ -362,16 +333,16 @@ $(document).ready(function(){
FileList.replaceIsNewFile = null;
}
FileList.lastAction = null;
- $('#notification').fadeOut('400');
+ OC.Notification.hide();
});
$('#notification .replace').live('click', function() {
- $('#notification').fadeOut('400', function() {
- FileList.replace($('#notification').data('oldName'), $('#notification').data('newName'), $('#notification').data('isNewFile'));
- });
+ OC.Notification.hide(function() {
+ FileList.replace($('#notification').data('oldName'), $('#notification').data('newName'), $('#notification').data('isNewFile'));
+ });
});
$('#notification .suggest').live('click', function() {
$('tr').filterAttr('data-file', $('#notification').data('oldName')).show();
- $('#notification').fadeOut('400');
+ OC.Notification.hide();
});
$('#notification .cancel').live('click', function() {
if ($('#notification').data('isNewFile')) {
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index 3a4af6416e9..3d09d6aa2b6 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -26,15 +26,34 @@ Files={
});
procesSelection();
},
+ updateMaxUploadFilesize:function(response) {
+ if(response == undefined) {
+ return;
+ }
+ if(response.data !== undefined && response.data.uploadMaxFilesize !== undefined) {
+ $('#max_upload').val(response.data.uploadMaxFilesize);
+ $('#upload.button').attr('original-title', response.data.maxHumanFilesize);
+ $('#usedSpacePercent').val(response.data.usedSpacePercent);
+ Files.displayStorageWarnings();
+ }
+ if(response[0] == undefined) {
+ return;
+ }
+ if(response[0].uploadMaxFilesize !== undefined) {
+ $('#max_upload').val(response[0].uploadMaxFilesize);
+ $('#upload.button').attr('original-title', response[0].maxHumanFilesize);
+ $('#usedSpacePercent').val(response[0].usedSpacePercent);
+ Files.displayStorageWarnings();
+ }
+
+ },
isFileNameValid:function (name) {
if (name === '.') {
- $('#notification').text(t('files', '\'.\' is an invalid file name.'));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', '\'.\' is an invalid file name.'));
return false;
}
if (name.length == 0) {
- $('#notification').text(t('files', 'File name cannot be empty.'));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', 'File name cannot be empty.'));
return false;
}
@@ -42,13 +61,26 @@ Files={
var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*'];
for (var i = 0; i < invalid_characters.length; i++) {
if (name.indexOf(invalid_characters[i]) != -1) {
- $('#notification').text(t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."));
return false;
}
}
- $('#notification').fadeOut();
+ OC.Notification.hide();
return true;
+ },
+ displayStorageWarnings: function() {
+ if (!OC.Notification.isHidden()) {
+ return;
+ }
+
+ var usedSpacePercent = $('#usedSpacePercent').val();
+ if (usedSpacePercent > 98) {
+ OC.Notification.show(t('files', 'Your storage is full, files can not be updated or synced anymore!'));
+ return;
+ }
+ if (usedSpacePercent > 90) {
+ OC.Notification.show(t('files', 'Your storage is almost full ({usedSpacePercent}%)', {usedSpacePercent: usedSpacePercent}));
+ }
}
};
$(document).ready(function() {
@@ -82,6 +114,11 @@ $(document).ready(function() {
$(this).parent().children('#file_upload_start').trigger('click');
return false;
});
+
+ // Show trash bin
+ $('#trash a').live('click', function() {
+ window.location=OC.filePath('files_trashbin', '', 'index.php');
+ });
var lastChecked;
@@ -184,8 +221,7 @@ $(document).ready(function() {
$('.download').click('click',function(event) {
var files=getSelectedFiles('name').join(';');
var dir=$('#dir').val()||'/';
- $('#notification').text(t('files','generating ZIP-file, it may take some time.'));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
// use special download URL if provided, e.g. for public shared files
if ( (downloadURL = document.getElementById("downloadURL")) ) {
window.location=downloadURL.value+"&download&files="+files;
@@ -314,9 +350,9 @@ $(document).ready(function() {
var response;
response=jQuery.parseJSON(result);
if(response[0] == undefined || response[0].status != 'success') {
- $('#notification').text(t('files', response.data.message));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', response.data.message));
}
+ Files.updateMaxUploadFilesize(response);
var file=response[0];
// TODO: this doesn't work if the file name has been changed server side
delete uploadingFiles[dirName][file.name];
@@ -354,9 +390,7 @@ $(document).ready(function() {
uploadtext.text(t('files', '{count} files uploading', {count: currentUploads}));
}
delete uploadingFiles[dirName][fileName];
- $('#notification').hide();
- $('#notification').text(t('files', 'Upload cancelled.'));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', 'Upload cancelled.'));
}
});
//TODO test with filenames containing slashes
@@ -369,6 +403,8 @@ $(document).ready(function() {
.success(function(result, textStatus, jqXHR) {
var response;
response=jQuery.parseJSON(result);
+ Files.updateMaxUploadFilesize(response);
+
if(response[0] != undefined && response[0].status == 'success') {
var file=response[0];
delete uploadingFiles[file.name];
@@ -381,20 +417,17 @@ $(document).ready(function() {
FileList.loadingDone(file.name, file.id);
} else {
Files.cancelUpload(this.files[0].name);
- $('#notification').text(t('files', response.data.message));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', response.data.message));
$('#fileList > tr').not('[data-mime]').fadeOut();
$('#fileList > tr').not('[data-mime]').remove();
}
- })
- .error(function(jqXHR, textStatus, errorThrown) {
- if(errorThrown === 'abort') {
- Files.cancelUpload(this.files[0].name);
- $('#notification').hide();
- $('#notification').text(t('files', 'Upload cancelled.'));
- $('#notification').fadeIn();
- }
- });
+ })
+ .error(function(jqXHR, textStatus, errorThrown) {
+ if(errorThrown === 'abort') {
+ Files.cancelUpload(this.files[0].name);
+ OC.Notification.show(t('files', 'Upload cancelled.'));
+ }
+ });
uploadingFiles[uniqueName] = jqXHR;
}
}
@@ -402,6 +435,7 @@ $(document).ready(function() {
data.submit().success(function(data, status) {
// in safari data is a string
response = jQuery.parseJSON(typeof data === 'string' ? data : data[0].body.innerText);
+ Files.updateMaxUploadFilesize(response);
if(response[0] != undefined && response[0].status == 'success') {
var file=response[0];
delete uploadingFiles[file.name];
@@ -414,8 +448,7 @@ $(document).ready(function() {
FileList.loadingDone(file.name, file.id);
} else {
//TODO Files.cancelUpload(/*where do we get the filename*/);
- $('#notification').text(t('files', response.data.message));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', response.data.message));
$('#fileList > tr').not('[data-mime]').fadeOut();
$('#fileList > tr').not('[data-mime]').remove();
}
@@ -434,6 +467,10 @@ $(document).ready(function() {
$('#uploadprogressbar').progressbar('value',progress);
},
start: function(e, data) {
+ //IE < 10 does not fire the necessary events for the progress bar.
+ if($.browser.msie && parseInt($.browser.version) < 10) {
+ return;
+ }
$('#uploadprogressbar').progressbar({value:0});
$('#uploadprogressbar').fadeIn();
if(data.dataType != 'iframe ') {
@@ -535,14 +572,12 @@ $(document).ready(function() {
event.preventDefault();
var newname=input.val();
if(type == 'web' && newname.length == 0) {
- $('#notification').text(t('files', 'URL cannot be empty.'));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files', 'URL cannot be empty.'));
return false;
} else if (type != 'web' && !Files.isFileNameValid(newname)) {
return false;
} else if( type == 'folder' && $('#dir').val() == '/' && newname == 'Shared') {
- $('#notification').text(t('files','Invalid folder name. Usage of \'Shared\' is reserved by Owncloud'));
- $('#notification').fadeIn();
+ OC.Notification.show(t('files','Invalid folder name. Usage of \'Shared\' is reserved by Owncloud'));
return false;
}
if (FileList.lastAction) {
@@ -640,12 +675,8 @@ $(document).ready(function() {
});
});
- //check if we need to scan the filesystem
- $.get(OC.filePath('files','ajax','scan.php'),{checkonly:'true'}, function(response) {
- if(response.data.done){
- scanFiles();
- }
- }, "json");
+ //do a background scan if needed
+ scanFiles();
var lastWidth = 0;
var breadcrumbs = [];
@@ -712,35 +743,62 @@ $(document).ready(function() {
});
resizeBreadcrumbs(true);
+
+ // display storage warnings
+ setTimeout ( "Files.displayStorageWarnings()", 100 );
+ OC.Notification.setDefault(Files.displayStorageWarnings);
+
+ // file space size sync
+ function update_storage_statistics() {
+ $.getJSON(OC.filePath('files','ajax','getstoragestats.php'),function(response) {
+ Files.updateMaxUploadFilesize(response);
+ });
+ }
+
+ // start on load - we ask the server every 5 minutes
+ var update_storage_statistics_interval = 5*60*1000;
+ var update_storage_statistics_interval_id = setInterval(update_storage_statistics, update_storage_statistics_interval);
+
+ // Use jquery-visibility to de-/re-activate file stats sync
+ if ($.support.pageVisibility) {
+ $(document).on({
+ 'show.visibility': function() {
+ if (!update_storage_statistics_interval_id) {
+ update_storage_statistics_interval_id = setInterval(update_storage_statistics, update_storage_statistics_interval);
+ }
+ },
+ 'hide.visibility': function() {
+ clearInterval(update_storage_statistics_interval_id);
+ update_storage_statistics_interval_id = 0;
+ }
+ });
+ }
});
-function scanFiles(force,dir){
+function scanFiles(force, dir){
if(!dir){
- dir='';
+ dir = '';
}
- force=!!force; //cast to bool
- scanFiles.scanning=true;
- $('#scanning-message').show();
- $('#fileList').remove();
- var scannerEventSource=new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force:force,dir:dir});
- scanFiles.cancel=scannerEventSource.close.bind(scannerEventSource);
- scannerEventSource.listen('scanning',function(data){
- $('#scan-count').text(t('files', '{count} files scanned', {count: data.count}));
- $('#scan-current').text(data.file+'/');
+ force = !!force; //cast to bool
+ scanFiles.scanning = true;
+ var scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force:force,dir:dir});
+ scanFiles.cancel = scannerEventSource.close.bind(scannerEventSource);
+ scannerEventSource.listen('count',function(count){
+ console.log(count + 'files scanned')
});
- scannerEventSource.listen('success',function(success){
+ scannerEventSource.listen('folder',function(path){
+ console.log('now scanning ' + path)
+ });
+ scannerEventSource.listen('done',function(count){
scanFiles.scanning=false;
- if(success){
- window.location.reload();
- }else{
- alert(t('files', 'error while scanning'));
- }
+ console.log('done after ' + count + 'files');
});
}
scanFiles.scanning=false;
function boolOperationFinished(data, callback) {
result = jQuery.parseJSON(data.responseText);
+ Files.updateMaxUploadFilesize(result);
if(result.status == 'success'){
callback.call();
} else {
@@ -752,32 +810,101 @@ function updateBreadcrumb(breadcrumbHtml) {
$('p.nav').empty().html(breadcrumbHtml);
}
-//options for file drag/dropp
+var createDragShadow = function(event){
+ //select dragged file
+ var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
+ if (!isDragSelected) {
+ //select dragged file
+ $(event.target).parents('tr').find('td input:first').prop('checked',true);
+ }
+
+ var selectedFiles = getSelectedFiles();
+
+ if (!isDragSelected && selectedFiles.length == 1) {
+ //revert the selection
+ $(event.target).parents('tr').find('td input:first').prop('checked',false);
+ }
+
+ //also update class when we dragged more than one file
+ if (selectedFiles.length > 1) {
+ $(event.target).parents('tr').addClass('selected');
+ }
+
+ // build dragshadow
+ var dragshadow = $('
';
+ var undeleteAction = $('tr').filterAttr('data-file',filename).children("td.date");
+ undeleteAction[0].innerHTML = undeleteAction[0].innerHTML+spinner;
+ $.post(OC.filePath('files_trashbin','ajax','undelete.php'),
+ {files:tr.attr('data-file'), dirlisting:tr.attr('data-dirlisting') },
+ function(result){
+ for (var i = 0; i < result.data.success.length; i++) {
+ var row = document.getElementById(result.data.success[i].filename);
+ row.parentNode.removeChild(row);
+ }
+ if (result.status != 'success') {
+ OC.dialogs.alert(result.data.message, 'Error');
+ }
+ });
+
+ });
+ };
+
+ // Sets the select_all checkbox behaviour :
+ $('#select_all').click(function() {
+ if($(this).attr('checked')){
+ // Check all
+ $('td.filename input:checkbox').attr('checked', true);
+ $('td.filename input:checkbox').parent().parent().addClass('selected');
+ }else{
+ // Uncheck all
+ $('td.filename input:checkbox').attr('checked', false);
+ $('td.filename input:checkbox').parent().parent().removeClass('selected');
+ }
+ processSelection();
+ });
+
+ $('td.filename input:checkbox').live('change',function(event) {
+ if (event.shiftKey) {
+ var last = $(lastChecked).parent().parent().prevAll().length;
+ var first = $(this).parent().parent().prevAll().length;
+ var start = Math.min(first, last);
+ var end = Math.max(first, last);
+ var rows = $(this).parent().parent().parent().children('tr');
+ for (var i = start; i < end; i++) {
+ $(rows).each(function(index) {
+ if (index == i) {
+ var checkbox = $(this).children().children('input:checkbox');
+ $(checkbox).attr('checked', 'checked');
+ $(checkbox).parent().parent().addClass('selected');
+ }
+ });
+ }
+ }
+ var selectedCount=$('td.filename input:checkbox:checked').length;
+ $(this).parent().parent().toggleClass('selected');
+ if(!$(this).attr('checked')){
+ $('#select_all').attr('checked',false);
+ }else{
+ if(selectedCount==$('td.filename input:checkbox').length){
+ $('#select_all').attr('checked',true);
+ }
+ }
+ processSelection();
+ });
+
+ $('.undelete').click('click',function(event) {
+ var spinner = '
';
+ var files=getSelectedFiles('file');
+ var fileslist=files.join(';');
+ var dirlisting=getSelectedFiles('dirlisting')[0];
+
+ for (var i in files) {
+ var undeleteAction = $('tr').filterAttr('data-file',files[i]).children("td.date");
+ undeleteAction[0].innerHTML = undeleteAction[0].innerHTML+spinner;
+ }
+
+ $.post(OC.filePath('files_trashbin','ajax','undelete.php'),
+ {files:fileslist, dirlisting:dirlisting},
+ function(result){
+ for (var i = 0; i < result.data.success.length; i++) {
+ var row = document.getElementById(result.data.success[i].filename);
+ row.parentNode.removeChild(row);
+ }
+ if (result.status != 'success') {
+ OC.dialogs.alert(result.data.message, 'Error');
+ }
+ });
+ });
+
+
+});
+
+function processSelection(){
+ var selected=getSelectedFiles();
+ var selectedFiles=selected.filter(function(el){return el.type=='file'});
+ var selectedFolders=selected.filter(function(el){return el.type=='dir'});
+ if(selectedFiles.length==0 && selectedFolders.length==0) {
+ $('#headerName>span.name').text(t('files','Name'));
+ $('#modified').text(t('files','Deleted'));
+ $('table').removeClass('multiselect');
+ $('.selectedActions').hide();
+ }
+ else {
+ $('.selectedActions').show();
+ var selection='';
+ if(selectedFolders.length>0){
+ if(selectedFolders.length==1){
+ selection+=t('files','1 folder');
+ }else{
+ selection+=t('files','{count} folders',{count: selectedFolders.length});
+ }
+ if(selectedFiles.length>0){
+ selection+=' & ';
+ }
+ }
+ if(selectedFiles.length>0){
+ if(selectedFiles.length==1){
+ selection+=t('files','1 file');
+ }else{
+ selection+=t('files','{count} files',{count: selectedFiles.length});
+ }
+ }
+ $('#headerName>span.name').text(selection);
+ $('#modified').text('');
+ $('table').addClass('multiselect');
+ }
+}
+
+/**
+ * @brief get a list of selected files
+ * @param string property (option) the property of the file requested
+ * @return array
+ *
+ * possible values for property: name, mime, size and type
+ * if property is set, an array with that property for each file is returnd
+ * if it's ommited an array of objects with all properties is returned
+ */
+function getSelectedFiles(property){
+ var elements=$('td.filename input:checkbox:checked').parent().parent();
+ var files=[];
+ elements.each(function(i,element){
+ var file={
+ name:$(element).attr('data-filename'),
+ file:$(element).attr('data-file'),
+ timestamp:$(element).attr('data-timestamp'),
+ type:$(element).attr('data-type'),
+ dirlisting:$(element).attr('data-dirlisting')
+ };
+ if(property){
+ files.push(file[property]);
+ }else{
+ files.push(file);
+ }
+ });
+ return files;
+}
\ No newline at end of file
diff --git a/apps/files_trashbin/l10n/.gitkeep b/apps/files_trashbin/l10n/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/apps/files_trashbin/lib/hooks.php b/apps/files_trashbin/lib/hooks.php
new file mode 100644
index 00000000000..d3bee105b51
--- /dev/null
+++ b/apps/files_trashbin/lib/hooks.php
@@ -0,0 +1,45 @@
+.
+ *
+ */
+
+/**
+ * This class contains all hooks.
+ */
+
+namespace OCA_Trash;
+
+class Hooks {
+
+ /**
+ * @brief Copy files to trash bin
+ * @param array
+ *
+ * This function is connected to the delete signal of OC_Filesystem
+ * to copy the file to the trash bin
+ */
+ public static function remove_hook($params) {
+
+ if ( \OCP\App::isEnabled('files_trashbin') ) {
+ $path = $params['path'];
+ Trashbin::move2trash($path);
+ }
+ }
+}
diff --git a/apps/files_trashbin/lib/trash.php b/apps/files_trashbin/lib/trash.php
new file mode 100644
index 00000000000..a7eff3d44e0
--- /dev/null
+++ b/apps/files_trashbin/lib/trash.php
@@ -0,0 +1,264 @@
+.
+ *
+ */
+
+namespace OCA_Trash;
+
+class Trashbin {
+
+ const DEFAULT_RETENTION_OBLIGATION=180; // how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
+ /**
+ * move file to the trash bin
+ *
+ * @param $file_path path to the deleted file/directory relative to the files root directory
+ */
+ public static function move2trash($file_path) {
+ $user = \OCP\User::getUser();
+ $view = new \OC_FilesystemView('/'. $user);
+ if (!$view->is_dir('files_trashbin')) {
+ $view->mkdir('files_trashbin');
+ $view->mkdir("versions_trashbin");
+ }
+
+ $path_parts = pathinfo($file_path);
+
+ $deleted = $path_parts['basename'];
+ $location = $path_parts['dirname'];
+ $timestamp = time();
+ $mime = $view->getMimeType('files'.$file_path);
+
+ if ( $view->is_dir('files'.$file_path) ) {
+ $type = 'dir';
+ } else {
+ $type = 'file';
+ }
+
+ self::copy_recursive($file_path, 'files_trashbin/'.$deleted.'.d'.$timestamp, $view);
+
+ if ( $view->file_exists('files_trashbin/'.$deleted.'.d'.$timestamp) ) {
+ $query = \OC_DB::prepare("INSERT INTO *PREFIX*files_trash (id,timestamp,location,type,mime,user) VALUES (?,?,?,?,?,?)");
+ $result = $query->execute(array($deleted, $timestamp, $location, $type, $mime, $user));
+ if ( !$result ) { // if file couldn't be added to the database than also don't store it in the trash bin.
+ $view->deleteAll('files_trashbin/'.$deleted.'.d'.$timestamp);
+ \OC_Log::write('files_trashbin', 'trash bin database couldn\'t be updated', \OC_log::ERROR);
+ return;
+ }
+
+ if ( \OCP\App::isEnabled('files_versions') ) {
+ if ( $view->is_dir('files_versions'.$file_path) ) {
+ $view->rename('files_versions'.$file_path, 'versions_trashbin/'. $deleted.'.d'.$timestamp);
+ } else if ( $versions = \OCA_Versions\Storage::getVersions($file_path) ) {
+ foreach ($versions as $v) {
+ $view->rename('files_versions'.$v['path'].'.v'.$v['version'], 'versions_trashbin/'. $deleted.'.v'.$v['version'].'.d'.$timestamp);
+ }
+ }
+ }
+ } else {
+ \OC_Log::write('files_trashbin', 'Couldn\'t move '.$file_path.' to the trash bin' , \OC_log::ERROR);
+ }
+
+ self::expire();
+ }
+
+
+ /**
+ * restore files from trash bin
+ * @param $file path to the deleted file
+ * @param $filename name of the file
+ * @param $timestamp time when the file was deleted
+ */
+ public static function restore($file, $filename, $timestamp) {
+
+ $user = \OCP\User::getUser();
+ $view = new \OC_FilesystemView('/'.$user);
+
+ if ( $timestamp ) {
+ $query = \OC_DB::prepare('SELECT location,type FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
+ $result = $query->execute(array($user,$filename,$timestamp))->fetchAll();
+ if ( count($result) != 1 ) {
+ \OC_Log::write('files_trashbin', 'trash bin database inconsistent!', \OC_Log::ERROR);
+ return false;
+ }
+
+ // if location no longer exists, restore file in the root directory
+ $location = $result[0]['location'];
+ if ( $result[0]['location'] != '/' &&
+ (!$view->is_dir('files'.$result[0]['location']) ||
+ !$view->isUpdatable('files'.$result[0]['location'])) ) {
+ $location = '';
+ }
+ } else {
+ $path_parts = pathinfo($filename);
+ $result[] = array(
+ 'location' => $path_parts['dirname'],
+ 'type' => $view->is_dir('/files_trashbin/'.$file) ? 'dir' : 'files',
+ );
+ $location = '';
+ }
+
+ $source = \OC_Filesystem::normalizePath('files_trashbin/'.$file);
+ $target = \OC_Filesystem::normalizePath('files/'.$location.'/'.$filename);
+
+ // we need a extension in case a file/dir with the same name already exists
+ $ext = self::getUniqueExtension($location, $filename, $view);
+ $mtime = $view->filemtime($source);
+ if( $view->rename($source, $target.$ext) ) {
+ $view->touch($target.$ext, $mtime);
+ // if versioning app is enabled, copy versions from the trash bin back to the original location
+ if ( \OCP\App::isEnabled('files_versions') ) {
+ if ( $result[0]['type'] == 'dir' ) {
+ $view->rename(\OC_Filesystem::normalizePath('versions_trashbin/'. $file), \OC_Filesystem::normalizePath('files_versions/'.$location.'/'.$filename.$ext));
+ } else if ( $versions = self::getVersionsFromTrash($file, $timestamp) ) {
+ foreach ($versions as $v) {
+ if ($timestamp ) {
+ $view->rename('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
+ } else {
+ $view->rename('versions_trashbin/'.$file.'.v'.$v, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
+ }
+ }
+ }
+ }
+
+ if ( $timestamp ) {
+ $query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
+ $query->execute(array($user,$filename,$timestamp));
+ }
+
+ return true;
+ } else {
+ \OC_Log::write('files_trashbin', 'Couldn\'t restore file from trash bin, '.$filename , \OC_log::ERROR);
+ }
+
+ return false;
+ }
+
+ /**
+ * clean up the trash bin
+ */
+ private static function expire() {
+
+ $view = new \OC_FilesystemView('/'.\OCP\User::getUser());
+ $user = \OCP\User::getUser();
+
+ $query = \OC_DB::prepare('SELECT location,type,id,timestamp FROM *PREFIX*files_trash WHERE user=?');
+ $result = $query->execute(array($user))->fetchAll();
+
+ $retention_obligation = \OC_Config::getValue('trashbin_retention_obligation', self::DEFAULT_RETENTION_OBLIGATION);
+
+ $limit = time() - ($retention_obligation * 86400);
+
+ foreach ( $result as $r ) {
+ $timestamp = $r['timestamp'];
+ $filename = $r['id'];
+ if ( $r['timestamp'] < $limit ) {
+ $view->unlink('files_trashbin/'.$filename.'.d'.$timestamp);
+ if ($r['type'] == 'dir') {
+ $view->unlink('versions_trashbin/'.$filename.'.d'.$timestamp);
+ } else if ( $versions = self::getVersionsFromTrash($filename, $timestamp) ) {
+ foreach ($versions as $v) {
+ $view->unlink('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp);
+ }
+ }
+ }
+ }
+
+ $query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND timestamp');
+ $query->execute(array($user,$limit));
+ }
+
+ /**
+ * recursive copy to copy a whole directory
+ *
+ * @param $source source path, relative to the users files directory
+ * @param $destination destination path relative to the users root directoy
+ * @param $view file view for the users root directory
+ */
+ private static function copy_recursive( $source, $destination, $view ) {
+ if ( $view->is_dir( 'files'.$source ) ) {
+ $view->mkdir( $destination );
+ $view->touch($destination, $view->filemtime('files'.$source));
+ foreach ( \OC_Files::getDirectoryContent($source) as $i ) {
+ $pathDir = $source.'/'.$i['name'];
+ if ( $view->is_dir('files'.$pathDir) ) {
+ self::copy_recursive($pathDir, $destination.'/'.$i['name'], $view);
+ } else {
+ $view->copy( 'files'.$pathDir, $destination . '/' . $i['name'] );
+ $view->touch($destination . '/' . $i['name'], $view->filemtime('files'.$pathDir));
+ }
+ }
+ } else {
+ $view->copy( 'files'.$source, $destination );
+ $view->touch($destination, $view->filemtime('files'.$source));
+ }
+ }
+
+ /**
+ * find all versions which belong to the file we want to restore
+ * @param $filename name of the file which should be restored
+ * @param $timestamp timestamp when the file was deleted
+ */
+ private static function getVersionsFromTrash($filename, $timestamp) {
+ $view = new \OC_FilesystemView('/'.\OCP\User::getUser().'/versions_trashbin');
+ $versionsName = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath($filename);
+ $versions = array();
+
+ if ($timestamp ) {
+ // fetch for old versions
+ $matches = glob( $versionsName.'.v*.d'.$timestamp );
+ $offset = -strlen($timestamp)-2;
+ } else {
+ $matches = glob( $versionsName.'.v*' );
+ }
+
+ foreach( $matches as $ma ) {
+ if ( $timestamp ) {
+ $parts = explode( '.v', substr($ma, 0, $offset) );
+ $versions[] = ( end( $parts ) );
+ } else {
+ $parts = explode( '.v', $ma );
+ $versions[] = ( end( $parts ) );
+ }
+ }
+ return $versions;
+ }
+
+ /**
+ * find unique extension for restored file if a file with the same name already exists
+ * @param $location where the file should be restored
+ * @param $filename name of the file
+ * @param $view filesystem view relative to users root directory
+ * @return string with unique extension
+ */
+ private static function getUniqueExtension($location, $filename, $view) {
+ $ext = '';
+ if ( $view->file_exists('files'.$location.'/'.$filename) ) {
+ $tmpext = '.restored';
+ $ext = $tmpext;
+ $i = 1;
+ while ( $view->file_exists('files'.$location.'/'.$filename.$ext) ) {
+ $ext = $tmpext.$i;
+ $i++;
+ }
+ }
+ return $ext;
+ }
+
+}
diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php
new file mode 100644
index 00000000000..c3e51b4becd
--- /dev/null
+++ b/apps/files_trashbin/templates/index.php
@@ -0,0 +1,34 @@
+
+|
+
+ t( 'Name' ); ?>
+
+
+ |
+ + t( 'Deleted' ); ?> + | +
|---|
t('Help');?>
+
t('Help');?>