summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorris Jobke <hey@morrisjobke.de>2018-09-28 16:03:24 +0200
committerGitHub <noreply@github.com>2018-09-28 16:03:24 +0200
commitd867f9f091933ebc134cc50ba1ed835dbd39d36d (patch)
treeed0d4f75fb529d0bf323dcee9937989f6e7bfe58
parenta23d5240987392f4eb140eefbb81882ef6ae6a5a (diff)
parentc5f77de3e270f3e6ad25e662ab77e1d68eaee67b (diff)
downloadnextcloud-server-d867f9f091933ebc134cc50ba1ed835dbd39d36d.tar.gz
nextcloud-server-d867f9f091933ebc134cc50ba1ed835dbd39d36d.zip
Merge pull request #11037 from nextcloud/trash-webui-dav
Use trashbin dav endpoint to list trash in webui
-rw-r--r--apps/files_trashbin/ajax/delete.php93
-rw-r--r--apps/files_trashbin/ajax/isEmpty.php33
-rw-r--r--apps/files_trashbin/ajax/list.php48
-rw-r--r--apps/files_trashbin/ajax/undelete.php98
-rw-r--r--apps/files_trashbin/appinfo/routes.php10
-rw-r--r--apps/files_trashbin/composer/composer/autoload_classmap.php1
-rw-r--r--apps/files_trashbin/composer/composer/autoload_static.php1
-rw-r--r--apps/files_trashbin/js/app.js83
-rw-r--r--apps/files_trashbin/js/filelist.js202
-rw-r--r--apps/files_trashbin/lib/Sabre/AbstractTrash.php69
-rw-r--r--apps/files_trashbin/lib/Sabre/ITrash.php4
-rw-r--r--apps/files_trashbin/lib/Sabre/PropfindPlugin.php36
-rw-r--r--apps/files_trashbin/lib/Sabre/TrashFile.php37
-rw-r--r--apps/files_trashbin/lib/Sabre/TrashFolder.php27
-rw-r--r--apps/files_trashbin/lib/Sabre/TrashFolderFile.php39
-rw-r--r--apps/files_trashbin/lib/Sabre/TrashFolderFolder.php32
-rw-r--r--apps/files_trashbin/tests/js/filelistSpec.js284
-rw-r--r--build/integration/config/behat.yml20
-rw-r--r--build/integration/features/bootstrap/Trashbin.php166
-rw-r--r--build/integration/features/bootstrap/WebDav.php8
-rw-r--r--build/integration/features/sharing-v1-part3.feature6
-rw-r--r--build/integration/features/trashbin.feature72
-rw-r--r--core/js/files/client.js3
23 files changed, 584 insertions, 788 deletions
diff --git a/apps/files_trashbin/ajax/delete.php b/apps/files_trashbin/ajax/delete.php
deleted file mode 100644
index 5fb69d7f2ee..00000000000
--- a/apps/files_trashbin/ajax/delete.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-use OCP\ILogger;
-
-\OC_JSON::checkLoggedIn();
-\OC_JSON::callCheck();
-\OC::$server->getSession()->close();
-
-$folder = isset($_POST['dir']) ? $_POST['dir'] : '/';
-
-// "empty trash" command
-if (isset($_POST['allfiles']) && (string)$_POST['allfiles'] === 'true'){
- $deleteAll = true;
- if ($folder === '/' || $folder === '') {
- OCA\Files_Trashbin\Trashbin::deleteAll();
- $list = array();
- } else {
- $list[] = $folder;
- $folder = dirname($folder);
- }
-}
-else {
- $deleteAll = false;
- $files = (string)$_POST['files'];
- $list = json_decode($files);
-}
-
-$folder = rtrim($folder, '/') . '/';
-$error = array();
-$success = array();
-
-$i = 0;
-foreach ($list as $file) {
- if ($folder === '/') {
- $file = ltrim($file, '/');
- $delimiter = strrpos($file, '.d');
- $filename = substr($file, 0, $delimiter);
- $timestamp = substr($file, $delimiter+2);
- } else {
- $filename = $folder . '/' . $file;
- $timestamp = null;
- }
-
- OCA\Files_Trashbin\Trashbin::delete($filename, \OCP\User::getUser(), $timestamp);
- if (OCA\Files_Trashbin\Trashbin::file_exists($filename, $timestamp)) {
- $error[] = $filename;
- \OCP\Util::writeLog('trashbin','can\'t delete ' . $filename . ' permanently.', ILogger::ERROR);
- }
- // only list deleted files if not deleting everything
- else if (!$deleteAll) {
- $success[$i]['filename'] = $file;
- $success[$i]['timestamp'] = $timestamp;
- $i++;
- }
-}
-
-if ( $error ) {
- $filelist = '';
- foreach ( $error as $e ) {
- $filelist .= $e.', ';
- }
- $l = \OC::$server->getL10N('files_trashbin');
- $message = $l->t("Couldn't delete %s permanently", array(rtrim($filelist, ', ')));
- \OC_JSON::error(array("data" => array("message" => $message,
- "success" => $success, "error" => $error)));
-} else {
- \OC_JSON::success(array("data" => array("success" => $success)));
-}
diff --git a/apps/files_trashbin/ajax/isEmpty.php b/apps/files_trashbin/ajax/isEmpty.php
deleted file mode 100644
index 73356047e74..00000000000
--- a/apps/files_trashbin/ajax/isEmpty.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-\OC_JSON::checkLoggedIn();
-\OC_JSON::callCheck();
-\OC::$server->getSession()->close();
-
-$trashStatus = OCA\Files_Trashbin\Trashbin::isEmpty(OCP\User::getUser());
-
-\OC_JSON::success(array("data" => array("isEmpty" => $trashStatus)));
-
-
diff --git a/apps/files_trashbin/ajax/list.php b/apps/files_trashbin/ajax/list.php
deleted file mode 100644
index e72c063f428..00000000000
--- a/apps/files_trashbin/ajax/list.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-\OC_JSON::checkLoggedIn();
-\OC::$server->getSession()->close();
-
-// Load the files
-$dir = isset($_GET['dir']) ? (string)$_GET['dir'] : '';
-$sortAttribute = isset($_GET['sort']) ? (string)$_GET['sort'] : 'name';
-$sortDirection = isset($_GET['sortdirection']) ? ($_GET['sortdirection'] === 'desc') : false;
-$data = array();
-
-// make filelist
-try {
- $files = \OCA\Files_Trashbin\Helper::getTrashFiles($dir, \OCP\User::getUser(), $sortAttribute, $sortDirection);
-} catch (Exception $e) {
- http_response_code(404);
- exit();
-}
-
-$encodedDir = \OCP\Util::encodePath($dir);
-
-$data['permissions'] = 0;
-$data['directory'] = $dir;
-$data['files'] = \OCA\Files_Trashbin\Helper::formatFileInfos($files);
-
-\OC_JSON::success(array('data' => $data));
-
diff --git a/apps/files_trashbin/ajax/undelete.php b/apps/files_trashbin/ajax/undelete.php
deleted file mode 100644
index 348148b03bc..00000000000
--- a/apps/files_trashbin/ajax/undelete.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-use OCP\ILogger;
-
-\OC_JSON::checkLoggedIn();
-\OC_JSON::callCheck();
-\OC::$server->getSession()->close();
-
-$dir = '/';
-if (isset($_POST['dir'])) {
- $dir = rtrim((string)$_POST['dir'], '/'). '/';
-}
-$allFiles = false;
-if (isset($_POST['allfiles']) && (string)$_POST['allfiles'] === 'true') {
- $allFiles = true;
- $list = array();
- $dirListing = true;
- if ($dir === '' || $dir === '/') {
- $dirListing = false;
- }
- foreach (OCA\Files_Trashbin\Helper::getTrashFiles($dir, \OCP\User::getUser()) as $file) {
- $fileName = $file['name'];
- if (!$dirListing) {
- $fileName .= '.d' . $file['mtime'];
- }
- $list[] = $fileName;
- }
-} else {
- $list = json_decode($_POST['files']);
-}
-
-$error = array();
-$success = array();
-
-$i = 0;
-foreach ($list as $file) {
- $path = $dir . '/' . $file;
- if ($dir === '/') {
- $file = ltrim($file, '/');
- $delimiter = strrpos($file, '.d');
- $filename = substr($file, 0, $delimiter);
- $timestamp = substr($file, $delimiter+2);
- } else {
- $path_parts = pathinfo($file);
- $filename = $path_parts['basename'];
- $timestamp = null;
- }
-
- if ( !OCA\Files_Trashbin\Trashbin::restore($path, $filename, $timestamp) ) {
- $error[] = $filename;
- \OCP\Util::writeLog('trashbin', 'can\'t restore ' . $filename, ILogger::ERROR);
- } else {
- $success[$i]['filename'] = $file;
- $success[$i]['timestamp'] = $timestamp;
- $i++;
- }
-
-}
-
-if ( $error ) {
- $filelist = '';
- foreach ( $error as $e ) {
- $filelist .= $e.', ';
- }
- $l = OC::$server->getL10N('files_trashbin');
- $message = $l->t("Couldn't restore %s", array(rtrim($filelist, ', ')));
- \OC_JSON::error(array("data" => array("message" => $message,
- "success" => $success, "error" => $error)));
-} else {
- \OC_JSON::success(array("data" => array("success" => $success)));
-}
diff --git a/apps/files_trashbin/appinfo/routes.php b/apps/files_trashbin/appinfo/routes.php
index 21b4bc2d8c9..20d52adf3f0 100644
--- a/apps/files_trashbin/appinfo/routes.php
+++ b/apps/files_trashbin/appinfo/routes.php
@@ -34,13 +34,3 @@ $application->registerRoutes($this, [
],
],
]);
-
-$this->create('files_trashbin_ajax_delete', 'ajax/delete.php')
- ->actionInclude('files_trashbin/ajax/delete.php');
-$this->create('files_trashbin_ajax_isEmpty', 'ajax/isEmpty.php')
- ->actionInclude('files_trashbin/ajax/isEmpty.php');
-$this->create('files_trashbin_ajax_list', 'ajax/list.php')
- ->actionInclude('files_trashbin/ajax/list.php');
-$this->create('files_trashbin_ajax_undelete', 'ajax/undelete.php')
- ->actionInclude('files_trashbin/ajax/undelete.php');
-
diff --git a/apps/files_trashbin/composer/composer/autoload_classmap.php b/apps/files_trashbin/composer/composer/autoload_classmap.php
index 3713de530c6..164d64333ce 100644
--- a/apps/files_trashbin/composer/composer/autoload_classmap.php
+++ b/apps/files_trashbin/composer/composer/autoload_classmap.php
@@ -18,6 +18,7 @@ return array(
'OCA\\Files_Trashbin\\Expiration' => $baseDir . '/../lib/Expiration.php',
'OCA\\Files_Trashbin\\Helper' => $baseDir . '/../lib/Helper.php',
'OCA\\Files_Trashbin\\Hooks' => $baseDir . '/../lib/Hooks.php',
+ 'OCA\\Files_Trashbin\\Sabre\\AbstractTrash' => $baseDir . '/../lib/Sabre/AbstractTrash.php',
'OCA\\Files_Trashbin\\Sabre\\ITrash' => $baseDir . '/../lib/Sabre/ITrash.php',
'OCA\\Files_Trashbin\\Sabre\\PropfindPlugin' => $baseDir . '/../lib/Sabre/PropfindPlugin.php',
'OCA\\Files_Trashbin\\Sabre\\RestoreFolder' => $baseDir . '/../lib/Sabre/RestoreFolder.php',
diff --git a/apps/files_trashbin/composer/composer/autoload_static.php b/apps/files_trashbin/composer/composer/autoload_static.php
index b00778741b3..6ebb8c35f31 100644
--- a/apps/files_trashbin/composer/composer/autoload_static.php
+++ b/apps/files_trashbin/composer/composer/autoload_static.php
@@ -33,6 +33,7 @@ class ComposerStaticInitFiles_Trashbin
'OCA\\Files_Trashbin\\Expiration' => __DIR__ . '/..' . '/../lib/Expiration.php',
'OCA\\Files_Trashbin\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
'OCA\\Files_Trashbin\\Hooks' => __DIR__ . '/..' . '/../lib/Hooks.php',
+ 'OCA\\Files_Trashbin\\Sabre\\AbstractTrash' => __DIR__ . '/..' . '/../lib/Sabre/AbstractTrash.php',
'OCA\\Files_Trashbin\\Sabre\\ITrash' => __DIR__ . '/..' . '/../lib/Sabre/ITrash.php',
'OCA\\Files_Trashbin\\Sabre\\PropfindPlugin' => __DIR__ . '/..' . '/../lib/Sabre/PropfindPlugin.php',
'OCA\\Files_Trashbin\\Sabre\\RestoreFolder' => __DIR__ . '/..' . '/../lib/Sabre/RestoreFolder.php',
diff --git a/apps/files_trashbin/js/app.js b/apps/files_trashbin/js/app.js
index 7cdc157fe47..82e47d510bf 100644
--- a/apps/files_trashbin/js/app.js
+++ b/apps/files_trashbin/js/app.js
@@ -17,12 +17,21 @@ OCA.Trashbin = {};
*/
OCA.Trashbin.App = {
_initialized: false,
+ /** @type {OC.Files.Client} */
+ client: null,
- initialize: function($el) {
+ initialize: function ($el) {
if (this._initialized) {
return;
}
this._initialized = true;
+
+ this.client = new OC.Files.Client({
+ host: OC.getHost(),
+ port: OC.getPort(),
+ root: OC.linkToRemoteBase('dav') + '/trashbin/' + OC.getCurrentUser().uid,
+ useHTTPS: OC.getProtocol() === 'https'
+ });
var urlParams = OC.Util.History.parseUrlQuery();
this.fileList = new OCA.Trashbin.FileList(
$('#app-content-trashbin'), {
@@ -31,22 +40,24 @@ OCA.Trashbin.App = {
scrollTo: urlParams.scrollto,
config: OCA.Files.App.getFilesConfig(),
multiSelectMenu: [
- {
- name: 'restore',
- displayName: t('files', 'Restore'),
- iconClass: 'icon-history',
- },
- {
- name: 'delete',
- displayName: t('files', 'Delete'),
- iconClass: 'icon-delete',
- }
- ]
+ {
+ name: 'restore',
+ displayName: t('files', 'Restore'),
+ iconClass: 'icon-history',
+ },
+ {
+ name: 'delete',
+ displayName: t('files', 'Delete'),
+ iconClass: 'icon-delete',
+ }
+ ],
+ client: this.client
}
);
},
- _createFileActions: function() {
+ _createFileActions: function () {
+ var client = this.client;
var fileActions = new OCA.Files.FileActions();
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
var dir = context.fileList.getCurrentDirectory();
@@ -62,17 +73,19 @@ OCA.Trashbin.App = {
mime: 'all',
permissions: OC.PERMISSION_READ,
iconClass: 'icon-history',
- actionHandler: function(filename, context) {
+ actionHandler: function (filename, context) {
var fileList = context.fileList;
var tr = fileList.findFileEl(filename);
- var deleteAction = tr.children("td.date").children(".action.delete");
- deleteAction.removeClass('icon-delete').addClass('icon-loading-small');
- $.post(OC.filePath('files_trashbin', 'ajax', 'undelete.php'), {
- files: JSON.stringify([filename]),
- dir: fileList.getCurrentDirectory()
- },
- _.bind(fileList._removeCallback, fileList)
- );
+ fileList.showFileBusyState(tr, true);
+ var dir = context.fileList.getCurrentDirectory();
+ client.move(OC.joinPaths('trash', dir, filename), OC.joinPaths('restore', filename), true)
+ .then(
+ fileList._removeCallback.bind(fileList, [filename]),
+ function () {
+ fileList.showFileBusyState(tr, false);
+ OC.Notification.show(t('files_trashbin', 'Error while restoring file from trashbin'));
+ }
+ );
}
});
@@ -82,33 +95,35 @@ OCA.Trashbin.App = {
mime: 'all',
permissions: OC.PERMISSION_READ,
iconClass: 'icon-delete',
- render: function(actionSpec, isDefault, context) {
+ render: function (actionSpec, isDefault, context) {
var $actionLink = fileActions._makeActionLink(actionSpec, context);
$actionLink.attr('original-title', t('files_trashbin', 'Delete permanently'));
$actionLink.children('img').attr('alt', t('files_trashbin', 'Delete permanently'));
context.$file.find('td:last').append($actionLink);
return $actionLink;
},
- actionHandler: function(filename, context) {
+ actionHandler: function (filename, context) {
var fileList = context.fileList;
$('.tipsy').remove();
var tr = fileList.findFileEl(filename);
- var deleteAction = tr.children("td.date").children(".action.delete");
- deleteAction.removeClass('icon-delete').addClass('icon-loading-small');
- $.post(OC.filePath('files_trashbin', 'ajax', 'delete.php'), {
- files: JSON.stringify([filename]),
- dir: fileList.getCurrentDirectory()
- },
- _.bind(fileList._removeCallback, fileList)
- );
+ fileList.showFileBusyState(tr, true);
+ var dir = context.fileList.getCurrentDirectory();
+ client.remove(OC.joinPaths('trash', dir, filename))
+ .then(
+ fileList._removeCallback.bind(fileList, [filename]),
+ function () {
+ fileList.showFileBusyState(tr, false);
+ OC.Notification.show(t('files_trashbin', 'Error while removing file from trashbin'));
+ }
+ );
}
});
return fileActions;
}
};
-$(document).ready(function() {
- $('#app-content-trashbin').one('show', function() {
+$(document).ready(function () {
+ $('#app-content-trashbin').one('show', function () {
var App = OCA.Trashbin.App;
App.initialize($('#app-content-trashbin'));
// force breadcrumb init
diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js
index 324e4d8a7e0..3159506fae9 100644
--- a/apps/files_trashbin/js/filelist.js
+++ b/apps/files_trashbin/js/filelist.js
@@ -9,6 +9,8 @@
*/
(function() {
var DELETED_REGEXP = new RegExp(/^(.+)\.d[0-9]+$/);
+ var FILENAME_PROP = '{http://nextcloud.org/ns}trashbin-filename';
+ var DELETION_TIME_PROP = '{http://nextcloud.org/ns}trashbin-deletion-time';
/**
* Convert a file name in the format filename.d12345 to the real file name.
@@ -36,17 +38,30 @@
* @param [options] map of options
*/
var FileList = function($el, options) {
+ this.client = options.client;
this.initialize($el, options);
};
FileList.prototype = _.extend({}, OCA.Files.FileList.prototype,
/** @lends OCA.Trashbin.FileList.prototype */ {
id: 'trashbin',
appName: t('files_trashbin', 'Deleted files'),
+ /** @type {OC.Files.Client} */
+ client: null,
/**
* @private
*/
initialize: function() {
+ this.client.addFileInfoParser(function(response, data) {
+ var props = response.propStat[0].properties;
+ return {
+ displayName: props[FILENAME_PROP],
+ mtime: parseInt(props[DELETION_TIME_PROP], 10) * 1000,
+ hasPreview: true,
+ path: data.path.substr(6), // remove leading /trash
+ }
+ });
+
var result = OCA.Files.FileList.prototype.initialize.apply(this, arguments);
this.$el.find('.undelete').click('click', _.bind(this._onClickRestoreSelected, this));
@@ -91,23 +106,6 @@
return tr;
},
- _renderRow: function(fileData, options) {
- options = options || {};
- // make a copy to avoid changing original object
- fileData = _.extend({}, fileData);
- var dir = this.getCurrentDirectory();
- var dirListing = dir !== '' && dir !== '/';
- // show deleted time as mtime
- if (fileData.mtime) {
- fileData.mtime = parseInt(fileData.mtime, 10);
- }
- if (!dirListing) {
- fileData.displayName = fileData.name;
- fileData.name = fileData.name + '.d' + Math.floor(fileData.mtime / 1000);
- }
- return OCA.Files.FileList.prototype._renderRow.call(this, fileData, options);
- },
-
getAjaxUrl: function(action, params) {
var q = '';
if (params) {
@@ -140,15 +138,10 @@
this.$el.find('#filestable th').toggleClass('hidden', !exists);
},
- _removeCallback: function(result) {
- if (result.status !== 'success') {
- OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
- }
-
- var files = result.data.success;
+ _removeCallback: function(files) {
var $el;
for (var i = 0; i < files.length; i++) {
- $el = this.remove(OC.basename(files[i].filename), {updateSummary: false});
+ $el = this.remove(OC.basename(files[i]), {updateSummary: false});
this.fileSummary.remove({type: $el.attr('data-type'), size: $el.attr('data-size')});
}
this.fileSummary.update();
@@ -158,97 +151,71 @@
_onClickRestoreSelected: function(event) {
event.preventDefault();
var self = this;
- var allFiles = this.$el.find('.select-all').is(':checked');
- var files = [];
- var params = {};
- this.fileMultiSelectMenu.toggleLoading('restore', true);
- if (allFiles) {
- this.showMask();
- params = {
- allfiles: true,
- dir: this.getCurrentDirectory()
- };
- }
- else {
- files = _.pluck(this.getSelectedFiles(), 'name');
- for (var i = 0; i < files.length; i++) {
- var deleteAction = this.findFileEl(files[i]).children("td.date").children(".action.delete");
- deleteAction.removeClass('icon-delete').addClass('icon-loading-small');
- }
- params = {
- files: JSON.stringify(files),
- dir: this.getCurrentDirectory()
- };
+ var files = _.pluck(this.getSelectedFiles(), 'name');
+ for (var i = 0; i < files.length; i++) {
+ var tr = this.findFileEl(files[i]);
+ this.showFileBusyState(tr, true);
}
- $.post(OC.filePath('files_trashbin', 'ajax', 'undelete.php'),
- params,
- function(result) {
- if (allFiles) {
- if (result.status !== 'success') {
- OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
+ this.fileMultiSelectMenu.toggleLoading('restore', true);
+ var restorePromises = files.map(function(file) {
+ return self.client.move(OC.joinPaths('trash', self.getCurrentDirectory(), file), OC.joinPaths('restore', file), true)
+ .then(
+ function() {
+ self._removeCallback([file]);
}
- self.hideMask();
- // simply remove all files
- self.setFiles([]);
- }
- else {
- self._removeCallback(result);
- }
+ );
+ });
+ return Promise.all(restorePromises).then(
+ function() {
self.fileMultiSelectMenu.toggleLoading('restore', false);
+ },
+ function() {
+ OC.Notification.show(t('files_trashbin', 'Error while restoring files from trashbin'));
}
);
- event.preventDefault();
},
_onClickDeleteSelected: function(event) {
event.preventDefault();
var self = this;
var allFiles = this.$el.find('.select-all').is(':checked');
- var files = [];
- var params = {};
- if (allFiles) {
- params = {
- allfiles: true,
- dir: this.getCurrentDirectory()
- };
- }
- else {
- files = _.pluck(this.getSelectedFiles(), 'name');
- params = {
- files: JSON.stringify(files),
- dir: this.getCurrentDirectory()
- };
+ var files = _.pluck(this.getSelectedFiles(), 'name');
+ for (var i = 0; i < files.length; i++) {
+ var tr = this.findFileEl(files[i]);
+ this.showFileBusyState(tr, true);
}
- this.fileMultiSelectMenu.toggleLoading('delete', true);
if (allFiles) {
- this.showMask();
- }
- else {
- for (var i = 0; i < files.length; i++) {
- var deleteAction = this.findFileEl(files[i]).children("td.date").children(".action.delete");
- deleteAction.removeClass('icon-delete').addClass('icon-loading-small');
- }
- }
-
- $.post(OC.filePath('files_trashbin', 'ajax', 'delete.php'),
- params,
- function(result) {
- if (allFiles) {
- if (result.status !== 'success') {
- OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
- }
+ return this.client.remove(OC.joinPaths('trash', this.getCurrentDirectory()))
+ .then(
+ function() {
self.hideMask();
- // simply remove all files
self.setFiles([]);
+ },
+ function() {
+ OC.Notification.show(t('files_trashbin', 'Error while emptying trashbin'));
}
- else {
- self._removeCallback(result);
- }
+ );
+ } else {
+ this.fileMultiSelectMenu.toggleLoading('delete', true);
+ var deletePromises = files.map(function(file) {
+ return self.client.remove(OC.joinPaths('trash', self.getCurrentDirectory(), file))
+ .then(
+ function() {
+ self._removeCallback([file]);
+ }
+ );
+ });
+ return Promise.all(deletePromises).then(
+ function() {
self.fileMultiSelectMenu.toggleLoading('delete', false);
+ },
+ function() {
+ OC.Notification.show(t('files_trashbin', 'Error while removing files from trashbin'));
}
- );
+ );
+ }
},
_onClickFile: function(event) {
@@ -278,6 +245,13 @@
},
/**
+ * Returns list of webdav properties to request
+ */
+ _getWebdavProperties: function() {
+ return [FILENAME_PROP, DELETION_TIME_PROP].concat(this.filesClient.getPropfindProperties());
+ },
+
+ /**
* Reloads the file list using ajax call
*
* @return ajax call object
@@ -290,39 +264,25 @@
if (this._reloadCall) {
this._reloadCall.abort();
}
- this._reloadCall = $.ajax({
- url: this.getAjaxUrl('list'),
- data: {
- dir : this.getCurrentDirectory(),
- sort: this._sort,
- sortdirection: this._sortDirection
+ this._reloadCall = this.client.getFolderContents(
+ 'trash/' + this.getCurrentDirectory(), {
+ includeParent: false,
+ properties: this._getWebdavProperties()
}
- });
+ );
var callBack = this.reloadCallback.bind(this);
return this._reloadCall.then(callBack, callBack);
},
- reloadCallback: function(result) {
+ reloadCallback: function(status, result) {
delete this._reloadCall;
this.hideMask();
- if (!result || result.status === 'error') {
- // if the error is not related to folder we're trying to load, reload the page to handle logout etc
- if (result.data.error === 'authentication_error' ||
- result.data.error === 'token_expired' ||
- result.data.error === 'application_not_enabled'
- ) {
- OC.redirect(OC.generateUrl('apps/files'));
- }
- OC.Notification.show(result.data.message);
- return false;
- }
-
- if (result.status === 401) {
+ if (status === 401) {
return false;
}
// Firewall Blocked request?
- if (result.status === 403) {
+ if (status === 403) {
// Go home
this.changeDirectory('/');
OC.Notification.show(t('files', 'This operation is forbidden'));
@@ -330,24 +290,24 @@
}
// Did share service die or something else fail?
- if (result.status === 500) {
+ if (status === 500) {
// Go home
this.changeDirectory('/');
OC.Notification.show(t('files', 'This directory is unavailable, please check the logs or contact the administrator'));
return false;
}
- if (result.status === 404) {
+ if (status === 404) {
// go back home
this.changeDirectory('/');
return false;
}
// aborted ?
- if (result.status === 0){
+ if (status === 0){
return true;
}
- this.setFiles(result.data.files);
+ this.setFiles(result);
return true;
},
diff --git a/apps/files_trashbin/lib/Sabre/AbstractTrash.php b/apps/files_trashbin/lib/Sabre/AbstractTrash.php
new file mode 100644
index 00000000000..43f9cc02749
--- /dev/null
+++ b/apps/files_trashbin/lib/Sabre/AbstractTrash.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Trashbin\Sabre;
+
+use OCP\Files\FileInfo;
+
+abstract class AbstractTrash implements ITrash {
+ /** @var FileInfo */
+ protected $data;
+
+ public function __construct(FileInfo $data) {
+ $this->data = $data;
+ }
+
+ public function getFilename(): string {
+ return $this->data->getName();
+ }
+
+ public function getDeletionTime(): int {
+ return $this->data->getMtime();
+ }
+
+ public function getFileId(): int {
+ return $this->data->getId();
+ }
+
+ public function getFileInfo(): FileInfo {
+ return $this->data;
+ }
+
+ public function getSize(): int {
+ return $this->data->getSize();
+ }
+
+ public function getLastModified(): int {
+ return $this->data->getMtime();
+ }
+
+ public function getContentType(): string {
+ return $this->data->getMimetype();
+ }
+
+ public function getETag(): string {
+ return $this->data->getEtag();
+ }
+
+ public function getName(): string {
+ return $this->data->getName();
+ }
+}
diff --git a/apps/files_trashbin/lib/Sabre/ITrash.php b/apps/files_trashbin/lib/Sabre/ITrash.php
index 6db9bccf0a2..49c600c3f18 100644
--- a/apps/files_trashbin/lib/Sabre/ITrash.php
+++ b/apps/files_trashbin/lib/Sabre/ITrash.php
@@ -23,6 +23,8 @@ declare(strict_types=1);
*/
namespace OCA\Files_Trashbin\Sabre;
+use OCP\Files\FileInfo;
+
interface ITrash {
public function restore(): bool;
@@ -35,4 +37,6 @@ interface ITrash {
public function getSize();
public function getFileId(): int;
+
+ public function getFileInfo(): FileInfo;
}
diff --git a/apps/files_trashbin/lib/Sabre/PropfindPlugin.php b/apps/files_trashbin/lib/Sabre/PropfindPlugin.php
index 492035304ba..19da79fd2a3 100644
--- a/apps/files_trashbin/lib/Sabre/PropfindPlugin.php
+++ b/apps/files_trashbin/lib/Sabre/PropfindPlugin.php
@@ -25,6 +25,8 @@ declare(strict_types=1);
namespace OCA\Files_Trashbin\Sabre;
use OCA\DAV\Connector\Sabre\FilesPlugin;
+use OCP\Constants;
+use OCP\IPreview;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\DAV\Server;
@@ -39,7 +41,13 @@ class PropfindPlugin extends ServerPlugin {
/** @var Server */
private $server;
- public function __construct() {
+ /** @var IPreview */
+ private $previewManager;
+
+ public function __construct(
+ IPreview $previewManager
+ ) {
+ $this->previewManager = $previewManager;
}
public function initialize(Server $server) {
@@ -54,11 +62,11 @@ class PropfindPlugin extends ServerPlugin {
return;
}
- $propFind->handle(self::TRASHBIN_FILENAME, function() use ($node) {
+ $propFind->handle(self::TRASHBIN_FILENAME, function () use ($node) {
return $node->getFilename();
});
- $propFind->handle(self::TRASHBIN_ORIGINAL_LOCATION, function() use ($node) {
+ $propFind->handle(self::TRASHBIN_ORIGINAL_LOCATION, function () use ($node) {
return $node->getOriginalLocation();
});
@@ -73,6 +81,28 @@ class PropfindPlugin extends ServerPlugin {
$propFind->handle(FilesPlugin::FILEID_PROPERTYNAME, function () use ($node) {
return $node->getFileId();
});
+
+ $propFind->handle(FilesPlugin::PERMISSIONS_PROPERTYNAME, function () {
+ return 'GD'; // read + delete
+ });
+
+ $propFind->handle(FilesPlugin::GETETAG_PROPERTYNAME, function () use ($node) {
+ // add fake etag, it is only needed to identify the preview image
+ return $node->getLastModified();
+ });
+
+ $propFind->handle(FilesPlugin::INTERNAL_FILEID_PROPERTYNAME, function () use ($node) {
+ // add fake etag, it is only needed to identify the preview image
+ return $node->getFileId();
+ });
+
+ $propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
+ return $this->previewManager->isAvailable($node->getFileInfo());
+ });
+
+ $propFind->handle(FilesPlugin::MOUNT_TYPE_PROPERTYNAME, function () {
+ return '';
+ });
}
}
diff --git a/apps/files_trashbin/lib/Sabre/TrashFile.php b/apps/files_trashbin/lib/Sabre/TrashFile.php
index eba9eee641b..840ca6a1938 100644
--- a/apps/files_trashbin/lib/Sabre/TrashFile.php
+++ b/apps/files_trashbin/lib/Sabre/TrashFile.php
@@ -27,16 +27,13 @@ use OCP\Files\FileInfo;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\IFile;
-class TrashFile implements IFile, ITrash {
+class TrashFile extends AbstractTrash implements IFile, ITrash {
/** @var string */
private $userId;
- /** @var FileInfo */
- private $data;
-
public function __construct(string $userId, FileInfo $data) {
$this->userId = $userId;
- $this->data = $data;
+ parent::__construct($data);
}
public function put($data) {
@@ -47,18 +44,6 @@ class TrashFile implements IFile, ITrash {
return $this->data->getStorage()->fopen($this->data->getInternalPath().'.d'.$this->getLastModified(), 'rb');
}
- public function getContentType(): string {
- return $this->data->getMimetype();
- }
-
- public function getETag(): string {
- return $this->data->getEtag();
- }
-
- public function getSize(): int {
- return $this->data->getSize();
- }
-
public function delete() {
\OCA\Files_Trashbin\Trashbin::delete($this->data->getName(), $this->userId, $this->getLastModified());
}
@@ -71,29 +56,11 @@ class TrashFile implements IFile, ITrash {
throw new Forbidden();
}
- public function getLastModified(): int {
- return $this->data->getMtime();
- }
-
public function restore(): bool {
return \OCA\Files_Trashbin\Trashbin::restore($this->getName(), $this->data->getName(), $this->getLastModified());
}
- public function getFilename(): string {
- return $this->data->getName();
- }
-
public function getOriginalLocation(): string {
return $this->data['extraData'];
}
-
- public function getDeletionTime(): int {
- return $this->getLastModified();
- }
-
- public function getFileId(): int {
- return $this->data->getId();
- }
-
-
}
diff --git a/apps/files_trashbin/lib/Sabre/TrashFolder.php b/apps/files_trashbin/lib/Sabre/TrashFolder.php
index 6b7d71b80ee..d884eefcc9f 100644
--- a/apps/files_trashbin/lib/Sabre/TrashFolder.php
+++ b/apps/files_trashbin/lib/Sabre/TrashFolder.php
@@ -28,16 +28,13 @@ use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ICollection;
-class TrashFolder implements ICollection, ITrash {
+class TrashFolder extends AbstractTrash implements ICollection, ITrash {
/** @var string */
private $userId;
- /** @var FileInfo */
- private $data;
-
public function __construct(string $root, string $userId, FileInfo $data) {
$this->userId = $userId;
- $this->data = $data;
+ parent::__construct($data);
}
public function createFile($name, $data = null) {
@@ -100,31 +97,11 @@ class TrashFolder implements ICollection, ITrash {
throw new Forbidden();
}
- public function getLastModified(): int {
- return $this->data->getMtime();
- }
-
public function restore(): bool {
return \OCA\Files_Trashbin\Trashbin::restore($this->getName(), $this->data->getName(), $this->getLastModified());
}
- public function getFilename(): string {
- return $this->data->getName();
- }
-
public function getOriginalLocation(): string {
return $this->data['extraData'];
}
-
- public function getDeletionTime(): int {
- return $this->getLastModified();
- }
-
- public function getSize(): int {
- return $this->data->getSize();
- }
-
- public function getFileId(): int {
- return $this->data->getId();
- }
}
diff --git a/apps/files_trashbin/lib/Sabre/TrashFolderFile.php b/apps/files_trashbin/lib/Sabre/TrashFolderFile.php
index 921c98b02fb..3e28d048b42 100644
--- a/apps/files_trashbin/lib/Sabre/TrashFolderFile.php
+++ b/apps/files_trashbin/lib/Sabre/TrashFolderFile.php
@@ -27,16 +27,13 @@ use OCP\Files\FileInfo;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\IFile;
-class TrashFolderFile implements IFile, ITrash {
+class TrashFolderFile extends AbstractTrash implements IFile, ITrash {
/** @var string */
private $root;
/** @var string */
private $userId;
- /** @var FileInfo */
- private $data;
-
/** @var string */
private $location;
@@ -46,8 +43,8 @@ class TrashFolderFile implements IFile, ITrash {
string $location) {
$this->root = $root;
$this->userId = $userId;
- $this->data = $data;
$this->location = $location;
+ parent::__construct($data);
}
public function put($data) {
@@ -58,51 +55,19 @@ class TrashFolderFile implements IFile, ITrash {
return $this->data->getStorage()->fopen($this->data->getInternalPath(), 'rb');
}
- public function getContentType(): string {
- return $this->data->getMimetype();
- }
-
- public function getETag(): string {
- return $this->data->getEtag();
- }
-
- public function getSize(): int {
- return $this->data->getSize();
- }
-
public function delete() {
\OCA\Files_Trashbin\Trashbin::delete($this->root . '/' . $this->getName(), $this->userId, null);
}
- public function getName(): string {
- return $this->data->getName();
- }
-
public function setName($name) {
throw new Forbidden();
}
- public function getLastModified(): int {
- return $this->data->getMtime();
- }
-
public function restore(): bool {
return \OCA\Files_Trashbin\Trashbin::restore($this->root . '/' . $this->getName(), $this->data->getName(), null);
}
- public function getFilename(): string {
- return $this->data->getName();
- }
-
public function getOriginalLocation(): string {
return $this->location . '/' . $this->getFilename();
}
-
- public function getDeletionTime(): int {
- return $this->getLastModified();
- }
-
- public function getFileId(): int {
- return $this->data->getId();
- }
}
diff --git a/apps/files_trashbin/lib/Sabre/TrashFolderFolder.php b/apps/files_trashbin/lib/Sabre/TrashFolderFolder.php
index 2fe75479c1b..4ee9a0e2db0 100644
--- a/apps/files_trashbin/lib/Sabre/TrashFolderFolder.php
+++ b/apps/files_trashbin/lib/Sabre/TrashFolderFolder.php
@@ -28,7 +28,7 @@ use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ICollection;
-class TrashFolderFolder implements ICollection, ITrash {
+class TrashFolderFolder extends AbstractTrash implements ICollection, ITrash {
/** @var string */
private $root;
@@ -36,9 +36,6 @@ class TrashFolderFolder implements ICollection, ITrash {
/** @var string */
private $userId;
- /** @var FileInfo */
- private $data;
-
/** @var string */
private $location;
@@ -48,8 +45,8 @@ class TrashFolderFolder implements ICollection, ITrash {
string $location) {
$this->root = $root;
$this->userId = $userId;
- $this->data = $data;
$this->location = $location;
+ parent::__construct($data);
}
public function createFile($name, $data = null) {
@@ -104,40 +101,15 @@ class TrashFolderFolder implements ICollection, ITrash {
\OCA\Files_Trashbin\Trashbin::delete($this->root . '/' . $this->getName(), $this->userId, null);
}
- public function getName(): string {
- return $this->data->getName();
-
- }
-
public function setName($name) {
throw new Forbidden();
}
- public function getLastModified(): int {
- return $this->data->getMtime();
- }
-
public function restore(): bool {
return \OCA\Files_Trashbin\Trashbin::restore($this->root . '/' . $this->getName(), $this->data->getName(), null);
}
- public function getFilename(): string {
- return $this->data->getName();
- }
-
public function getOriginalLocation(): string {
return $this->location . '/' . $this->getFilename();
}
-
- public function getDeletionTime(): int {
- return $this->getLastModified();
- }
-
- public function getSize(): int {
- return $this->data->getSize();
- }
-
- public function getFileId(): int {
- return $this->data->getId();
- }
}
diff --git a/apps/files_trashbin/tests/js/filelistSpec.js b/apps/files_trashbin/tests/js/filelistSpec.js
index c5b1018856b..e9b519ad1fe 100644
--- a/apps/files_trashbin/tests/js/filelistSpec.js
+++ b/apps/files_trashbin/tests/js/filelistSpec.js
@@ -1,31 +1,38 @@
/**
-* ownCloud
-*
-* @author Vincent Petry
-* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*
-*/
+ * ownCloud
+ *
+ * @author Vincent Petry
+ * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
-describe('OCA.Trashbin.FileList tests', function() {
- var testFiles, alertStub, notificationStub, fileList;
+describe('OCA.Trashbin.FileList tests', function () {
+ var testFiles, alertStub, notificationStub, fileList, client;
- beforeEach(function() {
+ beforeEach(function () {
alertStub = sinon.stub(OC.dialogs, 'alert');
notificationStub = sinon.stub(OC.Notification, 'show');
+ client = new OC.Files.Client({
+ host: 'localhost',
+ port: 80,
+ root: '/remote.php/dav/trashbin/user',
+ useHTTPS: OC.getProtocol() === 'https'
+ });
+
// init parameters and test table elements
$('#testArea').append(
'<div id="app-content-trashbin">' +
@@ -59,21 +66,24 @@ describe('OCA.Trashbin.FileList tests', function() {
testFiles = [{
id: 1,
type: 'file',
- name: 'One.txt',
+ name: 'One.txt.d11111',
+ displayName: 'One.txt',
mtime: 11111000,
mimetype: 'text/plain',
etag: 'abc'
}, {
id: 2,
type: 'file',
- name: 'Two.jpg',
+ name: 'Two.jpg.d22222',
+ displayName: 'Two.jpg',
mtime: 22222000,
mimetype: 'image/jpeg',
etag: 'def',
}, {
id: 3,
type: 'file',
- name: 'Three.pdf',
+ name: 'Three.pdf.d33333',
+ displayName: 'Three.pdf',
mtime: 33333000,
mimetype: 'application/pdf',
etag: '123',
@@ -81,7 +91,8 @@ describe('OCA.Trashbin.FileList tests', function() {
id: 4,
type: 'dir',
mtime: 99999000,
- name: 'somedir',
+ name: 'somedir.d99999',
+ displayName: 'somedir',
mimetype: 'httpd/unix-directory',
etag: '456'
}];
@@ -92,20 +103,21 @@ describe('OCA.Trashbin.FileList tests', function() {
$('#app-content-trashbin'), {
fileActions: fileActions,
multiSelectMenu: [{
- name: 'restore',
- displayName: t('files', 'Restore'),
- iconClass: 'icon-history',
- },
+ name: 'restore',
+ displayName: t('files', 'Restore'),
+ iconClass: 'icon-history',
+ },
{
name: 'delete',
displayName: t('files', 'Delete'),
iconClass: 'icon-delete',
}
- ]
+ ],
+ client: client
}
);
});
- afterEach(function() {
+ afterEach(function () {
testFiles = undefined;
fileList.destroy();
fileList = undefined;
@@ -114,17 +126,17 @@ describe('OCA.Trashbin.FileList tests', function() {
notificationStub.restore();
alertStub.restore();
});
- describe('Initialization', function() {
- it('Sorts by mtime by default', function() {
+ describe('Initialization', function () {
+ it('Sorts by mtime by default', function () {
expect(fileList._sort).toEqual('mtime');
expect(fileList._sortDirection).toEqual('desc');
});
- it('Always returns read and delete permission', function() {
+ it('Always returns read and delete permission', function () {
expect(fileList.getDirectoryPermissions()).toEqual(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
});
});
- describe('Breadcrumbs', function() {
- beforeEach(function() {
+ describe('Breadcrumbs', function () {
+ beforeEach(function () {
var data = {
status: 'success',
data: {
@@ -133,13 +145,13 @@ describe('OCA.Trashbin.FileList tests', function() {
}
};
fakeServer.respondWith(/\/index\.php\/apps\/files_trashbin\/ajax\/list.php\?dir=%2Fsubdir/, [
- 200, {
- "Content-Type": "application/json"
- },
- JSON.stringify(data)
+ 200, {
+ "Content-Type": "application/json"
+ },
+ JSON.stringify(data)
]);
});
- it('links the breadcrumb to the trashbin view', function() {
+ it('links the breadcrumb to the trashbin view', function () {
fileList.changeDirectory('/subdir', false, true);
fakeServer.respond();
var $crumbs = fileList.$el.find('#controls .crumb');
@@ -152,8 +164,8 @@ describe('OCA.Trashbin.FileList tests', function() {
.toEqual(OC.webroot + '/index.php/apps/files?view=trashbin&dir=/subdir');
});
});
- describe('Rendering rows', function() {
- it('renders rows with the correct data when in root', function() {
+ describe('Rendering rows', function () {
+ it('renders rows with the correct data when in root', function () {
// dir listing is false when in root
$('#dir').val('/');
fileList.setFiles(testFiles);
@@ -174,7 +186,7 @@ describe('OCA.Trashbin.FileList tests', function() {
expect(fileList.findFileEl('One.txt.d11111')[0]).toEqual($tr[0]);
});
- it('renders rows with the correct data when in root after calling setFiles with the same data set', function() {
+ it('renders rows with the correct data when in root after calling setFiles with the same data set', function () {
// dir listing is false when in root
$('#dir').val('/');
fileList.setFiles(testFiles);
@@ -196,11 +208,14 @@ describe('OCA.Trashbin.FileList tests', function() {
expect(fileList.findFileEl('One.txt.d11111')[0]).toEqual($tr[0]);
});
- it('renders rows with the correct data when in subdirectory', function() {
+ it('renders rows with the correct data when in subdirectory', function () {
// dir listing is true when in a subdir
$('#dir').val('/subdir');
- fileList.setFiles(testFiles);
+ fileList.setFiles(testFiles.map(function (file) {
+ file.name = file.displayName;
+ return file;
+ }));
var $rows = fileList.$el.find('tbody tr');
var $tr = $rows.eq(0);
expect($rows.length).toEqual(4);
@@ -218,42 +233,42 @@ describe('OCA.Trashbin.FileList tests', function() {
expect(fileList.findFileEl('One.txt')[0]).toEqual($tr[0]);
});
- it('does not render a size column', function() {
+ it('does not render a size column', function () {
expect(fileList.$el.find('tbody tr .filesize').length).toEqual(0);
});
});
- describe('File actions', function() {
- describe('Deleting single files', function() {
+ describe('File actions', function () {
+ describe('Deleting single files', function () {
// TODO: checks ajax call
// TODO: checks spinner
// TODO: remove item after delete
// TODO: bring back item if delete failed
});
- describe('Restoring single files', function() {
+ describe('Restoring single files', function () {
// TODO: checks ajax call
// TODO: checks spinner
// TODO: remove item after restore
// TODO: bring back item if restore failed
});
});
- describe('file previews', function() {
+ describe('file previews', function () {
// TODO: check that preview URL is going through files_trashbin
});
- describe('loading file list', function() {
+ describe('loading file list', function () {
// TODO: check that ajax URL is going through files_trashbin
});
- describe('breadcrumbs', function() {
+ describe('breadcrumbs', function () {
// TODO: test label + URL
});
- describe('elementToFile', function() {
+ describe('elementToFile', function () {
var $tr;
- beforeEach(function() {
+ beforeEach(function () {
fileList.setFiles(testFiles);
$tr = fileList.findFileEl('One.txt.d11111');
});
- it('converts data attributes to file info structure', function() {
+ it('converts data attributes to file info structure', function () {
var fileInfo = fileList.elementToFile($tr);
expect(fileInfo.id).toEqual(1);
expect(fileInfo.name).toEqual('One.txt.d11111');
@@ -265,8 +280,8 @@ describe('OCA.Trashbin.FileList tests', function() {
expect(fileInfo.type).toEqual('file');
});
});
- describe('Global Actions', function() {
- beforeEach(function() {
+ describe('Global Actions', function () {
+ beforeEach(function () {
fileList.setFiles(testFiles);
fileList.findFileEl('One.txt.d11111').find('input:checkbox').click();
fileList.findFileEl('Three.pdf.d33333').find('input:checkbox').click();
@@ -274,12 +289,12 @@ describe('OCA.Trashbin.FileList tests', function() {
fileList.$el.find('.actions-selected').click();
});
- afterEach(function() {
+ afterEach(function () {
fileList.$el.find('.actions-selected').click();
});
- describe('Delete', function() {
- it('Shows trashbin actions', function() {
+ describe('Delete', function () {
+ it('Shows trashbin actions', function () {
// visible because a few files were selected
expect($('.selectedActions').is(':visible')).toEqual(true);
expect($('.selectedActions .item-delete').is(':visible')).toEqual(true);
@@ -301,99 +316,82 @@ describe('OCA.Trashbin.FileList tests', function() {
expect($('.selectedActions .item-delete').is(':visible')).toEqual(false);
expect($('.selectedActions .item-restore').is(':visible')).toEqual(false);
});
- it('Deletes selected files when "Delete" clicked', function() {
+ it('Deletes selected files when "Delete" clicked', function () {
var request;
- var $deleteLink = $('.selectedActions .filesSelectMenu .delete');
- $deleteLink.click();
- expect($deleteLink.find('.icon-loading-small').length).toEqual(1);
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/delete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/', files: '["One.txt.d11111","Three.pdf.d33333","somedir.d99999"]'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- success: [
- {filename: 'One.txt.d11111'},
- {filename: 'Three.pdf.d33333'},
- {filename: 'somedir.d99999'}
- ]
- }
- })
- );
- expect($deleteLink.find('.icon-loading-small').length).toEqual(0);
- expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0);
- expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0);
- expect(fileList.findFileEl('somedir.d99999').length).toEqual(0);
- expect(fileList.findFileEl('Two.jpg.d22222').length).toEqual(1);
+ var promise = fileList._onClickDeleteSelected({
+ preventDefault: function () {
+ }
+ });
+ var files = ["One.txt.d11111", "Three.pdf.d33333", "somedir.d99999"];
+ expect(fakeServer.requests.length).toEqual(files.length);
+ for (var i = 0; i < files.length; i++) {
+ request = fakeServer.requests[i];
+ expect(request.url).toEqual(OC.webroot + '/remote.php/dav/trashbin/user/trash/' + files[i]);
+ request.respond(200);
+ }
+ return promise.then(function () {
+ expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0);
+ expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0);
+ expect(fileList.findFileEl('somedir.d99999').length).toEqual(0);
+ expect(fileList.findFileEl('Two.jpg.d22222').length).toEqual(1);
+ });
});
- it('Deletes all files when all selected when "Delete" clicked', function() {
+ it('Deletes all files when all selected when "Delete" clicked', function () {
var request;
$('.select-all').click();
- $('.selectedActions .filesSelectMenu .delete').click();
+ var promise = fileList._onClickDeleteSelected({
+ preventDefault: function () {
+ }
+ });
expect(fakeServer.requests.length).toEqual(1);
request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/delete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/', allfiles: 'true'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
- expect(fileList.isEmpty).toEqual(true);
+ expect(request.url).toEqual(OC.webroot + '/remote.php/dav/trashbin/user/trash');
+ request.respond(200);
+ return promise.then(function () {
+ expect(fileList.isEmpty).toEqual(true);
+ });
});
});
- describe('Restore', function() {
- it('Restores selected files when "Restore" clicked', function() {
+ describe('Restore', function () {
+ it('Restores selected files when "Restore" clicked', function () {
var request;
- var $restoreLink = $('.selectedActions .filesSelectMenu .restore');
- $restoreLink.click();
- expect($restoreLink.find('.icon-loading-small').length).toEqual(1);
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/undelete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/', files: '["One.txt.d11111","Three.pdf.d33333","somedir.d99999"]'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- success: [
- {filename: 'One.txt.d11111'},
- {filename: 'Three.pdf.d33333'},
- {filename: 'somedir.d99999'}
- ]
- }
- })
- );
- expect($restoreLink.find('.icon-loading-small').length).toEqual(0);
- expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0);
- expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0);
- expect(fileList.findFileEl('somedir.d99999').length).toEqual(0);
- expect(fileList.findFileEl('Two.jpg.d22222').length).toEqual(1);
+ var promise = fileList._onClickRestoreSelected({
+ preventDefault: function () {
+ }
+ });
+ var files = ["One.txt.d11111", "Three.pdf.d33333", "somedir.d99999"];
+ expect(fakeServer.requests.length).toEqual(files.length);
+ for (var i = 0; i < files.length; i++) {
+ request = fakeServer.requests[i];
+ expect(request.url).toEqual(OC.webroot + '/remote.php/dav/trashbin/user/trash/' + files[i]);
+ expect(request.requestHeaders.Destination).toEqual(OC.webroot + '/remote.php/dav/trashbin/user/restore/' + files[i]);
+ request.respond(200);
+ }
+ return promise.then(function() {
+ expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0);
+ expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0);
+ expect(fileList.findFileEl('somedir.d99999').length).toEqual(0);
+ expect(fileList.findFileEl('Two.jpg.d22222').length).toEqual(1);
+ });
});
- it('Restores all files when all selected when "Restore" clicked', function() {
+ it('Restores all files when all selected when "Restore" clicked', function () {
var request;
$('.select-all').click();
- $('.selectedActions .filesSelectMenu .restore').click();
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/undelete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/', allfiles: 'true'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
- expect(fileList.isEmpty).toEqual(true);
+ var promise = fileList._onClickRestoreSelected({
+ preventDefault: function () {
+ }
+ });
+ var files = ["One.txt.d11111", "Two.jpg.d22222", "Three.pdf.d33333", "somedir.d99999"];
+ expect(fakeServer.requests.length).toEqual(files.length);
+ for (var i = 0; i < files.length; i++) {
+ request = fakeServer.requests[i];
+ expect(request.url).toEqual(OC.webroot + '/remote.php/dav/trashbin/user/trash/' + files[i]);
+ expect(request.requestHeaders.Destination).toEqual(OC.webroot + '/remote.php/dav/trashbin/user/restore/' + files[i]);
+ request.respond(200);
+ }
+ return promise.then(function() {
+ expect(fileList.isEmpty).toEqual(true);
+ });
});
});
});
diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml
index 428d4d45b78..7fd3686b8bb 100644
--- a/build/integration/config/behat.yml
+++ b/build/integration/config/behat.yml
@@ -1,10 +1,10 @@
default:
autoload:
- '': %paths.base%/../features/bootstrap
+ '': "%paths.base%/../features/bootstrap"
suites:
default:
paths:
- - %paths.base%/../features
+ - "%paths.base%/../features"
contexts:
- FeatureContext:
baseUrl: http://localhost:8080/ocs/
@@ -27,7 +27,7 @@ default:
ocPath: ../../
federation:
paths:
- - %paths.base%/../federation_features
+ - "%paths.base%/../federation_features"
contexts:
- FederationContext:
baseUrl: http://localhost:8080/ocs/
@@ -37,7 +37,7 @@ default:
regular_user_password: 123456
capabilities:
paths:
- - %paths.base%/../capabilities_features
+ - "%paths.base%/../capabilities_features"
contexts:
- CapabilitiesContext:
baseUrl: http://localhost:8080/ocs/
@@ -47,7 +47,7 @@ default:
regular_user_password: 123456
sharees:
paths:
- - %paths.base%/../sharees_features
+ - "%paths.base%/../sharees_features"
contexts:
- ShareesContext:
baseUrl: http://localhost:8080/ocs/
@@ -57,7 +57,7 @@ default:
regular_user_password: 123456
setup:
paths:
- - %paths.base%/../setup_features
+ - "%paths.base%/../setup_features"
contexts:
- SetupContext:
baseUrl: http://localhost:8080/ocs/
@@ -67,7 +67,7 @@ default:
regular_user_password: 123456
filesdrop:
paths:
- - %paths.base%/../filesdrop_features
+ - "%paths.base%/../filesdrop_features"
contexts:
- FilesDropContext:
baseUrl: http://localhost:8080
@@ -77,7 +77,7 @@ default:
regular_user_password: 123456
ldap:
paths:
- - %paths.base%/../ldap_features
+ - "%paths.base%/../ldap_features"
contexts:
- LDAPContext:
baseUrl: http://localhost:8080
@@ -87,7 +87,7 @@ default:
regular_user_password: what_for
remoteapi:
paths:
- - %paths.base%/../remoteapi_features
+ - "%paths.base%/../remoteapi_features"
contexts:
- FeatureContext:
baseUrl: http://localhost:8080/ocs/
@@ -100,4 +100,4 @@ default:
extensions:
jarnaiz\JUnitFormatter\JUnitFormatterExtension:
filename: report.xml
- outputDir: %paths.base%/../output/
+ outputDir: "%paths.base%/../output/"
diff --git a/build/integration/features/bootstrap/Trashbin.php b/build/integration/features/bootstrap/Trashbin.php
index 49d547a5edc..8e4d0892bc8 100644
--- a/build/integration/features/bootstrap/Trashbin.php
+++ b/build/integration/features/bootstrap/Trashbin.php
@@ -20,8 +20,6 @@
*
*/
-use GuzzleHttp\Client;
-use GuzzleHttp\Message\ResponseInterface;
use PHPUnit\Framework\Assert;
require __DIR__ . '/../../vendor/autoload.php';
@@ -30,16 +28,46 @@ require __DIR__ . '/../../vendor/autoload.php';
* Trashbin functions
*/
trait Trashbin {
+ use WebDav;
/**
* @When User :user empties trashbin
* @param string $user user
*/
public function emptyTrashbin($user) {
- $this->asAn($user);
- $body = new \Behat\Gherkin\Node\TableNode([['allfiles', 'true'], ['dir', '%2F']]);
- $this->sendingToWithDirectUrl('POST', "/index.php/apps/files_trashbin/ajax/delete.php", $body);
- $this->theHTTPStatusCodeShouldBe('200');
+ $client = $this->getSabreClient($user);
+ $response = $client->request('DELETE', $this->makeSabrePath($user, 'trash', 'trashbin'));
+ Assert::assertEquals(204, $response['statusCode']);
+ }
+
+ private function findFullTrashname($user, $name) {
+ $rootListing = $this->listTrashbinFolder($user, '/');
+
+ foreach ($rootListing as $href => $rootItem) {
+ if ($rootItem['{http://nextcloud.org/ns}trashbin-filename'] === $name) {
+ return basename($href);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the full /startofpath.dxxxx/rest/of/path from /startofpath/rest/of/path
+ */
+ private function getFullTrashPath($user, $path) {
+ if ($path !== '' && $path !== '/') {
+ $parts = explode('/', $path);
+ $fullName = $this->findFullTrashname($user, $parts[1]);
+ if ($fullName === null) {
+ Assert::fail("cant find $path in trash");
+ return '/dummy_full_path_not_found';
+ }
+ $parts[1] = $fullName;
+
+ $path = implode('/', $parts);
+ }
+ return $path;
}
/**
@@ -49,74 +77,92 @@ trait Trashbin {
* @param string $path path
* @return array response
*/
- public function listTrashbinFolder($user, $path){
- $this->asAn($user);
- $params = '?dir=' . rawurlencode('/' . trim($path, '/'));
- $this->sendingToWithDirectUrl('GET', '/index.php/apps/files_trashbin/ajax/list.php' . $params, null);
- $this->theHTTPStatusCodeShouldBe('200');
-
- $response = json_decode($this->response->getBody(), true);
-
- return $response['data']['files'];
+ public function listTrashbinFolder($user, $path) {
+ $path = $this->getFullTrashPath($user, $path);
+ $client = $this->getSabreClient($user);
+
+ $results = $client->propfind($this->makeSabrePath($user, 'trash' . $path, 'trashbin'), [
+ '{http://nextcloud.org/ns}trashbin-filename',
+ '{http://nextcloud.org/ns}trashbin-original-location',
+ '{http://nextcloud.org/ns}trashbin-deletion-time'
+ ], 1);
+ $results = array_filter($results, function (array $item) {
+ return isset($item['{http://nextcloud.org/ns}trashbin-filename']);
+ });
+ if ($path !== '' && $path !== '/') {
+ array_shift($results);
+ }
+ return $results;
}
/**
- * @Then /^as "([^"]*)" the (file|folder|entry) "([^"]*)" exists in trash$/
+ * @Then /^user "([^"]*)" in trash folder "([^"]*)" should have the following elements$/
* @param string $user
- * @param string $entryText
- * @param string $path
+ * @param string $folder
+ * @param \Behat\Gherkin\Node\TableNode|null $expectedElements
*/
- public function asTheFileOrFolderExistsInTrash($user, $entryText, $path) {
- $path = trim($path, '/');
- $sections = explode('/', $path, 2);
-
- $firstEntry = $this->findFirstTrashedEntry($user, trim($sections[0], '/'));
-
- Assert::assertNotNull($firstEntry);
-
- // query was on the main element ?
- if (count($sections) === 1) {
- // already found, return
- return;
- }
-
- $subdir = trim(dirname($sections[1]), '/');
- if ($subdir !== '' && $subdir !== '.') {
- $subdir = $firstEntry . '/' . $subdir;
- } else {
- $subdir = $firstEntry;
+ public function checkTrashContents($user, $folder, $expectedElements) {
+ $elementList = $this->listTrashbinFolder($user, $folder);
+ $trashContent = array_filter(array_map(function (array $item) {
+ return $item['{http://nextcloud.org/ns}trashbin-filename'];
+ }, $elementList));
+ if ($expectedElements instanceof \Behat\Gherkin\Node\TableNode) {
+ $elementRows = $expectedElements->getRows();
+ $elementsSimplified = $this->simplifyArray($elementRows);
+ foreach ($elementsSimplified as $expectedElement) {
+ $expectedElement = ltrim($expectedElement, '/');
+ if (array_search($expectedElement, $trashContent) === false) {
+ Assert::fail("$expectedElement" . " is not in trash listing");
+ }
+ }
}
+ }
- $listing = $this->listTrashbinFolder($user, $subdir);
- $checkedName = basename($path);
-
- $found = false;
- foreach ($listing as $entry) {
- if ($entry['name'] === $checkedName) {
- $found = true;
- break;
- }
+ /**
+ * @Then /^as "([^"]*)" the (file|folder) "([^"]*)" exists in trash$/
+ * @param string $user
+ * @param string $type
+ * @param string $file
+ */
+ public function checkTrashContains($user, $type, $file) {
+ $parent = dirname($file);
+ if ($parent === '.') {
+ $parent = '/';
}
+ $name = basename($file);
+ $elementList = $this->listTrashbinFolder($user, $parent);
+ $trashContent = array_filter(array_map(function (array $item) {
+ return $item['{http://nextcloud.org/ns}trashbin-filename'];
+ }, $elementList));
- Assert::assertTrue($found);
+ Assert::assertArraySubset([$name], array_values($trashContent));
}
/**
- * Finds the first trashed entry matching the given name
- *
- * @param string $name
- * @return string|null real entry name with timestamp suffix or null if not found
+ * @Then /^user "([^"]*)" in trash folder "([^"]*)" should have (\d+) elements?$/
+ * @param string $user
+ * @param string $folder
+ * @param \Behat\Gherkin\Node\TableNode|null $expectedElements
*/
- private function findFirstTrashedEntry($user, $name) {
- $listing = $this->listTrashbinFolder($user, '/');
-
- foreach ($listing as $entry) {
- if ($entry['name'] === $name) {
- return $entry['name'] . '.d' . ((int)$entry['mtime'] / 1000);
- }
- }
+ public function checkTrashSize($user, $folder, $expectedCount) {
+ $elementList = $this->listTrashbinFolder($user, $folder);
+ Assert::assertEquals($expectedCount, count($elementList));
+ }
- return null;
+ /**
+ * @When /^user "([^"]*)" in restores "([^"]*)" from trash$/
+ * @param string $user
+ * @param string $file
+ */
+ public function restoreFromTrash($user, $file) {
+ $file = $this->getFullTrashPath($user, $file);
+ $url = $this->makeSabrePath($user, 'trash' . $file, 'trashbin');
+ $client = $this->getSabreClient($user);
+ $response = $client->request('MOVE', $url, null, [
+ 'Destination' => $this->makeSabrePath($user, 'restore/' . basename($file), 'trashbin'),
+ ]);
+ Assert::assertEquals(201, $response['statusCode']);
+ return;
}
}
diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php
index 37a398e2aae..b36cdfaea68 100644
--- a/build/integration/features/bootstrap/WebDav.php
+++ b/build/integration/features/bootstrap/WebDav.php
@@ -423,8 +423,12 @@ trait WebDav {
return $parsedResponse;
}
- public function makeSabrePath($user, $path) {
- return $this->encodePath($this->getDavFilesPath($user) . $path);
+ public function makeSabrePath($user, $path, $type = 'files') {
+ if ($type === 'files') {
+ return $this->encodePath($this->getDavFilesPath($user) . $path);
+ } else {
+ return $this->encodePath($this->davPath . '/' . $type . '/' . $user . '/' . $path);
+ }
}
public function getSabreClient($user) {
diff --git a/build/integration/features/sharing-v1-part3.feature b/build/integration/features/sharing-v1-part3.feature
index 44a41341a02..6ab7cfdf9a0 100644
--- a/build/integration/features/sharing-v1-part3.feature
+++ b/build/integration/features/sharing-v1-part3.feature
@@ -1,7 +1,7 @@
Feature: sharing
Background:
Given using api version "1"
- Given using old dav path
+ Given using new dav path
# See sharing-v1-part2.feature
@@ -295,7 +295,7 @@ Feature: sharing
And user "user0" exists
And User "user0" deletes file "/textfile0.txt"
When User "user0" empties trashbin
- Then the HTTP status code should be "200"
+ Then the HTTP status code should be "204"
Scenario: orphaned shares
Given As an "admin"
@@ -392,4 +392,4 @@ Feature: sharing
And folder "/shared" of user "user0" is shared with user "user1"
When User "user1" moved file "/textfile0.txt" to "/shared/shared_file.txt"
Then as "user1" the file "/shared/shared_file.txt" exists
- And as "user0" the file "/shared/shared_file.txt" exists \ No newline at end of file
+ And as "user0" the file "/shared/shared_file.txt" exists
diff --git a/build/integration/features/trashbin.feature b/build/integration/features/trashbin.feature
index adb73f2b5ea..3a9c29f7cb8 100644
--- a/build/integration/features/trashbin.feature
+++ b/build/integration/features/trashbin.feature
@@ -1,7 +1,7 @@
Feature: trashbin
Background:
Given using api version "1"
- And using old dav path
+ And using new dav path
And As an "admin"
And app "files_trashbin" is enabled
@@ -9,5 +9,73 @@ Feature: trashbin
Given As an "admin"
And user "user0" exists
When User "user0" deletes file "/textfile0.txt"
- Then as "user0" the file "/textfile0.txt" exists in trash
+ Then user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | textfile0.txt |
+
+ Scenario: clearing the trashbin
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" deletes file "/textfile0.txt"
+ And User "user0" empties trashbin
+ Then user "user0" in trash folder "/" should have 0 elements
+
+ Scenario: restoring file from trashbin
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" deletes file "/textfile0.txt"
+ And user "user0" in restores "/textfile0.txt" from trash
+ Then user "user0" in trash folder "/" should have 0 elements
+ And as "user0" the file "/textfile0.txt" exists
+
+ Scenario: deleting and restoring a folder
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" created a folder "/testfolder"
+ And User "user0" moves file "/textfile0.txt" to "/testfolder/textfile0.txt"
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+ And User "user0" deletes file "/testfolder"
+ And user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | testfolder |
+ And user "user0" in trash folder "/testfolder" should have 1 element
+ And user "user0" in trash folder "/testfolder" should have the following elements
+ | textfile0.txt |
+ And user "user0" in restores "/testfolder" from trash
+ Then user "user0" in trash folder "/" should have 0 elements
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+
+ Scenario: deleting a file from a subfolder and restoring it moves it back to the subfolder
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" created a folder "/testfolder"
+ And User "user0" moves file "/textfile0.txt" to "/testfolder/textfile0.txt"
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+ And User "user0" deletes file "/testfolder/textfile0.txt"
+ And user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | textfile0.txt |
+ And user "user0" in restores "/textfile0.txt" from trash
+ Then user "user0" in trash folder "/" should have 0 elements
+ And as "user0" the file "/textfile0.txt" does not exist
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+
+ Scenario: deleting and a folder and restoring a file inside it
+ Given As an "admin"
+ And user "user0" exists
+ When User "user0" created a folder "/testfolder"
+ And User "user0" moves file "/textfile0.txt" to "/testfolder/textfile0.txt"
+ And as "user0" the file "/testfolder/textfile0.txt" exists
+ And User "user0" deletes file "/testfolder"
+ And user "user0" in trash folder "/" should have 1 element
+ And user "user0" in trash folder "/" should have the following elements
+ | testfolder |
+ And user "user0" in trash folder "/testfolder" should have 1 element
+ And user "user0" in trash folder "/testfolder" should have the following elements
+ | textfile0.txt |
+ And user "user0" in restores "/testfolder/textfile0.txt" from trash
+ Then user "user0" in trash folder "/" should have 1 elements
+ And user "user0" in trash folder "/testfolder" should have 0 element
+ And as "user0" the file "/textfile0.txt" exists
+
diff --git a/core/js/files/client.js b/core/js/files/client.js
index 9d3f5c4a3d6..aa450df1773 100644
--- a/core/js/files/client.js
+++ b/core/js/files/client.js
@@ -61,6 +61,7 @@
}
this._client = new dav.Client(clientOptions);
this._client.xhrProvider = _.bind(this._xhrProvider, this);
+ this._fileInfoParsers = [];
};
Client.NS_OWNCLOUD = 'http://owncloud.org/ns';
@@ -390,7 +391,7 @@
// extend the parsed data using the custom parsers
_.each(this._fileInfoParsers, function(parserFunction) {
- _.extend(data, parserFunction(response) || {});
+ _.extend(data, parserFunction(response, data) || {});
});
return new FileInfo(data);