summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/lib/caldav/caldavbackend.php7
-rw-r--r--apps/dav/lib/carddav/carddavbackend.php6
-rw-r--r--apps/dav/lib/connector/sabre/auth.php9
-rw-r--r--apps/dav/lib/connector/sabre/fakelockerplugin.php4
-rw-r--r--apps/dav/lib/connector/sabre/file.php10
-rw-r--r--apps/dav/lib/connector/sabre/filesplugin.php27
-rw-r--r--apps/dav/lib/connector/sabre/lockplugin.php1
-rw-r--r--apps/dav/lib/connector/sabre/node.php6
-rw-r--r--apps/dav/lib/connector/sabre/principal.php2
-rw-r--r--apps/dav/tests/unit/connector/sabre/auth.php36
-rw-r--r--apps/dav/tests/unit/connector/sabre/file.php5
-rw-r--r--apps/dav/tests/unit/connector/sabre/filesplugin.php3
-rw-r--r--apps/dav/tests/unit/connector/sabre/requesttest/auth.php4
-rw-r--r--apps/encryption/l10n/tr.js2
-rw-r--r--apps/encryption/l10n/tr.json2
-rw-r--r--apps/federation/api/ocsauthapi.php145
-rw-r--r--apps/federation/appinfo/app.php25
-rw-r--r--apps/federation/appinfo/application.php130
-rw-r--r--apps/federation/appinfo/database.xml63
-rw-r--r--apps/federation/appinfo/info.xml14
-rw-r--r--apps/federation/appinfo/routes.php47
-rw-r--r--apps/federation/backgroundjob/getsharedsecret.php185
-rw-r--r--apps/federation/backgroundjob/requestsharedsecret.php164
-rw-r--r--apps/federation/controller/settingscontroller.php123
-rw-r--r--apps/federation/css/settings-admin.css26
-rw-r--r--apps/federation/js/settings-admin.js82
-rw-r--r--apps/federation/lib/dbhandler.php269
-rw-r--r--apps/federation/lib/trustedservers.php254
-rw-r--r--apps/federation/middleware/addservermiddleware.php71
-rw-r--r--apps/federation/settings/settings-admin.php43
-rw-r--r--apps/federation/templates/settings-admin.php40
-rw-r--r--apps/federation/tests/api/ocsauthapitest.php184
-rw-r--r--apps/federation/tests/backgroundjob/getsharedsecrettest.php190
-rw-r--r--apps/federation/tests/backgroundjob/requestsharedsecrettest.php169
-rw-r--r--apps/federation/tests/controller/settingscontrollertest.php166
-rw-r--r--apps/federation/tests/lib/dbhandlertest.php243
-rw-r--r--apps/federation/tests/lib/trustedserverstest.php344
-rw-r--r--apps/federation/tests/middleware/addservermiddlewaretest.php100
-rw-r--r--apps/files/ajax/delete.php81
-rw-r--r--apps/files/ajax/move.php59
-rw-r--r--apps/files/ajax/newfile.php103
-rw-r--r--apps/files/ajax/newfolder.php99
-rw-r--r--apps/files/ajax/rename.php58
-rw-r--r--apps/files/ajax/upload.php7
-rw-r--r--apps/files/appinfo/info.xml2
-rw-r--r--apps/files/controller/viewcontroller.php4
-rw-r--r--apps/files/js/app.js3
-rw-r--r--apps/files/js/favoritesplugin.js2
-rw-r--r--apps/files/js/fileactions.js8
-rw-r--r--apps/files/js/filelist.js591
-rw-r--r--apps/files/js/files.js32
-rw-r--r--apps/files/js/tagsplugin.js32
-rw-r--r--apps/files/l10n/hy.js14
-rw-r--r--apps/files/l10n/hy.json14
-rw-r--r--apps/files/l10n/lt_LT.js8
-rw-r--r--apps/files/l10n/lt_LT.json8
-rw-r--r--apps/files/l10n/nds.js4
-rw-r--r--apps/files/l10n/nds.json4
-rw-r--r--apps/files/l10n/ru.js6
-rw-r--r--apps/files/l10n/ru.json6
-rw-r--r--apps/files/l10n/tr.js8
-rw-r--r--apps/files/l10n/tr.json8
-rw-r--r--apps/files/lib/app.php88
-rw-r--r--apps/files/lib/helper.php3
-rw-r--r--apps/files/templates/list.php11
-rw-r--r--apps/files/tests/ajax_rename.php232
-rw-r--r--apps/files/tests/js/favoritesfilelistspec.js3
-rw-r--r--apps/files/tests/js/fileUploadSpec.js2
-rw-r--r--apps/files/tests/js/fileactionsSpec.js2
-rw-r--r--apps/files/tests/js/fileactionsmenuSpec.js7
-rw-r--r--apps/files/tests/js/filelistSpec.js843
-rw-r--r--apps/files/tests/js/filesSpec.js6
-rw-r--r--apps/files_external/js/app.js2
-rw-r--r--apps/files_external/l10n/hy.js3
-rw-r--r--apps/files_external/l10n/hy.json3
-rw-r--r--apps/files_external/l10n/lt_LT.js1
-rw-r--r--apps/files_external/l10n/lt_LT.json1
-rw-r--r--apps/files_external/l10n/tr.js2
-rw-r--r--apps/files_external/l10n/tr.json2
-rwxr-xr-xapps/files_external/tests/env/start-webdav-ownCloud.sh4
-rw-r--r--apps/files_sharing/ajax/list.php96
-rw-r--r--apps/files_sharing/api/local.php1
-rw-r--r--apps/files_sharing/js/app.js2
-rw-r--r--apps/files_sharing/js/public.js16
-rw-r--r--apps/files_sharing/js/share.js22
-rw-r--r--apps/files_sharing/js/sharedfilelist.js4
-rw-r--r--apps/files_sharing/tests/js/publicAppSpec.js18
-rw-r--r--apps/files_sharing/tests/js/sharedfilelistSpec.js26
-rw-r--r--apps/files_trashbin/js/app.js5
-rw-r--r--apps/files_trashbin/js/filelist.js72
-rw-r--r--apps/files_trashbin/l10n/hy.js4
-rw-r--r--apps/files_trashbin/l10n/hy.json4
-rw-r--r--apps/files_trashbin/l10n/nds.js1
-rw-r--r--apps/files_trashbin/l10n/nds.json1
-rw-r--r--apps/files_trashbin/l10n/ru.js4
-rw-r--r--apps/files_trashbin/l10n/ru.json4
-rw-r--r--apps/files_versions/l10n/hy.js3
-rw-r--r--apps/files_versions/l10n/hy.json3
-rw-r--r--apps/user_ldap/l10n/es.js1
-rw-r--r--apps/user_ldap/l10n/es.json1
-rw-r--r--apps/user_ldap/l10n/lt_LT.js3
-rw-r--r--apps/user_ldap/l10n/lt_LT.json3
102 files changed, 4220 insertions, 1651 deletions
diff --git a/apps/dav/lib/caldav/caldavbackend.php b/apps/dav/lib/caldav/caldavbackend.php
index 08a2a70c56d..99338650793 100644
--- a/apps/dav/lib/caldav/caldavbackend.php
+++ b/apps/dav/lib/caldav/caldavbackend.php
@@ -217,7 +217,6 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
*
* Read the PropPatch documentation for more info and examples.
*
- * @param string $path
* @param \Sabre\DAV\PropPatch $propPatch
* @return void
*/
@@ -375,7 +374,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
* If the backend supports this, it may allow for some speed-ups.
*
* @param mixed $calendarId
- * @param array $uris
+ * @param string[] $uris
* @return array
*/
function getMultipleCalendarObjects($calendarId, array $uris) {
@@ -422,7 +421,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
* @param mixed $calendarId
* @param string $objectUri
* @param string $calendarData
- * @return string|null
+ * @return string
*/
function createCalendarObject($calendarId, $objectUri, $calendarData) {
$extraData = $this->getDenormalizedData($calendarData);
@@ -464,7 +463,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
* @param mixed $calendarId
* @param string $objectUri
* @param string $calendarData
- * @return string|null
+ * @return string
*/
function updateCalendarObject($calendarId, $objectUri, $calendarData) {
$extraData = $this->getDenormalizedData($calendarData);
diff --git a/apps/dav/lib/carddav/carddavbackend.php b/apps/dav/lib/carddav/carddavbackend.php
index 348c166a531..daa31725fa1 100644
--- a/apps/dav/lib/carddav/carddavbackend.php
+++ b/apps/dav/lib/carddav/carddavbackend.php
@@ -343,7 +343,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* If the backend supports this, it may allow for some speed-ups.
*
* @param mixed $addressBookId
- * @param array $uris
+ * @param string[] $uris
* @return array
*/
function getMultipleCards($addressBookId, array $uris) {
@@ -390,7 +390,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
- * @return string|null
+ * @return string
*/
function createCard($addressBookId, $cardUri, $cardData) {
$etag = md5($cardData);
@@ -435,7 +435,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
- * @return string|null
+ * @return string
*/
function updateCard($addressBookId, $cardUri, $cardData) {
diff --git a/apps/dav/lib/connector/sabre/auth.php b/apps/dav/lib/connector/sabre/auth.php
index 0394bfd6772..27f6704ba2c 100644
--- a/apps/dav/lib/connector/sabre/auth.php
+++ b/apps/dav/lib/connector/sabre/auth.php
@@ -150,7 +150,7 @@ class Auth extends AbstractBasic {
/**
* @param \Sabre\DAV\Server $server
- * @param $realm
+ * @param string $realm
* @return bool
*/
private function auth(\Sabre\DAV\Server $server, $realm) {
@@ -164,6 +164,13 @@ class Auth extends AbstractBasic {
return true;
}
+ if ($server->httpRequest->getHeader('X-Requested-With') === 'XMLHttpRequest') {
+ // do not re-authenticate over ajax, use dummy auth name to prevent browser popup
+ $server->httpResponse->addHeader('WWW-Authenticate','DummyBasic realm="' . $realm . '"');
+ $server->httpResponse->setStatus(401);
+ throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
+ }
+
return parent::authenticate($server, $realm);
}
}
diff --git a/apps/dav/lib/connector/sabre/fakelockerplugin.php b/apps/dav/lib/connector/sabre/fakelockerplugin.php
index 493d3b0ade4..b9d1a30a041 100644
--- a/apps/dav/lib/connector/sabre/fakelockerplugin.php
+++ b/apps/dav/lib/connector/sabre/fakelockerplugin.php
@@ -59,7 +59,7 @@ class FakeLockerPlugin extends ServerPlugin {
* Indicate that we support LOCK and UNLOCK
*
* @param string $path
- * @return array
+ * @return string[]
*/
public function getHTTPMethods($path) {
return [
@@ -71,7 +71,7 @@ class FakeLockerPlugin extends ServerPlugin {
/**
* Indicate that we support locking
*
- * @return array
+ * @return integer[]
*/
function getFeatures() {
return [2];
diff --git a/apps/dav/lib/connector/sabre/file.php b/apps/dav/lib/connector/sabre/file.php
index a0c35fb2baf..ef7b9891dc9 100644
--- a/apps/dav/lib/connector/sabre/file.php
+++ b/apps/dav/lib/connector/sabre/file.php
@@ -213,6 +213,9 @@ class File extends Node implements IFile {
return '"' . $this->info->getEtag() . '"';
}
+ /**
+ * @param string $path
+ */
private function emitPreHooks($exists, $path = null) {
if (is_null($path)) {
$path = $this->path;
@@ -238,6 +241,9 @@ class File extends Node implements IFile {
return $run;
}
+ /**
+ * @param string $path
+ */
private function emitPostHooks($exists, $path = null) {
if (is_null($path)) {
$path = $this->path;
@@ -260,7 +266,7 @@ class File extends Node implements IFile {
/**
* Returns the data
*
- * @return string|resource
+ * @return resource
* @throws Forbidden
* @throws ServiceUnavailable
*/
@@ -314,7 +320,7 @@ class File extends Node implements IFile {
*
* If null is returned, we'll assume application/octet-stream
*
- * @return mixed
+ * @return string
*/
public function getContentType() {
$mimeType = $this->info->getMimetype();
diff --git a/apps/dav/lib/connector/sabre/filesplugin.php b/apps/dav/lib/connector/sabre/filesplugin.php
index d68397dcaa3..e85a67a8759 100644
--- a/apps/dav/lib/connector/sabre/filesplugin.php
+++ b/apps/dav/lib/connector/sabre/filesplugin.php
@@ -116,6 +116,7 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
$this->server->on('afterMethod:GET', [$this,'httpGet']);
+ $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
$this->server->on('afterResponse', function($request, ResponseInterface $response) {
$body = $response->getBody();
if (is_resource($body)) {
@@ -149,6 +150,32 @@ class FilesPlugin extends \Sabre\DAV\ServerPlugin {
}
/**
+ * This sets a cookie to be able to recognize the start of the download
+ * the content must not be longer than 32 characters and must only contain
+ * alphanumeric characters
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ */
+ function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
+ $queryParams = $request->getQueryParameters();
+
+ /**
+ * this sets a cookie to be able to recognize the start of the download
+ * the content must not be longer than 32 characters and must only contain
+ * alphanumeric characters
+ */
+ if (isset($queryParams['downloadStartSecret'])) {
+ $token = $queryParams['downloadStartSecret'];
+ if (!isset($token[32])
+ && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
+ // FIXME: use $response->setHeader() instead
+ setcookie('ocDownloadStarted', $token, time() + 20, '/');
+ }
+ }
+ }
+
+ /**
* Plugin that adds a 'Content-Disposition: attachment' header to all files
* delivered by SabreDAV.
* @param RequestInterface $request
diff --git a/apps/dav/lib/connector/sabre/lockplugin.php b/apps/dav/lib/connector/sabre/lockplugin.php
index 8032d2b3fbf..d770b141eb9 100644
--- a/apps/dav/lib/connector/sabre/lockplugin.php
+++ b/apps/dav/lib/connector/sabre/lockplugin.php
@@ -27,7 +27,6 @@ use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ServerPlugin;
-use Sabre\DAV\Tree;
use Sabre\HTTP\RequestInterface;
class LockPlugin extends ServerPlugin {
diff --git a/apps/dav/lib/connector/sabre/node.php b/apps/dav/lib/connector/sabre/node.php
index daf82ba6f0d..c4e0614077f 100644
--- a/apps/dav/lib/connector/sabre/node.php
+++ b/apps/dav/lib/connector/sabre/node.php
@@ -178,7 +178,7 @@ abstract class Node implements \Sabre\DAV\INode {
/**
* Returns the size of the node, in bytes
*
- * @return int|float
+ * @return integer
*/
public function getSize() {
return $this->info->getSize();
@@ -207,14 +207,14 @@ abstract class Node implements \Sabre\DAV\INode {
}
/**
- * @return string
+ * @return integer
*/
public function getInternalFileId() {
return $this->info->getId();
}
/**
- * @return string|null
+ * @return string
*/
public function getDavPermissions() {
$p = '';
diff --git a/apps/dav/lib/connector/sabre/principal.php b/apps/dav/lib/connector/sabre/principal.php
index 35215e1f63c..7fb14c031f9 100644
--- a/apps/dav/lib/connector/sabre/principal.php
+++ b/apps/dav/lib/connector/sabre/principal.php
@@ -168,7 +168,7 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
* The principals should be passed as a list of uri's.
*
* @param string $principal
- * @param array $members
+ * @param string[] $members
* @throws \Sabre\DAV\Exception
*/
public function setGroupMemberSet($principal, array $members) {
diff --git a/apps/dav/tests/unit/connector/sabre/auth.php b/apps/dav/tests/unit/connector/sabre/auth.php
index d18747d732a..4c060ff04bb 100644
--- a/apps/dav/tests/unit/connector/sabre/auth.php
+++ b/apps/dav/tests/unit/connector/sabre/auth.php
@@ -295,16 +295,43 @@ class Auth extends TestCase {
$this->auth->authenticate($server, 'TestRealm');
}
- public function testAuthenticateValidCredentials() {
+ /**
+ * @expectedException \Sabre\DAV\Exception\NotAuthenticated
+ * @expectedExceptionMessage Cannot authenticate over ajax calls
+ */
+ public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjax() {
$server = $this->getMockBuilder('\Sabre\DAV\Server')
->disableOriginalConstructor()
->getMock();
$server->httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
->disableOriginalConstructor()
->getMock();
+ $server->httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
$server->httpRequest
->expects($this->once())
->method('getHeader')
+ ->with('X-Requested-With')
+ ->will($this->returnValue('XMLHttpRequest'));
+ $this->auth->authenticate($server, 'TestRealm');
+ }
+
+ public function testAuthenticateValidCredentials() {
+ $server = $this->getMockBuilder('\Sabre\DAV\Server')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $server->httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $server->httpRequest
+ ->expects($this->at(0))
+ ->method('getHeader')
+ ->with('X-Requested-With')
+ ->will($this->returnValue(null));
+ $server->httpRequest
+ ->expects($this->at(1))
+ ->method('getHeader')
->with('Authorization')
->will($this->returnValue('basic dXNlcm5hbWU6cGFzc3dvcmQ='));
$server->httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
@@ -340,7 +367,12 @@ class Auth extends TestCase {
->disableOriginalConstructor()
->getMock();
$server->httpRequest
- ->expects($this->once())
+ ->expects($this->at(0))
+ ->method('getHeader')
+ ->with('X-Requested-With')
+ ->will($this->returnValue(null));
+ $server->httpRequest
+ ->expects($this->at(1))
->method('getHeader')
->with('Authorization')
->will($this->returnValue('basic dXNlcm5hbWU6cGFzc3dvcmQ='));
diff --git a/apps/dav/tests/unit/connector/sabre/file.php b/apps/dav/tests/unit/connector/sabre/file.php
index 399634f8bee..0a52299cec7 100644
--- a/apps/dav/tests/unit/connector/sabre/file.php
+++ b/apps/dav/tests/unit/connector/sabre/file.php
@@ -41,6 +41,9 @@ class File extends \Test\TestCase {
parent::tearDown();
}
+ /**
+ * @param string $string
+ */
private function getStream($string) {
$stream = fopen('php://temp', 'r+');
fwrite($stream, $string);
@@ -239,7 +242,7 @@ class File extends \Test\TestCase {
* @param string $path path to put the file into
* @param string $viewRoot root to use for the view
*
- * @return result of the PUT operaiton which is usually the etag
+ * @return null|string of the PUT operaiton which is usually the etag
*/
private function doPut($path, $viewRoot = null) {
$view = \OC\Files\Filesystem::getView();
diff --git a/apps/dav/tests/unit/connector/sabre/filesplugin.php b/apps/dav/tests/unit/connector/sabre/filesplugin.php
index 2e3338fefa1..b33c8340f72 100644
--- a/apps/dav/tests/unit/connector/sabre/filesplugin.php
+++ b/apps/dav/tests/unit/connector/sabre/filesplugin.php
@@ -55,6 +55,9 @@ class FilesPlugin extends \Test\TestCase {
$this->plugin->initialize($this->server);
}
+ /**
+ * @param string $class
+ */
private function createTestNode($class) {
$node = $this->getMockBuilder($class)
->disableOriginalConstructor()
diff --git a/apps/dav/tests/unit/connector/sabre/requesttest/auth.php b/apps/dav/tests/unit/connector/sabre/requesttest/auth.php
index 41b554d11db..02b64ab070b 100644
--- a/apps/dav/tests/unit/connector/sabre/requesttest/auth.php
+++ b/apps/dav/tests/unit/connector/sabre/requesttest/auth.php
@@ -41,7 +41,7 @@ class Auth implements BackendInterface {
*
* @param \Sabre\DAV\Server $server
* @param string $realm
- * @return bool
+ * @return boolean|null
*/
function authenticate(\Sabre\DAV\Server $server, $realm) {
$userSession = \OC::$server->getUserSession();
@@ -61,7 +61,7 @@ class Auth implements BackendInterface {
*
* If nobody is currently logged in, this method should return null.
*
- * @return string|null
+ * @return string
*/
function getCurrentUser() {
return $this->user;
diff --git a/apps/encryption/l10n/tr.js b/apps/encryption/l10n/tr.js
index e1fcb526d06..5abbf87b813 100644
--- a/apps/encryption/l10n/tr.js
+++ b/apps/encryption/l10n/tr.js
@@ -32,6 +32,8 @@ OC.L10N.register(
"The share will expire on %s." : "Bu paylaşım %s tarihinde sona erecek.",
"Cheers!" : "Hoşçakalın!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Selam,<br><br>Sistem yöneticisi sunucu tarafında şifrelemeyi etkinleştirdi. Dosyalarınız <strong>%s</strong> parolası kullanılarak şifrelendi.<br><br>Lütfen web arayüzünde oturum açın ve kişisel ayarlarınızdan 'ownCloud temel şifreleme modülü'ne giderek 'eski oturum parolası' alanına bu parolayı girdikten sonra şifreleme parolanızı ve mevcut oturum açma parolanızı güncelleyin.<br><br>",
+ "Encrypt the home storage" : "Yerel depolamayı şifrele",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Bu seçeneği etkinleştirmek ana depolamadaki bütün dosyaları şifreler, aksi takdirde sadece harici depolamadaki dosyalar şifrelenir",
"Enable recovery key" : "Kurtarma anahtarını etkinleştir",
"Disable recovery key" : "Kurtarma anahtarını devre dışı bırak",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kurtarma anahtarı, dosyaların şifrelenmesi için daha fazla \nşifreleme sunar. Bu kullanıcının dosyasının şifresini unuttuğunda kurtarmasına imkan verir.",
diff --git a/apps/encryption/l10n/tr.json b/apps/encryption/l10n/tr.json
index 743d3e7d15c..31824461d84 100644
--- a/apps/encryption/l10n/tr.json
+++ b/apps/encryption/l10n/tr.json
@@ -30,6 +30,8 @@
"The share will expire on %s." : "Bu paylaşım %s tarihinde sona erecek.",
"Cheers!" : "Hoşçakalın!",
"Hey there,<br><br>the admin enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"ownCloud basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"old log-in password\" field and your current login-password.<br><br>" : "Selam,<br><br>Sistem yöneticisi sunucu tarafında şifrelemeyi etkinleştirdi. Dosyalarınız <strong>%s</strong> parolası kullanılarak şifrelendi.<br><br>Lütfen web arayüzünde oturum açın ve kişisel ayarlarınızdan 'ownCloud temel şifreleme modülü'ne giderek 'eski oturum parolası' alanına bu parolayı girdikten sonra şifreleme parolanızı ve mevcut oturum açma parolanızı güncelleyin.<br><br>",
+ "Encrypt the home storage" : "Yerel depolamayı şifrele",
+ "Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Bu seçeneği etkinleştirmek ana depolamadaki bütün dosyaları şifreler, aksi takdirde sadece harici depolamadaki dosyalar şifrelenir",
"Enable recovery key" : "Kurtarma anahtarını etkinleştir",
"Disable recovery key" : "Kurtarma anahtarını devre dışı bırak",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kurtarma anahtarı, dosyaların şifrelenmesi için daha fazla \nşifreleme sunar. Bu kullanıcının dosyasının şifresini unuttuğunda kurtarmasına imkan verir.",
diff --git a/apps/federation/api/ocsauthapi.php b/apps/federation/api/ocsauthapi.php
new file mode 100644
index 00000000000..42d7113820d
--- /dev/null
+++ b/apps/federation/api/ocsauthapi.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\API;
+
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\IRequest;
+use OCP\Security\ISecureRandom;
+use OCP\Security\StringUtils;
+
+/**
+ * Class OCSAuthAPI
+ *
+ * OCS API end-points to exchange shared secret between two connected ownClouds
+ *
+ * @package OCA\Federation\API
+ */
+class OCSAuthAPI {
+
+ /** @var IRequest */
+ private $request;
+
+ /** @var ISecureRandom */
+ private $secureRandom;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /**
+ * OCSAuthAPI constructor.
+ *
+ * @param IRequest $request
+ * @param ISecureRandom $secureRandom
+ * @param IJobList $jobList
+ * @param TrustedServers $trustedServers
+ * @param DbHandler $dbHandler
+ */
+ public function __construct(
+ IRequest $request,
+ ISecureRandom $secureRandom,
+ IJobList $jobList,
+ TrustedServers $trustedServers,
+ DbHandler $dbHandler
+ ) {
+ $this->request = $request;
+ $this->secureRandom = $secureRandom;
+ $this->jobList = $jobList;
+ $this->trustedServers = $trustedServers;
+ $this->dbHandler = $dbHandler;
+ }
+
+ /**
+ * request received to ask remote server for a shared secret
+ *
+ * @return \OC_OCS_Result
+ */
+ public function requestSharedSecret() {
+
+ $url = $this->request->getParam('url');
+ $token = $this->request->getParam('token');
+
+ if ($this->trustedServers->isTrustedServer($url) === false) {
+ return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
+ }
+
+ // if both server initiated the exchange of the shared secret the greater
+ // token wins
+ $localToken = $this->dbHandler->getToken($url);
+ if (strcmp($localToken, $token) > 0) {
+ return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
+ }
+
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\GetSharedSecret',
+ [
+ 'url' => $url,
+ 'token' => $token,
+ ]
+ );
+
+ return new \OC_OCS_Result(null, Http::STATUS_OK);
+
+ }
+
+ /**
+ * create shared secret and return it
+ *
+ * @return \OC_OCS_Result
+ */
+ public function getSharedSecret() {
+
+ $url = $this->request->getParam('url');
+ $token = $this->request->getParam('token');
+
+ if (
+ $this->trustedServers->isTrustedServer($url) === false
+ || $this->isValidToken($url, $token) === false
+ ) {
+ return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
+ }
+
+ $sharedSecret = $this->secureRandom->getMediumStrengthGenerator()->generate(32);
+
+ $this->trustedServers->addSharedSecret($url, $sharedSecret);
+ // reset token after the exchange of the shared secret was successful
+ $this->dbHandler->addToken($url, '');
+
+ return new \OC_OCS_Result(['sharedSecret' => $sharedSecret], Http::STATUS_OK);
+
+ }
+
+ protected function isValidToken($url, $token) {
+ $storedToken = $this->dbHandler->getToken($url);
+ return StringUtils::equals($storedToken, $token);
+ }
+
+}
diff --git a/apps/federation/appinfo/app.php b/apps/federation/appinfo/app.php
new file mode 100644
index 00000000000..9ed00f23866
--- /dev/null
+++ b/apps/federation/appinfo/app.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+namespace OCA\Federation\AppInfo;
+
+$app = new Application();
+$app->registerSettings();
diff --git a/apps/federation/appinfo/application.php b/apps/federation/appinfo/application.php
new file mode 100644
index 00000000000..350b140b4dd
--- /dev/null
+++ b/apps/federation/appinfo/application.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+namespace OCA\Federation\AppInfo;
+
+use OCA\Federation\API\OCSAuthAPI;
+use OCA\Federation\Controller\AuthController;
+use OCA\Federation\Controller\SettingsController;
+use OCA\Federation\DbHandler;
+use OCA\Federation\Middleware\AddServerMiddleware;
+use OCA\Federation\TrustedServers;
+use OCP\API;
+use OCP\App;
+use OCP\AppFramework\IAppContainer;
+
+class Application extends \OCP\AppFramework\App {
+
+ /**
+ * @param array $urlParams
+ */
+ public function __construct($urlParams = array()) {
+ parent::__construct('federation', $urlParams);
+ $this->registerService();
+ $this->registerMiddleware();
+ }
+
+ /**
+ * register setting scripts
+ */
+ public function registerSettings() {
+ App::registerAdmin('federation', 'settings/settings-admin');
+ }
+
+ private function registerService() {
+ $container = $this->getContainer();
+
+ $container->registerService('addServerMiddleware', function(IAppContainer $c) {
+ return new AddServerMiddleware(
+ $c->getAppName(),
+ \OC::$server->getL10N($c->getAppName()),
+ \OC::$server->getLogger()
+ );
+ });
+
+ $container->registerService('DbHandler', function(IAppContainer $c) {
+ return new DbHandler(
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getL10N($c->getAppName())
+ );
+ });
+
+ $container->registerService('TrustedServers', function(IAppContainer $c) {
+ return new TrustedServers(
+ $c->query('DbHandler'),
+ \OC::$server->getHTTPClientService(),
+ \OC::$server->getLogger(),
+ \OC::$server->getJobList(),
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+ );
+ });
+
+ $container->registerService('SettingsController', function (IAppContainer $c) {
+ $server = $c->getServer();
+ return new SettingsController(
+ $c->getAppName(),
+ $server->getRequest(),
+ $server->getL10N($c->getAppName()),
+ $c->query('TrustedServers')
+ );
+ });
+ }
+
+ private function registerMiddleware() {
+ $container = $this->getContainer();
+ $container->registerMiddleware('addServerMiddleware');
+ }
+
+ /**
+ * register OCS API Calls
+ */
+ public function registerOCSApi() {
+
+ $container = $this->getContainer();
+ $server = $container->getServer();
+
+ $auth = new OCSAuthAPI(
+ $server->getRequest(),
+ $server->getSecureRandom(),
+ $server->getJobList(),
+ $container->query('TrustedServers'),
+ $container->query('DbHandler')
+
+ );
+
+ API::register('get',
+ '/apps/federation/api/v1/shared-secret',
+ array($auth, 'getSharedSecret'),
+ 'federation',
+ API::GUEST_AUTH
+ );
+
+ API::register('post',
+ '/apps/federation/api/v1/request-shared-secret',
+ array($auth, 'requestSharedSecret'),
+ 'federation',
+ API::GUEST_AUTH
+ );
+
+ }
+
+}
diff --git a/apps/federation/appinfo/database.xml b/apps/federation/appinfo/database.xml
new file mode 100644
index 00000000000..e0bb241918e
--- /dev/null
+++ b/apps/federation/appinfo/database.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+ <name>*dbname*</name>
+ <create>true</create>
+ <overwrite>false</overwrite>
+ <charset>utf8</charset>
+ <table>
+ <name>*dbprefix*trusted_servers</name>
+ <declaration>
+ <field>
+ <name>id</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>4</length>
+ </field>
+ <field>
+ <name>url</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>512</length>
+ <comments>Url of trusted server</comments>
+ </field>
+ <field>
+ <name>url_hash</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>32</length>
+ <comments>md5 hash of the url without the protocol</comments>
+ </field>
+ <field>
+ <name>token</name>
+ <type>text</type>
+ <length>128</length>
+ <comments>toke used to exchange the shared secret</comments>
+ </field>
+ <field>
+ <name>shared_secret</name>
+ <type>text</type>
+ <length>256</length>
+ <comments>shared secret used to authenticate</comments>
+ </field>
+ <field>
+ <name>status</name>
+ <type>integer</type>
+ <length>4</length>
+ <notnull>true</notnull>
+ <default>2</default>
+ <comments>current status of the connection</comments>
+ </field>
+ <index>
+ <name>url_hash</name>
+ <unique>true</unique>
+ <field>
+ <name>url_hash</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+ </declaration>
+ </table>
+</database>
diff --git a/apps/federation/appinfo/info.xml b/apps/federation/appinfo/info.xml
new file mode 100644
index 00000000000..53b2926ba53
--- /dev/null
+++ b/apps/federation/appinfo/info.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info>
+ <id>federation</id>
+ <name>Federation</name>
+ <description>ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing.</description>
+ <licence>AGPL</licence>
+ <author>Bjoern Schiessle</author>
+ <version>0.0.1</version>
+ <namespace>Federation</namespace>
+ <category>other</category>
+ <dependencies>
+ <owncloud min-version="9.0" />
+ </dependencies>
+</info>
diff --git a/apps/federation/appinfo/routes.php b/apps/federation/appinfo/routes.php
new file mode 100644
index 00000000000..8c1629a4fc6
--- /dev/null
+++ b/apps/federation/appinfo/routes.php
@@ -0,0 +1,47 @@
+<?php
+/**
+* @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+$application = new \OCA\Federation\AppInfo\Application();
+
+$application->registerRoutes(
+ $this,
+ [
+ 'routes' => [
+ [
+ 'name' => 'Settings#addServer',
+ 'url' => '/trusted-servers',
+ 'verb' => 'POST'
+ ],
+ [
+ 'name' => 'Settings#removeServer',
+ 'url' => '/trusted-servers/{id}',
+ 'verb' => 'DELETE'
+ ],
+ [
+ 'name' => 'Settings#autoAddServers',
+ 'url' => '/auto-add-servers',
+ 'verb' => 'POST'
+ ],
+ ]
+ ]
+);
+
+$application->registerOCSApi();
diff --git a/apps/federation/backgroundjob/getsharedsecret.php b/apps/federation/backgroundjob/getsharedsecret.php
new file mode 100644
index 00000000000..eb55fa2d6ab
--- /dev/null
+++ b/apps/federation/backgroundjob/getsharedsecret.php
@@ -0,0 +1,185 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\BackgroundJob;
+
+use GuzzleHttp\Exception\ClientException;
+use OC\BackgroundJob\JobList;
+use OC\BackgroundJob\QueuedJob;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+
+/**
+ * Class GetSharedSecret
+ *
+ * request shared secret from remote ownCloud
+ *
+ * @package OCA\Federation\Backgroundjob
+ */
+class GetSharedSecret extends QueuedJob{
+
+ /** @var IClient */
+ private $httpClient;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /** @var ILogger */
+ private $logger;
+
+ private $endPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json';
+
+ /**
+ * RequestSharedSecret constructor.
+ *
+ * @param IClient $httpClient
+ * @param IURLGenerator $urlGenerator
+ * @param IJobList $jobList
+ * @param TrustedServers $trustedServers
+ * @param ILogger $logger
+ * @param DbHandler $dbHandler
+ */
+ public function __construct(
+ IClient $httpClient = null,
+ IURLGenerator $urlGenerator = null,
+ IJobList $jobList = null,
+ TrustedServers $trustedServers = null,
+ ILogger $logger = null,
+ dbHandler $dbHandler = null
+ ) {
+ $this->logger = $logger ? $logger : \OC::$server->getLogger();
+ $this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
+ $this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
+ $this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
+ $this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation'));
+ if ($trustedServers) {
+ $this->trustedServers = $trustedServers;
+ } else {
+ $this->trustedServers = new TrustedServers(
+ $this->dbHandler,
+ \OC::$server->getHTTPClientService(),
+ \OC::$server->getLogger(),
+ $this->jobList,
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+ );
+ }
+ }
+
+ /**
+ * run the job, then remove it from the joblist
+ *
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ public function execute($jobList, ILogger $logger = null) {
+ $jobList->remove($this, $this->argument);
+ $target = $this->argument['url'];
+ // only execute if target is still in the list of trusted domains
+ if ($this->trustedServers->isTrustedServer($target)) {
+ $this->parentExecute($jobList, $logger);
+ }
+ }
+
+ /**
+ * call execute() method of parent
+ *
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ protected function parentExecute($jobList, $logger) {
+ parent::execute($jobList, $logger);
+ }
+
+ protected function run($argument) {
+ $target = $argument['url'];
+ $source = $this->urlGenerator->getAbsoluteURL('/');
+ $source = rtrim($source, '/');
+ $token = $argument['token'];
+
+ try {
+ $result = $this->httpClient->get(
+ $target . $this->endPoint,
+ [
+ 'query' =>
+ [
+ 'url' => $source,
+ 'token' => $token
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ );
+
+ $status = $result->getStatusCode();
+
+ } catch (ClientException $e) {
+ $status = $e->getCode();
+ }
+
+ // if we received a unexpected response we try again later
+ if (
+ $status !== Http::STATUS_OK
+ && $status !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\GetSharedSecret',
+ $argument
+ );
+ } else {
+ // reset token if we received a valid response
+ $this->dbHandler->addToken($target, '');
+ }
+
+ if ($status === Http::STATUS_OK) {
+ $body = $result->getBody();
+ $result = json_decode($body, true);
+ if (isset($result['ocs']['data']['sharedSecret'])) {
+ $this->trustedServers->addSharedSecret(
+ $target,
+ $result['ocs']['data']['sharedSecret']
+ );
+ } else {
+ $this->logger->error(
+ 'remote server "' . $target . '"" does not return a valid shared secret',
+ ['app' => 'federation']
+ );
+ $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
+ }
+ }
+
+ }
+}
diff --git a/apps/federation/backgroundjob/requestsharedsecret.php b/apps/federation/backgroundjob/requestsharedsecret.php
new file mode 100644
index 00000000000..24d8adada11
--- /dev/null
+++ b/apps/federation/backgroundjob/requestsharedsecret.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\BackgroundJob;
+
+
+use GuzzleHttp\Exception\ClientException;
+use OC\BackgroundJob\JobList;
+use OC\BackgroundJob\QueuedJob;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+
+/**
+ * Class RequestSharedSecret
+ *
+ * Ask remote ownCloud to request a sharedSecret from this server
+ *
+ * @package OCA\Federation\Backgroundjob
+ */
+class RequestSharedSecret extends QueuedJob {
+
+ /** @var IClient */
+ private $httpClient;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ private $endPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json';
+
+ /**
+ * RequestSharedSecret constructor.
+ *
+ * @param IClient $httpClient
+ * @param IURLGenerator $urlGenerator
+ * @param IJobList $jobList
+ * @param TrustedServers $trustedServers
+ * @param DbHandler $dbHandler
+ */
+ public function __construct(
+ IClient $httpClient = null,
+ IURLGenerator $urlGenerator = null,
+ IJobList $jobList = null,
+ TrustedServers $trustedServers = null,
+ dbHandler $dbHandler = null
+ ) {
+ $this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
+ $this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
+ $this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
+ $this->dbHandler = $dbHandler ? $dbHandler : new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation'));
+ if ($trustedServers) {
+ $this->trustedServers = $trustedServers;
+ } else {
+ $this->trustedServers = new TrustedServers(
+ $this->dbHandler,
+ \OC::$server->getHTTPClientService(),
+ \OC::$server->getLogger(),
+ $this->jobList,
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+ );
+ }
+ }
+
+
+ /**
+ * run the job, then remove it from the joblist
+ *
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ public function execute($jobList, ILogger $logger = null) {
+ $jobList->remove($this, $this->argument);
+ $target = $this->argument['url'];
+ // only execute if target is still in the list of trusted domains
+ if ($this->trustedServers->isTrustedServer($target)) {
+ $this->parentExecute($jobList, $logger);
+ }
+ }
+
+ /**
+ * @param JobList $jobList
+ * @param ILogger $logger
+ */
+ protected function parentExecute($jobList, $logger) {
+ parent::execute($jobList, $logger);
+ }
+
+ protected function run($argument) {
+
+ $target = $argument['url'];
+ $source = $this->urlGenerator->getAbsoluteURL('/');
+ $source = rtrim($source, '/');
+ $token = $argument['token'];
+
+ try {
+ $result = $this->httpClient->post(
+ $target . $this->endPoint,
+ [
+ 'body' => [
+ 'url' => $source,
+ 'token' => $token,
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ );
+
+ $status = $result->getStatusCode();
+
+ } catch (ClientException $e) {
+ $status = $e->getCode();
+ }
+
+ // if we received a unexpected response we try again later
+ if (
+ $status !== Http::STATUS_OK
+ && $status !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\RequestSharedSecret',
+ $argument
+ );
+ }
+
+ if ($status === Http::STATUS_FORBIDDEN) {
+ // clear token if remote server refuses to ask for shared secret
+ $this->dbHandler->addToken($target, '');
+ }
+
+ }
+}
diff --git a/apps/federation/controller/settingscontroller.php b/apps/federation/controller/settingscontroller.php
new file mode 100644
index 00000000000..2e28cd60cfa
--- /dev/null
+++ b/apps/federation/controller/settingscontroller.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+namespace OCA\Federation\Controller;
+
+use OC\HintException;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\IConfig;
+use OCP\IL10N;
+use OCP\IRequest;
+
+
+class SettingsController extends Controller {
+
+ /** @var IL10N */
+ private $l;
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /**
+ * @param string $AppName
+ * @param IRequest $request
+ * @param IL10N $l10n
+ * @param TrustedServers $trustedServers
+ */
+ public function __construct($AppName,
+ IRequest $request,
+ IL10N $l10n,
+ TrustedServers $trustedServers
+ ) {
+ parent::__construct($AppName, $request);
+ $this->l = $l10n;
+ $this->trustedServers = $trustedServers;
+ }
+
+
+ /**
+ * add server to the list of trusted ownClouds
+ *
+ * @param string $url
+ * @return DataResponse
+ * @throws HintException
+ */
+ public function addServer($url) {
+ $this->checkServer($url);
+ $id = $this->trustedServers->addServer($url);
+
+ return new DataResponse(
+ [
+ 'url' => $url,
+ 'id' => $id,
+ 'message' => (string) $this->l->t('Server added to the list of trusted ownClouds')
+ ]
+ );
+ }
+
+ /**
+ * add server to the list of trusted ownClouds
+ *
+ * @param int $id
+ * @return DataResponse
+ */
+ public function removeServer($id) {
+ $this->trustedServers->removeServer($id);
+ return new DataResponse();
+ }
+
+ /**
+ * enable/disable to automatically add servers to the list of trusted servers
+ * once a federated share was created and accepted successfully
+ *
+ * @param bool $autoAddServers
+ */
+ public function autoAddServers($autoAddServers) {
+ $this->trustedServers->setAutoAddServers($autoAddServers);
+ }
+
+ /**
+ * check if the server should be added to the list of trusted servers or not
+ *
+ * @param string $url
+ * @return bool
+ * @throws HintException
+ */
+ protected function checkServer($url) {
+ if ($this->trustedServers->isTrustedServer($url) === true) {
+ $message = 'Server is already in the list of trusted servers.';
+ $hint = $this->l->t('Server is already in the list of trusted servers.');
+ throw new HintException($message, $hint);
+ }
+
+ if ($this->trustedServers->isOwnCloudServer($url) === false) {
+ $message = 'No ownCloud server found';
+ $hint = $this->l->t('No ownCloud server found');
+ throw new HintException($message, $hint);
+ }
+
+ return true;
+ }
+
+}
diff --git a/apps/federation/css/settings-admin.css b/apps/federation/css/settings-admin.css
new file mode 100644
index 00000000000..55b1dd64d15
--- /dev/null
+++ b/apps/federation/css/settings-admin.css
@@ -0,0 +1,26 @@
+#ocFederationSettings p {
+ padding-top: 10px;
+}
+
+#listOfTrustedServers li {
+ padding-top: 10px;
+ padding-left: 20px;
+}
+
+.removeTrustedServer {
+ display: none;
+ vertical-align:middle;
+ padding-left: 10px;
+}
+
+#ocFederationAddServerButton {
+ cursor: pointer;
+}
+
+#listOfTrustedServers li:hover {
+ cursor: pointer;
+}
+
+#listOfTrustedServers .status {
+ margin-right: 10px;
+}
diff --git a/apps/federation/js/settings-admin.js b/apps/federation/js/settings-admin.js
new file mode 100644
index 00000000000..7d531b39d8c
--- /dev/null
+++ b/apps/federation/js/settings-admin.js
@@ -0,0 +1,82 @@
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+$(document).ready(function () {
+
+ // show input field to add a new trusted server
+ $("#ocFederationAddServer").on('click', function() {
+ $('#ocFederationAddServerButton').addClass('hidden');
+ $("#serverUrl").removeClass('hidden');
+ $("#serverUrl").focus();
+ });
+
+ // add new trusted server
+ $("#serverUrl").keyup(function (e) {
+ if (e.keyCode === 13) { // add server on "enter"
+ var url = $('#serverUrl').val();
+ OC.msg.startSaving('#ocFederationAddServer .msg');
+ $.post(
+ OC.generateUrl('/apps/federation/trusted-servers'),
+ {
+ url: url
+ }
+ ).done(function (data) {
+ $('#serverUrl').attr('value', '');
+ $('ul#listOfTrustedServers').prepend(
+ $('<li>')
+ .attr('id', data.id)
+ .attr('class', 'icon-delete')
+ .html('<span class="status indeterminate"></span>' + data.url)
+ );
+ OC.msg.finishedSuccess('#ocFederationAddServer .msg', data.message);
+ })
+ .fail(function (jqXHR) {
+ OC.msg.finishedError('#ocFederationAddServer .msg', JSON.parse(jqXHR.responseText).message);
+ });
+ } else if (e.keyCode === 27) { // hide input filed again in ESC
+ $('#ocFederationAddServerButton').toggleClass('hidden');
+ $("#serverUrl").toggleClass('hidden');
+ }
+ });
+
+ // remove trusted server from list
+ $( "#listOfTrustedServers" ).on('click', 'li', function() {
+ var id = $(this).attr('id');
+ var $this = $(this);
+ $.ajax({
+ url: OC.generateUrl('/apps/federation/trusted-servers/' + id),
+ type: 'DELETE',
+ success: function(response) {
+ $this.remove();
+ }
+ });
+
+ });
+
+ $("#ocFederationSettings #autoAddServers").change(function() {
+ $.post(
+ OC.generateUrl('/apps/federation/auto-add-servers'),
+ {
+ autoAddServers: $(this).is(":checked")
+ }
+ );
+ });
+
+});
diff --git a/apps/federation/lib/dbhandler.php b/apps/federation/lib/dbhandler.php
new file mode 100644
index 00000000000..61ba5c87cfd
--- /dev/null
+++ b/apps/federation/lib/dbhandler.php
@@ -0,0 +1,269 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation;
+
+
+use OC\Files\Filesystem;
+use OC\HintException;
+use OCP\IDBConnection;
+use OCP\IL10N;
+
+/**
+ * Class DbHandler
+ *
+ * handles all database calls for the federation app
+ *
+ * @group DB
+ * @package OCA\Federation
+ */
+class DbHandler {
+
+ /** @var IDBConnection */
+ private $connection;
+
+ /** @var IL10N */
+ private $l;
+
+ /** @var string */
+ private $dbTable = 'trusted_servers';
+
+ /**
+ * @param IDBConnection $connection
+ * @param IL10N $il10n
+ */
+ public function __construct(
+ IDBConnection $connection,
+ IL10N $il10n
+ ) {
+ $this->connection = $connection;
+ $this->IL10N = $il10n;
+ }
+
+ /**
+ * add server to the list of trusted ownCloud servers
+ *
+ * @param string $url
+ * @return int
+ * @throws HintException
+ */
+ public function addServer($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->insert($this->dbTable)
+ ->values(
+ [
+ 'url' => $query->createParameter('url'),
+ 'url_hash' => $query->createParameter('url_hash'),
+ ]
+ )
+ ->setParameter('url', $url)
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute();
+
+ if ($result) {
+ return (int)$this->connection->lastInsertId('*PREFIX*'.$this->dbTable);
+ } else {
+ $message = 'Internal failure, Could not add ownCloud as trusted server: ' . $url;
+ $message_t = $this->l->t('Could not add server');
+ throw new HintException($message, $message_t);
+ }
+ }
+
+ /**
+ * remove server from the list of trusted ownCloud servers
+ *
+ * @param int $id
+ */
+ public function removeServer($id) {
+ $query = $this->connection->getQueryBuilder();
+ $query->delete($this->dbTable)
+ ->where($query->expr()->eq('id', $query->createParameter('id')))
+ ->setParameter('id', $id);
+ $query->execute();
+ }
+
+ /**
+ * get all trusted servers
+ *
+ * @return array
+ */
+ public function getAllServer() {
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['url', 'id', 'status'])->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ return $result;
+ }
+
+ /**
+ * check if server already exists in the database table
+ *
+ * @param string $url
+ * @return bool
+ */
+ public function serverExists($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('url')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+ $result = $query->execute()->fetchAll();
+
+ return !empty($result);
+ }
+
+ /**
+ * write token to database. Token is used to exchange the secret
+ *
+ * @param string $url
+ * @param string $token
+ */
+ public function addToken($url, $token) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->update($this->dbTable)
+ ->set('token', $query->createParameter('token'))
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash)
+ ->setParameter('token', $token);
+ $query->execute();
+ }
+
+ /**
+ * get token stored in database
+ *
+ * @param string $url
+ * @return string
+ */
+ public function getToken($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('token')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute()->fetch();
+ return $result['token'];
+ }
+
+ /**
+ * add shared Secret to database
+ *
+ * @param string $url
+ * @param string $sharedSecret
+ */
+ public function addSharedSecret($url, $sharedSecret) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->update($this->dbTable)
+ ->set('shared_secret', $query->createParameter('sharedSecret'))
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash)
+ ->setParameter('sharedSecret', $sharedSecret);
+ $query->execute();
+ }
+
+ /**
+ * get shared secret from database
+ *
+ * @param string $url
+ * @return string
+ */
+ public function getSharedSecret($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('shared_secret')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute()->fetch();
+ return $result['shared_secret'];
+ }
+
+ /**
+ * set server status
+ *
+ * @param string $url
+ * @param int $status
+ */
+ public function setServerStatus($url, $status) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->update($this->dbTable)
+ ->set('status', $query->createParameter('status'))
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash)
+ ->setParameter('status', $status);
+ $query->execute();
+ }
+
+ /**
+ * get server status
+ *
+ * @param string $url
+ * @return int
+ */
+ public function getServerStatus($url) {
+ $hash = $this->hash($url);
+ $query = $this->connection->getQueryBuilder();
+ $query->select('status')->from($this->dbTable)
+ ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
+ ->setParameter('url_hash', $hash);
+
+ $result = $query->execute()->fetch();
+ return (int)$result['status'];
+ }
+
+ /**
+ * create hash from URL
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function hash($url) {
+ $normalized = $this->normalizeUrl($url);
+ return md5($normalized);
+ }
+
+ /**
+ * normalize URL, used to create the md5 hash
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function normalizeUrl($url) {
+ $normalized = $url;
+
+ if (strpos($url, 'https://') === 0) {
+ $normalized = substr($url, strlen('https://'));
+ } else if (strpos($url, 'http://') === 0) {
+ $normalized = substr($url, strlen('http://'));
+ }
+
+ $normalized = Filesystem::normalizePath($normalized);
+ $normalized = trim($normalized, '/');
+
+ return $normalized;
+ }
+
+}
diff --git a/apps/federation/lib/trustedservers.php b/apps/federation/lib/trustedservers.php
new file mode 100644
index 00000000000..96a29178076
--- /dev/null
+++ b/apps/federation/lib/trustedservers.php
@@ -0,0 +1,254 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation;
+
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClientService;
+use OCP\IConfig;
+use OCP\ILogger;
+use OCP\Security\ISecureRandom;
+
+class TrustedServers {
+
+ /** after a user list was exchanged at least once successfully */
+ const STATUS_OK = 1;
+ /** waiting for shared secret or initial user list exchange */
+ const STATUS_PENDING = 2;
+ /** something went wrong, misconfigured server, software bug,... user interaction needed */
+ const STATUS_FAILURE = 3;
+
+ /** @var dbHandler */
+ private $dbHandler;
+
+ /** @var IClientService */
+ private $httpClientService;
+
+ /** @var ILogger */
+ private $logger;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var ISecureRandom */
+ private $secureRandom;
+
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * @param DbHandler $dbHandler
+ * @param IClientService $httpClientService
+ * @param ILogger $logger
+ * @param IJobList $jobList
+ * @param ISecureRandom $secureRandom
+ * @param IConfig $config
+ */
+ public function __construct(
+ DbHandler $dbHandler,
+ IClientService $httpClientService,
+ ILogger $logger,
+ IJobList $jobList,
+ ISecureRandom $secureRandom,
+ IConfig $config
+ ) {
+ $this->dbHandler = $dbHandler;
+ $this->httpClientService = $httpClientService;
+ $this->logger = $logger;
+ $this->jobList = $jobList;
+ $this->secureRandom = $secureRandom;
+ $this->config = $config;
+ }
+
+ /**
+ * add server to the list of trusted ownCloud servers
+ *
+ * @param $url
+ * @return int server id
+ */
+ public function addServer($url) {
+ $url = $this->updateProtocol($url);
+ $result = $this->dbHandler->addServer($url);
+ if ($result) {
+ $token = $this->secureRandom->getMediumStrengthGenerator()->generate(16);
+ $this->dbHandler->addToken($url, $token);
+ $this->jobList->add(
+ 'OCA\Federation\BackgroundJob\RequestSharedSecret',
+ [
+ 'url' => $url,
+ 'token' => $token
+ ]
+ );
+ }
+
+ return $result;
+ }
+
+ /**
+ * enable/disable to automatically add servers to the list of trusted servers
+ * once a federated share was created and accepted successfully
+ *
+ * @param bool $status
+ */
+ public function setAutoAddServers($status) {
+ $value = $status ? '1' : '0';
+ $this->config->setAppValue('federation', 'autoAddServers', $value);
+ }
+
+ /**
+ * return if we automatically add servers to the list of trusted servers
+ * once a federated share was created and accepted successfully
+ *
+ * @return bool
+ */
+ public function getAutoAddServers() {
+ $value = $this->config->getAppValue('federation', 'autoAddServers', '1');
+ return $value === '1';
+ }
+
+ /**
+ * get shared secret for the given server
+ *
+ * @param string $url
+ * @return string
+ */
+ public function getSharedSecret($url) {
+ return $this->dbHandler->getSharedSecret($url);
+ }
+
+ /**
+ * add shared secret for the given server
+ *
+ * @param string $url
+ * @param $sharedSecret
+ */
+ public function addSharedSecret($url, $sharedSecret) {
+ $this->dbHandler->addSharedSecret($url, $sharedSecret);
+ }
+
+ /**
+ * remove server from the list of trusted ownCloud servers
+ *
+ * @param int $id
+ */
+ public function removeServer($id) {
+ $this->dbHandler->removeServer($id);
+ }
+
+ /**
+ * get all trusted servers
+ *
+ * @return array
+ */
+ public function getServers() {
+ return $this->dbHandler->getAllServer();
+ }
+
+ /**
+ * check if given server is a trusted ownCloud server
+ *
+ * @param string $url
+ * @return bool
+ */
+ public function isTrustedServer($url) {
+ return $this->dbHandler->serverExists($url);
+ }
+
+ /**
+ * set server status
+ *
+ * @param string $url
+ * @param int $status
+ */
+ public function setServerStatus($url, $status) {
+ $this->dbHandler->setServerStatus($url, $status);
+ }
+
+ /**
+ * @param string $url
+ * @return int
+ */
+ public function getServerStatus($url) {
+ return $this->dbHandler->getServerStatus($url);
+ }
+
+ /**
+ * check if URL point to a ownCloud server
+ *
+ * @param string $url
+ * @return bool
+ */
+ public function isOwnCloudServer($url) {
+ $isValidOwnCloud = false;
+ $client = $this->httpClientService->newClient();
+ try {
+ $result = $client->get(
+ $url . '/status.php',
+ [
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ );
+ if ($result->getStatusCode() === Http::STATUS_OK) {
+ $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody());
+ }
+ } catch (\Exception $e) {
+ $this->logger->error($e->getMessage(), ['app' => 'federation']);
+ return false;
+ }
+ return $isValidOwnCloud;
+ }
+
+ /**
+ * check if ownCloud version is >= 9.0
+ *
+ * @param $statusphp
+ * @return bool
+ */
+ protected function checkOwnCloudVersion($statusphp) {
+ $decoded = json_decode($statusphp, true);
+ if (!empty($decoded) && isset($decoded['version'])) {
+ return version_compare($decoded['version'], '9.0.0', '>=');
+ }
+ return false;
+ }
+
+ /**
+ * check if the URL contain a protocol, if not add https
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function updateProtocol($url) {
+ if (
+ strpos($url, 'https://') === 0
+ || strpos($url, 'http://') === 0
+ ) {
+
+ return $url;
+
+ }
+
+ return 'https://' . $url;
+ }
+}
diff --git a/apps/federation/middleware/addservermiddleware.php b/apps/federation/middleware/addservermiddleware.php
new file mode 100644
index 00000000000..56552021dc2
--- /dev/null
+++ b/apps/federation/middleware/addservermiddleware.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+namespace OCA\Federation\Middleware ;
+
+use OC\HintException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Middleware;
+use OCP\IL10N;
+use OCP\ILogger;
+
+class AddServerMiddleware extends Middleware {
+
+ /** @var string */
+ protected $appName;
+
+ /** @var IL10N */
+ protected $l;
+
+ /** @var ILogger */
+ protected $logger;
+
+ public function __construct($appName, IL10N $l, ILogger $logger) {
+ $this->appName = $appName;
+ $this->l = $l;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Log error message and return a response which can be displayed to the user
+ *
+ * @param \OCP\AppFramework\Controller $controller
+ * @param string $methodName
+ * @param \Exception $exception
+ * @return JSONResponse
+ */
+ public function afterException($controller, $methodName, \Exception $exception) {
+ $this->logger->error($exception->getMessage(), ['app' => $this->appName]);
+ if ($exception instanceof HintException) {
+ $message = $exception->getHint();
+ } else {
+ $message = $this->l->t('Unknown error');
+ }
+
+ return new JSONResponse(
+ ['message' => $message],
+ Http::STATUS_BAD_REQUEST
+ );
+
+ }
+
+}
diff --git a/apps/federation/settings/settings-admin.php b/apps/federation/settings/settings-admin.php
new file mode 100644
index 00000000000..76ae0c3b6e0
--- /dev/null
+++ b/apps/federation/settings/settings-admin.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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_Util::checkAdminUser();
+
+$template = new OCP\Template('federation', 'settings-admin');
+
+$dbHandler = new \OCA\Federation\DbHandler(
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getL10N('federation')
+);
+
+$trustedServers = new \OCA\Federation\TrustedServers(
+ $dbHandler,
+ \OC::$server->getHTTPClientService(),
+ \OC::$server->getLogger(),
+ \OC::$server->getJobList(),
+ \OC::$server->getSecureRandom(),
+ \OC::$server->getConfig()
+);
+
+$template->assign('trustedServers', $trustedServers->getServers());
+$template->assign('autoAddServers', $trustedServers->getAutoAddServers());
+
+return $template->fetchPage();
diff --git a/apps/federation/templates/settings-admin.php b/apps/federation/templates/settings-admin.php
new file mode 100644
index 00000000000..854bb744179
--- /dev/null
+++ b/apps/federation/templates/settings-admin.php
@@ -0,0 +1,40 @@
+<?php
+/** @var array $_ */
+use OCA\Federation\TrustedServers;
+
+/** @var OC_L10N $l */
+script('federation', 'settings-admin');
+style('federation', 'settings-admin')
+?>
+<div id="ocFederationSettings" class="section">
+ <h2><?php p($l->t('Federation')); ?></h2>
+ <em><?php p($l->t('ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing.')); ?></em>
+
+ <p>
+ <input id="autoAddServers" type="checkbox" class="checkbox" <?php if($_['autoAddServers']) p('checked'); ?> />
+ <label for="autoAddServers">Add server automatically once a federated share was created successfully</label>
+ </p>
+
+ <h3>Trusted ownCloud Servers</h3>
+ <p id="ocFederationAddServer">
+ <button id="ocFederationAddServerButton" class="">+ Add ownCloud server</button>
+ <input id="serverUrl" class="hidden" type="text" value="" placeholder="ownCloud Server" name="server_url"/>
+ <span class="msg"></span>
+ </p>
+ <ul id="listOfTrustedServers">
+ <?php foreach($_['trustedServers'] as $trustedServer) { ?>
+ <li id="<?php p($trustedServer['id']); ?>" class="icon-delete">
+ <?php if((int)$trustedServer['status'] === TrustedServers::STATUS_OK) { ?>
+ <span class="status success"></span>
+ <?php } elseif((int)$trustedServer['status'] === TrustedServers::STATUS_PENDING) { ?>
+ <span class="status indeterminate"></span>
+ <?php } else {?>
+ <span class="status error"></span>
+ <?php } ?>
+ <?php p($trustedServer['url']); ?>
+ </li>
+ <?php } ?>
+ </ul>
+
+</div>
+
diff --git a/apps/federation/tests/api/ocsauthapitest.php b/apps/federation/tests/api/ocsauthapitest.php
new file mode 100644
index 00000000000..a334686c24e
--- /dev/null
+++ b/apps/federation/tests/api/ocsauthapitest.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\API;
+
+
+use OC\BackgroundJob\JobList;
+use OCA\Federation\API\OCSAuthAPI;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\IRequest;
+use OCP\Security\ISecureRandom;
+use Test\TestCase;
+
+class OCSAuthAPITest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IRequest */
+ private $request;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
+ private $secureRandom;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | JobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var OCSAuthApi */
+ private $ocsAuthApi;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->request = $this->getMock('OCP\IRequest');
+ $this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+ $this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->jobList = $this->getMockBuilder('OC\BackgroundJob\JobList')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->ocsAuthApi = new OCSAuthAPI(
+ $this->request,
+ $this->secureRandom,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler
+ );
+
+ }
+
+ /**
+ * @dataProvider dataTestRequestSharedSecret
+ *
+ * @param string $token
+ * @param string $localToken
+ * @param bool $isTrustedServer
+ * @param int $expected
+ */
+ public function testRequestSharedSecret($token, $localToken, $isTrustedServer, $expected) {
+
+ $url = 'url';
+
+ $this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
+ $this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
+ $this->dbHandler->expects($this->any())
+ ->method('getToken')->with($url)->willReturn($localToken);
+
+ if ($expected === Http::STATUS_OK) {
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\GetSharedSecret', ['url' => $url, 'token' => $token]);
+ } else {
+ $this->jobList->expects($this->never())->method('add');
+ }
+
+ $result = $this->ocsAuthApi->requestSharedSecret();
+ $this->assertSame($expected, $result->getStatusCode());
+ }
+
+ public function dataTestRequestSharedSecret() {
+ return [
+ ['token2', 'token1', true, Http::STATUS_OK],
+ ['token1', 'token2', false, Http::STATUS_FORBIDDEN],
+ ['token1', 'token2', true, Http::STATUS_FORBIDDEN],
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestGetSharedSecret
+ *
+ * @param bool $isTrustedServer
+ * @param bool $isValidToken
+ * @param int $expected
+ */
+ public function testGetSharedSecret($isTrustedServer, $isValidToken, $expected) {
+
+ $url = 'url';
+ $token = 'token';
+
+ $this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
+ $this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);
+
+ /** @var OCSAuthAPI | \PHPUnit_Framework_MockObject_MockObject $ocsAuthApi */
+ $ocsAuthApi = $this->getMockBuilder('OCA\Federation\API\OCSAuthAPI')
+ ->setConstructorArgs(
+ [
+ $this->request,
+ $this->secureRandom,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler
+ ]
+ )->setMethods(['isValidToken'])->getMock();
+
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
+ $ocsAuthApi->expects($this->any())
+ ->method('isValidToken')->with($url, $token)->willReturn($isValidToken);
+
+ if($expected === Http::STATUS_OK) {
+ $this->secureRandom->expects($this->once())->method('getMediumStrengthGenerator')
+ ->willReturn($this->secureRandom);
+ $this->secureRandom->expects($this->once())->method('generate')->with(32)
+ ->willReturn('secret');
+ $this->trustedServers->expects($this->once())
+ ->method('addSharedSecret')->willReturn($url, 'secret');
+ $this->dbHandler->expects($this->once())
+ ->method('addToken')->with($url, '');
+ } else {
+ $this->secureRandom->expects($this->never())->method('getMediumStrengthGenerator');
+ $this->secureRandom->expects($this->never())->method('generate');
+ $this->trustedServers->expects($this->never())->method('addSharedSecret');
+ $this->dbHandler->expects($this->never())->method('addToken');
+ }
+
+ $result = $ocsAuthApi->getSharedSecret();
+
+ $this->assertSame($expected, $result->getStatusCode());
+
+ if ($expected === Http::STATUS_OK) {
+ $data = $result->getData();
+ $this->assertSame('secret', $data['sharedSecret']);
+ }
+ }
+
+ public function dataTestGetSharedSecret() {
+ return [
+ [true, true, Http::STATUS_OK],
+ [false, true, Http::STATUS_FORBIDDEN],
+ [true, false, Http::STATUS_FORBIDDEN],
+ [false, false, Http::STATUS_FORBIDDEN],
+ ];
+ }
+
+}
diff --git a/apps/federation/tests/backgroundjob/getsharedsecrettest.php b/apps/federation/tests/backgroundjob/getsharedsecrettest.php
new file mode 100644
index 00000000000..953af5ff3e1
--- /dev/null
+++ b/apps/federation/tests/backgroundjob/getsharedsecrettest.php
@@ -0,0 +1,190 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\BackgroundJob;
+
+
+use OCA\Federation\BackgroundJob\GetSharedSecret;
+use OCA\Files_Sharing\Tests\TestCase;
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\AppFramework\Http;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\Http\Client\IResponse;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+
+class GetSharedSecretTest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
+ private $httpClient;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IURLGenerator */
+ private $urlGenerator;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
+ private $logger;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
+ private $response;
+
+ /** @var GetSharedSecret */
+ private $getSharedSecret;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->httpClient = $this->getMock('OCP\Http\Client\IClient');
+ $this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
+ $this->urlGenerator = $this->getMock('OCP\IURLGenerator');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+ $this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->logger = $this->getMock('OCP\ILogger');
+ $this->response = $this->getMock('OCP\Http\Client\IResponse');
+
+ $this->getSharedSecret = new GetSharedSecret(
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->logger,
+ $this->dbHandler
+ );
+ }
+
+ /**
+ * @dataProvider dataTestExecute
+ *
+ * @param bool $isTrustedServer
+ */
+ public function testExecute($isTrustedServer) {
+ /** @var GetSharedSecret |\PHPUnit_Framework_MockObject_MockObject $getSharedSecret */
+ $getSharedSecret = $this->getMockBuilder('OCA\Federation\BackgroundJob\GetSharedSecret')
+ ->setConstructorArgs(
+ [
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->logger,
+ $this->dbHandler
+ ]
+ )->setMethods(['parentExecute'])->getMock();
+ $this->invokePrivate($getSharedSecret, 'argument', [['url' => 'url']]);
+
+ $this->jobList->expects($this->once())->method('remove');
+ $this->trustedServers->expects($this->once())->method('isTrustedServer')
+ ->with('url')->willReturn($isTrustedServer);
+ if ($isTrustedServer) {
+ $getSharedSecret->expects($this->once())->method('parentExecute');
+ } else {
+ $getSharedSecret->expects($this->never())->method('parentExecute');
+ }
+
+ $getSharedSecret->execute($this->jobList);
+
+ }
+
+ public function dataTestExecute() {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestRun
+ *
+ * @param int $statusCode
+ */
+ public function testRun($statusCode) {
+
+ $target = 'targetURL';
+ $source = 'sourceURL';
+ $token = 'token';
+
+ $argument = ['url' => $target, 'token' => $token];
+
+ $this->urlGenerator->expects($this->once())->method('getAbsoluteURL')->with('/')
+ ->willReturn($source);
+ $this->httpClient->expects($this->once())->method('get')
+ ->with(
+ $target . '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json',
+ [
+ 'query' =>
+ [
+ 'url' => $source,
+ 'token' => $token
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ )->willReturn($this->response);
+
+ $this->response->expects($this->once())->method('getStatusCode')
+ ->willReturn($statusCode);
+
+ if (
+ $statusCode !== Http::STATUS_OK
+ && $statusCode !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\GetSharedSecret', $argument);
+ $this->dbHandler->expects($this->never())->method('addToken');
+ } else {
+ $this->dbHandler->expects($this->once())->method('addToken')->with($target, '');
+ $this->jobList->expects($this->never())->method('add');
+ }
+
+ if ($statusCode === Http::STATUS_OK) {
+ $this->response->expects($this->once())->method('getBody')
+ ->willReturn('{"ocs":{"data":{"sharedSecret":"secret"}}}');
+ $this->trustedServers->expects($this->once())->method('addSharedSecret')
+ ->with($target, 'secret');
+ } else {
+ $this->trustedServers->expects($this->never())->method('addSharedSecret');
+ }
+
+ $this->invokePrivate($this->getSharedSecret, 'run', [$argument]);
+ }
+
+ public function dataTestRun() {
+ return [
+ [Http::STATUS_OK],
+ [Http::STATUS_FORBIDDEN],
+ [Http::STATUS_CONFLICT],
+ ];
+ }
+
+}
diff --git a/apps/federation/tests/backgroundjob/requestsharedsecrettest.php b/apps/federation/tests/backgroundjob/requestsharedsecrettest.php
new file mode 100644
index 00000000000..df81113c686
--- /dev/null
+++ b/apps/federation/tests/backgroundjob/requestsharedsecrettest.php
@@ -0,0 +1,169 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\BackgroundJob;
+
+
+use OCA\Federation\BackgroundJob\RequestSharedSecret;
+use OCP\AppFramework\Http;
+use Test\TestCase;
+
+class RequestSharedSecretTest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
+ private $httpClient;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IURLGenerator */
+ private $urlGenerator;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
+ private $response;
+
+ /** @var RequestSharedSecret */
+ private $requestSharedSecret;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->httpClient = $this->getMock('OCP\Http\Client\IClient');
+ $this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
+ $this->urlGenerator = $this->getMock('OCP\IURLGenerator');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+ $this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->response = $this->getMock('OCP\Http\Client\IResponse');
+
+ $this->requestSharedSecret = new RequestSharedSecret(
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler
+ );
+ }
+
+ /**
+ * @dataProvider dataTestExecute
+ *
+ * @param bool $isTrustedServer
+ */
+ public function testExecute($isTrustedServer) {
+ /** @var RequestSharedSecret |\PHPUnit_Framework_MockObject_MockObject $requestSharedSecret */
+ $requestSharedSecret = $this->getMockBuilder('OCA\Federation\BackgroundJob\RequestSharedSecret')
+ ->setConstructorArgs(
+ [
+ $this->httpClient,
+ $this->urlGenerator,
+ $this->jobList,
+ $this->trustedServers,
+ $this->dbHandler
+ ]
+ )->setMethods(['parentExecute'])->getMock();
+ $this->invokePrivate($requestSharedSecret, 'argument', [['url' => 'url']]);
+
+ $this->jobList->expects($this->once())->method('remove');
+ $this->trustedServers->expects($this->once())->method('isTrustedServer')
+ ->with('url')->willReturn($isTrustedServer);
+ if ($isTrustedServer) {
+ $requestSharedSecret->expects($this->once())->method('parentExecute');
+ } else {
+ $requestSharedSecret->expects($this->never())->method('parentExecute');
+ }
+
+ $requestSharedSecret->execute($this->jobList);
+
+ }
+
+ public function dataTestExecute() {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestRun
+ *
+ * @param int $statusCode
+ */
+ public function testRun($statusCode) {
+
+ $target = 'targetURL';
+ $source = 'sourceURL';
+ $token = 'token';
+
+ $argument = ['url' => $target, 'token' => $token];
+
+ $this->urlGenerator->expects($this->once())->method('getAbsoluteURL')->with('/')
+ ->willReturn($source);
+ $this->httpClient->expects($this->once())->method('post')
+ ->with(
+ $target . '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json',
+ [
+ 'body' =>
+ [
+ 'url' => $source,
+ 'token' => $token
+ ],
+ 'timeout' => 3,
+ 'connect_timeout' => 3,
+ ]
+ )->willReturn($this->response);
+
+ $this->response->expects($this->once())->method('getStatusCode')
+ ->willReturn($statusCode);
+
+ if (
+ $statusCode !== Http::STATUS_OK
+ && $statusCode !== Http::STATUS_FORBIDDEN
+ ) {
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\RequestSharedSecret', $argument);
+ $this->dbHandler->expects($this->never())->method('addToken');
+ }
+
+ if ($statusCode === Http::STATUS_FORBIDDEN) {
+ $this->jobList->expects($this->never())->method('add');
+ $this->dbHandler->expects($this->once())->method('addToken')->with($target, '');
+ }
+
+ $this->invokePrivate($this->requestSharedSecret, 'run', [$argument]);
+ }
+
+ public function dataTestRun() {
+ return [
+ [Http::STATUS_OK],
+ [Http::STATUS_FORBIDDEN],
+ [Http::STATUS_CONFLICT],
+ ];
+ }
+}
diff --git a/apps/federation/tests/controller/settingscontrollertest.php b/apps/federation/tests/controller/settingscontrollertest.php
new file mode 100644
index 00000000000..efbc6911c52
--- /dev/null
+++ b/apps/federation/tests/controller/settingscontrollertest.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\Controller;
+
+
+use OCA\Federation\Controller\SettingsController;
+use OCP\AppFramework\Http\DataResponse;
+use Test\TestCase;
+
+class SettingsControllerTest extends TestCase {
+
+ /** @var SettingsController */
+ private $controller;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IRequest */
+ private $request;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */
+ private $l10n;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCA\Federation\TrustedServers */
+ private $trustedServers;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->request = $this->getMock('OCP\IRequest');
+ $this->l10n = $this->getMock('OCP\IL10N');
+ $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->controller = new SettingsController(
+ 'SettingsControllerTest',
+ $this->request,
+ $this->l10n,
+ $this->trustedServers
+ );
+ }
+
+ public function testAddServer() {
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn(false);
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn(true);
+
+ $result = $this->controller->addServer('url');
+ $this->assertTrue($result instanceof DataResponse);
+
+ $data = $result->getData();
+ $this->assertSame(200, $result->getStatus());
+ $this->assertSame('url', $data['url']);
+ $this->assertArrayHasKey('id', $data);
+ }
+
+ /**
+ * @dataProvider checkServerFails
+ * @expectedException \OC\HintException
+ *
+ * @param bool $isTrustedServer
+ * @param bool $isOwnCloud
+ */
+ public function testAddServerFail($isTrustedServer, $isOwnCloud) {
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn($isTrustedServer);
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn($isOwnCloud);
+
+ $this->controller->addServer('url');
+ }
+
+ public function testRemoveServer() {
+ $this->trustedServers->expects($this->once())->method('removeServer')
+ ->with('url');
+ $result = $this->controller->removeServer('url');
+ $this->assertTrue($result instanceof DataResponse);
+ $this->assertSame(200, $result->getStatus());
+ }
+
+ public function testCheckServer() {
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn(false);
+ $this->trustedServers
+ ->expects($this->once())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn(true);
+
+ $this->assertTrue(
+ $this->invokePrivate($this->controller, 'checkServer', ['url'])
+ );
+
+ }
+
+ /**
+ * @dataProvider checkServerFails
+ * @expectedException \OC\HintException
+ *
+ * @param bool $isTrustedServer
+ * @param bool $isOwnCloud
+ */
+ public function testCheckServerFail($isTrustedServer, $isOwnCloud) {
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isTrustedServer')
+ ->with('url')
+ ->willReturn($isTrustedServer);
+ $this->trustedServers
+ ->expects($this->any())
+ ->method('isOwnCloudServer')
+ ->with('url')
+ ->willReturn($isOwnCloud);
+
+ $this->assertTrue(
+ $this->invokePrivate($this->controller, 'checkServer', ['url'])
+ );
+
+ }
+
+ /**
+ * data to simulate checkServer fails
+ *
+ * @return array
+ */
+ public function checkServerFails() {
+ return [
+ [true, true],
+ [false, false]
+ ];
+ }
+
+}
diff --git a/apps/federation/tests/lib/dbhandlertest.php b/apps/federation/tests/lib/dbhandlertest.php
new file mode 100644
index 00000000000..e47df092f8c
--- /dev/null
+++ b/apps/federation/tests/lib/dbhandlertest.php
@@ -0,0 +1,243 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\lib;
+
+
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\IDBConnection;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class DbHandlerTest extends TestCase {
+
+ /** @var DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject */
+ private $il10n;
+
+ /** @var IDBConnection */
+ private $connection;
+
+ /** @var string */
+ private $dbTable = 'trusted_servers';
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->il10n = $this->getMock('OCP\IL10N');
+
+ $this->dbHandler = new DbHandler(
+ $this->connection,
+ $this->il10n
+ );
+
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertEmpty($result, 'we need to start with a empty trusted_servers table');
+ }
+
+ public function tearDown() {
+ parent::tearDown();
+ $query = $this->connection->getQueryBuilder()->delete($this->dbTable);
+ $query->execute();
+ }
+
+ public function testAddServer() {
+ $id = $this->dbHandler->addServer('server1');
+
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame('server1', $result[0]['url']);
+ $this->assertSame($id, (int)$result[0]['id']);
+ $this->assertSame(TrustedServers::STATUS_PENDING, (int)$result[0]['status']);
+ }
+
+ public function testRemove() {
+ $id1 = $this->dbHandler->addServer('server1');
+ $id2 = $this->dbHandler->addServer('server2');
+
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(2, count($result));
+ $this->assertSame('server1', $result[0]['url']);
+ $this->assertSame('server2', $result[1]['url']);
+ $this->assertSame($id1, (int)$result[0]['id']);
+ $this->assertSame($id2, (int)$result[1]['id']);
+
+ $this->dbHandler->removeServer($id2);
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame('server1', $result[0]['url']);
+ $this->assertSame($id1, (int)$result[0]['id']);
+ }
+
+ public function testGetAll() {
+ $id1 = $this->dbHandler->addServer('server1');
+ $id2 = $this->dbHandler->addServer('server2');
+
+ $result = $this->dbHandler->getAllServer();
+ $this->assertSame(2, count($result));
+ $this->assertSame('server1', $result[0]['url']);
+ $this->assertSame('server2', $result[1]['url']);
+ $this->assertSame($id1, (int)$result[0]['id']);
+ $this->assertSame($id2, (int)$result[1]['id']);
+ }
+
+ /**
+ * @dataProvider dataTestServerExists
+ *
+ * @param string $serverInTable
+ * @param string $checkForServer
+ * @param bool $expected
+ */
+ public function testServerExists($serverInTable, $checkForServer, $expected) {
+ $this->dbHandler->addServer($serverInTable);
+ $this->assertSame($expected,
+ $this->dbHandler->serverExists($checkForServer)
+ );
+ }
+
+ public function dataTestServerExists() {
+ return [
+ ['server1', 'server1', true],
+ ['server1', 'http://server1', true],
+ ['server1', 'server2', false]
+ ];
+ }
+
+ public function testAddToken() {
+ $this->dbHandler->addServer('server1');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(null, $result[0]['token']);
+ $this->dbHandler->addToken('http://server1', 'token');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame('token', $result[0]['token']);
+ }
+
+ public function testGetToken() {
+ $this->dbHandler->addServer('server1');
+ $this->dbHandler->addToken('http://server1', 'token');
+ $this->assertSame('token',
+ $this->dbHandler->getToken('https://server1')
+ );
+ }
+
+ public function testAddSharedSecret() {
+ $this->dbHandler->addServer('server1');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(null, $result[0]['shared_secret']);
+ $this->dbHandler->addSharedSecret('http://server1', 'secret');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame('secret', $result[0]['shared_secret']);
+ }
+
+ public function testGetSharedSecret() {
+ $this->dbHandler->addServer('server1');
+ $this->dbHandler->addSharedSecret('http://server1', 'secret');
+ $this->assertSame('secret',
+ $this->dbHandler->getSharedSecret('https://server1')
+ );
+ }
+
+ public function testSetServerStatus() {
+ $this->dbHandler->addServer('server1');
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(TrustedServers::STATUS_PENDING, (int)$result[0]['status']);
+ $this->dbHandler->setServerStatus('http://server1', TrustedServers::STATUS_OK);
+ $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
+ $result = $query->execute()->fetchAll();
+ $this->assertSame(1, count($result));
+ $this->assertSame(TrustedServers::STATUS_OK, (int)$result[0]['status']);
+ }
+
+ public function testGetServerStatus() {
+ $this->dbHandler->addServer('server1');
+ $this->dbHandler->setServerStatus('http://server1', TrustedServers::STATUS_OK);
+ $this->assertSame(TrustedServers::STATUS_OK,
+ $this->dbHandler->getServerStatus('https://server1')
+ );
+ }
+
+ /**
+ * hash should always be computed with the normalized URL
+ *
+ * @dataProvider dataTestHash
+ *
+ * @param string $url
+ * @param string $expected
+ */
+ public function testHash($url, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->dbHandler, 'hash', [$url])
+ );
+ }
+
+ public function dataTestHash() {
+ return [
+ ['server1', md5('server1')],
+ ['http://server1', md5('server1')],
+ ['https://server1', md5('server1')],
+ ['http://server1/', md5('server1')],
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestNormalizeUrl
+ *
+ * @param string $url
+ * @param string $expected
+ */
+ public function testNormalizeUrl($url, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->dbHandler, 'normalizeUrl', [$url])
+ );
+ }
+
+ public function dataTestNormalizeUrl() {
+ return [
+ ['owncloud.org', 'owncloud.org'],
+ ['http://owncloud.org', 'owncloud.org'],
+ ['https://owncloud.org', 'owncloud.org'],
+ ['https://owncloud.org//mycloud', 'owncloud.org/mycloud'],
+ ['https://owncloud.org/mycloud/', 'owncloud.org/mycloud'],
+ ];
+ }
+
+}
diff --git a/apps/federation/tests/lib/trustedserverstest.php b/apps/federation/tests/lib/trustedserverstest.php
new file mode 100644
index 00000000000..d067cd1c185
--- /dev/null
+++ b/apps/federation/tests/lib/trustedserverstest.php
@@ -0,0 +1,344 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\lib;
+
+
+use OCA\Federation\DbHandler;
+use OCA\Federation\TrustedServers;
+use OCP\BackgroundJob\IJobList;
+use OCP\Http\Client\IClient;
+use OCP\Http\Client\IClientService;
+use OCP\Http\Client\IResponse;
+use OCP\IConfig;
+use OCP\ILogger;
+use OCP\Security\ISecureRandom;
+use Test\TestCase;
+
+class TrustedServersTest extends TestCase {
+
+ /** @var TrustedServers */
+ private $trustedServers;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
+ private $dbHandler;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClientService */
+ private $httpClientService;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IClient */
+ private $httpClient;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */
+ private $response;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
+ private $logger;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
+ private $jobList;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
+ private $secureRandom;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | IConfig */
+ private $config;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->dbHandler = $this->getMockBuilder('\OCA\Federation\DbHandler')
+ ->disableOriginalConstructor()->getMock();
+ $this->httpClientService = $this->getMock('OCP\Http\Client\IClientService');
+ $this->httpClient = $this->getMock('OCP\Http\Client\IClient');
+ $this->response = $this->getMock('OCP\Http\Client\IResponse');
+ $this->logger = $this->getMock('OCP\ILogger');
+ $this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
+ $this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
+ $this->config = $this->getMock('OCP\IConfig');
+
+ $this->trustedServers = new TrustedServers(
+ $this->dbHandler,
+ $this->httpClientService,
+ $this->logger,
+ $this->jobList,
+ $this->secureRandom,
+ $this->config
+ );
+
+ }
+
+ /**
+ * @dataProvider dataTrueFalse
+ *
+ * @param bool $success
+ */
+ public function testAddServer($success) {
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */
+ $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->setConstructorArgs(
+ [
+ $this->dbHandler,
+ $this->httpClientService,
+ $this->logger,
+ $this->jobList,
+ $this->secureRandom,
+ $this->config
+ ]
+ )
+ ->setMethods(['normalizeUrl', 'updateProtocol'])
+ ->getMock();
+ $trustedServers->expects($this->once())->method('updateProtocol')
+ ->with('url')->willReturn('https://url');
+ $this->dbHandler->expects($this->once())->method('addServer')->with('https://url')
+ ->willReturn($success);
+
+ if ($success) {
+ $this->secureRandom->expects($this->once())->method('getMediumStrengthGenerator')
+ ->willReturn($this->secureRandom);
+ $this->secureRandom->expects($this->once())->method('generate')
+ ->willReturn('token');
+ $this->dbHandler->expects($this->once())->method('addToken')->with('https://url', 'token');
+ $this->jobList->expects($this->once())->method('add')
+ ->with('OCA\Federation\BackgroundJob\RequestSharedSecret',
+ ['url' => 'https://url', 'token' => 'token']);
+ } else {
+ $this->jobList->expects($this->never())->method('add');
+ }
+
+ $this->assertSame($success,
+ $trustedServers->addServer('url')
+ );
+ }
+
+ public function dataTrueFalse() {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTrueFalse
+ *
+ * @param bool $status
+ */
+ public function testSetAutoAddServers($status) {
+ if ($status) {
+ $this->config->expects($this->once())->method('setAppValue')
+ ->with('federation', 'autoAddServers', '1');
+ } else {
+ $this->config->expects($this->once())->method('setAppValue')
+ ->with('federation', 'autoAddServers', '0');
+ }
+
+ $this->trustedServers->setAutoAddServers($status);
+ }
+
+ /**
+ * @dataProvider dataTestGetAutoAddServers
+ *
+ * @param string $status
+ * @param bool $expected
+ */
+ public function testGetAutoAddServers($status, $expected) {
+ $this->config->expects($this->once())->method('getAppValue')
+ ->with('federation', 'autoAddServers', '1')->willReturn($status);
+
+ $this->assertSame($expected,
+ $this->trustedServers->getAutoAddServers($status)
+ );
+ }
+
+ public function dataTestGetAutoAddServers() {
+ return [
+ ['1', true],
+ ['0', false]
+ ];
+ }
+
+ public function testAddSharedSecret() {
+ $this->dbHandler->expects($this->once())->method('addSharedSecret')
+ ->with('url', 'secret');
+ $this->trustedServers->addSharedSecret('url', 'secret');
+ }
+
+ public function testGetSharedSecret() {
+ $this->dbHandler->expects($this->once())->method('getSharedSecret')
+ ->with('url')->willReturn(true);
+ $this->assertTrue(
+ $this->trustedServers->getSharedSecret('url')
+ );
+ }
+
+ public function testRemoveServer() {
+ $id = 42;
+ $this->dbHandler->expects($this->once())->method('removeServer')->with($id);
+ $this->trustedServers->removeServer($id);
+ }
+
+ public function testGetServers() {
+ $this->dbHandler->expects($this->once())->method('getAllServer')->willReturn(true);
+
+ $this->assertTrue(
+ $this->trustedServers->getServers()
+ );
+ }
+
+
+ public function testIsTrustedServer() {
+ $this->dbHandler->expects($this->once())->method('serverExists')->with('url')
+ ->willReturn(true);
+
+ $this->assertTrue(
+ $this->trustedServers->isTrustedServer('url')
+ );
+ }
+
+ public function testSetServerStatus() {
+ $this->dbHandler->expects($this->once())->method('setServerStatus')
+ ->with('url', 'status');
+ $this->trustedServers->setServerStatus('url', 'status');
+ }
+
+ public function testGetServerStatus() {
+ $this->dbHandler->expects($this->once())->method('getServerStatus')
+ ->with('url')->willReturn(true);
+ $this->assertTrue(
+ $this->trustedServers->getServerStatus('url')
+ );
+ }
+
+ /**
+ * @dataProvider dataTestIsOwnCloudServer
+ *
+ * @param int $statusCode
+ * @param bool $isValidOwnCloudVersion
+ * @param bool $expected
+ */
+ public function testIsOwnCloudServer($statusCode, $isValidOwnCloudVersion, $expected) {
+
+ $server = 'server1';
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */
+ $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
+ ->setConstructorArgs(
+ [
+ $this->dbHandler,
+ $this->httpClientService,
+ $this->logger,
+ $this->jobList,
+ $this->secureRandom,
+ $this->config
+ ]
+ )
+ ->setMethods(['checkOwnCloudVersion'])
+ ->getMock();
+
+ $this->httpClientService->expects($this->once())->method('newClient')
+ ->willReturn($this->httpClient);
+
+ $this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
+ ->willReturn($this->response);
+
+ $this->response->expects($this->once())->method('getStatusCode')
+ ->willReturn($statusCode);
+
+ if ($statusCode === 200) {
+ $trustedServers->expects($this->once())->method('checkOwnCloudVersion')
+ ->willReturn($isValidOwnCloudVersion);
+ } else {
+ $trustedServers->expects($this->never())->method('checkOwnCloudVersion');
+ }
+
+ $this->assertSame($expected,
+ $trustedServers->isOwnCloudServer($server)
+ );
+
+ }
+
+ public function dataTestIsOwnCloudServer() {
+ return [
+ [200, true, true],
+ [200, false, false],
+ [404, true, false],
+ ];
+ }
+
+ public function testIsOwnCloudServerFail() {
+ $server = 'server1';
+
+ $this->httpClientService->expects($this->once())->method('newClient')
+ ->willReturn($this->httpClient);
+
+ $this->logger->expects($this->once())->method('error')
+ ->with('simulated exception', ['app' => 'federation']);
+
+ $this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
+ ->willReturnCallback(function () {
+ throw new \Exception('simulated exception');
+ });
+
+ $this->assertFalse($this->trustedServers->isOwnCloudServer($server));
+
+ }
+
+ /**
+ * @dataProvider dataTestCheckOwnCloudVersion
+ *
+ * @param $statusphp
+ * @param $expected
+ */
+ public function testCheckOwnCloudVersion($statusphp, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->trustedServers, 'checkOwnCloudVersion', [$statusphp])
+ );
+ }
+
+ public function dataTestCheckOwnCloudVersion() {
+ return [
+ ['{"version":"8.4.0"}', false],
+ ['{"version":"9.0.0"}', true],
+ ['{"version":"9.1.0"}', true]
+ ];
+ }
+
+ /**
+ * @dataProvider dataTestUpdateProtocol
+ * @param string $url
+ * @param string $expected
+ */
+ public function testUpdateProtocol($url, $expected) {
+ $this->assertSame($expected,
+ $this->invokePrivate($this->trustedServers, 'updateProtocol', [$url])
+ );
+ }
+
+ public function dataTestUpdateProtocol() {
+ return [
+ ['http://owncloud.org', 'http://owncloud.org'],
+ ['https://owncloud.org', 'https://owncloud.org'],
+ ['owncloud.org', 'https://owncloud.org'],
+ ['httpserver', 'https://httpserver'],
+ ];
+ }
+}
diff --git a/apps/federation/tests/middleware/addservermiddlewaretest.php b/apps/federation/tests/middleware/addservermiddlewaretest.php
new file mode 100644
index 00000000000..1be5a342285
--- /dev/null
+++ b/apps/federation/tests/middleware/addservermiddlewaretest.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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/>
+ *
+ */
+
+
+namespace OCA\Federation\Tests\Middleware;
+
+
+use OC\HintException;
+use OCA\Federation\Middleware\AddServerMiddleware;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use Test\TestCase;
+
+class AddServerMiddlewareTest extends TestCase {
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
+ private $logger;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */
+ private $l10n;
+
+ /** @var AddServerMiddleware */
+ private $middleware;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | Controller */
+ private $controller;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->logger = $this->getMock('OCP\ILogger');
+ $this->l10n = $this->getMock('OCP\IL10N');
+ $this->controller = $this->getMockBuilder('OCP\AppFramework\Controller')
+ ->disableOriginalConstructor()->getMock();
+
+ $this->middleware = new AddServerMiddleware(
+ 'AddServerMiddlewareTest',
+ $this->l10n,
+ $this->logger
+ );
+ }
+
+ /**
+ * @dataProvider dataTestAfterException
+ *
+ * @param \Exception $exception
+ * @param string $message
+ * @param string $hint
+ */
+ public function testAfterException($exception, $message, $hint) {
+
+ $this->logger->expects($this->once())->method('error')
+ ->with($message, ['app' => 'AddServerMiddlewareTest']);
+
+ $this->l10n->expects($this->any())->method('t')
+ ->willReturnCallback(
+ function($message) {
+ return $message;
+ }
+ );
+
+ $result = $this->middleware->afterException($this->controller, 'method', $exception);
+
+ $this->assertSame(Http::STATUS_BAD_REQUEST,
+ $result->getStatus()
+ );
+
+ $data = $result->getData();
+
+ $this->assertSame($hint,
+ $data['message']
+ );
+ }
+
+ public function dataTestAfterException() {
+ return [
+ [new HintException('message', 'hint'), 'message', 'hint'],
+ [new \Exception('message'), 'message', 'Unknown error'],
+ ];
+ }
+
+}
diff --git a/apps/files/ajax/delete.php b/apps/files/ajax/delete.php
deleted file mode 100644
index 2d02869df14..00000000000
--- a/apps/files/ajax/delete.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-
-// Get data
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$allFiles = isset($_POST["allfiles"]) ? (string)$_POST["allfiles"] : false;
-
-// delete all files in dir ?
-if ($allFiles === 'true') {
- $files = array();
- $fileList = \OC\Files\Filesystem::getDirectoryContent($dir);
- foreach ($fileList as $fileInfo) {
- $files[] = $fileInfo['name'];
- }
-} else {
- $files = isset($_POST["file"]) ? (string)$_POST["file"] : (string)$_POST["files"];
- $files = json_decode($files);
-}
-$filesWithError = '';
-
-$success = true;
-
-//Now delete
-foreach ($files as $file) {
- try {
- if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) &&
- !(\OC\Files\Filesystem::isDeletable($dir . '/' . $file) &&
- \OC\Files\Filesystem::unlink($dir . '/' . $file))
- ) {
- $filesWithError .= $file . "\n";
- $success = false;
- }
- } catch (\Exception $e) {
- $filesWithError .= $file . "\n";
- $success = false;
- }
-}
-
-// get array with updated storage stats (e.g. max file size) after upload
-try {
- $storageStats = \OCA\Files\Helper::buildFileStorageStatistics($dir);
-} catch(\OCP\Files\NotFoundException $e) {
- OCP\JSON::error(['data' => ['message' => 'File not found']]);
- return;
-}
-
-if ($success) {
- OCP\JSON::success(array("data" => array_merge(array("dir" => $dir, "files" => $files), $storageStats)));
-} else {
- OCP\JSON::error(array("data" => array_merge(array("message" => "Could not delete:\n" . $filesWithError), $storageStats)));
-}
diff --git a/apps/files/ajax/move.php b/apps/files/ajax/move.php
deleted file mode 100644
index 0961636a116..00000000000
--- a/apps/files/ajax/move.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-// Get data
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$file = isset($_POST['file']) ? (string)$_POST['file'] : '';
-$target = isset($_POST['target']) ? rawurldecode((string)$_POST['target']) : '';
-
-$l = \OC::$server->getL10N('files');
-
-if(\OC\Files\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)) )));
- exit;
-}
-
-if ($target != '' || strtolower($file) != 'shared') {
- $targetFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file);
- $sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file);
- try {
- 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" => $l->t("Could not move %s", array($file)) )));
- }
- } catch (\OCP\Files\NotPermittedException $e) {
- OCP\JSON::error(array("data" => array( "message" => $l->t("Permission denied") )));
- } catch (\Exception $e) {
- OCP\JSON::error(array("data" => array( "message" => $e->getMessage())));
- }
-}else{
- OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
-}
diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php
deleted file mode 100644
index be09b288d4b..00000000000
--- a/apps/files/ajax/newfile.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-/**
- * @author Andreas Fischer <bantu@owncloud.com>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-// Init owncloud
-global $eventSource;
-
-\OCP\JSON::checkLoggedIn();
-\OCP\JSON::callCheck();
-
-\OC::$server->getSession()->close();
-
-// Get the params
-$dir = isset( $_REQUEST['dir'] ) ? '/'.trim((string)$_REQUEST['dir'], '/\\') : '';
-$fileName = isset( $_REQUEST['filename'] ) ? trim((string)$_REQUEST['filename'], '/\\') : '';
-
-$l10n = \OC::$server->getL10N('files');
-
-$result = array(
- 'success' => false,
- 'data' => NULL
-);
-
-try {
- \OC\Files\Filesystem::getView()->verifyPath($dir, $fileName);
-} catch (\OCP\Files\InvalidPathException $ex) {
- $result['data'] = [
- 'message' => $ex->getMessage()];
- OCP\JSON::error($result);
- return;
-}
-
-if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
- $result['data'] = array('message' => (string)$l10n->t(
- 'The target folder has been moved or deleted.'),
- 'code' => 'targetnotfound'
- );
- OCP\JSON::error($result);
- exit();
-}
-
-$target = $dir.'/'.$fileName;
-
-if (\OC\Files\Filesystem::file_exists($target)) {
- $result['data'] = array('message' => (string)$l10n->t(
- 'The name %s is already used in the folder %s. Please choose a different name.',
- array($fileName, $dir))
- );
- OCP\JSON::error($result);
- exit();
-}
-
-$success = false;
-$templateManager = OC_Helper::getFileTemplateManager();
-$mimeType = OC_Helper::getMimetypeDetector()->detectPath($target);
-$content = $templateManager->getTemplate($mimeType);
-
-try {
- if($content) {
- $success = \OC\Files\Filesystem::file_put_contents($target, $content);
- } else {
- $success = \OC\Files\Filesystem::touch($target);
- }
-} catch (\Exception $e) {
- $result = [
- 'success' => false,
- 'data' => [
- 'message' => $e->getMessage()
- ]
- ];
- OCP\JSON::error($result);
- exit();
-}
-
-if($success) {
- $meta = \OC\Files\Filesystem::getFileInfo($target);
- OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
- return;
-}
-
-OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the file') )));
diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php
deleted file mode 100644
index a2897dd437a..00000000000
--- a/apps/files/ajax/newfolder.php
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-// Init owncloud
-
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-// Get the params
-$dir = isset($_POST['dir']) ? (string)$_POST['dir'] : '';
-$folderName = isset($_POST['foldername']) ?(string) $_POST['foldername'] : '';
-
-$l10n = \OC::$server->getL10N('files');
-
-$result = array(
- 'success' => false,
- 'data' => NULL
- );
-
-try {
- \OC\Files\Filesystem::getView()->verifyPath($dir, $folderName);
-} catch (\OCP\Files\InvalidPathException $ex) {
- $result['data'] = [
- 'message' => $ex->getMessage()];
- OCP\JSON::error($result);
- return;
-}
-
-if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
- $result['data'] = array('message' => (string)$l10n->t(
- 'The target folder has been moved or deleted.'),
- 'code' => 'targetnotfound'
- );
- OCP\JSON::error($result);
- exit();
-}
-
-$target = $dir . '/' . $folderName;
-
-if (\OC\Files\Filesystem::file_exists($target)) {
- $result['data'] = array('message' => $l10n->t(
- 'The name %s is already used in the folder %s. Please choose a different name.',
- array($folderName, $dir))
- );
- OCP\JSON::error($result);
- exit();
-}
-
-try {
- if(\OC\Files\Filesystem::mkdir($target)) {
- if ( $dir !== '/') {
- $path = $dir.'/'.$folderName;
- } else {
- $path = '/'.$folderName;
- }
- $meta = \OC\Files\Filesystem::getFileInfo($path);
- $meta['type'] = 'dir'; // missing ?!
- OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
- exit();
- }
-} catch (\Exception $e) {
- $result = [
- 'success' => false,
- 'data' => [
- 'message' => $e->getMessage()
- ]
- ];
- OCP\JSON::error($result);
- exit();
-}
-
-OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the folder') )));
diff --git a/apps/files/ajax/rename.php b/apps/files/ajax/rename.php
deleted file mode 100644
index a24a57b1046..00000000000
--- a/apps/files/ajax/rename.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Frank Karlitschek <frank@owncloud.org>
- * @author Jakob Sack <mail@jakobsack.de>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-\OC::$server->getSession()->close();
-
-$l10n = \OC::$server->getL10N('files');
-
-$files = new \OCA\Files\App(
- \OC\Files\Filesystem::getView(),
- \OC::$server->getL10N('files')
-);
-try {
- $result = $files->rename(
- isset($_GET['dir']) ? (string)$_GET['dir'] : '',
- isset($_GET['file']) ? (string)$_GET['file'] : '',
- isset($_GET['newname']) ? (string)$_GET['newname'] : ''
- );
-} catch (\Exception $e) {
- $result = [
- 'success' => false,
- 'data' => [
- 'message' => $e->getMessage()
- ]
- ];
-}
-
-if($result['success'] === true){
- OCP\JSON::success(['data' => $result['data']]);
-} else {
- OCP\JSON::error(['data' => $result['data']]);
-}
diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index a784642728f..18e9cfe6117 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -41,7 +41,6 @@ OCP\JSON::setContentTypeHeader('text/plain');
// If not, check the login.
// If no token is sent along, rely on login only
-$allowedPermissions = \OCP\Constants::PERMISSION_ALL;
$errorCode = null;
$l = \OC::$server->getL10N('files');
@@ -60,8 +59,6 @@ if (empty($_POST['dirToken'])) {
\OC_User::setIncognitoMode(true);
- // return only read permissions for public upload
- $allowedPermissions = \OCP\Constants::PERMISSION_READ;
$publicDirectory = !empty($_POST['subdir']) ? (string)$_POST['subdir'] : '/';
$linkItem = OCP\Share::getShareByToken((string)$_POST['dirToken']);
@@ -207,7 +204,7 @@ if (\OC\Files\Filesystem::isValidPath($dir) === true) {
$data['originalname'] = $files['name'][$i];
$data['uploadMaxFilesize'] = $maxUploadFileSize;
$data['maxHumanFilesize'] = $maxHumanFileSize;
- $data['permissions'] = $meta['permissions'] & $allowedPermissions;
+ $data['permissions'] = $meta['permissions'];
$data['directory'] = $returnedDir;
$result[] = $data;
}
@@ -234,7 +231,7 @@ if (\OC\Files\Filesystem::isValidPath($dir) === true) {
$data['originalname'] = $files['name'][$i];
$data['uploadMaxFilesize'] = $maxUploadFileSize;
$data['maxHumanFilesize'] = $maxHumanFileSize;
- $data['permissions'] = $meta['permissions'] & $allowedPermissions;
+ $data['permissions'] = $meta['permissions'];
$data['directory'] = $returnedDir;
$result[] = $data;
}
diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml
index ba8bb62494e..4ab226f3968 100644
--- a/apps/files/appinfo/info.xml
+++ b/apps/files/appinfo/info.xml
@@ -8,7 +8,7 @@
<shipped>true</shipped>
<standalone/>
<default_enable/>
- <version>1.3.0</version>
+ <version>1.4.0</version>
<types>
<filesystem/>
</types>
diff --git a/apps/files/controller/viewcontroller.php b/apps/files/controller/viewcontroller.php
index c274680e525..1d1a9111d19 100644
--- a/apps/files/controller/viewcontroller.php
+++ b/apps/files/controller/viewcontroller.php
@@ -119,6 +119,8 @@ class ViewController extends Controller {
* @throws \OCP\Files\NotFoundException
*/
public function index($dir = '', $view = '') {
+ $nav = new \OCP\Template('files', 'appnavigation', '');
+
// Load the files we need
\OCP\Util::addStyle('files', 'files');
\OCP\Util::addStyle('files', 'upload');
@@ -169,8 +171,6 @@ class ViewController extends Controller {
// FIXME: Make non static
$storageInfo = $this->getStorageInfo();
- $nav = new \OCP\Template('files', 'appnavigation', '');
-
\OCA\Files\App::getNavigationManager()->add(
[
'id' => 'favorites',
diff --git a/apps/files/js/app.js b/apps/files/js/app.js
index f31770466fe..ff505d417f1 100644
--- a/apps/files/js/app.js
+++ b/apps/files/js/app.js
@@ -71,7 +71,8 @@
folderDropOptions: folderDropOptions,
fileActions: fileActions,
allowLegacyActions: true,
- scrollTo: urlParams.scrollto
+ scrollTo: urlParams.scrollto,
+ filesClient: OC.Files.getClient()
}
);
this.files.initialize();
diff --git a/apps/files/js/favoritesplugin.js b/apps/files/js/favoritesplugin.js
index 417a32ef804..454a505c7bd 100644
--- a/apps/files/js/favoritesplugin.js
+++ b/apps/files/js/favoritesplugin.js
@@ -92,7 +92,7 @@
// folder in the files app instead of opening it directly
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
OCA.Files.App.setActiveView('files', {silent: true});
- OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+ OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true);
});
fileActions.setDefault('dir', 'Open');
return fileActions;
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 6a767d48a28..871a2149c88 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -575,7 +575,8 @@
},
actionHandler: function (filename, context) {
var dir = context.dir || context.fileList.getCurrentDirectory();
- var url = context.fileList.getDownloadUrl(filename, dir);
+ var isDir = context.$file.attr('data-type') === 'dir';
+ var url = context.fileList.getDownloadUrl(filename, dir, isDir);
var downloadFileaction = $(context.$file).find('.fileactions .action-download');
@@ -611,10 +612,7 @@
this.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
var dir = context.$file.attr('data-path') || context.fileList.getCurrentDirectory();
- if (dir !== '/') {
- dir = dir + '/';
- }
- context.fileList.changeDirectory(dir + filename);
+ context.fileList.changeDirectory(OC.joinPaths(dir, filename));
});
this.registerAction({
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index d1f68d98eab..672c39a8bb1 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -22,11 +22,12 @@
*
* @param $el container element with existing markup for the #controls
* and a table
- * @param [options] map of options, see other parameters
- * @param [options.scrollContainer] scrollable container, defaults to $(window)
- * @param [options.dragOptions] drag options, disabled by default
- * @param [options.folderDropOptions] folder drop options, disabled by default
- * @param [options.detailsViewEnabled=true] whether to enable details view
+ * @param {Object} [options] map of options, see other parameters
+ * @param {Object} [options.scrollContainer] scrollable container, defaults to $(window)
+ * @param {Object} [options.dragOptions] drag options, disabled by default
+ * @param {Object} [options.folderDropOptions] folder drop options, disabled by default
+ * @param {boolean} [options.detailsViewEnabled=true] whether to enable details view
+ * @param {OC.Files.Client} [options.filesClient] files client to use
*/
var FileList = function($el, options) {
this.initialize($el, options);
@@ -74,6 +75,13 @@
_detailsView: null,
/**
+ * Files client instance
+ *
+ * @type OC.Files.Client
+ */
+ filesClient: null,
+
+ /**
* Whether the file list was initialized already.
* @type boolean
*/
@@ -92,11 +100,18 @@
* Array of files in the current folder.
* The entries are of file data.
*
- * @type Array.<Object>
+ * @type Array.<OC.Files.FileInfo>
*/
files: [],
/**
+ * Current directory entry
+ *
+ * @type OC.Files.FileInfo
+ */
+ dirInfo: null,
+
+ /**
* File actions handler, defaults to OCA.Files.FileActions
* @type OCA.Files.FileActions
*/
@@ -149,7 +164,7 @@
* When false, clicking on a table header will call reload().
* When true, clicking on a table header will simply resort the list.
*/
- _clientSideSort: false,
+ _clientSideSort: true,
/**
* Current directory
@@ -170,6 +185,7 @@
* @param options.dragOptions drag options, disabled by default
* @param options.folderDropOptions folder drop options, disabled by default
* @param options.scrollTo name of file to scroll to after the first load
+ * @param {OC.Files.Client} [options.filesClient] files API client
* @private
*/
initialize: function($el, options) {
@@ -185,6 +201,12 @@
if (options.folderDropOptions) {
this._folderDropOptions = options.folderDropOptions;
}
+ if (options.filesClient) {
+ this.filesClient = options.filesClient;
+ } else {
+ // default client if not specified
+ this.filesClient = OC.Files.getClient();
+ }
this.$el = $el;
if (options.id) {
@@ -209,6 +231,8 @@
this.files = [];
this._selectedFiles = {};
this._selectionSummary = new OCA.Files.FileSummary();
+ // dummy root dir info
+ this.dirInfo = new OC.Files.FileInfo({});
this.fileSummary = this._createSummary();
@@ -359,7 +383,7 @@
var highlightState = $tr.hasClass('highlighted');
$tr = self.updateRow(
$tr,
- _.extend({isPreviewAvailable: true}, model.toJSON()),
+ model.toJSON(),
{updateSummary: true, silent: false, animate: true}
);
$tr.toggleClass('highlighted', highlightState);
@@ -618,7 +642,7 @@
};
OCA.Files.FileActions.updateFileActionSpinner(downloadFileaction, true);
- OCA.Files.Files.handleDownload(this.getDownloadUrl(files, dir), disableLoadingState);
+ OCA.Files.Files.handleDownload(this.getDownloadUrl(files, dir, true), disableLoadingState);
return false;
},
@@ -894,16 +918,39 @@
self.$el.closest('#app-content').trigger(jQuery.Event('apprendered'));
});
},
+
+ /**
+ * Returns the icon URL matching the given file info
+ *
+ * @param {OC.Files.FileInfo} fileInfo file info
+ *
+ * @return {string} icon URL
+ */
+ _getIconUrl: function(fileInfo) {
+ var mimeType = fileInfo.mimetype || 'application/octet-stream';
+ if (mimeType === 'httpd/unix-directory') {
+ // use default folder icon
+ if (fileInfo.mountType === 'shared' || fileInfo.mountType === 'shared-root') {
+ return OC.MimeType.getIconUrl('dir-shared');
+ } else if (fileInfo.mountType === 'external-root') {
+ return OC.MimeType.getIconUrl('dir-external');
+ }
+ return OC.MimeType.getIconUrl('dir');
+ }
+ return OC.MimeType.getIconUrl(mimeType);
+ },
+
/**
* Creates a new table row element using the given file data.
- * @param {OCA.Files.FileInfo} fileData file info attributes
+ * @param {OC.Files.FileInfo} fileData file info attributes
* @param options map of attributes
* @return new tr element (not appended to the table)
*/
_createRow: function(fileData, options) {
var td, simpleSize, basename, extension, sizeColor,
- icon = OC.MimeType.getIconUrl(fileData.mimetype),
+ icon = fileData.icon || this._getIconUrl(fileData),
name = fileData.name,
+ // TODO: get rid of type, only use mime type
type = fileData.type || 'file',
mtime = parseInt(fileData.mtime, 10),
mime = fileData.mimetype,
@@ -943,6 +990,14 @@
}
if (fileData.mountType) {
+ // FIXME: HACK: detect shared-root
+ if (fileData.mountType === 'shared' && this.dirInfo.mountType !== 'shared') {
+ // if parent folder isn't share, assume the displayed folder is a share root
+ fileData.mountType = 'shared-root';
+ } else if (fileData.mountType === 'external' && this.dirInfo.mountType !== 'external') {
+ // if parent folder isn't external, assume the displayed folder is the external storage root
+ fileData.mountType = 'external-root';
+ }
tr.attr('data-mounttype', fileData.mountType);
}
@@ -953,24 +1008,16 @@
path = this.getCurrentDirectory();
}
- if (type === 'dir') {
- // use default folder icon
- icon = icon || OC.imagePath('core', 'filetypes/folder');
- }
- else {
- icon = icon || OC.imagePath('core', 'filetypes/file');
- }
-
// filename td
td = $('<td class="filename"></td>');
// linkUrl
- if (type === 'dir') {
+ if (mime === 'httpd/unix-directory') {
linkUrl = this.linkTo(path + '/' + name);
}
else {
- linkUrl = this.getDownloadUrl(name, path);
+ linkUrl = this.getDownloadUrl(name, path, type === 'dir');
}
if (this._allowSelection) {
td.append(
@@ -996,7 +1043,7 @@
basename = '';
extension = name;
// split extension from filename for non dirs
- } else if (type !== 'dir' && name.indexOf('.') !== -1) {
+ } else if (mime !== 'httpd/unix-directory' && name.indexOf('.') !== -1) {
basename = name.substr(0, name.lastIndexOf('.'));
extension = name.substr(name.lastIndexOf('.'));
} else {
@@ -1018,7 +1065,7 @@
nameSpan.tooltip({placement: 'right'});
}
// dirs can show the number of uploaded files
- if (type === 'dir') {
+ if (mime !== 'httpd/unix-directory') {
linkElem.append($('<span></span>').attr({
'class': 'uploadtext',
'currentUploads': 0
@@ -1074,7 +1121,7 @@
* Adds an entry to the files array and also into the DOM
* in a sorted manner.
*
- * @param {OCA.Files.FileInfo} fileData map of file attributes
+ * @param {OC.Files.FileInfo} fileData map of file attributes
* @param {Object} [options] map of attributes
* @param {boolean} [options.updateSummary] true to update the summary
* after adding (default), false otherwise. Defaults to true.
@@ -1147,7 +1194,7 @@
* Creates a new row element based on the given attributes
* and returns it.
*
- * @param {OCA.Files.FileInfo} fileData map of file attributes
+ * @param {OC.Files.FileInfo} fileData map of file attributes
* @param {Object} [options] map of attributes
* @param {int} [options.index] index at which to insert the element
* @param {boolean} [options.updateSummary] true to update the summary
@@ -1182,7 +1229,7 @@
filenameTd.draggable(this._dragOptions);
}
// allow dropping on folders
- if (this._folderDropOptions && fileData.type === 'dir') {
+ if (this._folderDropOptions && mime === 'httpd/unix-directory') {
filenameTd.droppable(this._folderDropOptions);
}
@@ -1193,7 +1240,7 @@
// display actions
this.fileActions.display(filenameTd, !options.silent, this);
- if (fileData.isPreviewAvailable && mime !== 'httpd/unix-directory') {
+ if (mime !== 'httpd/unix-directory') {
var iconDiv = filenameTd.find('.thumbnail');
// lazy load / newly inserted td ?
// the typeof check ensures that the default value of animate is true
@@ -1330,6 +1377,13 @@
},
/**
+ * Returns list of webdav properties to request
+ */
+ _getWebdavProperties: function() {
+ return this.filesClient.getPropfindProperties();
+ },
+
+ /**
* Reloads the file list using ajax call
*
* @return ajax call object
@@ -1343,17 +1397,12 @@
this._currentFileModel = null;
this.$el.find('.select-all').prop('checked', false);
this.showMask();
- 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.filesClient.getFolderContents(
+ this.getCurrentDirectory(), {
+ includeParent: true,
+ properties: this._getWebdavProperties()
}
- });
+ );
if (this._detailsView) {
// close sidebar
this._updateDetailsView(null);
@@ -1361,24 +1410,19 @@
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.showTemporary(result.data.message);
+ if (status === 401) {
+ // TODO: append current URL to be able to get back after logging in again
+ OC.redirect(OC.generateUrl('apps/files'));
+ OC.Notification.show(result);
return false;
}
// Firewall Blocked request?
- if (result.status === 403) {
+ if (status === 403) {
// Go home
this.changeDirectory('/');
OC.Notification.showTemporary(t('files', 'This operation is forbidden'));
@@ -1386,32 +1430,49 @@
}
// Did share service die or something else fail?
- if (result.status === 500) {
+ if (status === 500) {
// Go home
this.changeDirectory('/');
- OC.Notification.showTemporary(t('files', 'This directory is unavailable, please check the logs or contact the administrator'));
+ OC.Notification.showTemporary(
+ t('files', 'This directory is unavailable, please check the logs or contact the administrator')
+ );
+ return false;
+ }
+
+ if (status === 503) {
+ // Go home
+ if (this.getCurrentDirectory() !== '/') {
+ this.changeDirectory('/');
+ // TODO: read error message from exception
+ OC.Notification.showTemporary(
+ t('files', 'Storage not available')
+ );
+ }
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;
}
- // TODO: should rather return upload file size through
- // the files list ajax call
+ // TODO: parse remaining quota from PROPFIND response
this.updateStorageStatistics(true);
- if (result.data.permissions) {
- this.setDirectoryPermissions(result.data.permissions);
+ // first entry is the root
+ this.dirInfo = result.shift();
+
+ if (this.dirInfo.permissions) {
+ this.setDirectoryPermissions(this.dirInfo.permissions);
}
- this.setFiles(result.data.files);
+ result.sort(this._sortComparator);
+ this.setFiles(result);
return true;
},
@@ -1419,12 +1480,15 @@
OCA.Files.Files.updateStorageStatistics(this.getCurrentDirectory(), force);
},
+ /**
+ * @deprecated do not use nor override
+ */
getAjaxUrl: function(action, params) {
return OCA.Files.Files.getAjaxUrl(action, params);
},
- getDownloadUrl: function(files, dir) {
- return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory());
+ getDownloadUrl: function(files, dir, isDir) {
+ return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory(), isDir);
},
/**
@@ -1489,8 +1553,6 @@
if (etag){
// use etag as cache buster
urlSpec.c = etag;
- } else {
- console.warn('OCA.Files.FileList.lazyLoadPreview(): missing etag argument');
}
previewURL = self.generatePreviewUrl(urlSpec);
@@ -1514,6 +1576,9 @@
img.src = previewURL;
},
+ /**
+ * @deprecated
+ */
setDirectoryPermissions: function(permissions) {
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
this.$el.find('#permissions').val(permissions);
@@ -1610,7 +1675,7 @@
* fileData should be inserted, considering the current
* sorting
*
- * @param {OCA.Files.FileInfo} fileData file info
+ * @param {OC.Files.FileInfo} fileData file info
*/
_findInsertionIndex: function(fileData) {
var index = 0;
@@ -1628,6 +1693,9 @@
move: function(fileNames, targetPath) {
var self = this;
var dir = this.getCurrentDirectory();
+ if (dir.charAt(dir.length - 1) !== '/') {
+ dir += '/';
+ }
var target = OC.basename(targetPath);
if (!_.isArray(fileNames)) {
fileNames = [fileNames];
@@ -1635,46 +1703,42 @@
_.each(fileNames, function(fileName) {
var $tr = self.findFileEl(fileName);
self.showFileBusyState($tr, true);
- // TODO: improve performance by sending all file names in a single call
- $.post(
- OC.filePath('files', 'ajax', 'move.php'),
- {
- dir: dir,
- file: fileName,
- target: targetPath
- },
- function(result) {
- if (result) {
- if (result.status === 'success') {
- // if still viewing the same directory
- if (self.getCurrentDirectory() === dir) {
- // recalculate folder size
- var oldFile = self.findFileEl(target);
- var newFile = self.findFileEl(fileName);
- var oldSize = oldFile.data('size');
- var newSize = oldSize + newFile.data('size');
- oldFile.data('size', newSize);
- oldFile.find('td.filesize').text(OC.Util.humanFileSize(newSize));
-
- // TODO: also update entry in FileList.files
-
- self.remove(fileName);
- }
- } else {
- OC.Notification.hide();
- if (result.status === 'error' && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- }
- else {
- OC.Notification.showTemporary(t('files', 'Error moving file.'));
- }
- }
+ if (targetPath.charAt(targetPath.length - 1) !== '/') {
+ // make sure we move the files into the target dir,
+ // not overwrite it
+ targetPath = targetPath + '/';
+ }
+ self.filesClient.move(dir + fileName, targetPath + fileName)
+ .done(function() {
+ // if still viewing the same directory
+ if (OC.joinPaths(self.getCurrentDirectory(), '/') === dir) {
+ // recalculate folder size
+ var oldFile = self.findFileEl(target);
+ var newFile = self.findFileEl(fileName);
+ var oldSize = oldFile.data('size');
+ var newSize = oldSize + newFile.data('size');
+ oldFile.data('size', newSize);
+ oldFile.find('td.filesize').text(OC.Util.humanFileSize(newSize));
+
+ // TODO: also update entry in FileList.files
+ self.remove(fileName);
+ }
+ })
+ .fail(function(status) {
+ if (status === 412) {
+ // TODO: some day here we should invoke the conflict dialog
+ OC.Notification.showTemporary(
+ t('files', 'Could not move "{file}", target exists', {file: fileName})
+ );
} else {
- OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
+ OC.Notification.showTemporary(
+ t('files', 'Could not move "{file}"', {file: fileName})
+ );
}
+ })
+ .always(function() {
self.showFileBusyState($tr, false);
- }
- );
+ });
});
},
@@ -1700,16 +1764,16 @@
* Triggers file rename input field for the given file name.
* If the user enters a new name, the file will be renamed.
*
- * @param oldname file name of the file to rename
+ * @param oldName file name of the file to rename
*/
- rename: function(oldname) {
+ rename: function(oldName) {
var self = this;
var tr, td, input, form;
- tr = this.findFileEl(oldname);
+ tr = this.findFileEl(oldName);
var oldFileInfo = this.files[tr.index()];
tr.data('renaming',true);
td = tr.children('td.filename');
- input = $('<input type="text" class="filename"/>').val(oldname);
+ input = $('<input type="text" class="filename"/>').val(oldName);
form = $('<form></form>');
form.append(input);
td.children('a.name').hide();
@@ -1724,11 +1788,11 @@
input.selectRange(0, len);
var checkInput = function () {
var filename = input.val();
- if (filename !== oldname) {
+ if (filename !== oldName) {
// Files.isFileNameValid(filename) throws an exception itself
OCA.Files.Files.isFileNameValid(filename);
if (self.inList(filename)) {
- throw t('files', '{new_name} already exists', {new_name: filename});
+ throw t('files', '{newName} already exists', {newName: filename});
}
}
return true;
@@ -1741,6 +1805,12 @@
td.children('a.name').show();
}
+ function updateInList(fileInfo) {
+ self.updateRow(tr, fileInfo);
+ self._updateDetailsView(fileInfo.name, false);
+ }
+
+ // TODO: too many nested blocks, move parts into functions
form.submit(function(event) {
event.stopPropagation();
event.preventDefault();
@@ -1753,7 +1823,7 @@
input.tooltip('hide');
form.remove();
- if (newName !== oldname) {
+ if (newName !== oldName) {
checkInput();
// mark as loading (temp element)
self.showFileBusyState(tr, true);
@@ -1765,34 +1835,45 @@
td.find('a.name span.nametext').text(basename);
td.children('a.name').show();
- $.ajax({
- url: OC.filePath('files','ajax','rename.php'),
- data: {
- dir : tr.attr('data-path') || self.getCurrentDirectory(),
- newname: newName,
- file: oldname
- },
- success: function(result) {
- var fileInfo;
- if (!result || result.status === 'error') {
- OC.dialogs.alert(result.data.message, t('files', 'Could not rename file'));
- fileInfo = oldFileInfo;
- if (result.data.code === 'sourcenotfound') {
- self.remove(result.data.newname, {updateSummary: true});
- return;
- }
- }
- else {
- fileInfo = result.data;
+ var path = tr.attr('data-path') || self.getCurrentDirectory();
+ self.filesClient.move(OC.joinPaths(path, oldName), OC.joinPaths(path, newName))
+ .done(function() {
+ oldFileInfo.name = newName;
+ updateInList(oldFileInfo);
+ })
+ .fail(function(status) {
+ // TODO: 409 means current folder does not exist, redirect ?
+ if (status === 404) {
+ // source not found, so remove it from the list
+ OC.Notification.showTemporary(
+ t(
+ 'files',
+ 'Could not rename "{fileName}", it does not exist any more',
+ {fileName: oldName}
+ )
+ );
+ self.remove(newName, {updateSummary: true});
+ return;
+ } else if (status === 412) {
+ // target exists
+ OC.Notification.showTemporary(
+ t(
+ 'files',
+ 'The name "{targetName}" is already used in the folder "{dir}". Please choose a different name.',
+ {
+ targetName: newName,
+ dir: self.getCurrentDirectory()
+ }
+ )
+ );
+ } else {
+ // restore the item to its previous state
+ OC.Notification.showTemporary(
+ t('files', 'Could not rename "{fileName}"', {fileName: oldName})
+ );
}
- // reinsert row
- self.files.splice(tr.index(), 1);
- tr.remove();
- tr = self.add(fileInfo, {updateSummary: false, silent: true});
- self.$fileList.trigger($.Event('fileActionsReady', {fileList: self, $files: $(tr)}));
- self._updateDetailsView(fileInfo.name, false);
- }
- });
+ updateInList(oldFileInfo);
+ });
} else {
// add back the old file info when cancelled
self.files.splice(tr.index(), 1);
@@ -1849,32 +1930,48 @@
var promise = deferred.promise();
OCA.Files.Files.isFileNameValid(name);
- name = this.getUniqueName(name);
if (this.lastAction) {
this.lastAction();
}
- $.post(
- OC.generateUrl('/apps/files/ajax/newfile.php'),
- {
- dir: this.getCurrentDirectory(),
- filename: name
- },
- function(result) {
- if (result.status === 'success') {
- self.add(result.data, {animate: true, scrollTo: true});
- deferred.resolve(result.status, result.data);
+ name = this.getUniqueName(name);
+ var targetPath = this.getCurrentDirectory() + '/' + name;
+
+ self.filesClient.putFileContents(
+ targetPath,
+ '',
+ {
+ contentType: 'text/plain',
+ overwrite: true
+ }
+ )
+ .done(function() {
+ // TODO: error handling / conflicts
+ self.filesClient.getFileInfo(
+ targetPath, {
+ properties: self._getWebdavProperties()
+ }
+ )
+ .then(function(status, data) {
+ self.add(data, {animate: true, scrollTo: true});
+ deferred.resolve(status, data);
+ })
+ .fail(function(status) {
+ OC.Notification.showTemporary(t('files', 'Could not create file "{file}"', {file: name}));
+ deferred.reject(status);
+ });
+ })
+ .fail(function(status) {
+ if (status === 412) {
+ OC.Notification.showTemporary(
+ t('files', 'Could not create file "{file}" because it already exists', {file: name})
+ );
} else {
- if (result.data && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- } else {
- OC.Notification.showTemporary(t('core', 'Could not create file'));
- }
- deferred.reject(result.status, result.data);
+ OC.Notification.showTemporary(t('files', 'Could not create file "{file}"', {file: name}));
}
- }
- );
+ deferred.reject(status);
+ });
return promise;
},
@@ -1895,32 +1992,58 @@
var promise = deferred.promise();
OCA.Files.Files.isFileNameValid(name);
- name = this.getUniqueName(name);
if (this.lastAction) {
this.lastAction();
}
- $.post(
- OC.generateUrl('/apps/files/ajax/newfolder.php'),
- {
- dir: this.getCurrentDirectory(),
- foldername: name
- },
- function(result) {
- if (result.status === 'success') {
- self.add(result.data, {animate: true, scrollTo: true});
- deferred.resolve(result.status, result.data);
+ name = this.getUniqueName(name);
+ var targetPath = this.getCurrentDirectory() + '/' + name;
+
+ this.filesClient.createDirectory(targetPath)
+ .done(function(createStatus) {
+ self.filesClient.getFileInfo(
+ targetPath, {
+ properties: self._getWebdavProperties()
+ }
+ )
+ .done(function(status, data) {
+ self.add(data, {animate: true, scrollTo: true});
+ deferred.resolve(status, data);
+ })
+ .fail(function() {
+ OC.Notification.showTemporary(t('files', 'Could not create folder "{dir}"', {dir: name}));
+ deferred.reject(createStatus);
+ });
+ })
+ .fail(function(createStatus) {
+ // method not allowed, folder might exist already
+ if (createStatus === 405) {
+ self.filesClient.getFileInfo(
+ targetPath, {
+ properties: self._getWebdavProperties()
+ }
+ )
+ .done(function(status, data) {
+ // add it to the list, for completeness
+ self.add(data, {animate: true, scrollTo: true});
+ OC.Notification.showTemporary(
+ t('files', 'Could not create folder "{dir}" because it already exists', {dir: name})
+ );
+ // still consider a failure
+ deferred.reject(createStatus, data);
+ })
+ .fail(function() {
+ OC.Notification.showTemporary(
+ t('files', 'Could not create folder "{dir}"', {dir: name})
+ );
+ deferred.reject(status);
+ });
} else {
- if (result.data && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- } else {
- OC.Notification.showTemporary(t('core', 'Could not create folder'));
- }
- deferred.reject(result.status);
+ OC.Notification.showTemporary(t('files', 'Could not create folder "{dir}"', {dir: name}));
+ deferred.reject(createStatus);
}
- }
- );
+ });
return promise;
},
@@ -1981,76 +2104,59 @@
*/
do_delete:function(files, dir) {
var self = this;
- var params;
if (files && files.substr) {
files=[files];
}
+ if (!files) {
+ // delete all files in directory
+ files = _.pluck(this.files, 'name');
+ }
if (files) {
this.showFileBusyState(files, true);
- for (var i=0; i<files.length; i++) {
- }
}
// Finish any existing actions
if (this.lastAction) {
this.lastAction();
}
- params = {
- dir: dir || this.getCurrentDirectory()
- };
- if (files) {
- params.files = JSON.stringify(files);
+ dir = dir || this.getCurrentDirectory();
+
+ function removeFromList(file) {
+ var fileEl = self.remove(file, {updateSummary: false});
+ // FIXME: not sure why we need this after the
+ // element isn't even in the DOM any more
+ fileEl.find('.selectCheckBox').prop('checked', false);
+ fileEl.removeClass('selected');
+ self.fileSummary.remove({type: fileEl.attr('data-type'), size: fileEl.attr('data-size')});
+ // TODO: this info should be returned by the ajax call!
+ self.updateEmptyContent();
+ self.fileSummary.update();
+ self.updateSelectionSummary();
+ // FIXME: don't repeat this, do it once all files are done
+ self.updateStorageStatistics();
}
- else {
- // no files passed, delete all in current dir
- params.allfiles = true;
- // show spinner for all files
- this.showFileBusyState(this.$fileList.find('tr'), true);
- }
-
- $.post(OC.filePath('files', 'ajax', 'delete.php'),
- params,
- function(result) {
- if (result.status === 'success') {
- if (params.allfiles) {
- self.setFiles([]);
- }
- else {
- $.each(files,function(index,file) {
- var fileEl = self.remove(file, {updateSummary: false});
- // FIXME: not sure why we need this after the
- // element isn't even in the DOM any more
- fileEl.find('.selectCheckBox').prop('checked', false);
- fileEl.removeClass('selected');
- self.fileSummary.remove({type: fileEl.attr('data-type'), size: fileEl.attr('data-size')});
- });
- }
- // TODO: this info should be returned by the ajax call!
- self.updateEmptyContent();
- self.fileSummary.update();
- self.updateSelectionSummary();
- self.updateStorageStatistics();
- // in case there was a "storage full" permanent notification
- OC.Notification.hide();
+
+ _.each(files, function(file) {
+ self.filesClient.remove(dir + '/' + file)
+ .done(function() {
+ removeFromList(file);
+ })
+ .fail(function(status) {
+ if (status === 404) {
+ // the file already did not exist, remove it from the list
+ removeFromList(file);
} else {
- if (result.status === 'error' && result.data.message) {
- OC.Notification.showTemporary(result.data.message);
- }
- else {
- OC.Notification.showTemporary(t('files', 'Error deleting file.'));
- }
- if (params.allfiles) {
- // reload the page as we don't know what files were deleted
- // and which ones remain
- self.reload();
- }
- else {
- $.each(files,function(index,file) {
- self.showFileBusyState(file, false);
- });
- }
+ // only reset the spinner for that one file
+ OC.Notification.showTemporary(
+ t('files', 'Error deleting file "{fileName}".', {fileName: file}),
+ {timeout: 10}
+ );
+ var deleteAction = self.findFileEl(file).find('.action.delete');
+ deleteAction.removeClass('icon-loading-small').addClass('icon-delete');
+ self.showFileBusyState(files, false);
}
});
+ });
},
/**
* Creates the file summary section
@@ -2659,8 +2765,8 @@
* Compares two file infos by name, making directories appear
* first.
*
- * @param {OCA.Files.FileInfo} fileInfo1 file info
- * @param {OCA.Files.FileInfo} fileInfo2 file info
+ * @param {OC.Files.FileInfo} fileInfo1 file info
+ * @param {OC.Files.FileInfo} fileInfo2 file info
* @return {int} -1 if the first file must appear before the second one,
* 0 if they are identify, 1 otherwise.
*/
@@ -2676,8 +2782,8 @@
/**
* Compares two file infos by size.
*
- * @param {OCA.Files.FileInfo} fileInfo1 file info
- * @param {OCA.Files.FileInfo} fileInfo2 file info
+ * @param {OC.Files.FileInfo} fileInfo1 file info
+ * @param {OC.Files.FileInfo} fileInfo2 file info
* @return {int} -1 if the first file must appear before the second one,
* 0 if they are identify, 1 otherwise.
*/
@@ -2687,8 +2793,8 @@
/**
* Compares two file infos by timestamp.
*
- * @param {OCA.Files.FileInfo} fileInfo1 file info
- * @param {OCA.Files.FileInfo} fileInfo2 file info
+ * @param {OC.Files.FileInfo} fileInfo1 file info
+ * @param {OC.Files.FileInfo} fileInfo2 file info
* @return {int} -1 if the first file must appear before the second one,
* 0 if they are identify, 1 otherwise.
*/
@@ -2700,23 +2806,14 @@
/**
* File info attributes.
*
- * @todo make this a real class in the future
- * @typedef {Object} OCA.Files.FileInfo
+ * @typedef {Object} OC.Files.FileInfo
+ *
+ * @lends OC.Files.FileInfo
+ *
+ * @deprecated use OC.Files.FileInfo instead
*
- * @property {int} id file id
- * @property {String} name file name
- * @property {String} [path] file path, defaults to the list's current path
- * @property {String} mimetype mime type
- * @property {String} type "file" for files or "dir" for directories
- * @property {int} permissions file permissions
- * @property {int} mtime modification time in milliseconds
- * @property {boolean} [isShareMountPoint] whether the file is a share mount
- * point
- * @property {boolean} [isPreviewAvailable] whether a preview is available
- * for the given file type
- * @property {String} [icon] path to the mime type icon
- * @property {String} etag etag of the file
*/
+ OCA.Files.FileInfo = OC.Files.FileInfo;
OCA.Files.FileList = FileList;
})();
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index ae38511ec05..e33b8354437 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -136,13 +136,27 @@
/**
* Returns the download URL of the given file(s)
- * @param filename string or array of file names to download
- * @param dir optional directory in which the file name is, defaults to the current directory
+ * @param {string} filename string or array of file names to download
+ * @param {string} [dir] optional directory in which the file name is, defaults to the current directory
+ * @param {bool} [isDir=false] whether the given filename is a directory and might need a special URL
*/
- getDownloadUrl: function(filename, dir) {
- if ($.isArray(filename)) {
+ getDownloadUrl: function(filename, dir, isDir) {
+ if (!_.isArray(filename) && !isDir) {
+ var pathSections = dir.split('/');
+ pathSections.push(filename);
+ var encodedPath = '';
+ _.each(pathSections, function(section) {
+ if (section !== '') {
+ encodedPath += '/' + encodeURIComponent(section);
+ }
+ });
+ return OC.linkToRemoteBase('webdav') + encodedPath;
+ }
+
+ if (_.isArray(filename)) {
filename = JSON.stringify(filename);
}
+
var params = {
dir: dir,
files: filename
@@ -193,7 +207,7 @@
*/
lazyLoadPreview : function(path, mime, ready, width, height, etag) {
console.warn('DEPRECATED: please use lazyLoadPreview() from an OCA.Files.FileList instance');
- return OCA.Files.App.fileList.lazyLoadPreview({
+ return FileList.lazyLoadPreview({
path: path,
mime: mime,
callback: ready,
@@ -356,8 +370,10 @@ scanFiles.scanning=false;
// TODO: move to FileList
var createDragShadow = function(event) {
+ // FIXME: inject file list instance somehow
+ /* global FileList, Files */
+
//select dragged file
- var FileList = OCA.Files.App.fileList;
var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
if (!isDragSelected) {
//select dragged file
@@ -394,7 +410,7 @@ var createDragShadow = function(event) {
.css('background-image', 'url(' + OC.imagePath('core', 'filetypes/folder.png') + ')');
} else {
var path = dir + '/' + elem.name;
- OCA.Files.App.files.lazyLoadPreview(path, elem.mime, function(previewpath) {
+ Files.lazyLoadPreview(path, elem.mimetype, function(previewpath) {
newtr.find('td.filename')
.css('background-image', 'url(' + previewpath + ')');
}, null, null, elem.etag);
@@ -441,7 +457,7 @@ var folderDropOptions = {
hoverClass: "canDrop",
drop: function( event, ui ) {
// don't allow moving a file into a selected folder
- var FileList = OCA.Files.App.fileList;
+ /* global FileList */
if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) {
return false;
}
diff --git a/apps/files/js/tagsplugin.js b/apps/files/js/tagsplugin.js
index 23945d52603..81b22e34cc2 100644
--- a/apps/files/js/tagsplugin.js
+++ b/apps/files/js/tagsplugin.js
@@ -161,6 +161,38 @@
fileInfo.tags = tags;
return fileInfo;
};
+
+ var NS_OC = 'http://owncloud.org/ns';
+
+ var oldGetWebdavProperties = fileList._getWebdavProperties;
+ fileList._getWebdavProperties = function() {
+ var props = oldGetWebdavProperties.apply(this, arguments);
+ props.push('{' + NS_OC + '}tags');
+ props.push('{' + NS_OC + '}favorite');
+ return props;
+ };
+
+ fileList.filesClient.addFileInfoParser(function(response) {
+ var data = {};
+ var props = response.propStat[0].properties;
+ var tags = props['{' + NS_OC + '}tags'];
+ var favorite = props['{' + NS_OC + '}favorite'];
+ if (tags && tags.length) {
+ tags = _.chain(tags).filter(function(xmlvalue) {
+ return (xmlvalue.namespaceURI === NS_OC && xmlvalue.nodeName.split(':')[1] === 'tag');
+ }).map(function(xmlvalue) {
+ return xmlvalue.textContent || xmlvalue.text;
+ }).value();
+ }
+ if (tags) {
+ data.tags = tags;
+ }
+ if (favorite && parseInt(favorite, 10) !== 0) {
+ data.tags = data.tags || [];
+ data.tags.push(OC.TAG_FAVORITE);
+ }
+ return data;
+ });
},
attach: function(fileList) {
diff --git a/apps/files/l10n/hy.js b/apps/files/l10n/hy.js
index 62bc84d6c7b..ae06fed4cd6 100644
--- a/apps/files/l10n/hy.js
+++ b/apps/files/l10n/hy.js
@@ -2,17 +2,29 @@ OC.L10N.register(
"files",
{
"Files" : "Ֆայլեր",
+ "All files" : "Բոլոր ֆայլերը",
"Close" : "Փակել",
"Download" : "Բեռնել",
"Rename" : "Վերանվանել",
"Delete" : "Ջնջել",
"Select" : "Նշել",
+ "Error" : "Սխալ",
+ "Could not rename file" : "Չկարողացա վերանվանել ֆայլը",
+ "Could not create file" : "Չկարողացա ստեղծել ֆայլը",
+ "Could not create folder" : "Չկարողացա ստեղծել պանակը",
"Name" : "Անուն",
"Size" : "Չափս",
+ "Modified" : "Փոփոխված",
+ "_%n folder_::_%n folders_" : ["%n պանակ","%n պանակ"],
+ "_%n file_::_%n files_" : ["%n ֆայլ","%n ֆայլ"],
+ "{dirs} and {files}" : "{dirs} և {files}",
"New" : "Նոր",
+ "_%n byte_::_%n bytes_" : ["%n բայտ","%n բայտ"],
"Folder" : "Պանակ",
"New folder" : "Նոր պանակ",
"Save" : "Պահպանել",
- "Select all" : "Նշել բոլորը"
+ "Select all" : "Նշել բոլորը",
+ "Text file" : "Տեքստ ֆայլ",
+ "New text file.txt" : "Նոր տեքստ ֆայլ.txt"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files/l10n/hy.json b/apps/files/l10n/hy.json
index c5afd306272..4874c47b3a4 100644
--- a/apps/files/l10n/hy.json
+++ b/apps/files/l10n/hy.json
@@ -1,16 +1,28 @@
{ "translations": {
"Files" : "Ֆայլեր",
+ "All files" : "Բոլոր ֆայլերը",
"Close" : "Փակել",
"Download" : "Բեռնել",
"Rename" : "Վերանվանել",
"Delete" : "Ջնջել",
"Select" : "Նշել",
+ "Error" : "Սխալ",
+ "Could not rename file" : "Չկարողացա վերանվանել ֆայլը",
+ "Could not create file" : "Չկարողացա ստեղծել ֆայլը",
+ "Could not create folder" : "Չկարողացա ստեղծել պանակը",
"Name" : "Անուն",
"Size" : "Չափս",
+ "Modified" : "Փոփոխված",
+ "_%n folder_::_%n folders_" : ["%n պանակ","%n պանակ"],
+ "_%n file_::_%n files_" : ["%n ֆայլ","%n ֆայլ"],
+ "{dirs} and {files}" : "{dirs} և {files}",
"New" : "Նոր",
+ "_%n byte_::_%n bytes_" : ["%n բայտ","%n բայտ"],
"Folder" : "Պանակ",
"New folder" : "Նոր պանակ",
"Save" : "Պահպանել",
- "Select all" : "Նշել բոլորը"
+ "Select all" : "Նշել բոլորը",
+ "Text file" : "Տեքստ ֆայլ",
+ "New text file.txt" : "Նոր տեքստ ֆայլ.txt"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files/l10n/lt_LT.js b/apps/files/l10n/lt_LT.js
index ac7084cfc2d..13e7a03e45b 100644
--- a/apps/files/l10n/lt_LT.js
+++ b/apps/files/l10n/lt_LT.js
@@ -75,8 +75,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n baitas","%n baitai","%n baitų"],
"Favorited" : "Pažymėta mėgstamu",
"Favorite" : "Mėgiamas",
- "Text file" : "Teksto failas",
- "New text file.txt" : "Naujas tekstas file.txt",
"Folder" : "Katalogas",
"New folder" : "Naujas aplankas",
"{newname} already exists" : "{newname} jau egzistuoja",
@@ -106,6 +104,8 @@ OC.L10N.register(
"Maximum upload size" : "Maksimalus įkeliamo failo dydis",
"max. possible: " : "maks. galima:",
"Save" : "Išsaugoti",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Su PHP-FPM atnaujinimai gali užtrukti apie 5min.",
+ "Missing permissions to edit from here." : "Draudžiama iš čia redaguoti",
"Settings" : "Nustatymai",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Naudokite šį adresą, kad <a href=\"%s\" target=\"_blank\">pasiektumėte savo failus per WebDAV</a>",
@@ -119,6 +119,8 @@ OC.L10N.register(
"Files are being scanned, please wait." : "Skenuojami failai, prašome palaukti.",
"Currently scanning" : "Šiuo metu skenuojama",
"No favorites" : "Nėra mėgstamiausių",
- "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia"
+ "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia",
+ "Text file" : "Teksto failas",
+ "New text file.txt" : "Naujas tekstas file.txt"
},
"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);");
diff --git a/apps/files/l10n/lt_LT.json b/apps/files/l10n/lt_LT.json
index aef54469542..c6e4a35c815 100644
--- a/apps/files/l10n/lt_LT.json
+++ b/apps/files/l10n/lt_LT.json
@@ -73,8 +73,6 @@
"_%n byte_::_%n bytes_" : ["%n baitas","%n baitai","%n baitų"],
"Favorited" : "Pažymėta mėgstamu",
"Favorite" : "Mėgiamas",
- "Text file" : "Teksto failas",
- "New text file.txt" : "Naujas tekstas file.txt",
"Folder" : "Katalogas",
"New folder" : "Naujas aplankas",
"{newname} already exists" : "{newname} jau egzistuoja",
@@ -104,6 +102,8 @@
"Maximum upload size" : "Maksimalus įkeliamo failo dydis",
"max. possible: " : "maks. galima:",
"Save" : "Išsaugoti",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Su PHP-FPM atnaujinimai gali užtrukti apie 5min.",
+ "Missing permissions to edit from here." : "Draudžiama iš čia redaguoti",
"Settings" : "Nustatymai",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Naudokite šį adresą, kad <a href=\"%s\" target=\"_blank\">pasiektumėte savo failus per WebDAV</a>",
@@ -117,6 +117,8 @@
"Files are being scanned, please wait." : "Skenuojami failai, prašome palaukti.",
"Currently scanning" : "Šiuo metu skenuojama",
"No favorites" : "Nėra mėgstamiausių",
- "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia"
+ "Files and folders you mark as favorite will show up here" : "Failai ir aplankai, kuriuos pažymite mėgstamais, atsiras čia",
+ "Text file" : "Teksto failas",
+ "New text file.txt" : "Naujas tekstas file.txt"
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"
} \ No newline at end of file
diff --git a/apps/files/l10n/nds.js b/apps/files/l10n/nds.js
index 9b28220ae43..37043dbe6c1 100644
--- a/apps/files/l10n/nds.js
+++ b/apps/files/l10n/nds.js
@@ -3,7 +3,11 @@ OC.L10N.register(
{
"Files" : "Dateien",
"Delete" : "Löschen",
+ "Details" : "Details",
+ "Error" : "Fehler",
"Name" : "Name",
+ "New folder" : "Neuer Ordner",
+ "Upload" : "Hochladen",
"Settings" : "Einstellungen",
"WebDAV" : "WebDAV"
},
diff --git a/apps/files/l10n/nds.json b/apps/files/l10n/nds.json
index 4ab8de68b35..dbd6bad9573 100644
--- a/apps/files/l10n/nds.json
+++ b/apps/files/l10n/nds.json
@@ -1,7 +1,11 @@
{ "translations": {
"Files" : "Dateien",
"Delete" : "Löschen",
+ "Details" : "Details",
+ "Error" : "Fehler",
"Name" : "Name",
+ "New folder" : "Neuer Ordner",
+ "Upload" : "Hochladen",
"Settings" : "Einstellungen",
"WebDAV" : "WebDAV"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/files/l10n/ru.js b/apps/files/l10n/ru.js
index 254e701a17c..29f46270af6 100644
--- a/apps/files/l10n/ru.js
+++ b/apps/files/l10n/ru.js
@@ -75,8 +75,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байтов","%n байта(ов)"],
"Favorited" : "Избранное",
"Favorite" : "Избранное",
- "Text file" : "Текстовый файл",
- "New text file.txt" : "Новый текстовый документ.txt",
"Folder" : "Каталог",
"New folder" : "Новый каталог",
"{newname} already exists" : "{newname} уже существует",
@@ -119,6 +117,8 @@ OC.L10N.register(
"Files are being scanned, please wait." : "Идет сканирование файлов. Пожалуйста подождите.",
"Currently scanning" : "В настоящее время сканируется",
"No favorites" : "Нет избранного",
- "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные"
+ "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные",
+ "Text file" : "Текстовый файл",
+ "New text file.txt" : "Новый текстовый документ.txt"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/apps/files/l10n/ru.json b/apps/files/l10n/ru.json
index 7666ebb75d4..19999734621 100644
--- a/apps/files/l10n/ru.json
+++ b/apps/files/l10n/ru.json
@@ -73,8 +73,6 @@
"_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байтов","%n байта(ов)"],
"Favorited" : "Избранное",
"Favorite" : "Избранное",
- "Text file" : "Текстовый файл",
- "New text file.txt" : "Новый текстовый документ.txt",
"Folder" : "Каталог",
"New folder" : "Новый каталог",
"{newname} already exists" : "{newname} уже существует",
@@ -117,6 +115,8 @@
"Files are being scanned, please wait." : "Идет сканирование файлов. Пожалуйста подождите.",
"Currently scanning" : "В настоящее время сканируется",
"No favorites" : "Нет избранного",
- "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные"
+ "Files and folders you mark as favorite will show up here" : "Здесь появятся файлы и каталоги, отмеченные как избранные",
+ "Text file" : "Текстовый файл",
+ "New text file.txt" : "Новый текстовый документ.txt"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files/l10n/tr.js b/apps/files/l10n/tr.js
index b2c4fd56df9..e95f458b304 100644
--- a/apps/files/l10n/tr.js
+++ b/apps/files/l10n/tr.js
@@ -75,8 +75,6 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n bayt","%n bayt"],
"Favorited" : "Sık kullanılanlara eklendi",
"Favorite" : "Sık kullanılan",
- "Text file" : "Metin dosyası",
- "New text file.txt" : "Yeni metin dosyası.txt",
"Folder" : "Klasör",
"New folder" : "Yeni klasör",
"{newname} already exists" : "{newname} zaten mevcut",
@@ -106,6 +104,8 @@ OC.L10N.register(
"Maximum upload size" : "Azami yükleme boyutu",
"max. possible: " : "mümkün olan en fazla: ",
"Save" : "Kaydet",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM ile değişikliklerin uygulanması 5 dakika sürebilir.",
+ "Missing permissions to edit from here." : "Buradan düzenleme için eksik yetki.",
"Settings" : "Ayarlar",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">Dosyalarınıza WebDAV aracılığıyla erişmek için</a> bu adresi kullanın",
@@ -119,6 +119,8 @@ OC.L10N.register(
"Files are being scanned, please wait." : "Dosyalar taranıyor, lütfen bekleyin.",
"Currently scanning" : "Şu anda taranan",
"No favorites" : "Sık kullanılan öge yok.",
- "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek"
+ "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek",
+ "Text file" : "Metin dosyası",
+ "New text file.txt" : "Yeni metin dosyası.txt"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files/l10n/tr.json b/apps/files/l10n/tr.json
index fcb87d74fa1..1bcb92501b9 100644
--- a/apps/files/l10n/tr.json
+++ b/apps/files/l10n/tr.json
@@ -73,8 +73,6 @@
"_%n byte_::_%n bytes_" : ["%n bayt","%n bayt"],
"Favorited" : "Sık kullanılanlara eklendi",
"Favorite" : "Sık kullanılan",
- "Text file" : "Metin dosyası",
- "New text file.txt" : "Yeni metin dosyası.txt",
"Folder" : "Klasör",
"New folder" : "Yeni klasör",
"{newname} already exists" : "{newname} zaten mevcut",
@@ -104,6 +102,8 @@
"Maximum upload size" : "Azami yükleme boyutu",
"max. possible: " : "mümkün olan en fazla: ",
"Save" : "Kaydet",
+ "With PHP-FPM it might take 5 minutes for changes to be applied." : "PHP-FPM ile değişikliklerin uygulanması 5 dakika sürebilir.",
+ "Missing permissions to edit from here." : "Buradan düzenleme için eksik yetki.",
"Settings" : "Ayarlar",
"WebDAV" : "WebDAV",
"Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">Dosyalarınıza WebDAV aracılığıyla erişmek için</a> bu adresi kullanın",
@@ -117,6 +117,8 @@
"Files are being scanned, please wait." : "Dosyalar taranıyor, lütfen bekleyin.",
"Currently scanning" : "Şu anda taranan",
"No favorites" : "Sık kullanılan öge yok.",
- "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek"
+ "Files and folders you mark as favorite will show up here" : "Sık kullanılan olarak işaretlediğiniz dosya ve klasörler burada gösterilecek",
+ "Text file" : "Metin dosyası",
+ "New text file.txt" : "Yeni metin dosyası.txt"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php
index 5bd8c127586..18813e224de 100644
--- a/apps/files/lib/app.php
+++ b/apps/files/lib/app.php
@@ -29,107 +29,21 @@ namespace OCA\Files;
class App {
/**
- * @var \OC_L10N
- */
- private $l10n;
-
- /**
* @var \OCP\INavigationManager
*/
private static $navigationManager;
/**
- * @var \OC\Files\View
- */
- private $view;
-
- public function __construct($view, $l10n) {
- $this->view = $view;
- $this->l10n = $l10n;
- }
-
- /**
* Returns the app's navigation manager
*
* @return \OCP\INavigationManager
*/
public static function getNavigationManager() {
+ // TODO: move this into a service in the Application class
if (self::$navigationManager === null) {
self::$navigationManager = new \OC\NavigationManager();
}
return self::$navigationManager;
}
- /**
- * rename a file
- *
- * @param string $dir
- * @param string $oldname
- * @param string $newname
- * @return array
- */
- public function rename($dir, $oldname, $newname) {
- $result = array(
- 'success' => false,
- 'data' => NULL
- );
-
- try {
- // check if the new name is conform to file name restrictions
- $this->view->verifyPath($dir, $newname);
- } catch (\OCP\Files\InvalidPathException $ex) {
- $result['data'] = array(
- 'message' => $this->l10n->t($ex->getMessage()),
- 'code' => 'invalidname',
- );
- return $result;
- }
-
- $normalizedOldPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $oldname);
- $normalizedNewPath = \OC\Files\Filesystem::normalizePath($dir . '/' . $newname);
-
- // rename to non-existing folder is denied
- if (!$this->view->file_exists($normalizedOldPath)) {
- $result['data'] = array(
- 'message' => $this->l10n->t('%s could not be renamed as it has been deleted', array($oldname)),
- 'code' => 'sourcenotfound',
- 'oldname' => $oldname,
- 'newname' => $newname,
- );
- }else if (!$this->view->file_exists($dir)) {
- $result['data'] = array('message' => (string)$this->l10n->t(
- 'The target folder has been moved or deleted.',
- array($dir)),
- 'code' => 'targetnotfound'
- );
- // rename to existing file is denied
- } else if ($this->view->file_exists($normalizedNewPath)) {
-
- $result['data'] = array(
- 'message' => $this->l10n->t(
- "The name %s is already used in the folder %s. Please choose a different name.",
- array($newname, $dir))
- );
- } else if (
- // rename to "." is denied
- $newname !== '.' and
- // THEN try to rename
- $this->view->rename($normalizedOldPath, $normalizedNewPath)
- ) {
- // successful rename
- $meta = $this->view->getFileInfo($normalizedNewPath);
- $meta = \OCA\Files\Helper::populateTags(array($meta));
- $fileInfo = \OCA\Files\Helper::formatFileInfo(current($meta));
- $fileInfo['path'] = dirname($normalizedNewPath);
- $result['success'] = true;
- $result['data'] = $fileInfo;
- } else {
- // rename failed
- $result['data'] = array(
- 'message' => $this->l10n->t('%s could not be renamed', array($oldname))
- );
- }
- return $result;
- }
-
}
diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php
index fb14cea731f..9a4e8d59786 100644
--- a/apps/files/lib/helper.php
+++ b/apps/files/lib/helper.php
@@ -139,9 +139,6 @@ class Helper {
$entry['parentId'] = $i['parent'];
$entry['mtime'] = $i['mtime'] * 1000;
// only pick out the needed attributes
- if (\OC::$server->getPreviewManager()->isAvailable($i)) {
- $entry['isPreviewAvailable'] = true;
- }
$entry['name'] = $i->getName();
$entry['permissions'] = $i['permissions'];
$entry['mimetype'] = $i['mimetype'];
diff --git a/apps/files/templates/list.php b/apps/files/templates/list.php
index 7ebf80ee8b2..04550f945b6 100644
--- a/apps/files/templates/list.php
+++ b/apps/files/templates/list.php
@@ -1,16 +1,5 @@
<div id="controls">
<div class="actions creatable hidden">
- <?php /*
- Only show upload button for public page
- */ ?>
- <?php if(isset($_['dirToken'])):?>
- <div id="upload" class="button upload"
- title="<?php isset($_['uploadMaxHumanFilesize']) ? p($l->t('Upload (max. %s)', array($_['uploadMaxHumanFilesize']))) : '' ?>">
- <label for="file_upload_start" class="svg icon-upload">
- <span class="hidden-visually"><?php p($l->t('Upload'))?></span>
- </label>
- </div>
- <?php endif; ?>
<div id="uploadprogresswrapper">
<div id="uploadprogressbar"></div>
<button class="stop icon-close" style="display:none">
diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php
deleted file mode 100644
index 859c7042b89..00000000000
--- a/apps/files/tests/ajax_rename.php
+++ /dev/null
@@ -1,232 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Christopher Schäpers <kondou@ts.unde.re>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-
-class Test_OC_Files_App_Rename extends \Test\TestCase {
- private static $user;
-
- /**
- * @var PHPUnit_Framework_MockObject_MockObject
- */
- private $viewMock;
-
- /**
- * @var \OCA\Files\App
- */
- private $files;
-
- protected function setUp() {
- parent::setUp();
-
- // mock OC_L10n
- if (!self::$user) {
- self::$user = uniqid();
- }
- \OC_User::createUser(self::$user, 'password');
- $this->loginAsUser(self::$user);
-
- $l10nMock = $this->getMock('\OC_L10N', array('t'), array(), '', false);
- $l10nMock->expects($this->any())
- ->method('t')
- ->will($this->returnArgument(0));
- $viewMock = $this->getMock('\OC\Files\View', array('rename', 'normalizePath', 'getFileInfo', 'file_exists'), array(), '', false);
- $viewMock->expects($this->any())
- ->method('normalizePath')
- ->will($this->returnArgument(0));
- $viewMock->expects($this->any())
- ->method('rename')
- ->will($this->returnValue(true));
- $this->viewMock = $viewMock;
- $this->files = new \OCA\Files\App($viewMock, $l10nMock);
- }
-
- protected function tearDown() {
- $result = \OC_User::deleteUser(self::$user);
- $this->assertTrue($result);
-
- $this->logout();
- parent::tearDown();
- }
-
- /**
- * test rename of file/folder
- */
- function testRenameFolder() {
- $dir = '/';
- $oldname = 'oldname';
- $newname = 'newname';
-
- $this->viewMock->expects($this->any())
- ->method('file_exists')
- ->with($this->anything())
- ->will($this->returnValueMap(array(
- array('/', true),
- array('/oldname', true)
- )));
-
-
- $this->viewMock->expects($this->any())
- ->method('getFileInfo')
- ->will($this->returnValue(new \OC\Files\FileInfo(
- '/new_name',
- new \OC\Files\Storage\Local(array('datadir' => '/')),
- '/',
- array(
- 'fileid' => 123,
- 'type' => 'dir',
- 'mimetype' => 'httpd/unix-directory',
- 'mtime' => 0,
- 'permissions' => 31,
- 'size' => 18,
- 'etag' => 'abcdef',
- 'directory' => '/',
- 'name' => 'new_name',
- ), null)));
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertTrue($result['success']);
- $this->assertEquals(123, $result['data']['id']);
- $this->assertEquals('new_name', $result['data']['name']);
- $this->assertEquals(18, $result['data']['size']);
- $this->assertEquals('httpd/unix-directory', $result['data']['mimetype']);
- $this->assertEquals('abcdef', $result['data']['etag']);
- $this->assertFalse(isset($result['data']['tags']));
- $this->assertEquals('/', $result['data']['path']);
- }
-
- /**
- * test rename of file with tag
- */
- function testRenameFileWithTag() {
- $taggerMock = $this->getMock('\OCP\ITags');
- $taggerMock->expects($this->any())
- ->method('getTagsForObjects')
- ->with(array(123))
- ->will($this->returnValue(array(123 => array('tag1', 'tag2'))));
- $tagManagerMock = $this->getMock('\OCP\ITagManager');
- $tagManagerMock->expects($this->any())
- ->method('load')
- ->with('files')
- ->will($this->returnValue($taggerMock));
- $oldTagManager = \OC::$server->query('TagManager');
- \OC::$server->registerService('TagManager', function ($c) use ($tagManagerMock) {
- return $tagManagerMock;
- });
-
- $dir = '/';
- $oldname = 'oldname.txt';
- $newname = 'newname.txt';
-
- $this->viewMock->expects($this->any())
- ->method('file_exists')
- ->with($this->anything())
- ->will($this->returnValueMap(array(
- array('/', true),
- array('/oldname.txt', true)
- )));
-
-
- $this->viewMock->expects($this->any())
- ->method('getFileInfo')
- ->will($this->returnValue(new \OC\Files\FileInfo(
- '/new_name.txt',
- new \OC\Files\Storage\Local(array('datadir' => '/')),
- '/',
- array(
- 'fileid' => 123,
- 'type' => 'file',
- 'mimetype' => 'text/plain',
- 'mtime' => 0,
- 'permissions' => 31,
- 'size' => 18,
- 'etag' => 'abcdef',
- 'directory' => '/',
- 'name' => 'new_name.txt',
- ), null)));
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertTrue($result['success']);
- $this->assertEquals(123, $result['data']['id']);
- $this->assertEquals('new_name.txt', $result['data']['name']);
- $this->assertEquals(18, $result['data']['size']);
- $this->assertEquals('text/plain', $result['data']['mimetype']);
- $this->assertEquals('abcdef', $result['data']['etag']);
- $this->assertEquals(array('tag1', 'tag2'), $result['data']['tags']);
- $this->assertEquals('/', $result['data']['path']);
-
- \OC::$server->registerService('TagManager', function ($c) use ($oldTagManager) {
- return $oldTagManager;
- });
- }
-
- /**
- * Test rename inside a folder that doesn't exist any more
- */
- function testRenameInNonExistingFolder() {
- $dir = '/unexist';
- $oldname = 'oldname';
- $newname = 'newname';
-
- $this->viewMock->expects($this->at(0))
- ->method('file_exists')
- ->with('/unexist/oldname')
- ->will($this->returnValue(false));
-
- $this->viewMock->expects($this->any())
- ->method('getFileInfo')
- ->will($this->returnValue(array(
- 'fileid' => 123,
- 'type' => 'dir',
- 'mimetype' => 'httpd/unix-directory',
- 'size' => 18,
- 'etag' => 'abcdef',
- 'directory' => '/unexist',
- 'name' => 'new_name',
- )));
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertFalse($result['success']);
- $this->assertEquals('sourcenotfound', $result['data']['code']);
- }
-
- /**
- * Test move to invalid name
- */
- function testRenameToInvalidName() {
- $dir = '/';
- $oldname = 'oldname';
- $newname = 'abc\\';
-
- $result = $this->files->rename($dir, $oldname, $newname);
-
- $this->assertFalse($result['success']);
- $this->assertEquals('File name contains at least one invalid character', $result['data']['message']);
- $this->assertEquals('invalidname', $result['data']['code']);
- }
-}
diff --git a/apps/files/tests/js/favoritesfilelistspec.js b/apps/files/tests/js/favoritesfilelistspec.js
index 608ddaca18b..1c833d334e2 100644
--- a/apps/files/tests/js/favoritesfilelistspec.js
+++ b/apps/files/tests/js/favoritesfilelistspec.js
@@ -100,8 +100,7 @@ describe('OCA.Files.FavoritesFileList tests', function() {
expect($tr.attr('data-mtime')).toEqual('11111000');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Fsomedir&files=test.txt'
+ '/remote.php/webdav/somedir/test.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('test.txt');
});
diff --git a/apps/files/tests/js/fileUploadSpec.js b/apps/files/tests/js/fileUploadSpec.js
index a49a5d4e2e0..8a0d6b01952 100644
--- a/apps/files/tests/js/fileUploadSpec.js
+++ b/apps/files/tests/js/fileUploadSpec.js
@@ -19,6 +19,8 @@
*
*/
+/* global FileList */
+
describe('OC.Upload tests', function() {
var $dummyUploader;
var testFile;
diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js
index d29164c5136..a905a4d969d 100644
--- a/apps/files/tests/js/fileactionsSpec.js
+++ b/apps/files/tests/js/fileactionsSpec.js
@@ -584,7 +584,7 @@ describe('OCA.Files.FileActions tests', function() {
expect(busyStub.calledWith('testName.txt', true)).toEqual(true);
expect(handleDownloadStub.calledOnce).toEqual(true);
expect(handleDownloadStub.getCall(0).args[0]).toEqual(
- OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt'
+ OC.webroot + '/remote.php/webdav/subdir/testName.txt'
);
busyStub.reset();
handleDownloadStub.yield();
diff --git a/apps/files/tests/js/fileactionsmenuSpec.js b/apps/files/tests/js/fileactionsmenuSpec.js
index dee542458b6..747a746a602 100644
--- a/apps/files/tests/js/fileactionsmenuSpec.js
+++ b/apps/files/tests/js/fileactionsmenuSpec.js
@@ -237,8 +237,8 @@ describe('OCA.Files.FileActionsMenu tests', function() {
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Fsubdir&files=testName.txt');
+ '/remote.php/webdav/subdir/testName.txt'
+ );
redirectStub.restore();
});
it('takes the file\'s path into account when clicking download', function() {
@@ -269,8 +269,7 @@ describe('OCA.Files.FileActionsMenu tests', function() {
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(
- OC.webroot + '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Fanotherpath%2Fthere&files=testName.txt'
+ OC.webroot + '/remote.php/webdav/anotherpath/there/testName.txt'
);
redirectStub.restore();
});
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index 05e6fcc6122..9f7ad50bc60 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -20,8 +20,11 @@
*/
describe('OCA.Files.FileList tests', function() {
- var testFiles, alertStub, notificationStub, fileList, pageSizeStub;
+ var FileInfo = OC.Files.FileInfo;
+ var testFiles, testRoot, notificationStub, fileList, pageSizeStub;
var bcResizeStub;
+ var filesClient;
+ var redirectStub;
/**
* Generate test file data
@@ -38,21 +41,29 @@ describe('OCA.Files.FileList tests', function() {
name += '0';
}
name += i + '.txt';
- files.push({
+ files.push(new FileInfo({
id: i,
type: 'file',
name: name,
mimetype: 'text/plain',
size: i * 2,
etag: 'abc'
- });
+ }));
}
return files;
}
beforeEach(function() {
- alertStub = sinon.stub(OC.dialogs, 'alert');
- notificationStub = sinon.stub(OC.Notification, 'show');
+ filesClient = new OC.Files.Client({
+ host: 'localhost',
+ port: 80,
+ // FIXME: uncomment after fixing the test OC.webroot
+ //root: OC.webroot + '/remote.php/webdav',
+ root: '/remote.php/webdav',
+ useHTTPS: false
+ });
+ redirectStub = sinon.stub(OC, 'redirect');
+ notificationStub = sinon.stub(OC.Notification, 'showTemporary');
// prevent resize algo to mess up breadcrumb order while
// testing
bcResizeStub = sinon.stub(OCA.Files.BreadCrumb.prototype, '_resize');
@@ -93,7 +104,17 @@ describe('OCA.Files.FileList tests', function() {
'</div>'
);
- testFiles = [{
+ testRoot = new FileInfo({
+ // root entry
+ id: 99,
+ type: 'dir',
+ name: '/subdir',
+ mimetype: 'httpd/unix-directory',
+ size: 1200000,
+ etag: 'a0b0c0d0',
+ permissions: OC.PERMISSION_ALL
+ });
+ testFiles = [new FileInfo({
id: 1,
type: 'file',
name: 'One.txt',
@@ -102,7 +123,7 @@ describe('OCA.Files.FileList tests', function() {
size: 12,
etag: 'abc',
permissions: OC.PERMISSION_ALL
- }, {
+ }), new FileInfo({
id: 2,
type: 'file',
name: 'Two.jpg',
@@ -111,7 +132,7 @@ describe('OCA.Files.FileList tests', function() {
size: 12049,
etag: 'def',
permissions: OC.PERMISSION_ALL
- }, {
+ }), new FileInfo({
id: 3,
type: 'file',
name: 'Three.pdf',
@@ -120,7 +141,7 @@ describe('OCA.Files.FileList tests', function() {
size: 58009,
etag: '123',
permissions: OC.PERMISSION_ALL
- }, {
+ }), new FileInfo({
id: 4,
type: 'dir',
name: 'somedir',
@@ -129,9 +150,11 @@ describe('OCA.Files.FileList tests', function() {
size: 250,
etag: '456',
permissions: OC.PERMISSION_ALL
- }];
+ })];
pageSizeStub = sinon.stub(OCA.Files.FileList.prototype, 'pageSize').returns(20);
- fileList = new OCA.Files.FileList($('#app-content-files'));
+ fileList = new OCA.Files.FileList($('#app-content-files'), {
+ filesClient: filesClient
+ });
});
afterEach(function() {
testFiles = undefined;
@@ -141,9 +164,9 @@ describe('OCA.Files.FileList tests', function() {
fileList = undefined;
notificationStub.restore();
- alertStub.restore();
bcResizeStub.restore();
pageSizeStub.restore();
+ redirectStub.restore();
});
describe('Getters', function() {
it('Returns the current directory', function() {
@@ -166,15 +189,14 @@ describe('OCA.Files.FileList tests', function() {
clock.restore();
});
it('generates file element with correct attributes when calling add() with file data', function() {
- var fileData = {
+ var fileData = new FileInfo({
id: 18,
- type: 'file',
name: 'testName.txt',
mimetype: 'text/plain',
- size: '1234',
+ size: 1234,
etag: 'a01234c',
- mtime: '123456'
- };
+ mtime: 123456
+ });
var $tr = fileList.add(fileData);
expect($tr).toBeDefined();
@@ -188,7 +210,7 @@ describe('OCA.Files.FileList tests', function() {
expect($tr.attr('data-mime')).toEqual('text/plain');
expect($tr.attr('data-mtime')).toEqual('123456');
expect($tr.find('a.name').attr('href'))
- .toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt');
+ .toEqual(OC.webroot + '/remote.php/webdav/subdir/testName.txt');
expect($tr.find('.nametext').text().trim()).toEqual('testName.txt');
expect($tr.find('.filesize').text()).toEqual('1 kB');
@@ -196,15 +218,14 @@ describe('OCA.Files.FileList tests', function() {
expect(fileList.findFileEl('testName.txt')[0]).toEqual($tr[0]);
});
it('generates dir element with correct attributes when calling add() with dir data', function() {
- var fileData = {
+ var fileData = new FileInfo({
id: 19,
- type: 'dir',
name: 'testFolder',
mimetype: 'httpd/unix-directory',
- size: '1234',
+ size: 1234,
etag: 'a01234c',
- mtime: '123456'
- };
+ mtime: 123456
+ });
var $tr = fileList.add(fileData);
expect($tr).toBeDefined();
@@ -297,7 +318,6 @@ describe('OCA.Files.FileList tests', function() {
expect($tr.index()).toEqual(4);
});
it('inserts files in a sorted manner when insert option is enabled', function() {
- var $tr;
for (var i = 0; i < testFiles.length; i++) {
fileList.add(testFiles[i]);
}
@@ -423,28 +443,31 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('Deleting files', function() {
+ var deferredDelete;
+ var deleteStub;
+
+ beforeEach(function() {
+ deferredDelete = $.Deferred();
+ deleteStub = sinon.stub(filesClient, 'remove').returns(deferredDelete.promise());
+ });
+ afterEach(function() {
+ deleteStub.restore();
+ });
+
function doDelete() {
- var request, query;
// note: normally called from FileActions
fileList.do_delete(['One.txt', 'Two.jpg']);
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
-
- query = fakeServer.requests[0].requestBody;
- expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir', files: '["One.txt","Two.jpg"]'});
+ expect(deleteStub.calledTwice).toEqual(true);
+ expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
}
it('calls delete.php, removes the deleted entries and updates summary', function() {
var $summary;
fileList.setFiles(testFiles);
doDelete();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+ deferredDelete.resolve(200);
expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
@@ -482,11 +505,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.setFiles([testFiles[0], testFiles[1]]);
doDelete();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+ deferredDelete.resolve(200);
expect(fileList.$fileList.find('tr').length).toEqual(0);
@@ -501,21 +520,41 @@ describe('OCA.Files.FileList tests', function() {
fileList.setFiles(testFiles);
doDelete();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'error', data: {message: 'WOOT'}})
- );
+ deferredDelete.reject(403);
// files are still in the list
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(fileList.findFileEl('Two.jpg').length).toEqual(1);
expect(fileList.$fileList.find('tr').length).toEqual(4);
- expect(notificationStub.calledOnce).toEqual(true);
+ expect(notificationStub.calledTwice).toEqual(true);
+ });
+ it('remove file from list if delete call returned 404 not found', function() {
+ fileList.setFiles(testFiles);
+ doDelete();
+
+ deferredDelete.reject(404);
+
+ // files are still in the list
+ expect(fileList.findFileEl('One.txt').length).toEqual(0);
+ expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
+ expect(fileList.$fileList.find('tr').length).toEqual(2);
+
+ expect(notificationStub.notCalled).toEqual(true);
});
});
describe('Renaming files', function() {
+ var deferredRename;
+ var renameStub;
+
+ beforeEach(function() {
+ deferredRename = $.Deferred();
+ renameStub = sinon.stub(filesClient, 'move').returns(deferredRename.promise());
+ });
+ afterEach(function() {
+ renameStub.restore();
+ });
+
function doCancelRename() {
var $input;
for (var i = 0; i < testFiles.length; i++) {
@@ -530,10 +569,10 @@ describe('OCA.Files.FileList tests', function() {
// trigger submit because triggering blur doesn't work in all browsers
$input.closest('form').trigger('submit');
- expect(fakeServer.requests.length).toEqual(0);
+ expect(renameStub.notCalled).toEqual(true);
}
function doRename() {
- var $input, request;
+ var $input;
for (var i = 0; i < testFiles.length; i++) {
var file = testFiles[i];
@@ -548,83 +587,61 @@ describe('OCA.Files.FileList tests', function() {
// trigger submit because triggering blur doesn't work in all browsers
$input.closest('form').trigger('submit');
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url.substr(0, request.url.indexOf('?'))).toEqual(OC.webroot + '/index.php/apps/files/ajax/rename.php');
- expect(OC.parseQueryString(request.url)).toEqual({'dir': '/some/subdir', newname: 'Tu_after_three.txt', file: 'One.txt'});
+ expect(renameStub.calledOnce).toEqual(true);
+ expect(renameStub.getCall(0).args[0]).toEqual('/some/subdir/One.txt');
+ expect(renameStub.getCall(0).args[1]).toEqual('/some/subdir/Tu_after_three.txt');
}
it('Inserts renamed file entry at correct position if rename ajax call suceeded', function() {
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt',
- type: 'file'
- }
- }));
+ deferredRename.resolve(201);
// element stays renamed
expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('Tu_after_three.txt').length).toEqual(1);
- expect(fileList.findFileEl('Tu_after_three.txt').index()).toEqual(2); // after Two.txt
+ expect(fileList.findFileEl('Tu_after_three.txt').index()).toEqual(2); // after Two.jpg
- expect(alertStub.notCalled).toEqual(true);
+ expect(notificationStub.notCalled).toEqual(true);
});
it('Reverts file entry if rename ajax call failed', function() {
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Something went wrong'
- }
- }));
+ deferredRename.reject(403);
// element was reverted
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(fileList.findFileEl('One.txt').index()).toEqual(1); // after somedir
expect(fileList.findFileEl('Tu_after_three.txt').length).toEqual(0);
- expect(alertStub.calledOnce).toEqual(true);
+ expect(notificationStub.calledOnce).toEqual(true);
});
it('Correctly updates file link after rename', function() {
var $tr;
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt'
- }
- }));
+ deferredRename.resolve(201);
$tr = fileList.findFileEl('Tu_after_three.txt');
- expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=Tu_after_three.txt');
+ expect($tr.find('a.name').attr('href'))
+ .toEqual(OC.webroot + '/remote.php/webdav/some/subdir/Tu_after_three.txt');
});
it('Triggers "fileActionsReady" event after rename', function() {
var handler = sinon.stub();
fileList.$fileList.on('fileActionsReady', handler);
doRename();
expect(handler.notCalled).toEqual(true);
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt'
- }
- }));
+
+ deferredRename.resolve(201);
+
expect(handler.calledOnce).toEqual(true);
expect(fileList.$fileList.find('.test').length).toEqual(0);
});
it('Leaves the summary alone when reinserting renamed element', function() {
var $summary = $('#filestable .summary');
doRename();
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Tu_after_three.txt'
- }
- }));
+
+ deferredRename.resolve(201);
+
expect($summary.find('.info').text()).toEqual('1 folder and 3 files');
});
it('Leaves the summary alone when cancel renaming', function() {
@@ -668,7 +685,7 @@ describe('OCA.Files.FileList tests', function() {
// trigger submit does not send server request
$input.closest('form').trigger('submit');
- expect(fakeServer.requests.length).toEqual(0);
+ expect(renameStub.notCalled).toEqual(true);
// simulate escape key
$input.trigger(new $.Event('keyup', {keyCode: 27}));
@@ -694,12 +711,7 @@ describe('OCA.Files.FileList tests', function() {
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('Tu_after_three.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'loading.gif'));
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Something went wrong'
- }
- }));
+ deferredRename.reject(409);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
@@ -707,25 +719,27 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('Moving files', function() {
+ var deferredMove;
+ var moveStub;
+
beforeEach(function() {
+ deferredMove = $.Deferred();
+ moveStub = sinon.stub(filesClient, 'move').returns(deferredMove.promise());
+
fileList.setFiles(testFiles);
});
+ afterEach(function() {
+ moveStub.restore();
+ });
+
it('Moves single file to target folder', function() {
- var request;
fileList.move('One.txt', '/somedir');
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+ expect(moveStub.calledOnce).toEqual(true);
+ expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'One.txt',
- type: 'file'
- }
- }));
+ deferredMove.resolve(201);
expect(fileList.findFileEl('One.txt').length).toEqual(0);
@@ -736,39 +750,28 @@ describe('OCA.Files.FileList tests', function() {
expect(notificationStub.notCalled).toEqual(true);
});
it('Moves list of files to target folder', function() {
- var request;
+ var deferredMove1 = $.Deferred();
+ var deferredMove2 = $.Deferred();
+ moveStub.onCall(0).returns(deferredMove1.promise());
+ moveStub.onCall(1).returns(deferredMove2.promise());
+
fileList.move(['One.txt', 'Two.jpg'], '/somedir');
- expect(fakeServer.requests.length).toEqual(2);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+ expect(moveStub.calledTwice).toEqual(true);
+ expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
+ expect(moveStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
+ expect(moveStub.getCall(1).args[1]).toEqual('/somedir/Two.jpg');
- request = fakeServer.requests[1];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'Two.jpg', target: '/somedir'});
-
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'One.txt',
- type: 'file'
- }
- }));
+ deferredMove1.resolve(201);
expect(fileList.findFileEl('One.txt').length).toEqual(0);
- // folder size has increased
+ // folder size has increased during move
expect(fileList.findFileEl('somedir').data('size')).toEqual(262);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');
- fakeServer.requests[1].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'success',
- data: {
- name: 'Two.jpg',
- type: 'file'
- }
- }));
+ deferredMove2.resolve(201);
expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
@@ -779,47 +782,31 @@ describe('OCA.Files.FileList tests', function() {
expect(notificationStub.notCalled).toEqual(true);
});
it('Shows notification if a file could not be moved', function() {
- var request;
fileList.move('One.txt', '/somedir');
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+ expect(moveStub.calledOnce).toEqual(true);
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Error while moving file'
- }
- }));
+ deferredMove.reject(409);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(notificationStub.calledOnce).toEqual(true);
- expect(notificationStub.getCall(0).args[0]).toEqual('Error while moving file');
+ expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
});
it('Restores thumbnail if a file could not be moved', function() {
- var request;
fileList.move('One.txt', '/somedir');
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'loading.gif'));
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
+ expect(moveStub.calledOnce).toEqual(true);
- fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
- status: 'error',
- data: {
- message: 'Error while moving file'
- }
- }));
+ deferredMove.reject(409);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(notificationStub.calledOnce).toEqual(true);
- expect(notificationStub.getCall(0).args[0]).toEqual('Error while moving file');
+ expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'filetypes/text.svg'));
@@ -878,7 +865,7 @@ describe('OCA.Files.FileList tests', function() {
name: 'testFile.txt',
directory: '/current dir'
};
- var $tr = fileList.add(fileData);
+ fileList.add(fileData);
expect(fileList.findFileEl('testFile.txt').length).toEqual(1);
});
it('triggers "fileActionsReady" event after update', function() {
@@ -1143,69 +1130,85 @@ describe('OCA.Files.FileList tests', function() {
afterEach(function() {
previewLoadStub.restore();
});
- it('renders default icon for file when none provided and no preview is available', function() {
+ it('renders default file icon when none provided and no mime type is set', function() {
var fileData = {
- type: 'file',
name: 'testFile.txt'
};
var $tr = fileList.add(fileData);
var $imgDiv = $tr.find('td.filename .thumbnail');
expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
- expect(previewLoadStub.notCalled).toEqual(true);
+ // tries to load preview
+ expect(previewLoadStub.calledOnce).toEqual(true);
});
- it('renders default icon for dir when none provided and no preview is available', function() {
+ it('renders default icon for folder when none provided', function() {
var fileData = {
- type: 'dir',
- name: 'test dir'
+ name: 'test dir',
+ mimetype: 'httpd/unix-directory'
};
+
var $tr = fileList.add(fileData);
var $imgDiv = $tr.find('td.filename .thumbnail');
expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/folder.svg');
+ // no preview since it's a directory
expect(previewLoadStub.notCalled).toEqual(true);
});
it('renders provided icon for file when provided', function() {
- var fileData = {
+ var fileData = new FileInfo({
type: 'file',
name: 'test file',
icon: OC.webroot + '/core/img/filetypes/application-pdf.svg',
mimetype: 'application/pdf'
- };
+ });
var $tr = fileList.add(fileData);
var $imgDiv = $tr.find('td.filename .thumbnail');
expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg');
+ // try loading preview
+ expect(previewLoadStub.calledOnce).toEqual(true);
+ });
+ it('renders provided icon for file when provided', function() {
+ var fileData = new FileInfo({
+ name: 'somefile.pdf',
+ icon: OC.webroot + '/core/img/filetypes/application-pdf.svg'
+ });
+
+ var $tr = fileList.add(fileData);
+ var $imgDiv = $tr.find('td.filename .thumbnail');
+ expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg');
+ // try loading preview
+ expect(previewLoadStub.calledOnce).toEqual(true);
+ });
+ it('renders provided icon for folder when provided', function() {
+ var fileData = new FileInfo({
+ name: 'some folder',
+ mimetype: 'httpd/unix-directory',
+ icon: OC.webroot + '/core/img/filetypes/folder-alt.svg'
+ });
+
+ var $tr = fileList.add(fileData);
+ var $imgDiv = $tr.find('td.filename .thumbnail');
+ expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/folder-alt.svg');
+ // do not load preview for folders
expect(previewLoadStub.notCalled).toEqual(true);
});
- it('renders preview when no icon was provided and preview is available', function() {
+ it('renders preview when no icon was provided', function() {
var fileData = {
type: 'file',
- name: 'test file',
- isPreviewAvailable: true
+ name: 'test file'
};
var $tr = fileList.add(fileData);
var $td = $tr.find('td.filename');
- expect(OC.TestUtil.getImageUrl($td.find('.thumbnail'))).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
+ expect(OC.TestUtil.getImageUrl($td.find('.thumbnail')))
+ .toEqual(OC.webroot + '/core/img/filetypes/file.svg');
expect(previewLoadStub.calledOnce).toEqual(true);
// third argument is callback
previewLoadStub.getCall(0).args[0].callback(OC.webroot + '/somepath.png');
expect(OC.TestUtil.getImageUrl($td.find('.thumbnail'))).toEqual(OC.webroot + '/somepath.png');
});
- it('renders default file type icon when no icon was provided and no preview is available', function() {
- var fileData = {
- type: 'file',
- name: 'test file',
- isPreviewAvailable: false
- };
- var $tr = fileList.add(fileData);
- var $imgDiv = $tr.find('td.filename .thumbnail');
- expect(OC.TestUtil.getImageUrl($imgDiv)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
- expect(previewLoadStub.notCalled).toEqual(true);
- });
it('does not render preview for directories', function() {
var fileData = {
type: 'dir',
mimetype: 'httpd/unix-directory',
- name: 'test dir',
- isPreviewAvailable: true
+ name: 'test dir'
};
var $tr = fileList.add(fileData);
var $td = $tr.find('td.filename');
@@ -1217,7 +1220,6 @@ describe('OCA.Files.FileList tests', function() {
type: 'dir',
mimetype: 'httpd/unix-directory',
name: 'test dir',
- isPreviewAvailable: true,
mountType: 'external-root'
};
var $tr = fileList.add(fileData);
@@ -1230,7 +1232,6 @@ describe('OCA.Files.FileList tests', function() {
type: 'dir',
mimetype: 'httpd/unix-directory',
name: 'test dir',
- isPreviewAvailable: true,
mountType: 'external'
};
var $tr = fileList.add(fileData);
@@ -1278,75 +1279,47 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('loading file list', function() {
+ var deferredList;
+ var getFolderContentsStub;
+
beforeEach(function() {
- var data = {
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- };
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2F(subdir|anothersubdir)/, [
- 200, {
- "Content-Type": "application/json"
- },
- JSON.stringify(data)
- ]);
+ deferredList = $.Deferred();
+ getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+ });
+ afterEach(function() {
+ getFolderContentsStub.restore();
});
it('fetches file list from server and renders it when reload() is called', function() {
fileList.reload();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = url.substr(url.indexOf('?') + 1);
- expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir', sort: 'name', sortdirection: 'asc'});
- fakeServer.respond();
+ expect(getFolderContentsStub.calledOnce).toEqual(true);
+ expect(getFolderContentsStub.calledWith('/subdir')).toEqual(true);
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect($('#fileList tr').length).toEqual(4);
expect(fileList.findFileEl('One.txt').length).toEqual(1);
});
it('switches dir and fetches file list when calling changeDirectory()', function() {
fileList.changeDirectory('/anothersubdir');
expect(fileList.getCurrentDirectory()).toEqual('/anothersubdir');
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = url.substr(url.indexOf('?') + 1);
- expect(OC.parseQueryString(query)).toEqual({'dir': '/anothersubdir', sort: 'name', sortdirection: 'asc'});
- fakeServer.respond();
+ expect(getFolderContentsStub.calledOnce).toEqual(true);
+ expect(getFolderContentsStub.calledWith('/anothersubdir')).toEqual(true);
});
it('converts backslashes to slashes when calling changeDirectory()', function() {
fileList.changeDirectory('/another\\subdir');
expect(fileList.getCurrentDirectory()).toEqual('/another/subdir');
});
it('switches to root dir when current directory does not exist', function() {
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
- 404, {
- "Content-Type": "application/json"
- },
- ''
- ]);
fileList.changeDirectory('/unexist');
- fakeServer.respond();
+ deferredList.reject(404);
expect(fileList.getCurrentDirectory()).toEqual('/');
});
it('switches to root dir when current directory is forbidden', function() {
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
- 403, {
- "Content-Type": "application/json"
- },
- ''
- ]);
fileList.changeDirectory('/unexist');
- fakeServer.respond();
+ deferredList.reject(403);
expect(fileList.getCurrentDirectory()).toEqual('/');
});
it('switches to root dir when current directory is unavailable', function() {
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
- 500, {
- "Content-Type": "application/json"
- },
- ''
- ]);
fileList.changeDirectory('/unexist');
- fakeServer.respond();
+ deferredList.reject(500);
expect(fileList.getCurrentDirectory()).toEqual('/');
});
it('shows mask before loading file list then hides it at the end', function() {
@@ -1355,7 +1328,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.changeDirectory('/anothersubdir');
expect(showMaskStub.calledOnce).toEqual(true);
expect(hideMaskStub.calledOnce).toEqual(false);
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect(showMaskStub.calledOnce).toEqual(true);
expect(hideMaskStub.calledOnce).toEqual(true);
showMaskStub.restore();
@@ -1365,6 +1338,7 @@ describe('OCA.Files.FileList tests', function() {
var handler = sinon.stub();
$('#app-content-files').on('changeDirectory', handler);
fileList.changeDirectory('/somedir');
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect(handler.calledOnce).toEqual(true);
expect(handler.getCall(0).args[0].dir).toEqual('/somedir');
});
@@ -1375,31 +1349,27 @@ describe('OCA.Files.FileList tests', function() {
it('refreshes breadcrumb after update', function() {
var setDirSpy = sinon.spy(fileList.breadcrumb, 'setDirectory');
fileList.changeDirectory('/anothersubdir');
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
expect(fileList.breadcrumb.setDirectory.calledOnce).toEqual(true);
expect(fileList.breadcrumb.setDirectory.calledWith('/anothersubdir')).toEqual(true);
setDirSpy.restore();
+ getFolderContentsStub.restore();
});
});
describe('breadcrumb events', function() {
+ var deferredList;
+ var getFolderContentsStub;
+
beforeEach(function() {
- var data = {
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- };
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2Fsubdir/, [
- 200, {
- "Content-Type": "application/json"
- },
- JSON.stringify(data)
- ]);
+ deferredList = $.Deferred();
+ getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+ });
+ afterEach(function() {
+ getFolderContentsStub.restore();
});
it('clicking on root breadcrumb changes directory to root', function() {
fileList.changeDirectory('/subdir/two/three with space/four/five');
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var changeDirStub = sinon.stub(fileList, 'changeDirectory');
fileList.breadcrumb.$el.find('.crumb:eq(0)').trigger({type: 'click', which: 1});
@@ -1409,7 +1379,7 @@ describe('OCA.Files.FileList tests', function() {
});
it('clicking on breadcrumb changes directory', function() {
fileList.changeDirectory('/subdir/two/three with space/four/five');
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var changeDirStub = sinon.stub(fileList, 'changeDirectory');
fileList.breadcrumb.$el.find('.crumb:eq(3)').trigger({type: 'click', which: 1});
@@ -1418,9 +1388,10 @@ describe('OCA.Files.FileList tests', function() {
changeDirStub.restore();
});
it('dropping files on breadcrumb calls move operation', function() {
- var request, query, testDir = '/subdir/two/three with space/four/five';
+ var testDir = '/subdir/two/three with space/four/five';
+ var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
fileList.changeDirectory(testDir);
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var $crumb = fileList.breadcrumb.$el.find('.crumb:eq(3)');
// no idea what this is but is required by the handler
var ui = {
@@ -1436,33 +1407,18 @@ describe('OCA.Files.FileList tests', function() {
// simulate drop event
fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
- // will trigger two calls to move.php (first one was previous list.php)
- expect(fakeServer.requests.length).toEqual(3);
-
- request = fakeServer.requests[1];
- expect(request.method).toEqual('POST');
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- query = OC.parseQueryString(request.requestBody);
- expect(query).toEqual({
- target: '/subdir/two/three with space',
- dir: testDir,
- file: 'One.txt'
- });
-
- request = fakeServer.requests[2];
- expect(request.method).toEqual('POST');
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
- query = OC.parseQueryString(request.requestBody);
- expect(query).toEqual({
- target: '/subdir/two/three with space',
- dir: testDir,
- file: 'Two.jpg'
- });
+ expect(moveStub.callCount).toEqual(2);
+ expect(moveStub.getCall(0).args[0]).toEqual(testDir + '/One.txt');
+ expect(moveStub.getCall(0).args[1]).toEqual('/subdir/two/three with space/One.txt');
+ expect(moveStub.getCall(1).args[0]).toEqual(testDir + '/Two.jpg');
+ expect(moveStub.getCall(1).args[1]).toEqual('/subdir/two/three with space/Two.jpg');
+ moveStub.restore();
});
it('dropping files on same dir breadcrumb does nothing', function() {
var testDir = '/subdir/two/three with space/four/five';
+ var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
fileList.changeDirectory(testDir);
- fakeServer.respond();
+ deferredList.resolve(200, [testRoot].concat(testFiles));
var $crumb = fileList.breadcrumb.$el.find('.crumb:last');
// no idea what this is but is required by the handler
var ui = {
@@ -1479,21 +1435,26 @@ describe('OCA.Files.FileList tests', function() {
fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
// no extra server request
- expect(fakeServer.requests.length).toEqual(1);
+ expect(moveStub.notCalled).toEqual(true);
});
});
describe('Download Url', function() {
it('returns correct download URL for single files', function() {
- expect(fileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=some%20file.txt');
- expect(fileList.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fanotherpath%2Fabc&files=some%20file.txt');
+ expect(fileList.getDownloadUrl('some file.txt'))
+ .toEqual(OC.webroot + '/remote.php/webdav/subdir/some%20file.txt');
+ expect(fileList.getDownloadUrl('some file.txt', '/anotherpath/abc'))
+ .toEqual(OC.webroot + '/remote.php/webdav/anotherpath/abc/some%20file.txt');
$('#dir').val('/');
- expect(fileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=some%20file.txt');
+ expect(fileList.getDownloadUrl('some file.txt'))
+ .toEqual(OC.webroot + '/remote.php/webdav/some%20file.txt');
});
it('returns correct download URL for multiple files', function() {
- expect(fileList.getDownloadUrl(['a b c.txt', 'd e f.txt'])).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D');
+ expect(fileList.getDownloadUrl(['a b c.txt', 'd e f.txt']))
+ .toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D');
});
it('returns the correct ajax URL', function() {
- expect(fileList.getAjaxUrl('test', {a:1, b:'x y'})).toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
+ expect(fileList.getAjaxUrl('test', {a:1, b:'x y'}))
+ .toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
});
});
describe('File selection', function() {
@@ -1672,24 +1633,17 @@ describe('OCA.Files.FileList tests', function() {
});
it('Selection is cleared when switching dirs', function() {
$('.select-all').click();
- var data = {
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- };
- fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php/, [
- 200, {
- "Content-Type": "application/json"
- },
- JSON.stringify(data)
- ]
- );
+ var deferredList = $.Deferred();
+ var getFolderContentsStub = sinon.stub(filesClient, 'getFolderContents').returns(deferredList.promise());
+
fileList.changeDirectory('/');
- fakeServer.respond();
+
+ deferredList.resolve(200, [testRoot].concat(testFiles));
+
expect($('.select-all').prop('checked')).toEqual(false);
expect(_.pluck(fileList.getSelectedFiles(), 'name')).toEqual([]);
+
+ getFolderContentsStub.restore();
});
it('getSelectedFiles returns the selected files even when they are on the next page', function() {
var selectedFiles;
@@ -1796,6 +1750,12 @@ describe('OCA.Files.FileList tests', function() {
etag: '456',
permissions: OC.PERMISSION_ALL
});
+ expect(files[0].id).toEqual(1);
+ expect(files[0].name).toEqual('One.txt');
+ expect(files[1].id).toEqual(3);
+ expect(files[1].name).toEqual('Three.pdf');
+ expect(files[2].id).toEqual(4);
+ expect(files[2].name).toEqual('somedir');
});
it('Removing a file removes it from the selection', function() {
fileList.remove('Three.pdf');
@@ -1824,7 +1784,6 @@ describe('OCA.Files.FileList tests', function() {
});
describe('Download', function() {
it('Opens download URL when clicking "Download"', function() {
- var redirectStub = sinon.stub(OC, 'redirect');
$('.selectedActions .download').click();
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22One.txt%22%2C%22Three.pdf%22%2C%22somedir%22%5D');
@@ -1833,54 +1792,53 @@ describe('OCA.Files.FileList tests', function() {
it('Downloads root folder when all selected in root folder', function() {
$('#dir').val('/');
$('.select-all').click();
- var redirectStub = sinon.stub(OC, 'redirect');
$('.selectedActions .download').click();
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=');
- redirectStub.restore();
});
it('Downloads parent folder when all selected in subfolder', function() {
$('.select-all').click();
- var redirectStub = sinon.stub(OC, 'redirect');
$('.selectedActions .download').click();
expect(redirectStub.calledOnce).toEqual(true);
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=subdir');
- redirectStub.restore();
});
});
describe('Delete', function() {
+ var deleteStub, deferredDelete;
+ beforeEach(function() {
+ deferredDelete = $.Deferred();
+ deleteStub = sinon.stub(filesClient, 'remove').returns(deferredDelete.promise());
+ });
+ afterEach(function() {
+ deleteStub.restore();
+ });
it('Deletes selected files when "Delete" clicked', function() {
- var request;
$('.selectedActions .delete-selected').click();
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/subdir', files: '["One.txt","Three.pdf","somedir"]'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+
+ expect(deleteStub.callCount).toEqual(3);
+ expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Three.pdf');
+ expect(deleteStub.getCall(2).args[0]).toEqual('/subdir/somedir');
+
+ deferredDelete.resolve(204);
+
expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('Three.pdf').length).toEqual(0);
expect(fileList.findFileEl('somedir').length).toEqual(0);
expect(fileList.findFileEl('Two.jpg').length).toEqual(1);
});
it('Deletes all files when all selected when "Delete" clicked', function() {
- var request;
$('.select-all').click();
$('.selectedActions .delete-selected').click();
- expect(fakeServer.requests.length).toEqual(1);
- request = fakeServer.requests[0];
- expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
- expect(OC.parseQueryString(request.requestBody))
- .toEqual({'dir': '/subdir', allfiles: 'true'});
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({status: 'success'})
- );
+
+ expect(deleteStub.callCount).toEqual(4);
+ expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
+ expect(deleteStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
+ expect(deleteStub.getCall(2).args[0]).toEqual('/subdir/Three.pdf');
+ expect(deleteStub.getCall(3).args[0]).toEqual('/subdir/somedir');
+
+ deferredDelete.resolve(204);
+
expect(fileList.isEmpty).toEqual(true);
});
});
@@ -2118,30 +2076,6 @@ describe('OCA.Files.FileList tests', function() {
});
});
describe('Sorting files', function() {
- it('Sorts by name by default', function() {
- fileList.reload();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
- expect(query.sort).toEqual('name');
- expect(query.sortdirection).toEqual('asc');
- });
- it('Reloads file list with a different sort when clicking on column header of unsorted column', function() {
- fileList.$el.find('.column-size .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
- expect(query.sort).toEqual('size');
- expect(query.sortdirection).toEqual('desc');
- });
- it('Toggles sort direction when clicking on already sorted column', function() {
- fileList.$el.find('.column-name .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- var url = fakeServer.requests[0].url;
- var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
- expect(query.sort).toEqual('name');
- expect(query.sortdirection).toEqual('desc');
- });
it('Toggles the sort indicator when clicking on a column header', function() {
var ASC_CLASS = fileList.SORT_INDICATOR_ASC_CLASS;
var DESC_CLASS = fileList.SORT_INDICATOR_DESC_CLASS;
@@ -2191,28 +2125,15 @@ describe('OCA.Files.FileList tests', function() {
it('Uses correct sort comparator when inserting files', function() {
testFiles.sort(OCA.Files.FileList.Comparators.size);
testFiles.reverse(); //default is descending
- // this will make it reload the testFiles with the correct sorting
+ fileList.setFiles(testFiles);
fileList.$el.find('.column-size .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- })
- );
- var newFileData = {
+ var newFileData = new FileInfo({
id: 999,
- type: 'file',
name: 'new file.txt',
mimetype: 'text/plain',
size: 40001,
etag: '999'
- };
+ });
fileList.add(newFileData);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(0);
expect(fileList.findFileEl('new file.txt').index()).toEqual(1);
@@ -2224,41 +2145,18 @@ describe('OCA.Files.FileList tests', function() {
});
it('Uses correct reversed sort comparator when inserting files', function() {
testFiles.sort(OCA.Files.FileList.Comparators.size);
- // this will make it reload the testFiles with the correct sorting
+ fileList.setFiles(testFiles);
fileList.$el.find('.column-size .columntitle').click();
- expect(fakeServer.requests.length).toEqual(1);
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- })
- );
+
// reverse sort
fileList.$el.find('.column-size .columntitle').click();
- fakeServer.requests[1].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- files: testFiles,
- permissions: 31
- }
- })
- );
- var newFileData = {
+ var newFileData = new FileInfo({
id: 999,
- type: 'file',
name: 'new file.txt',
mimetype: 'text/plain',
size: 40001,
etag: '999'
- };
+ });
fileList.add(newFileData);
expect(fileList.findFileEl('One.txt').index()).toEqual(0);
expect(fileList.findFileEl('somedir').index()).toEqual(1);
@@ -2290,87 +2188,96 @@ describe('OCA.Files.FileList tests', function() {
});
describe('create file', function() {
var deferredCreate;
+ var deferredInfo;
+ var createStub;
+ var getFileInfoStub;
beforeEach(function() {
deferredCreate = $.Deferred();
+ deferredInfo = $.Deferred();
+ createStub = sinon.stub(filesClient, 'putFileContents')
+ .returns(deferredCreate.promise());
+ getFileInfoStub = sinon.stub(filesClient, 'getFileInfo')
+ .returns(deferredInfo.promise());
+ });
+ afterEach(function() {
+ createStub.restore();
+ getFileInfoStub.restore();
});
it('creates file with given name and adds it to the list', function() {
- var deferred = fileList.createFile('test file.txt');
- var successStub = sinon.stub();
- var failureStub = sinon.stub();
+ fileList.createFile('test.txt');
- deferred.done(successStub);
- deferred.fail(failureStub);
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.getCall(0).args[0]).toEqual('/subdir/test.txt');
+ expect(createStub.getCall(0).args[2]).toEqual({
+ contentType: 'text/plain',
+ overwrite: true
+ });
- expect(fakeServer.requests.length).toEqual(1);
- expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfile.php'));
+ deferredCreate.resolve(200);
- var query = fakeServer.requests[0].requestBody;
- expect(OC.parseQueryString(query)).toEqual({
- dir: '/subdir',
- filename: 'test file.txt'
- });
+ expect(getFileInfoStub.calledOnce).toEqual(true);
+ expect(getFileInfoStub.getCall(0).args[0]).toEqual('/subdir/test.txt');
- fakeServer.requests[0].respond(
+ deferredInfo.resolve(
200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- path: '/subdir',
- name: 'test file.txt',
- mimetype: 'text/plain'
- }
+ new FileInfo({
+ path: '/subdir',
+ name: 'test.txt',
+ mimetype: 'text/plain'
})
);
- var $tr = fileList.findFileEl('test file.txt');
+ var $tr = fileList.findFileEl('test.txt');
expect($tr.length).toEqual(1);
expect($tr.attr('data-mime')).toEqual('text/plain');
-
- expect(successStub.calledOnce).toEqual(true);
- expect(failureStub.notCalled).toEqual(true);
});
// TODO: error cases
// TODO: unique name cases
});
- describe('create directory', function() {
- it('creates directory with given name and adds it to the list', function() {
- var deferred = fileList.createDirectory('test directory');
- var successStub = sinon.stub();
- var failureStub = sinon.stub();
-
- deferred.done(successStub);
- deferred.fail(failureStub);
-
- expect(fakeServer.requests.length).toEqual(1);
- expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfolder.php'));
- var query = fakeServer.requests[0].requestBody;
- expect(OC.parseQueryString(query)).toEqual({
- dir: '/subdir',
- foldername: 'test directory'
- });
+ describe('create folder', function() {
+ var deferredCreate;
+ var deferredInfo;
+ var createStub;
+ var getFileInfoStub;
+
+ beforeEach(function() {
+ deferredCreate = $.Deferred();
+ deferredInfo = $.Deferred();
+ createStub = sinon.stub(filesClient, 'createDirectory')
+ .returns(deferredCreate.promise());
+ getFileInfoStub = sinon.stub(filesClient, 'getFileInfo')
+ .returns(deferredInfo.promise());
+ });
+ afterEach(function() {
+ createStub.restore();
+ getFileInfoStub.restore();
+ });
+
+ it('creates folder with given name and adds it to the list', function() {
+ fileList.createDirectory('sub dir');
+
+ expect(createStub.calledOnce).toEqual(true);
+ expect(createStub.getCall(0).args[0]).toEqual('/subdir/sub dir');
- fakeServer.requests[0].respond(
+ deferredCreate.resolve(200);
+
+ expect(getFileInfoStub.calledOnce).toEqual(true);
+ expect(getFileInfoStub.getCall(0).args[0]).toEqual('/subdir/sub dir');
+
+ deferredInfo.resolve(
200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- path: '/subdir',
- name: 'test directory',
- mimetype: 'httpd/unix-directory'
- }
+ new FileInfo({
+ path: '/subdir',
+ name: 'sub dir',
+ mimetype: 'httpd/unix-directory'
})
);
- var $tr = fileList.findFileEl('test directory');
+ var $tr = fileList.findFileEl('sub dir');
expect($tr.length).toEqual(1);
expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
-
- expect(successStub.calledOnce).toEqual(true);
- expect(failureStub.notCalled).toEqual(true);
});
// TODO: error cases
// TODO: unique name cases
@@ -2481,14 +2388,14 @@ describe('OCA.Files.FileList tests', function() {
expect(ev.result).not.toEqual(false);
});
it('drop on a folder row inside the table triggers upload to target folder', function() {
- var ev, formData;
+ var ev;
ev = dropOn(fileList.findFileEl('somedir').find('td:eq(2)'), uploadData);
expect(ev.result).not.toEqual(false);
expect(uploadData.targetDir).toEqual('/subdir/somedir');
});
it('drop on a breadcrumb inside the table triggers upload to target folder', function() {
- var ev, formData;
+ var ev;
fileList.changeDirectory('a/b/c/d');
ev = dropOn(fileList.$el.find('.crumb:eq(2)'), uploadData);
@@ -2497,32 +2404,50 @@ describe('OCA.Files.FileList tests', function() {
});
});
});
- describe('Handeling errors', function () {
- var redirectStub;
+ describe('Handling errors', function () {
+ var deferredList;
+ var getFolderContentsStub;
- beforeEach(function () {
- redirectStub = sinon.stub(OC, 'redirect');
-
- fileList = new OCA.Files.FileList($('#app-content-files'));
+ beforeEach(function() {
+ deferredList = $.Deferred();
+ getFolderContentsStub =
+ sinon.stub(filesClient, 'getFolderContents');
+ getFolderContentsStub.onCall(0).returns(deferredList.promise());
+ getFolderContentsStub.onCall(1).returns($.Deferred().promise());
+ fileList.reload();
});
- afterEach(function () {
+ afterEach(function() {
+ getFolderContentsStub.restore();
fileList = undefined;
+ });
+ it('redirects to files app in case of auth error', function () {
+ deferredList.reject(401, 'Authentication error');
- redirectStub.restore();
+ expect(redirectStub.calledOnce).toEqual(true);
+ expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files');
+ expect(getFolderContentsStub.calledOnce).toEqual(true);
});
- it('reloads the page on authentication errors', function () {
- fileList.reload();
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'error',
- data: {
- 'error': 'authentication_error'
- }
- })
- );
- expect(redirectStub.calledWith(OC.generateUrl('apps/files'))).toEqual(true);
+ it('redirects to root folder in case of forbidden access', function () {
+ deferredList.reject(403);
+
+ expect(fileList.getCurrentDirectory()).toEqual('/');
+ expect(getFolderContentsStub.calledTwice).toEqual(true);
+ });
+ it('redirects to root folder and shows notification in case of internal server error', function () {
+ expect(notificationStub.notCalled).toEqual(true);
+ deferredList.reject(500);
+
+ expect(fileList.getCurrentDirectory()).toEqual('/');
+ expect(getFolderContentsStub.calledTwice).toEqual(true);
+ expect(notificationStub.calledOnce).toEqual(true);
+ });
+ it('redirects to root folder and shows notification in case of storage not available', function () {
+ expect(notificationStub.notCalled).toEqual(true);
+ deferredList.reject(503, 'Storage not available');
+
+ expect(fileList.getCurrentDirectory()).toEqual('/');
+ expect(getFolderContentsStub.calledTwice).toEqual(true);
+ expect(notificationStub.calledOnce).toEqual(true);
});
});
describe('showFileBusyState', function() {
diff --git a/apps/files/tests/js/filesSpec.js b/apps/files/tests/js/filesSpec.js
index 30e6675c155..b7627d59fdf 100644
--- a/apps/files/tests/js/filesSpec.js
+++ b/apps/files/tests/js/filesSpec.js
@@ -76,11 +76,11 @@ describe('OCA.Files.Files tests', function() {
describe('getDownloadUrl', function() {
it('returns the ajax download URL when filename and dir specified', function() {
var url = Files.getDownloadUrl('test file.txt', '/subdir');
- expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=test%20file.txt');
+ expect(url).toEqual(OC.webroot + '/remote.php/webdav/subdir/test%20file.txt');
});
- it('returns the ajax download URL when filename and root dir specific', function() {
+ it('returns the webdav download URL when filename and root dir specified', function() {
var url = Files.getDownloadUrl('test file.txt', '/');
- expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=test%20file.txt');
+ expect(url).toEqual(OC.webroot + '/remote.php/webdav/test%20file.txt');
});
it('returns the ajax download URL when multiple files specified', function() {
var url = Files.getDownloadUrl(['test file.txt', 'abc.txt'], '/subdir');
diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js
index bf853f926dc..1bff3014bd6 100644
--- a/apps/files_external/js/app.js
+++ b/apps/files_external/js/app.js
@@ -54,7 +54,7 @@ OCA.External.App = {
// folder in the files app instead of opening it directly
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
OCA.Files.App.setActiveView('files', {silent: true});
- OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+ OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true);
});
fileActions.setDefault('dir', 'Open');
return fileActions;
diff --git a/apps/files_external/l10n/hy.js b/apps/files_external/l10n/hy.js
index 9996681f88b..1092d48d575 100644
--- a/apps/files_external/l10n/hy.js
+++ b/apps/files_external/l10n/hy.js
@@ -2,11 +2,14 @@ OC.L10N.register(
"files_external",
{
"Personal" : "Անձնական",
+ "Never" : "Երբեք",
+ "Username" : "Օգտանուն",
"Password" : "Գաղտնաբառ",
"URL" : "URL",
"Dropbox" : "Dropbox",
"Share" : "Կիսվել",
"Name" : "Անուն",
+ "Folder name" : "Պանակի անուն",
"Delete" : "Ջնջել"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_external/l10n/hy.json b/apps/files_external/l10n/hy.json
index ac5a0edf013..1fecd4f3da1 100644
--- a/apps/files_external/l10n/hy.json
+++ b/apps/files_external/l10n/hy.json
@@ -1,10 +1,13 @@
{ "translations": {
"Personal" : "Անձնական",
+ "Never" : "Երբեք",
+ "Username" : "Օգտանուն",
"Password" : "Գաղտնաբառ",
"URL" : "URL",
"Dropbox" : "Dropbox",
"Share" : "Կիսվել",
"Name" : "Անուն",
+ "Folder name" : "Պանակի անուն",
"Delete" : "Ջնջել"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_external/l10n/lt_LT.js b/apps/files_external/l10n/lt_LT.js
index b6d334d792d..78d03a865f2 100644
--- a/apps/files_external/l10n/lt_LT.js
+++ b/apps/files_external/l10n/lt_LT.js
@@ -1,6 +1,7 @@
OC.L10N.register(
"files_external",
{
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.",
"External storage" : "Išorinė saugykla",
"Personal" : "Asmeniniai",
"Grant access" : "Suteikti priėjimą",
diff --git a/apps/files_external/l10n/lt_LT.json b/apps/files_external/l10n/lt_LT.json
index f1c46b145ee..fcb1f1f39bd 100644
--- a/apps/files_external/l10n/lt_LT.json
+++ b/apps/files_external/l10n/lt_LT.json
@@ -1,4 +1,5 @@
{ "translations": {
+ "Fetching request tokens failed. Verify that your app key and secret are correct." : "Nepavyko atsiųsti užklausos žymės. Patikrinkite savo programos raktą ir paslaptį.",
"External storage" : "Išorinė saugykla",
"Personal" : "Asmeniniai",
"Grant access" : "Suteikti priėjimą",
diff --git a/apps/files_external/l10n/tr.js b/apps/files_external/l10n/tr.js
index 619e5975ed8..9d46012454b 100644
--- a/apps/files_external/l10n/tr.js
+++ b/apps/files_external/l10n/tr.js
@@ -16,6 +16,7 @@ OC.L10N.register(
"Not permitted to use authentication mechanism \"%s\"" : "\"%s\" kimlik doğrulama mekanizmasına izin verilmiyor",
"Unsatisfied backend parameters" : "Yetersiz arka uç parametreleri",
"Unsatisfied authentication mechanism parameters" : "Yetersiz kimlik doğrulama mekanizması parametreleri",
+ "Insufficient data: %s" : "Yetersiz veri: %s",
"Personal" : "Kişisel",
"System" : "Sistem",
"Grant access" : "Erişimi sağla",
@@ -101,6 +102,7 @@ OC.L10N.register(
"Advanced settings" : "Gelişmiş ayarlar",
"Delete" : "Sil",
"Add storage" : "Depo ekle",
+ "Allow users to mount external storage" : "Kullanıcılara harici depolama bağlama izin ver",
"Allow users to mount the following external storage" : "Kullanıcıların aşağıdaki harici depolamayı bağlamalarına izin ver"
},
"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_external/l10n/tr.json b/apps/files_external/l10n/tr.json
index cb315a333c2..17c76b1916e 100644
--- a/apps/files_external/l10n/tr.json
+++ b/apps/files_external/l10n/tr.json
@@ -14,6 +14,7 @@
"Not permitted to use authentication mechanism \"%s\"" : "\"%s\" kimlik doğrulama mekanizmasına izin verilmiyor",
"Unsatisfied backend parameters" : "Yetersiz arka uç parametreleri",
"Unsatisfied authentication mechanism parameters" : "Yetersiz kimlik doğrulama mekanizması parametreleri",
+ "Insufficient data: %s" : "Yetersiz veri: %s",
"Personal" : "Kişisel",
"System" : "Sistem",
"Grant access" : "Erişimi sağla",
@@ -99,6 +100,7 @@
"Advanced settings" : "Gelişmiş ayarlar",
"Delete" : "Sil",
"Add storage" : "Depo ekle",
+ "Allow users to mount external storage" : "Kullanıcılara harici depolama bağlama izin ver",
"Allow users to mount the following external storage" : "Kullanıcıların aşağıdaki harici depolamayı bağlamalarına izin ver"
},"pluralForm" :"nplurals=2; plural=(n > 1);"
} \ No newline at end of file
diff --git a/apps/files_external/tests/env/start-webdav-ownCloud.sh b/apps/files_external/tests/env/start-webdav-ownCloud.sh
index 6e3904f2bad..f04616d4991 100755
--- a/apps/files_external/tests/env/start-webdav-ownCloud.sh
+++ b/apps/files_external/tests/env/start-webdav-ownCloud.sh
@@ -62,7 +62,9 @@ while ! (nc -c -w 1 ${host} 80 </dev/null >&/dev/null \
fi
done
echo
-sleep 1
+
+# wait at least 5 more seconds - sometimes the webserver still needs some additional time
+sleep 5
cat > $thisFolder/config.webdav.php <<DELIM
<?php
diff --git a/apps/files_sharing/ajax/list.php b/apps/files_sharing/ajax/list.php
deleted file mode 100644
index c7f0bde5d4a..00000000000
--- a/apps/files_sharing/ajax/list.php
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-
-OCP\JSON::checkAppEnabled('files_sharing');
-
-if(!isset($_GET['t'])){
- \OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
- \OCP\Util::writeLog('core-preview', 'No token parameter was passed', \OCP\Util::DEBUG);
- exit;
-}
-
-$token = $_GET['t'];
-
-$password = null;
-if (isset($_POST['password'])) {
- $password = $_POST['password'];
-}
-
-$relativePath = null;
-if (isset($_GET['dir'])) {
- $relativePath = $_GET['dir'];
-}
-
-$sortAttribute = isset( $_GET['sort'] ) ? $_GET['sort'] : 'name';
-$sortDirection = isset( $_GET['sortdirection'] ) ? ($_GET['sortdirection'] === 'desc') : false;
-
-$data = \OCA\Files_Sharing\Helper::setupFromToken($token, $relativePath, $password);
-
-$linkItem = $data['linkItem'];
-// Load the files
-$dir = $data['realPath'];
-
-$dir = \OC\Files\Filesystem::normalizePath($dir);
-if (!\OC\Files\Filesystem::is_dir($dir . '/')) {
- \OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND);
- \OCP\JSON::error(array('success' => false));
- exit();
-}
-
-$data = array();
-
-// make filelist
-$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection);
-
-$formattedFiles = array();
-foreach ($files as $file) {
- $entry = \OCA\Files\Helper::formatFileInfo($file);
- // for now
- unset($entry['directory']);
- // do not disclose share owner
- unset($entry['shareOwner']);
- // do not disclose if something is a remote shares
- unset($entry['mountType']);
- unset($entry['icon']);
- $entry['permissions'] = \OCP\Constants::PERMISSION_READ;
- $formattedFiles[] = $entry;
-}
-
-$data['directory'] = $relativePath;
-$data['files'] = $formattedFiles;
-$data['dirToken'] = $linkItem['token'];
-
-$permissions = $linkItem['permissions'];
-
-// if globally disabled
-if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') {
- // only allow reading
- $permissions = \OCP\Constants::PERMISSION_READ;
-}
-
-$data['permissions'] = $permissions;
-
-OCP\JSON::success(array('data' => $data));
diff --git a/apps/files_sharing/api/local.php b/apps/files_sharing/api/local.php
index bb5136a0c99..aaafafb269f 100644
--- a/apps/files_sharing/api/local.php
+++ b/apps/files_sharing/api/local.php
@@ -233,6 +233,7 @@ class Local {
if (\OC::$server->getPreviewManager()->isMimeSupported($share['mimetype'])) {
$share['isPreviewAvailable'] = true;
}
+ unset($share['path']);
}
}
$result = new \OC_OCS_Result($shares);
diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js
index 3168e930829..af198208de2 100644
--- a/apps/files_sharing/js/app.js
+++ b/apps/files_sharing/js/app.js
@@ -142,7 +142,7 @@ OCA.Sharing.App = {
// folder in the files app instead of opening it directly
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
OCA.Files.App.setActiveView('files', {silent: true});
- OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+ OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true);
});
fileActions.setDefault('dir', 'Open');
return fileActions;
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 246b639f652..82691129926 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -48,8 +48,20 @@ OCA.Sharing.PublicApp = {
this._initialized = true;
this.initialDir = $('#dir').val();
+ var token = $('#sharingToken').val();
+
// file list mode ?
if ($el.find('#filestable').length) {
+ var filesClient = new OC.Files.Client({
+ host: OC.getHost(),
+ port: OC.getPort(),
+ userName: token,
+ // note: password not be required, the endpoint
+ // will recognize previous validation from the session
+ root: OC.getRootPath() + '/public.php/webdav',
+ useHTTPS: OC.getProtocol() === 'https'
+ });
+
this.fileList = new OCA.Files.FileList(
$el,
{
@@ -58,7 +70,8 @@ OCA.Sharing.PublicApp = {
dragOptions: dragOptions,
folderDropOptions: folderDropOptions,
fileActions: fileActions,
- detailsViewEnabled: false
+ detailsViewEnabled: false,
+ filesClient: filesClient
}
);
this.files = OCA.Files.Files;
@@ -88,7 +101,6 @@ OCA.Sharing.PublicApp = {
// dynamically load image previews
- var token = $('#sharingToken').val();
var bottomMargin = 350;
var previewWidth = Math.ceil($(window).width() * window.devicePixelRatio);
var previewHeight = Math.ceil(($(window).height() - bottomMargin) * window.devicePixelRatio);
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 63225a0d8ec..3d105f283d8 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -50,7 +50,7 @@
if (fileData.shareOwner) {
tr.attr('data-share-owner', fileData.shareOwner);
// user should always be able to rename a mount point
- if (fileData.isShareMountPoint) {
+ if (fileData.mountType === 'shared-root') {
tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
}
}
@@ -68,6 +68,26 @@
return fileInfo;
};
+ var NS_OC = 'http://owncloud.org/ns';
+
+ var oldGetWebdavProperties = fileList._getWebdavProperties;
+ fileList._getWebdavProperties = function() {
+ var props = oldGetWebdavProperties.apply(this, arguments);
+ props.push('{' + NS_OC + '}owner-display-name');
+ return props;
+ };
+
+ fileList.filesClient.addFileInfoParser(function(response) {
+ var data = {};
+ var props = response.propStat[0].properties;
+ var permissionsProp = props['{' + NS_OC + '}permissions'];
+
+ if (permissionsProp && permissionsProp.indexOf('S') >= 0) {
+ data.shareOwner = props['{' + NS_OC + '}owner-display-name'];
+ }
+ return data;
+ });
+
// use delegate to catch the case with multiple file lists
fileList.$el.on('fileActionsReady', function(ev){
var fileList = ev.fileList;
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index 68bfd63ec89..a799d4a94c2 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -231,6 +231,7 @@
files = _.chain(files)
// convert share data to file data
.map(function(share) {
+ // TODO: use OC.Files.FileInfo
var file = {
id: share.file_source,
icon: OC.MimeType.getIconUrl(share.mimetype),
@@ -242,9 +243,6 @@
}
else {
file.type = 'file';
- if (share.isPreviewAvailable) {
- file.isPreviewAvailable = true;
- }
}
file.share = {
id: share.id,
diff --git a/apps/files_sharing/tests/js/publicAppSpec.js b/apps/files_sharing/tests/js/publicAppSpec.js
index d496b78acfa..1ea5f7ed1bc 100644
--- a/apps/files_sharing/tests/js/publicAppSpec.js
+++ b/apps/files_sharing/tests/js/publicAppSpec.js
@@ -21,11 +21,13 @@
describe('OCA.Sharing.PublicApp tests', function() {
var App = OCA.Sharing.PublicApp;
+ var hostStub, protocolStub, webrootStub;
var $preview;
- var fileListIn;
- var fileListOut;
beforeEach(function() {
+ protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ hostStub = sinon.stub(OC, 'getHost').returns('example.com');
+ webrootStub = sinon.stub(OC, 'getRootPath').returns('/owncloud');
$preview = $('<div id="preview"></div>');
$('#testArea').append($preview);
$preview.append(
@@ -35,6 +37,12 @@ describe('OCA.Sharing.PublicApp tests', function() {
);
});
+ afterEach(function() {
+ protocolStub.restore();
+ hostStub.restore();
+ webrootStub.restore();
+ });
+
describe('File list', function() {
// TODO: this should be moved to a separate file once the PublicFileList is extracted from public.js
beforeEach(function() {
@@ -78,6 +86,12 @@ describe('OCA.Sharing.PublicApp tests', function() {
App._initialized = false;
});
+ it('Uses public webdav endpoint', function() {
+ expect(fakeServer.requests.length).toEqual(1);
+ expect(fakeServer.requests[0].method).toEqual('PROPFIND');
+ expect(fakeServer.requests[0].url).toEqual('https://sh4tok@example.com/owncloud/public.php/webdav/subdir');
+ });
+
describe('Download Url', function() {
var fileList;
diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js
index b4b6ac4954a..fdc9de49c17 100644
--- a/apps/files_sharing/tests/js/sharedfilelistSpec.js
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -166,8 +166,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt'
+ '/remote.php/webdav/local%20path/local%20name.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
@@ -185,8 +184,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('8');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2F&files=b.txt'
+ '/remote.php/webdav/b.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('b.txt');
});
@@ -338,8 +336,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt'
+ '/remote.php/webdav/local%20path/local%20name.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -429,9 +426,8 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
- OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt');
+ OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
+ );
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -498,9 +494,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7,8,9');
expect($tr.find('a.name').attr('href')).toEqual(
- OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt'
+ OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
);
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -592,9 +586,8 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-owner')).not.toBeDefined();
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
- OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt');
+ OC.webroot + '/remote.php/webdav/local%20path/local%20name.txt'
+ );
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
@@ -634,8 +627,7 @@ describe('OCA.Sharing.FileList tests', function() {
expect($tr.attr('data-share-id')).toEqual('7');
expect($tr.find('a.name').attr('href')).toEqual(
OC.webroot +
- '/index.php/apps/files/ajax/download.php' +
- '?dir=%2Flocal%20path&files=local%20name.txt');
+ '/remote.php/webdav/local%20path/local%20name.txt');
expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
});
diff --git a/apps/files_trashbin/js/app.js b/apps/files_trashbin/js/app.js
index 1f46f568bf2..600a8ce2b03 100644
--- a/apps/files_trashbin/js/app.js
+++ b/apps/files_trashbin/js/app.js
@@ -38,10 +38,7 @@ OCA.Trashbin.App = {
var fileActions = new OCA.Files.FileActions();
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
var dir = context.fileList.getCurrentDirectory();
- if (dir !== '/') {
- dir = dir + '/';
- }
- context.fileList.changeDirectory(dir + filename);
+ context.fileList.changeDirectory(OC.joinPaths(dir, filename));
});
fileActions.setDefault('dir', 'Open');
diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js
index 6b624e333a0..5812aff82f7 100644
--- a/apps/files_trashbin/js/filelist.js
+++ b/apps/files_trashbin/js/filelist.js
@@ -283,7 +283,77 @@
isSelectedDeletable: function() {
return true;
- }
+ },
+
+ /**
+ * Reloads the file list using ajax call
+ *
+ * @return ajax call object
+ */
+ reload: function() {
+ this._selectedFiles = {};
+ this._selectionSummary.clear();
+ this.$el.find('.select-all').prop('checked', false);
+ this.showMask();
+ if (this._reloadCall) {
+ this._reloadCall.abort();
+ }
+ this._reloadCall = $.ajax({
+ url: this.getAjaxUrl('list'),
+ data: {
+ dir : this.getCurrentDirectory(),
+ sort: this._sort,
+ sortdirection: this._sortDirection
+ }
+ });
+ var callBack = this.reloadCallback.bind(this);
+ return this._reloadCall.then(callBack, callBack);
+ },
+ reloadCallback: function(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;
+ }
+
+ // Firewall Blocked request?
+ if (result.status === 403) {
+ // Go home
+ this.changeDirectory('/');
+ OC.Notification.show(t('files', 'This operation is forbidden'));
+ return false;
+ }
+
+ // Did share service die or something else fail?
+ if (result.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) {
+ // go back home
+ this.changeDirectory('/');
+ return false;
+ }
+ // aborted ?
+ if (result.status === 0){
+ return true;
+ }
+
+ this.setFiles(result.data.files);
+ return true;
+ },
});
diff --git a/apps/files_trashbin/l10n/hy.js b/apps/files_trashbin/l10n/hy.js
index 3cc05b39236..39e49b47ae1 100644
--- a/apps/files_trashbin/l10n/hy.js
+++ b/apps/files_trashbin/l10n/hy.js
@@ -5,8 +5,10 @@ OC.L10N.register(
"Restore" : "Վերականգնել",
"Delete" : "Ջնջել",
"Delete permanently" : "Ջնջել ընդմիշտ",
+ "Error" : "Սխալ",
"No deleted files" : "Ջնջված ֆայլեր չկան",
"Select all" : "Նշել բոլորը",
- "Name" : "Անուն"
+ "Name" : "Անուն",
+ "Deleted" : "Ջնջված"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/hy.json b/apps/files_trashbin/l10n/hy.json
index 994d6afaa58..4bd34056b3f 100644
--- a/apps/files_trashbin/l10n/hy.json
+++ b/apps/files_trashbin/l10n/hy.json
@@ -3,8 +3,10 @@
"Restore" : "Վերականգնել",
"Delete" : "Ջնջել",
"Delete permanently" : "Ջնջել ընդմիշտ",
+ "Error" : "Սխալ",
"No deleted files" : "Ջնջված ֆայլեր չկան",
"Select all" : "Նշել բոլորը",
- "Name" : "Անուն"
+ "Name" : "Անուն",
+ "Deleted" : "Ջնջված"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/nds.js b/apps/files_trashbin/l10n/nds.js
index b2dd9ff4ca6..8212e5210a9 100644
--- a/apps/files_trashbin/l10n/nds.js
+++ b/apps/files_trashbin/l10n/nds.js
@@ -2,6 +2,7 @@ OC.L10N.register(
"files_trashbin",
{
"Delete" : "Löschen",
+ "Error" : "Fehler",
"Name" : "Name"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_trashbin/l10n/nds.json b/apps/files_trashbin/l10n/nds.json
index 45b0caa74ac..d15a7c583ac 100644
--- a/apps/files_trashbin/l10n/nds.json
+++ b/apps/files_trashbin/l10n/nds.json
@@ -1,5 +1,6 @@
{ "translations": {
"Delete" : "Löschen",
+ "Error" : "Fehler",
"Name" : "Name"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/files_trashbin/l10n/ru.js b/apps/files_trashbin/l10n/ru.js
index b51486b6eb0..ef39fee4511 100644
--- a/apps/files_trashbin/l10n/ru.js
+++ b/apps/files_trashbin/l10n/ru.js
@@ -5,6 +5,7 @@ OC.L10N.register(
"Couldn't restore %s" : "%s не может быть восстановлен",
"Deleted files" : "Удалённые файлы",
"Restore" : "Восстановить",
+ "Delete" : "Удалить",
"Delete permanently" : "Удалить окончательно",
"Error" : "Ошибка",
"restored" : "восстановлен",
@@ -13,7 +14,6 @@ OC.L10N.register(
"No entries found in this folder" : "Нет элементов в этом каталоге",
"Select all" : "Выделить все",
"Name" : "Имя",
- "Deleted" : "Удалён",
- "Delete" : "Удалить"
+ "Deleted" : "Удалён"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/apps/files_trashbin/l10n/ru.json b/apps/files_trashbin/l10n/ru.json
index 9fecb3a9641..2fe089b7ace 100644
--- a/apps/files_trashbin/l10n/ru.json
+++ b/apps/files_trashbin/l10n/ru.json
@@ -3,6 +3,7 @@
"Couldn't restore %s" : "%s не может быть восстановлен",
"Deleted files" : "Удалённые файлы",
"Restore" : "Восстановить",
+ "Delete" : "Удалить",
"Delete permanently" : "Удалить окончательно",
"Error" : "Ошибка",
"restored" : "восстановлен",
@@ -11,7 +12,6 @@
"No entries found in this folder" : "Нет элементов в этом каталоге",
"Select all" : "Выделить все",
"Name" : "Имя",
- "Deleted" : "Удалён",
- "Delete" : "Удалить"
+ "Deleted" : "Удалён"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/apps/files_versions/l10n/hy.js b/apps/files_versions/l10n/hy.js
index 3924810e149..d48487a9a84 100644
--- a/apps/files_versions/l10n/hy.js
+++ b/apps/files_versions/l10n/hy.js
@@ -2,6 +2,7 @@ OC.L10N.register(
"files_versions",
{
"Versions" : "Տարբերակներ",
- "Restore" : "Վերականգնել"
+ "Restore" : "Վերականգնել",
+ "No other versions available" : "Այլ տարբերակներ չկան"
},
"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_versions/l10n/hy.json b/apps/files_versions/l10n/hy.json
index 7f61c267c7c..579b9240310 100644
--- a/apps/files_versions/l10n/hy.json
+++ b/apps/files_versions/l10n/hy.json
@@ -1,5 +1,6 @@
{ "translations": {
"Versions" : "Տարբերակներ",
- "Restore" : "Վերականգնել"
+ "Restore" : "Վերականգնել",
+ "No other versions available" : "Այլ տարբերակներ չկան"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/apps/user_ldap/l10n/es.js b/apps/user_ldap/l10n/es.js
index bfe48c28f99..e457978bcd7 100644
--- a/apps/user_ldap/l10n/es.js
+++ b/apps/user_ldap/l10n/es.js
@@ -24,6 +24,7 @@ OC.L10N.register(
"Could not detect Base DN, please enter it manually." : "No se pudo detectar Base DN, por favor ingrésela manualmente.",
"{nthServer}. Server" : "{nthServer}. servidor",
"No object found in the given Base DN. Please revise." : "No se encuentra ningún objeto en la Base DN dada. Por favor revisar.",
+ "More than 1,000 directory entries available." : "Más de 1.000 entradas de directorios disponibles.",
" entries available within the provided Base DN" : "entradas disponibles dentro de la BaseDN provista",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Un error ocurrió. Por favor revise la Base DN, también como la configuración de la conexión y credenciales.",
"Do you really want to delete the current Server Configuration?" : "¿Realmente desea eliminar la configuración actual del servidor?",
diff --git a/apps/user_ldap/l10n/es.json b/apps/user_ldap/l10n/es.json
index c8d64f6b9d6..ebce66270f1 100644
--- a/apps/user_ldap/l10n/es.json
+++ b/apps/user_ldap/l10n/es.json
@@ -22,6 +22,7 @@
"Could not detect Base DN, please enter it manually." : "No se pudo detectar Base DN, por favor ingrésela manualmente.",
"{nthServer}. Server" : "{nthServer}. servidor",
"No object found in the given Base DN. Please revise." : "No se encuentra ningún objeto en la Base DN dada. Por favor revisar.",
+ "More than 1,000 directory entries available." : "Más de 1.000 entradas de directorios disponibles.",
" entries available within the provided Base DN" : "entradas disponibles dentro de la BaseDN provista",
"An error occurred. Please check the Base DN, as well as connection settings and credentials." : "Un error ocurrió. Por favor revise la Base DN, también como la configuración de la conexión y credenciales.",
"Do you really want to delete the current Server Configuration?" : "¿Realmente desea eliminar la configuración actual del servidor?",
diff --git a/apps/user_ldap/l10n/lt_LT.js b/apps/user_ldap/l10n/lt_LT.js
index e9429c0de2a..a5b85499804 100644
--- a/apps/user_ldap/l10n/lt_LT.js
+++ b/apps/user_ldap/l10n/lt_LT.js
@@ -4,9 +4,12 @@ OC.L10N.register(
"Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.",
"Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos",
"The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!",
+ "No action specified" : "Nepasirinktas veiksmas",
"Select groups" : "Pasirinkti grupes",
"Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?",
"Confirm Deletion" : "Patvirtinkite trynimą",
+ "_%s group found_::_%s groups found_" : ["Rasta %s grupė","Rastos %s grupės","Rastos %s grupės"],
+ "_%s user found_::_%s users found_" : ["Rastas %s vartotojas","Rasti %s vartotojai","Rasti %s vartotojai"],
"Server" : "Serveris",
"Users" : "Vartotojai",
"Groups" : "Grupės",
diff --git a/apps/user_ldap/l10n/lt_LT.json b/apps/user_ldap/l10n/lt_LT.json
index 19ca042b62f..68dfbc38b9c 100644
--- a/apps/user_ldap/l10n/lt_LT.json
+++ b/apps/user_ldap/l10n/lt_LT.json
@@ -2,9 +2,12 @@
"Failed to clear the mappings." : "Nepavyko išvalyti sąsajų.",
"Failed to delete the server configuration" : "Nepavyko pašalinti serverio konfigūracijos",
"The configuration is valid and the connection could be established!" : "Konfigūracija yra tinkama bei prisijungta sėkmingai!",
+ "No action specified" : "Nepasirinktas veiksmas",
"Select groups" : "Pasirinkti grupes",
"Do you really want to delete the current Server Configuration?" : "Ar tikrai norite ištrinti dabartinę serverio konfigūraciją?",
"Confirm Deletion" : "Patvirtinkite trynimą",
+ "_%s group found_::_%s groups found_" : ["Rasta %s grupė","Rastos %s grupės","Rastos %s grupės"],
+ "_%s user found_::_%s users found_" : ["Rastas %s vartotojas","Rasti %s vartotojai","Rasti %s vartotojai"],
"Server" : "Serveris",
"Users" : "Vartotojai",
"Groups" : "Grupės",