Compare commits
592 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7562dc2c6e | |||
| 1ae1a63f79 | |||
| 990f86d3d4 | |||
| 87eb48275b | |||
| 1ec2f3233e | |||
| 5cab4a939e | |||
| 2eedf39b15 | |||
| 4d1bee9308 | |||
| cc79334acc | |||
| 91d17790d6 | |||
| f6be4f8ec1 | |||
| 2f6caa3075 | |||
| c8366f3de5 | |||
| 89fdca7748 | |||
| 582ca0a50d | |||
| 79857c975c | |||
| 667a562ed9 | |||
| 07fb3e329b | |||
| 1d65016980 | |||
| 2282ed373a | |||
| 254fc41f2d | |||
| 3808618ae9 | |||
| 5d7bd6f6ad | |||
| 64ae79a9d9 | |||
| 8bd90a12f1 | |||
| 76be8bb71b | |||
| fab59179f1 | |||
| ff214a3fb2 | |||
| dc2a6e2210 | |||
| 08866d54fd | |||
| 221de0060d | |||
| 9f6dfd3e38 | |||
| 2993a741cf | |||
| 8db22f5d50 | |||
| 345660b407 | |||
| 5ed0d6079d | |||
| ded50e8dbe | |||
| 3a3ccd47b9 | |||
| e92a0ff0e4 | |||
| 159e6b6444 | |||
| fe21a8dddb | |||
| 258496c951 | |||
| ec7e355afc | |||
| 8838e072c7 | |||
| 7e8f3ee28d | |||
| 6897cbebc0 | |||
| 2e0952b081 | |||
| 9444e07e80 | |||
| d78b4d0e72 | |||
| f69161ae87 | |||
| b64b8c1b48 | |||
| 4214df7bf6 | |||
| 28de9c7357 | |||
| 109a206ae3 | |||
| 96b812bee6 | |||
| 4c912e66db | |||
| 3f79484c45 | |||
| 5f81a5e641 | |||
| 7ff02a6daf | |||
| 07546d0e8c | |||
| bb5b7290ac | |||
| a283bf209b | |||
| 519e980f93 | |||
| 8d79c9576a | |||
| 019480a044 | |||
| f6a4d33ef7 | |||
| bc409d41c1 | |||
| 712ceb4443 | |||
| 6e816e4e61 | |||
| 751732f7ba | |||
| 4942646ada | |||
| 595381b9bd | |||
| 67c68253a2 | |||
| ef4abb39a5 | |||
| 12d70eb959 | |||
| 602ec0efa1 | |||
| 17082469de | |||
| 77b5ba9213 | |||
| 10a5b1b19d | |||
| f7eb4b17e8 | |||
| 0a8743a261 | |||
| fe2710f60b | |||
| 5296ef64cc | |||
| e4e4b6f902 | |||
| 6248dd19c5 | |||
| cb9aa372c8 | |||
| 30409c7419 | |||
| a34a683ef1 | |||
| 15806febcb | |||
| 811b7dff9f | |||
| 1d45298974 | |||
| fc3ce8441e | |||
| 47d25989dc | |||
| 232e3821cd | |||
| cc00aba7cf | |||
| b186a7822c | |||
| 11dc65e76c | |||
| 9f8c0a3a8d | |||
| 385aefdc8f | |||
| 4253838b24 | |||
| 9dcc7465aa | |||
| 6309dbfa6a | |||
| 36f17964e5 | |||
| 5d10c37b08 | |||
| 0d5b4b95ef | |||
| 7cd4425b71 | |||
| 9036a46145 | |||
| d64a6115f0 | |||
| 2b0de142ab | |||
| 535e4296b5 | |||
| 558f1ec1ec | |||
| f13ff381ae | |||
| 96b252195b | |||
| ad6a321266 | |||
| 28ce93aa02 | |||
| 7e7e2f2099 | |||
| f01ade72cd | |||
| 65e33be707 | |||
| c81823bb2d | |||
| 3fe4f53a1f | |||
| affe4d7a38 | |||
| 3561a1572b | |||
| e47bf07b5e | |||
| 97b3a82581 | |||
| 751092d6dc | |||
| f97b21da11 | |||
| 8b0b6924f5 | |||
| 97ac85164e | |||
| e9262dbe2f | |||
| 4ec2e6c357 | |||
| a24b6a352a | |||
| c9e77c7de4 | |||
| ecaad05c63 | |||
| b94657a554 | |||
| e0bf1e4f6e | |||
| 3bd5f5eb4c | |||
| 918ba60aae | |||
| 0a1b90929a | |||
| 229635d65a | |||
| 6029b41760 | |||
| 62fa899fd2 | |||
| a20487907b | |||
| 0d9ad14165 | |||
| bbd6f42c70 | |||
| 3906951e91 | |||
| 43be73b9b4 | |||
| 78dc8ca702 | |||
| 7ec91b9177 | |||
| 9eaa716667 | |||
| 40ab639013 | |||
| f8e6800cd4 | |||
| 5785378951 | |||
| 57789e15a9 | |||
| a9a5ac2fd1 | |||
| 4e85a426a4 | |||
| 8a1cfa4229 | |||
| 747cc45e9c | |||
| adf1b2b5f3 | |||
| eb76504df6 | |||
| 698274491a | |||
| 8538aabfb5 | |||
| 4cbf10f392 | |||
| 5b1b844867 | |||
| f3cddc9ec2 | |||
| 59bf55ca7b | |||
| 4e467c0b3c | |||
| b828d2885d | |||
| cc0b1e4bf6 | |||
| 1c36875429 | |||
| 5e555f18b1 | |||
| f4e0b344c4 | |||
| d6733e9ca7 | |||
| c000eb479b | |||
| 6bd4bff834 | |||
| dc0713941e | |||
| 6aeee4fbc8 | |||
| abf9f79185 | |||
| 1744333f5f | |||
| 1bdd3f7dc3 | |||
| 6464f6b25b | |||
| 4191844af5 | |||
| b3d2232028 | |||
| 74ce46a8c8 | |||
| a6b8902fd9 | |||
| 850e0750b9 | |||
| 7bd7056a4c | |||
| 9dd746489a | |||
| 48c17d2745 | |||
| ac8b748b88 | |||
| c9fcc429e4 | |||
| 855ae3f5d2 | |||
| 7759a9118c | |||
| 2972585ba1 | |||
| 0f7f5bdb34 | |||
| dead1acba8 | |||
| 6ea7e89649 | |||
| af4e04602a | |||
| 36e8162111 | |||
| ad3f9dbb74 | |||
| 64d502d602 | |||
| 75c7554f62 | |||
| 083356fe9d | |||
| 14c760124f | |||
| c391f74c2e | |||
| 952e774a0e | |||
| 000f3a5f26 | |||
| 7dabbf9340 | |||
| 1a8aae7282 | |||
| cb18bdd771 | |||
| 1754c9a989 | |||
| 2c118c3938 | |||
| 8cd359a182 | |||
| 28c6c2f4d4 | |||
| 70bcb1a1c1 | |||
| 4c4c12d905 | |||
| b2548b01df | |||
| 0c2ce1b495 | |||
| a040a5b08e | |||
| eeace88beb | |||
| 5fcab24e59 | |||
| 5865a3af8c | |||
| 783188d683 | |||
| 7213be29c9 | |||
| 0b38c13891 | |||
| fe1de11b23 | |||
| f81ba63a52 | |||
| ae89153701 | |||
| 533bb85a85 | |||
| bffcbe4895 | |||
| d1f99f1003 | |||
| e56fb7e368 | |||
| 1854c7f590 | |||
| 8c6e5907d1 | |||
| 30bc7a7418 | |||
| 1fb44bc7a7 | |||
| 72e576e529 | |||
| 7b5493ea21 | |||
| 6867d45ffc | |||
| a035198f4b | |||
| 960ca7b1a8 | |||
| c08c4684be | |||
| 43b7ac6ad2 | |||
| 52d09386d4 | |||
| 2c56909604 | |||
| 2396ddf9e9 | |||
| bf69107c25 | |||
| 080b837bc8 | |||
| b2e9f800a3 | |||
| 8b635cd7b7 | |||
| 2d24ad53c6 | |||
| cd311c1ac1 | |||
| f9e258437f | |||
| d5d3cbd50d | |||
| 777a6c454e | |||
| e1492d9e0b | |||
| a3b53a7738 | |||
| 94f7b3e25c | |||
| 609da64c3b | |||
| 6eb8bdb5c9 | |||
| d24d30f96b | |||
| 3bc312ef9a | |||
| 68b2a85ed0 | |||
| 71a88d5f1f | |||
| 0c231f5ac6 | |||
| 7015dd74ce | |||
| 80afbd3e4f | |||
| 488c4a92da | |||
| 524045cdbd | |||
| bb79a6b4f0 | |||
| 4e44d2ecd6 | |||
| 23b8277c27 | |||
| 1d35c01b19 | |||
| a5466fc909 | |||
| 15c8501483 | |||
| 8c4322ef5a | |||
| 6fa4ee8e86 | |||
| 485d415ed1 | |||
| 62e7696aed | |||
| a97dae9065 | |||
| f50fc14935 | |||
| dbaaae071b | |||
| 21c4331983 | |||
| b2903485c0 | |||
| df9de41767 | |||
| 3be30babf8 | |||
| 30ed561110 | |||
| 714ca7a3a2 | |||
| 7c0c34f682 | |||
| eded1f05fc | |||
| 3f4eba1acb | |||
| 8e59d4c64b | |||
| ecf8343905 | |||
| 5733878d66 | |||
| 45a36feec6 | |||
| 92ae7c284b | |||
| f3a6adff41 | |||
| 927eb763c3 | |||
| 2e0c3665b0 | |||
| b1a9e26c45 | |||
| 3dbe7e195c | |||
| 5b5bf27653 | |||
| c501ca9ba4 | |||
| 739e5f9fd6 | |||
| 67ee02574f | |||
| 6a6acd2a46 | |||
| a2af0aae5e | |||
| 1aeb4c0e8c | |||
| 66f1495538 | |||
| 053ac11273 | |||
| 5230854dc8 | |||
| c668a7c665 | |||
| 8d51e8eb72 | |||
| b453cccf51 | |||
| 5be2aa4426 | |||
| 84287feb08 | |||
| a4961afa7e | |||
| aacfe93fa2 | |||
| f87d492118 | |||
| 337c541c0c | |||
| d32a5d5e8c | |||
| ad2738f4f8 | |||
| ba46469202 | |||
| e296709815 | |||
| f6df1546f4 | |||
| 2e694edba2 | |||
| 3f2069bd66 | |||
| 0fb207a926 | |||
| 3b7d285c0a | |||
| 15f54c263e | |||
| 1f1e6f2e49 | |||
| 92febbf574 | |||
| 69ae83eca7 | |||
| ac062bd0aa | |||
| 8939d1307f | |||
| 2eced9ea99 | |||
| 3fe909305d | |||
| f98a624532 | |||
| fed8ff8504 | |||
| 01328b4622 | |||
| 0f314ce455 | |||
| 273719f620 | |||
| 6e041088b8 | |||
| da23ab0dd6 | |||
| b7ab280d8e | |||
| 76eadfa8dc | |||
| d3761e02f5 | |||
| 68d37afa3b | |||
| 823f2d205d | |||
| 80461daa28 | |||
| 1e60931119 | |||
| 9dac69b21b | |||
| e4f0892831 | |||
| 105b285874 | |||
| adfc8c79c4 | |||
| 06ab387509 | |||
| 7a3b4b464e | |||
| 486e7e5ed1 | |||
| f914be3e07 | |||
| 3f6db4c1ab | |||
| 628bb3fb3e | |||
| dfd302178a | |||
| 351a1ccaad | |||
| 3d45d0bd1d | |||
| 142694d095 | |||
| 94ada409bb | |||
| 8357a253b3 | |||
| ea647ede73 | |||
| 4905a4cd4a | |||
| 48082931d1 | |||
| e94152b226 | |||
| b1688311c8 | |||
| 86d3f85379 | |||
| c1f52508a5 | |||
| 03473c51c2 | |||
| c8c8d61431 | |||
| ddcb4e1b94 | |||
| 5e3203348e | |||
| a538f14b4a | |||
| baa2e4f995 | |||
| ae59df8492 | |||
| a64c3fb3a2 | |||
| 5964cd3751 | |||
| 893cbc917d | |||
| 48ceaa9502 | |||
| 944b301837 | |||
| 29c56fbfb2 | |||
| 3b69354d19 | |||
| 5ee843cd59 | |||
| 93ae742ad8 | |||
| cd47e72e88 | |||
| b896be821f | |||
| e90ead2a8d | |||
| bc7676089c | |||
| 3232dc76d4 | |||
| c0bcaa4980 | |||
| e12c76ed66 | |||
| 722faee4c6 | |||
| d04ad4be26 | |||
| ba9446a1b8 | |||
| 9bc1f0a67a | |||
| f7f14708a2 | |||
| 78c348381d | |||
| 4c92aafc19 | |||
| e4d8dc7825 | |||
| 6e26b117b9 | |||
| 4149fc40c2 | |||
| e2ea175ea2 | |||
| b960fa83ef | |||
| 31de51eacc | |||
| bda7b5c446 | |||
| 58ad3fac06 | |||
| 88a180fadb | |||
| 09631f691b | |||
| 95d81c36ff | |||
| 625cbc63a4 | |||
| 5720211f70 | |||
| 9d0ea7fa11 | |||
| 02f00c9980 | |||
| 4774d648bd | |||
| 3d7ed01135 | |||
| c28356fffc | |||
| 3dad31d6df | |||
| c9bafe5c7a | |||
| 637503a1ac | |||
| 9ad48e0fe9 | |||
| 97a65e153d | |||
| 5ad226cedb | |||
| 6843f1690f | |||
| 04809b6037 | |||
| 5538c27322 | |||
| 35abb4d71e | |||
| bc5ca78816 | |||
| f15d41e185 | |||
| 27df0a1735 | |||
| 171974e43c | |||
| 03ef085a4c | |||
| d9f6971d0b | |||
| b081bb24e5 | |||
| aa63a16f25 | |||
| 27990b5360 | |||
| 9383856ca5 | |||
| 78b2c8b0be | |||
| 4cfa4ecc28 | |||
| 92a024b2fd | |||
| a1c414c197 | |||
| e8ee079aa7 | |||
| 769f666663 | |||
| c6136de551 | |||
| 4bf3d2907d | |||
| 1f1078120c | |||
| 096ccb7a7b | |||
| e416b469de | |||
| 228d4087ac | |||
| b95405e09a | |||
| 8a5ef62b60 | |||
| f59b286a59 | |||
| 7e87cdab4a | |||
| 5effc4a53a | |||
| 1540d8fad1 | |||
| 81ae4b3687 | |||
| 79f827cf40 | |||
| 8781608ca7 | |||
| 5c10c05c1f | |||
| 9b573ee8c9 | |||
| 5d53314e8f | |||
| 625bb3c4d5 | |||
| 1374f25a0b | |||
| ed954bd941 | |||
| a03d39b1ad | |||
| 2bfd03e483 | |||
| c100d90793 | |||
| 8db687a1cd | |||
| 5def2c0998 | |||
| 10d0f0d9b3 | |||
| c477e24034 | |||
| 36bed7c2f6 | |||
| 860c59a347 | |||
| f6ceb0b0d5 | |||
| e5aefc8bda | |||
| ba1748bd80 | |||
| 6d5e60bd9b | |||
| a7fc0fc07b | |||
| c032b94b77 | |||
| 8961967fec | |||
| c0cfd2ddbb | |||
| 00d0120e22 | |||
| 3672ec39dd | |||
| 2f6eaa3832 | |||
| 8f23742ca6 | |||
| c0a4affe00 | |||
| efe635f0d5 | |||
| fa64ba356a | |||
| eb2ac86c5d | |||
| 598c4fdcae | |||
| fe9e2e9945 | |||
| 716e0e6645 | |||
| 266a655107 | |||
| 2e85c1fb9b | |||
| 8c529adf85 | |||
| fb8569499c | |||
| 1d9d0f653d | |||
| 846fdecbcc | |||
| 95cfc4185a | |||
| c78b5453ff | |||
| 75cae3b252 | |||
| a796021143 | |||
| 83dd98426c | |||
| 0ec73a58e9 | |||
| d29234382f | |||
| 411cd5b2d5 | |||
| 6d8d4ea546 | |||
| 9f6a640e73 | |||
| 810ac0fca7 | |||
| c77fd2eef6 | |||
| 3356abe5c7 | |||
| 5faf9f8192 | |||
| c8d61ddad8 | |||
| 80e3337bad | |||
| 17635053ab | |||
| e82f30caae | |||
| ca7acd8461 | |||
| c0550ed953 | |||
| b0a6a54651 | |||
| b057ae2da1 | |||
| e277a9b3dd | |||
| 5c7157e0af | |||
| 1188c74fe5 | |||
| 06742fe24b | |||
| 9e38e2c1a9 | |||
| 2e361618a3 | |||
| b63a6a4fc4 | |||
| bc14181563 | |||
| c6c888c8a1 | |||
| ced104c206 | |||
| 5fef637f87 | |||
| 2ed3c7af27 | |||
| 673c8a7531 | |||
| 089ad7c242 | |||
| ee83fa673e | |||
| 033635c9fb | |||
| 3c51f5ff38 | |||
| 62029c3541 | |||
| 9735fbb0f4 | |||
| c8f55ae5dd | |||
| 9e4be2909c | |||
| d8b676f485 | |||
| 08e1ae11d5 | |||
| 88f62bf4ea | |||
| e1985647d5 | |||
| 8e55425c93 | |||
| 42c6963acc | |||
| cb3060c940 | |||
| cd75ac2e2c | |||
| 968dc81a74 | |||
| fc4bb1ae88 | |||
| f4f5097b00 | |||
| f558ee5802 | |||
| 2740bdc1d9 | |||
| 1378c17b55 | |||
| 033873c6cc | |||
| 159d1e4ce7 | |||
| 5642f1b97a | |||
| b25bfb2796 | |||
| 4b8d1e8dbd | |||
| 95aa9a8890 | |||
| 05e56711f3 | |||
| 5dd63bdd04 | |||
| 8bd2f2eb23 | |||
| 676c91d4a3 | |||
| a719f022fb | |||
| 47ceebbfc5 | |||
| ae89229815 | |||
| 2885a84373 | |||
| def1ffad23 | |||
| 948ee0e398 | |||
| 4e9fd632ea | |||
| cc243e1296 | |||
| d6c7f6f413 | |||
| 662ebc6c80 | |||
| 4f1f68ead8 | |||
| ab456bed98 | |||
| 4825a4ca1e | |||
| 36cb41d15f | |||
| 61eaf0e832 | |||
| e95d274f17 | |||
| 1740fb236e | |||
| de0c16789e | |||
| f99ca64adc | |||
| 46186dc896 | |||
| d0fd28c97c | |||
| c5a87c2a18 | |||
| 85d695dbe8 |
@@ -1,4 +1,4 @@
|
||||
# Version: 8.0.0
|
||||
# Version: 8.0.10
|
||||
<IfModule mod_fcgid.c>
|
||||
<IfModule mod_setenvif.c>
|
||||
<IfModule mod_headers.c>
|
||||
@@ -13,6 +13,8 @@ php_value post_max_size 513M
|
||||
php_value memory_limit 512M
|
||||
php_value mbstring.func_overload 0
|
||||
php_value always_populate_raw_post_data -1
|
||||
php_value default_charset 'UTF-8'
|
||||
php_value output_buffering off
|
||||
<IfModule mod_env.c>
|
||||
SetEnv htaccessWorking true
|
||||
</IfModule>
|
||||
|
||||
@@ -3,3 +3,5 @@ post_max_size=513M
|
||||
memory_limit=512M
|
||||
mbstring.func_overload=0
|
||||
always_populate_raw_post_data=-1
|
||||
default_charset='UTF-8'
|
||||
output_buffering=off
|
||||
|
||||
+1
-1
Submodule 3rdparty updated: a32d3924bd...4a43dcef48
@@ -5,7 +5,7 @@ OCP\JSON::checkLoggedIn();
|
||||
$l = \OC::$server->getL10N('files');
|
||||
|
||||
// Load the files
|
||||
$dir = isset($_GET['dir']) ? $_GET['dir'] : '';
|
||||
$dir = isset($_GET['dir']) ? (string)$_GET['dir'] : '';
|
||||
$dir = \OC\Files\Filesystem::normalizePath($dir);
|
||||
|
||||
try {
|
||||
@@ -22,10 +22,32 @@ try {
|
||||
|
||||
$sortAttribute = isset($_GET['sort']) ? $_GET['sort'] : 'name';
|
||||
$sortDirection = isset($_GET['sortdirection']) ? ($_GET['sortdirection'] === 'desc') : false;
|
||||
$mimetypeFilters = isset($_GET['mimetypes']) ? json_decode($_GET['mimetypes']) : '';
|
||||
|
||||
// make filelist
|
||||
$files = [];
|
||||
// Clean up duplicates from array
|
||||
if (is_array($mimetypeFilters) && count($mimetypeFilters)) {
|
||||
$mimetypeFilters = array_unique($mimetypeFilters);
|
||||
|
||||
if (!in_array('httpd/unix-directory', $mimetypeFilters)) {
|
||||
// append folder filter to be able to browse folders
|
||||
$mimetypeFilters[] = 'httpd/unix-directory';
|
||||
}
|
||||
|
||||
// create filelist with mimetype filter - as getFiles only supports on
|
||||
// mimetype filter at once we will filter this folder for each
|
||||
// mimetypeFilter
|
||||
foreach ($mimetypeFilters as $mimetypeFilter) {
|
||||
$files = array_merge($files, \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection, $mimetypeFilter));
|
||||
}
|
||||
|
||||
// sort the files accordingly
|
||||
$files = \OCA\Files\Helper::sortFiles($files, $sortAttribute, $sortDirection);
|
||||
} else {
|
||||
// create file list without mimetype filter
|
||||
$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection);
|
||||
}
|
||||
|
||||
$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection);
|
||||
$files = \OCA\Files\Helper::populateTags($files);
|
||||
$data['directory'] = $dir;
|
||||
$data['files'] = \OCA\Files\Helper::formatFileInfos($files);
|
||||
|
||||
@@ -21,7 +21,6 @@ $listener = new ScanListener($eventSource);
|
||||
foreach ($users as $user) {
|
||||
$eventSource->send('user', $user);
|
||||
$scanner = new \OC\Files\Utils\Scanner($user, \OC::$server->getDatabaseConnection());
|
||||
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', array($listener, 'file'));
|
||||
$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', array($listener, 'folder'));
|
||||
if ($force) {
|
||||
$scanner->scan($dir);
|
||||
@@ -50,13 +49,6 @@ class ScanListener {
|
||||
$this->eventSource = $eventSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*/
|
||||
public function folder($path) {
|
||||
$this->eventSource->send('folder', $path);
|
||||
}
|
||||
|
||||
public function file() {
|
||||
$this->fileCount++;
|
||||
if ($this->fileCount > $this->lastCount + 20) { //send a count update every 20 files
|
||||
|
||||
@@ -51,6 +51,10 @@ if (empty($_POST['dirToken'])) {
|
||||
|
||||
// The token defines the target directory (security reasons)
|
||||
$path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
|
||||
if($path === null) {
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Unable to set upload directory.')))));
|
||||
die();
|
||||
}
|
||||
$dir = sprintf(
|
||||
"/%s/%s",
|
||||
$path,
|
||||
|
||||
@@ -76,10 +76,10 @@ class Scan extends Command {
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$path = $input->getOption('path');
|
||||
if ($path) {
|
||||
$path = '/'.trim($path, '/');
|
||||
list (, $user, ) = explode('/', $path, 3);
|
||||
$inputPath = $input->getOption('path');
|
||||
if ($inputPath) {
|
||||
$inputPath = '/' . trim($inputPath, '/');
|
||||
list (, $user,) = explode('/', $inputPath, 3);
|
||||
$users = array($user);
|
||||
} else if ($input->getOption('all')) {
|
||||
$users = $this->userManager->search('');
|
||||
@@ -98,6 +98,7 @@ class Scan extends Command {
|
||||
if (is_object($user)) {
|
||||
$user = $user->getUID();
|
||||
}
|
||||
$path = $inputPath ? $inputPath : '/' . $user;
|
||||
if ($this->userManager->userExists($user)) {
|
||||
$this->scanFiles($user, $path, $quiet, $output);
|
||||
} else {
|
||||
|
||||
@@ -63,7 +63,6 @@ class ApiController extends Controller {
|
||||
* replace the actual tag selection.
|
||||
*
|
||||
* @NoAdminRequired
|
||||
* @CORS
|
||||
*
|
||||
* @param string $path path
|
||||
* @param array $tags array of tags
|
||||
@@ -91,7 +90,6 @@ class ApiController extends Controller {
|
||||
* Returns a list of all files tagged with the given tag.
|
||||
*
|
||||
* @NoAdminRequired
|
||||
* @CORS
|
||||
*
|
||||
* @param array $tagName tag name to filter by
|
||||
* @return DataResponse
|
||||
@@ -102,7 +100,11 @@ class ApiController extends Controller {
|
||||
foreach ($fileInfos as &$fileInfo) {
|
||||
$file = \OCA\Files\Helper::formatFileInfo($fileInfo);
|
||||
$parts = explode('/', dirname($fileInfo->getPath()), 4);
|
||||
$file['path'] = '/' . $parts[3];
|
||||
if(isset($parts[3])) {
|
||||
$file['path'] = '/' . $parts[3];
|
||||
} else {
|
||||
$file['path'] = '/';
|
||||
}
|
||||
$file['tags'] = array($tagName);
|
||||
$files[] = $file;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ $ftype=\OC_Helper::getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filenam
|
||||
header('Content-Type:'.$ftype);
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '.\OC\Files\Filesystem::filesize($filename));
|
||||
OCP\Response::setContentLengthHeader(\OC\Files\Filesystem::filesize($filename));
|
||||
|
||||
OC_Util::obEnd();
|
||||
\OC\Files\Filesystem::readfile( $filename );
|
||||
|
||||
@@ -635,6 +635,8 @@
|
||||
* @param filesArray array of file data (map)
|
||||
*/
|
||||
setFiles: function(filesArray) {
|
||||
var self = this;
|
||||
|
||||
// detach to make adding multiple rows faster
|
||||
this.files = filesArray;
|
||||
|
||||
@@ -655,7 +657,10 @@
|
||||
this.updateSelectionSummary();
|
||||
$(window).scrollTop(0);
|
||||
|
||||
this.$fileList.trigger(jQuery.Event("updated"));
|
||||
this.$fileList.trigger(jQuery.Event('updated'));
|
||||
_.defer(function() {
|
||||
self.$el.closest('#app-content').trigger(jQuery.Event('apprendered'));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Creates a new table row element using the given file data.
|
||||
@@ -947,7 +952,7 @@
|
||||
mime: mime,
|
||||
etag: fileData.etag,
|
||||
callback: function(url) {
|
||||
iconDiv.css('background-image', 'url(' + url + ')');
|
||||
iconDiv.css('background-image', 'url("' + url + '")');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -959,7 +964,7 @@
|
||||
};
|
||||
var previewUrl = this.generatePreviewUrl(urlSpec);
|
||||
previewUrl = previewUrl.replace('(', '%28').replace(')', '%29');
|
||||
iconDiv.css('background-image', 'url(' + previewUrl + ')');
|
||||
iconDiv.css('background-image', 'url("' + previewUrl + '")');
|
||||
}
|
||||
}
|
||||
return tr;
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
var $target = $(ev.target);
|
||||
var itemId = $target.closest('li').attr('data-id');
|
||||
this.setActiveItem(itemId);
|
||||
return false;
|
||||
ev.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -170,10 +170,11 @@ class Helper
|
||||
* @param string $dir path to the directory
|
||||
* @param string $sortAttribute attribute to sort on
|
||||
* @param bool $sortDescending true for descending sort, false otherwise
|
||||
* @param string $mimetypeFilter limit returned content to this mimetype or mimepart
|
||||
* @return \OCP\Files\FileInfo[] files
|
||||
*/
|
||||
public static function getFiles($dir, $sortAttribute = 'name', $sortDescending = false) {
|
||||
$content = \OC\Files\Filesystem::getDirectoryContent($dir);
|
||||
public static function getFiles($dir, $sortAttribute = 'name', $sortDescending = false, $mimetypeFilter = '') {
|
||||
$content = \OC\Files\Filesystem::getDirectoryContent($dir, $mimetypeFilter);
|
||||
|
||||
return self::sortFiles($content, $sortAttribute, $sortDescending);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\Files\Controller;
|
||||
|
||||
use OC\Files\FileInfo;
|
||||
use OCP\AppFramework\Http;
|
||||
use OC\Preview;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
use Test\TestCase;
|
||||
use OCP\IRequest;
|
||||
use OCA\Files\Service\TagService;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
|
||||
/**
|
||||
* Class ApiController
|
||||
*
|
||||
* @package OCA\Files\Controller
|
||||
*/
|
||||
class ApiControllerTest extends TestCase {
|
||||
/** @var string */
|
||||
private $appName = 'files';
|
||||
/** @var IRequest */
|
||||
private $request;
|
||||
/** @var TagService */
|
||||
private $tagService;
|
||||
/** @var ApiController */
|
||||
private $apiController;
|
||||
|
||||
public function setUp() {
|
||||
$this->request = $this->getMockBuilder('\OCP\IRequest')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->tagService = $this->getMockBuilder('\OCA\Files\Service\TagService')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->apiController = new ApiController(
|
||||
$this->appName,
|
||||
$this->request,
|
||||
$this->tagService
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetFilesByTagEmpty() {
|
||||
$tagName = 'MyTagName';
|
||||
$this->tagService->expects($this->once())
|
||||
->method('getFilesByTag')
|
||||
->with($this->equalTo([$tagName]))
|
||||
->will($this->returnValue([]));
|
||||
|
||||
$expected = new DataResponse(['files' => []]);
|
||||
$this->assertEquals($expected, $this->apiController->getFilesByTag([$tagName]));
|
||||
}
|
||||
|
||||
public function testGetFilesByTagSingle() {
|
||||
$tagName = 'MyTagName';
|
||||
$fileInfo = new FileInfo(
|
||||
'/root.txt',
|
||||
$this->getMockBuilder('\OC\Files\Storage\Storage')
|
||||
->disableOriginalConstructor()
|
||||
->getMock(),
|
||||
'/var/www/root.txt',
|
||||
[
|
||||
'mtime' => 55,
|
||||
'mimetype' => 'application/pdf',
|
||||
'size' => 1234,
|
||||
'etag' => 'MyEtag',
|
||||
],
|
||||
$this->getMockBuilder('\OCP\Files\Mount\IMountPoint')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
);
|
||||
$this->tagService->expects($this->once())
|
||||
->method('getFilesByTag')
|
||||
->with($this->equalTo([$tagName]))
|
||||
->will($this->returnValue([$fileInfo]));
|
||||
|
||||
$expected = new DataResponse([
|
||||
'files' => [
|
||||
[
|
||||
'id' => null,
|
||||
'parentId' => null,
|
||||
'date' => \OCP\Util::formatDate(55),
|
||||
'mtime' => 55000,
|
||||
'icon' => \OCA\Files\Helper::determineIcon($fileInfo),
|
||||
'name' => 'root.txt',
|
||||
'permissions' => null,
|
||||
'mimetype' => 'application/pdf',
|
||||
'size' => 1234,
|
||||
'type' => 'file',
|
||||
'etag' => 'MyEtag',
|
||||
'path' => '/',
|
||||
'tags' => [
|
||||
[
|
||||
'MyTagName'
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$this->assertEquals($expected, $this->apiController->getFilesByTag([$tagName]));
|
||||
}
|
||||
|
||||
public function testGetFilesByTagMultiple() {
|
||||
$tagName = 'MyTagName';
|
||||
$fileInfo1 = new FileInfo(
|
||||
'/root.txt',
|
||||
$this->getMockBuilder('\OC\Files\Storage\Storage')
|
||||
->disableOriginalConstructor()
|
||||
->getMock(),
|
||||
'/var/www/root.txt',
|
||||
[
|
||||
'mtime' => 55,
|
||||
'mimetype' => 'application/pdf',
|
||||
'size' => 1234,
|
||||
'etag' => 'MyEtag',
|
||||
],
|
||||
$this->getMockBuilder('\OCP\Files\Mount\IMountPoint')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
);
|
||||
$fileInfo2 = new FileInfo(
|
||||
'/root.txt',
|
||||
$this->getMockBuilder('\OC\Files\Storage\Storage')
|
||||
->disableOriginalConstructor()
|
||||
->getMock(),
|
||||
'/var/www/some/sub.txt',
|
||||
[
|
||||
'mtime' => 999,
|
||||
'mimetype' => 'application/binary',
|
||||
'size' => 9876,
|
||||
'etag' => 'SubEtag',
|
||||
],
|
||||
$this->getMockBuilder('\OCP\Files\Mount\IMountPoint')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
);
|
||||
$this->tagService->expects($this->once())
|
||||
->method('getFilesByTag')
|
||||
->with($this->equalTo([$tagName]))
|
||||
->will($this->returnValue([$fileInfo1, $fileInfo2]));
|
||||
|
||||
$expected = new DataResponse([
|
||||
'files' => [
|
||||
[
|
||||
'id' => null,
|
||||
'parentId' => null,
|
||||
'date' => \OCP\Util::formatDate(55),
|
||||
'mtime' => 55000,
|
||||
'icon' => \OCA\Files\Helper::determineIcon($fileInfo1),
|
||||
'name' => 'root.txt',
|
||||
'permissions' => null,
|
||||
'mimetype' => 'application/pdf',
|
||||
'size' => 1234,
|
||||
'type' => 'file',
|
||||
'etag' => 'MyEtag',
|
||||
'path' => '/',
|
||||
'tags' => [
|
||||
[
|
||||
'MyTagName'
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => null,
|
||||
'parentId' => null,
|
||||
'date' => \OCP\Util::formatDate(999),
|
||||
'mtime' => 999000,
|
||||
'icon' => \OCA\Files\Helper::determineIcon($fileInfo2),
|
||||
'name' => 'root.txt',
|
||||
'permissions' => null,
|
||||
'mimetype' => 'application/binary',
|
||||
'size' => 9876,
|
||||
'type' => 'file',
|
||||
'etag' => 'SubEtag',
|
||||
'path' => '/',
|
||||
'tags' => [
|
||||
[
|
||||
'MyTagName'
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
]);
|
||||
$this->assertEquals($expected, $this->apiController->getFilesByTag([$tagName]));
|
||||
}
|
||||
|
||||
public function testUpdateFileTagsEmpty() {
|
||||
$expected = new DataResponse([]);
|
||||
$this->assertEquals($expected, $this->apiController->updateFileTags('/path.txt'));
|
||||
}
|
||||
|
||||
public function testUpdateFileTagsWorking() {
|
||||
$this->tagService->expects($this->once())
|
||||
->method('updateFileTags')
|
||||
->with('/path.txt', ['Tag1', 'Tag2']);
|
||||
|
||||
$expected = new DataResponse([
|
||||
'tags' => [
|
||||
'Tag1',
|
||||
'Tag2'
|
||||
],
|
||||
]);
|
||||
$this->assertEquals($expected, $this->apiController->updateFileTags('/path.txt', ['Tag1', 'Tag2']));
|
||||
}
|
||||
|
||||
public function testUpdateFileTagsNotFoundException() {
|
||||
$this->tagService->expects($this->once())
|
||||
->method('updateFileTags')
|
||||
->with('/path.txt', ['Tag1', 'Tag2'])
|
||||
->will($this->throwException(new NotFoundException('My error message')));
|
||||
|
||||
$expected = new DataResponse('My error message', Http::STATUS_NOT_FOUND);
|
||||
$this->assertEquals($expected, $this->apiController->updateFileTags('/path.txt', ['Tag1', 'Tag2']));
|
||||
}
|
||||
|
||||
public function testUpdateFileTagsStorageNotAvailableException() {
|
||||
$this->tagService->expects($this->once())
|
||||
->method('updateFileTags')
|
||||
->with('/path.txt', ['Tag1', 'Tag2'])
|
||||
->will($this->throwException(new StorageNotAvailableException('My error message')));
|
||||
|
||||
$expected = new DataResponse('My error message', Http::STATUS_SERVICE_UNAVAILABLE);
|
||||
$this->assertEquals($expected, $this->apiController->updateFileTags('/path.txt', ['Tag1', 'Tag2']));
|
||||
}
|
||||
|
||||
public function testUpdateFileTagsStorageGenericException() {
|
||||
$this->tagService->expects($this->once())
|
||||
->method('updateFileTags')
|
||||
->with('/path.txt', ['Tag1', 'Tag2'])
|
||||
->will($this->throwException(new \Exception('My error message')));
|
||||
|
||||
$expected = new DataResponse('My error message', Http::STATUS_NOT_FOUND);
|
||||
$this->assertEquals($expected, $this->apiController->updateFileTags('/path.txt', ['Tag1', 'Tag2']));
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class TagServiceTest extends \Test\TestCase {
|
||||
->withAnyParameters()
|
||||
->will($this->returnValue($user));
|
||||
|
||||
$this->root = \OC::$server->getUserFolder();
|
||||
$this->root = \OC::$server->getUserFolder($this->user);
|
||||
|
||||
$this->tagger = \OC::$server->getTagManager()->load('files');
|
||||
$this->tagService = new TagService(
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<types>
|
||||
<filesystem/>
|
||||
</types>
|
||||
<ocsid>166047</ocsid>
|
||||
<dependencies>
|
||||
<lib>openssl</lib>
|
||||
</dependencies>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.7.1
|
||||
0.7.2
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Saving..." => "Spašavam..."
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Saving..." => "Simpan..."
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=1; plural=0;";
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Saving..." => "Enregistra..."
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"personal settings" => "వ్యక్తిగత అమరికలు"
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -478,7 +478,7 @@ class Hooks {
|
||||
|
||||
list($ownerNew, $pathNew) = $util->getUidAndFilename($params['newpath']);
|
||||
|
||||
if ($util->isSystemWideMountPoint($pathNew)) {
|
||||
if ($util->isSystemWideMountPoint($pathNew, $ownerNew)) {
|
||||
$newKeysPath = 'files_encryption/keys/' . $pathNew;
|
||||
} else {
|
||||
$newKeysPath = $ownerNew . '/files_encryption/keys/' . $pathNew;
|
||||
|
||||
@@ -187,7 +187,7 @@ class Keymanager {
|
||||
$filePath_f = ltrim($filename, '/');
|
||||
|
||||
// in case of system wide mount points the keys are stored directly in the data directory
|
||||
if ($util->isSystemWideMountPoint($filename)) {
|
||||
if ($util->isSystemWideMountPoint($filename, $owner)) {
|
||||
$keyPath = self::$keys_base_dir . $filePath_f . '/';
|
||||
} else {
|
||||
$keyPath = '/' . $owner . self::$keys_base_dir . $filePath_f . '/';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
/**
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @copyright (C) 2014 ownCloud, Inc.
|
||||
@@ -35,6 +35,7 @@ class Migration {
|
||||
|
||||
public function __construct() {
|
||||
$this->view = new \OC\Files\View();
|
||||
$this->view->getUpdater()->disable();
|
||||
$this->public_share_key_id = Helper::getPublicShareKeyId();
|
||||
$this->recovery_key_id = Helper::getRecoveryKeyId();
|
||||
}
|
||||
@@ -50,7 +51,7 @@ class Migration {
|
||||
$this->reorganizeFolderStructureForUser($user);
|
||||
}
|
||||
$offset += $limit;
|
||||
} while(count($users) >= $limit);
|
||||
} while (count($users) >= $limit);
|
||||
}
|
||||
|
||||
public function reorganizeSystemFolderStructure() {
|
||||
@@ -74,6 +75,10 @@ class Migration {
|
||||
$this->view->deleteAll('/owncloud_private_key');
|
||||
$this->view->deleteAll('/files_encryption/share-keys');
|
||||
$this->view->deleteAll('/files_encryption/keyfiles');
|
||||
$storage = $this->view->getMount('')->getStorage();
|
||||
$storage->getScanner()->scan('files_encryption');
|
||||
$storage->getCache()->remove('owncloud_private_key');
|
||||
$storage->getCache()->remove('public-keys');
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +101,7 @@ class Migration {
|
||||
}
|
||||
// delete old folders
|
||||
$this->deleteOldKeys($user);
|
||||
$this->view->getMount('/' . $user)->getStorage()->getScanner()->scan('files_encryption');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +133,7 @@ class Migration {
|
||||
while (($oldPublicKey = readdir($dh)) !== false) {
|
||||
if (!\OC\Files\Filesystem::isIgnoredDir($oldPublicKey)) {
|
||||
$newPublicKey = substr($oldPublicKey, 0, strlen($oldPublicKey) - strlen('.public.key')) . '.publicKey';
|
||||
$this->view->rename('public-keys/' . $oldPublicKey , 'files_encryption/public_keys/' . $newPublicKey);
|
||||
$this->view->rename('public-keys/' . $oldPublicKey, 'files_encryption/public_keys/' . $newPublicKey);
|
||||
}
|
||||
}
|
||||
closedir($dh);
|
||||
@@ -141,7 +147,7 @@ class Migration {
|
||||
while (($oldPrivateKey = readdir($dh)) !== false) {
|
||||
if (!\OC\Files\Filesystem::isIgnoredDir($oldPrivateKey)) {
|
||||
$newPrivateKey = substr($oldPrivateKey, 0, strlen($oldPrivateKey) - strlen('.private.key')) . '.privateKey';
|
||||
$this->view->rename('owncloud_private_key/' . $oldPrivateKey , 'files_encryption/' . $newPrivateKey);
|
||||
$this->view->rename('owncloud_private_key/' . $oldPrivateKey, 'files_encryption/' . $newPrivateKey);
|
||||
}
|
||||
}
|
||||
closedir($dh);
|
||||
@@ -149,10 +155,10 @@ class Migration {
|
||||
}
|
||||
|
||||
private function renameUsersPrivateKey($user) {
|
||||
$oldPrivateKey = $user . '/files_encryption/' . $user . '.private.key';
|
||||
$newPrivateKey = substr($oldPrivateKey, 0, strlen($oldPrivateKey) - strlen('.private.key')) . '.privateKey';
|
||||
$oldPrivateKey = $user . '/files_encryption/' . $user . '.private.key';
|
||||
$newPrivateKey = substr($oldPrivateKey, 0, strlen($oldPrivateKey) - strlen('.private.key')) . '.privateKey';
|
||||
|
||||
$this->view->rename($oldPrivateKey, $newPrivateKey);
|
||||
$this->view->rename($oldPrivateKey, $newPrivateKey);
|
||||
}
|
||||
|
||||
private function getFileName($file, $trash) {
|
||||
@@ -186,7 +192,7 @@ class Migration {
|
||||
}
|
||||
|
||||
private function getFilePath($path, $user, $trash) {
|
||||
$offset = $trash ? strlen($user . '/files_trashbin/keyfiles') : strlen($user . '/files_encryption/keyfiles');
|
||||
$offset = $trash ? strlen($user . '/files_trashbin/keyfiles') : strlen($user . '/files_encryption/keyfiles');
|
||||
return substr($path, $offset);
|
||||
}
|
||||
|
||||
@@ -215,7 +221,7 @@ class Migration {
|
||||
$extension = $this->getExtension($file, $trash);
|
||||
$targetDir = $this->getTargetDir($user, $filePath, $filename, $extension, $trash);
|
||||
$this->createPathForKeys($targetDir);
|
||||
$this->view->copy($path . '/' . $file, $targetDir . '/fileKey');
|
||||
$this->view->rename($path . '/' . $file, $targetDir . '/fileKey');
|
||||
$this->renameShareKeys($user, $filePath, $filename, $targetDir, $trash);
|
||||
}
|
||||
}
|
||||
@@ -258,10 +264,10 @@ class Migration {
|
||||
if ($this->view->is_dir($oldShareKeyPath . '/' . $file)) {
|
||||
continue;
|
||||
} else {
|
||||
if (substr($file, 0, strlen($filename) +1) === $filename . '.') {
|
||||
if (substr($file, 0, strlen($filename) + 1) === $filename . '.') {
|
||||
|
||||
$uid = $this->getUidFromShareKey($file, $filename, $trash);
|
||||
$this->view->copy($oldShareKeyPath . '/' . $file, $target . '/' . $uid . '.shareKey');
|
||||
$this->view->rename($oldShareKeyPath . '/' . $file, $target . '/' . $uid . '.shareKey');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -299,7 +299,10 @@ class Proxy extends \OC_FileProxy {
|
||||
public function postGetFileInfo($path, $data) {
|
||||
|
||||
// if path is a folder do nothing
|
||||
if (\OCP\App::isEnabled('files_encryption') && $data !== false && array_key_exists('size', $data)) {
|
||||
if (\OCP\App::isEnabled('files_encryption') &&
|
||||
$data !== false &&
|
||||
array_key_exists('size', $data) &&
|
||||
$this->shouldEncrypt($path)) {
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
@@ -330,7 +333,8 @@ class Proxy extends \OC_FileProxy {
|
||||
// if encryption is no longer enabled or if the files aren't migrated yet
|
||||
// we return the default file size
|
||||
if(!\OCP\App::isEnabled('files_encryption') ||
|
||||
$util->getMigrationStatus() !== Util::MIGRATION_COMPLETED) {
|
||||
$util->getMigrationStatus() !== Util::MIGRATION_COMPLETED ||
|
||||
!$this->shouldEncrypt($path)) {
|
||||
return $size;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Encryption;
|
||||
use OC\User\NoUserException;
|
||||
|
||||
/**
|
||||
* Class for utilities relating to encrypted file storage system
|
||||
@@ -945,8 +946,14 @@ class Util {
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
$util = new Util($this->view, $user);
|
||||
return $util->ready();
|
||||
try {
|
||||
$util = new Util($this->view, $user);
|
||||
return $util->ready();
|
||||
} catch (NoUserException $e) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'No User object for '.$user, \OCP\Util::DEBUG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1610,15 +1617,16 @@ class Util {
|
||||
/**
|
||||
* check if the file is stored on a system wide mount point
|
||||
* @param string $path relative to /data/user with leading '/'
|
||||
* @param string $uid
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSystemWideMountPoint($path) {
|
||||
public function isSystemWideMountPoint($path, $uid) {
|
||||
$normalizedPath = ltrim($path, '/');
|
||||
if (\OCP\App::isEnabled("files_external")) {
|
||||
$mounts = \OC_Mount_Config::getSystemMountPoints();
|
||||
foreach ($mounts as $mount) {
|
||||
if ($mount['mountpoint'] == substr($normalizedPath, 0, strlen($mount['mountpoint']))) {
|
||||
if ($this->isMountPointApplicableToUser($mount)) {
|
||||
if ($this->isMountPointApplicableToUser($mount, $uid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1631,10 +1639,10 @@ class Util {
|
||||
* check if mount point is applicable to user
|
||||
*
|
||||
* @param array $mount contains $mount['applicable']['users'], $mount['applicable']['groups']
|
||||
* @param string $uid
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isMountPointApplicableToUser($mount) {
|
||||
$uid = \OCP\User::getUser();
|
||||
protected function isMountPointApplicableToUser($mount, $uid) {
|
||||
$acceptedUids = array('all', $uid);
|
||||
// check if mount point is applicable for the user
|
||||
$intersection = array_intersect($acceptedUids, $mount['applicable']['users']);
|
||||
|
||||
@@ -30,6 +30,7 @@ class Hooks extends TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1.dot";
|
||||
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2.dot";
|
||||
const TEST_ENCRYPTION_HOOKS_USER3 = "test-encryption-hooks-user3.dot";
|
||||
|
||||
/** @var \OC\Files\View */
|
||||
public $user1View; // view on /data/user1/files
|
||||
@@ -91,6 +92,7 @@ class Hooks extends TestCase {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
@@ -407,31 +409,35 @@ class Hooks extends TestCase {
|
||||
$view = new \OC\Files\View();
|
||||
|
||||
// set user password for the first time
|
||||
\OCA\Files_Encryption\Hooks::postCreateUser(array('uid' => 'newUser', 'password' => 'newUserPassword'));
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_HOOKS_USER3, 'newUserPassword');
|
||||
\OCA\Files_Encryption\Hooks::postCreateUser(array(
|
||||
'uid' => self::TEST_ENCRYPTION_HOOKS_USER3,
|
||||
'password' => 'newUserPassword')
|
||||
);
|
||||
|
||||
$this->assertTrue($view->file_exists(\OCA\Files_Encryption\Keymanager::getPublicKeyPath() . '/newUser.publicKey'));
|
||||
$this->assertTrue($view->file_exists('newUser/files_encryption/newUser.privateKey'));
|
||||
$this->assertTrue($view->file_exists(\OCA\Files_Encryption\Keymanager::getPublicKeyPath() . '/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.publicKey'));
|
||||
$this->assertTrue($view->file_exists(self::TEST_ENCRYPTION_HOOKS_USER3.'/files_encryption/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.privateKey'));
|
||||
|
||||
// check if we are able to decrypt the private key
|
||||
$encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, 'newUserPassword');
|
||||
$this->assertTrue(is_string($privateKey));
|
||||
|
||||
// change the password before the user logged-in for the first time,
|
||||
// we can replace the encryption keys
|
||||
\OCA\Files_Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged'));
|
||||
\OCA\Files_Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged'));
|
||||
|
||||
$encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged');
|
||||
$this->assertTrue(is_string($privateKey));
|
||||
|
||||
// now create a files folder to simulate a already used account
|
||||
$view->mkdir('/newUser/files');
|
||||
$view->mkdir('/'.self::TEST_ENCRYPTION_HOOKS_USER3.'/files');
|
||||
|
||||
// change the password after the user logged in, now the password should not change
|
||||
\OCA\Files_Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged2'));
|
||||
\OCA\Files_Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged2'));
|
||||
|
||||
$encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Files_Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Files_Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged2');
|
||||
$this->assertFalse($privateKey);
|
||||
|
||||
|
||||
@@ -587,9 +587,8 @@ class Util extends TestCase {
|
||||
* @dataProvider dataProviderFortestIsMountPointApplicableToUser
|
||||
*/
|
||||
function testIsMountPointApplicableToUser($mount, $expectedResult) {
|
||||
self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
$dummyClass = new DummyUtilClass($this->view, self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
$result = $dummyClass->testIsMountPointApplicableToUser($mount);
|
||||
$result = $dummyClass->testIsMountPointApplicableToUser($mount, self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
$this->assertSame($expectedResult, $result);
|
||||
}
|
||||
@@ -663,7 +662,7 @@ class Util extends TestCase {
|
||||
* dummy class extends \OCA\Files_Encryption\Util to access protected methods for testing
|
||||
*/
|
||||
class DummyUtilClass extends \OCA\Files_Encryption\Util {
|
||||
public function testIsMountPointApplicableToUser($mount) {
|
||||
return $this->isMountPointApplicableToUser($mount);
|
||||
public function testIsMountPointApplicableToUser($mount, $uid) {
|
||||
return $this->isMountPointApplicableToUser($mount, $uid);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -72,8 +72,16 @@ class Dropbox_OAuth_Curl extends Dropbox_OAuth {
|
||||
if (strtoupper($method) == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_URL, $uri);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
// if (is_array($arguments))
|
||||
// $arguments=http_build_query($arguments);
|
||||
|
||||
//if (is_array($arguments))
|
||||
// $arguments=http_build_query($arguments);
|
||||
if(is_array($arguments)) {
|
||||
foreach ($arguments as $key => $value) {
|
||||
if ($value[0] === '@') {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments);
|
||||
// $httpHeaders['Content-Length']=strlen($arguments);
|
||||
} else {
|
||||
|
||||
+8
-3
@@ -112,6 +112,11 @@ class smb {
|
||||
|
||||
|
||||
function execute ($command, $purl, $regexp = NULL) {
|
||||
if (strpos($command,';') !== false) {
|
||||
trigger_error('Semicolon not supported in commands');
|
||||
exit();
|
||||
}
|
||||
|
||||
return smb::client ('-d 0 '
|
||||
. escapeshellarg ('//' . $purl['host'] . '/' . $purl['share'])
|
||||
. ' -c ' . escapeshellarg ($command), $purl, $regexp
|
||||
@@ -319,14 +324,14 @@ class smb {
|
||||
trigger_error('rename(): error in URL', E_USER_ERROR);
|
||||
}
|
||||
smb::clearstatcache ($url_from);
|
||||
$cmd = '';
|
||||
// check if target file exists
|
||||
if (smb::url_stat($url_to)) {
|
||||
// delete target file first
|
||||
$cmd = 'del "' . $to['path'] . '"; ';
|
||||
$cmd = 'del "' . $to['path'] . '"';
|
||||
smb::execute($cmd, $to);
|
||||
$replace = true;
|
||||
}
|
||||
$cmd .= 'rename "' . $from['path'] . '" "' . $to['path'] . '"';
|
||||
$cmd = 'rename "' . $from['path'] . '" "' . $to['path'] . '"';
|
||||
$result = smb::execute($cmd, $to);
|
||||
if ($replace) {
|
||||
// clear again, else the cache will return the info
|
||||
|
||||
@@ -14,6 +14,7 @@ if (isset($_POST['client_id']) && isset($_POST['client_secret']) && isset($_POST
|
||||
$client->setClientSecret($_POST['client_secret']);
|
||||
$client->setRedirectUri($_POST['redirect']);
|
||||
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
|
||||
$client->setApprovalPrompt('force');
|
||||
$client->setAccessType('offline');
|
||||
if (isset($_POST['step'])) {
|
||||
$step = $_POST['step'];
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
<types>
|
||||
<filesystem/>
|
||||
</types>
|
||||
<ocsid>166048</ocsid>
|
||||
|
||||
<dependencies>
|
||||
<owncloud min-version="8" />
|
||||
</dependencies>
|
||||
|
||||
@@ -490,6 +490,11 @@ class OC_Mount_Config {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($classOptions['objectstore'])) {
|
||||
// objectstore cannot be set by client side
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($backends[$class])) {
|
||||
// invalid backend
|
||||
return false;
|
||||
@@ -843,6 +848,13 @@ class OC_Mount_Config {
|
||||
$mountPoint[$applicable][$mountPath]['priority']
|
||||
= $data[$mountType][$applicable][$mountPath]['priority'];
|
||||
}
|
||||
// Persistent objectstore
|
||||
if (isset($data[$mountType][$applicable][$mountPath])
|
||||
&& isset($data[$mountType][$applicable][$mountPath]['objectstore'])
|
||||
) {
|
||||
$mountPoint[$applicable][$mountPath]['objectstore']
|
||||
= $data[$mountType][$applicable][$mountPath]['objectstore'];
|
||||
}
|
||||
$data[$mountType][$applicable]
|
||||
= array_merge($data[$mountType][$applicable], $mountPoint[$applicable]);
|
||||
} else {
|
||||
|
||||
@@ -100,7 +100,12 @@ class Dropbox extends \OC\Files\Storage\Common {
|
||||
return $contents;
|
||||
} else {
|
||||
try {
|
||||
$response = $this->dropbox->getMetaData($path, 'false');
|
||||
$requestPath = $path;
|
||||
if ($path === '.') {
|
||||
$requestPath = '';
|
||||
}
|
||||
|
||||
$response = $this->dropbox->getMetaData($requestPath, 'false');
|
||||
if (!isset($response['is_deleted']) || !$response['is_deleted']) {
|
||||
$this->metaData[$path] = $response;
|
||||
return $response;
|
||||
|
||||
@@ -37,13 +37,13 @@ class OwnCloud extends \OC\Files\Storage\DAV{
|
||||
$host = substr($host, 0, $hostSlashPos);
|
||||
}
|
||||
|
||||
if (substr($contextPath , 1) !== '/'){
|
||||
if (substr($contextPath, -1) !== '/'){
|
||||
$contextPath .= '/';
|
||||
}
|
||||
|
||||
if (isset($params['root'])){
|
||||
$root = $params['root'];
|
||||
if (substr($root, 1) !== '/'){
|
||||
if (substr($root, 0, 1) !== '/'){
|
||||
$root = '/' . $root;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,19 @@ class SMB_OC extends \OC\Files\Storage\SMB {
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($params) {
|
||||
if (isset($params['host']) && \OC::$server->getSession()->exists('smb-credentials')) {
|
||||
if (isset($params['host'])) {
|
||||
$host=$params['host'];
|
||||
$this->username_as_share = ($params['username_as_share'] === 'true');
|
||||
|
||||
$params_auth = json_decode(\OC::$server->getCrypto()->decrypt(\OC::$server->getSession()->get('smb-credentials')), true);
|
||||
$user = \OC::$server->getSession()->get('loginname');
|
||||
$password = $params_auth['password'];
|
||||
$user = 'foo';
|
||||
$password = 'bar';
|
||||
if (\OC::$server->getSession()->exists('smb-credentials')) {
|
||||
$params_auth = json_decode(\OC::$server->getCrypto()->decrypt(\OC::$server->getSession()->get('smb-credentials')), true);
|
||||
$user = \OC::$server->getSession()->get('loginname');
|
||||
$password = $params_auth['password'];
|
||||
} else {
|
||||
// assume we are testing from the admin section
|
||||
}
|
||||
|
||||
$root=isset($params['root'])?$params['root']:'/';
|
||||
$share = '';
|
||||
|
||||
@@ -21,8 +21,11 @@ abstract class StreamWrapper extends Common {
|
||||
}
|
||||
|
||||
public function rmdir($path) {
|
||||
if ($this->file_exists($path) && $this->isDeletable($path)) {
|
||||
if ($this->is_dir($path) && $this->isDeletable($path)) {
|
||||
$dh = $this->opendir($path);
|
||||
if (!is_resource($dh)) {
|
||||
return false;
|
||||
}
|
||||
while (($file = readdir($dh)) !== false) {
|
||||
if ($this->is_dir($path . '/' . $file)) {
|
||||
$this->rmdir($path . '/' . $file);
|
||||
|
||||
@@ -68,6 +68,14 @@ class OwnCloudFunctions extends \Test\TestCase {
|
||||
),
|
||||
'http://testhost/testroot/remote.php/webdav/subdir/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'http://testhost/testroot/',
|
||||
'root' => '/subdir',
|
||||
'secure' => false
|
||||
),
|
||||
'http://testhost/testroot/remote.php/webdav/subdir/',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ if (OCA\Files_Sharing\Helper::isIncomingServer2serverShareEnabled() === false) {
|
||||
$token = $_POST['token'];
|
||||
$remote = $_POST['remote'];
|
||||
$owner = $_POST['owner'];
|
||||
$ownerDisplayName = $_POST['ownerDisplayName'];
|
||||
$name = $_POST['name'];
|
||||
$password = $_POST['password'];
|
||||
|
||||
@@ -30,6 +31,14 @@ if(!\OCP\Util::isValidFileName($name)) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
|
||||
$currentServer = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
|
||||
if (\OC\Share\Helper::isSameUserOnSameServer($owner, $remote, $currentUser, $currentServer )) {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t('Not allowed to create a federated share with the same user server'))));
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
$externalManager = new \OCA\Files_Sharing\External\Manager(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC\Files\Filesystem::getMountManager(),
|
||||
@@ -38,14 +47,12 @@ $externalManager = new \OCA\Files_Sharing\External\Manager(
|
||||
\OC::$server->getUserSession()->getUser()->getUID()
|
||||
);
|
||||
|
||||
$name = OCP\Files::buildNotExistingFileName('/', $name);
|
||||
|
||||
// check for ssl cert
|
||||
if (substr($remote, 0, 5) === 'https' and !OC_Util::getUrlContent($remote)) {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t('Invalid or untrusted SSL certificate'))));
|
||||
exit;
|
||||
} else {
|
||||
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner, true);
|
||||
$mount = $externalManager->addShare($remote, $token, $password, $name, $ownerDisplayName, true);
|
||||
|
||||
/**
|
||||
* @var \OCA\Files_Sharing\External\Storage $storage
|
||||
|
||||
@@ -46,6 +46,13 @@ $view = new \OC\Files\View('/' . $userId . '/files');
|
||||
|
||||
$pathId = $linkedItem['file_source'];
|
||||
$path = $view->getPath($pathId);
|
||||
|
||||
if($path === null) {
|
||||
\OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND);
|
||||
\OC_Log::write('core-preview', 'Could not resolve file for shared item', OC_Log::WARN);
|
||||
exit;
|
||||
}
|
||||
|
||||
$pathInfo = $view->getFileInfo($path);
|
||||
$sharedFile = null;
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ class Local {
|
||||
if(isset($params['_put']['permissions'])) {
|
||||
return self::updatePermissions($share, $params);
|
||||
} elseif (isset($params['_put']['password'])) {
|
||||
return self::updatePassword($share, $params);
|
||||
return self::updatePassword($params['id'], (int)$share['share_type'], $params['_put']['password']);
|
||||
} elseif (isset($params['_put']['publicUpload'])) {
|
||||
return self::updatePublicUpload($share, $params);
|
||||
} elseif (isset($params['_put']['expireDate'])) {
|
||||
@@ -446,47 +446,22 @@ class Local {
|
||||
|
||||
/**
|
||||
* update password for public link share
|
||||
* @param array $share information about the share
|
||||
* @param array $params 'password'
|
||||
* @param int $shareId
|
||||
* @param int $shareType
|
||||
* @param string $password
|
||||
* @return \OC_OCS_Result
|
||||
*/
|
||||
private static function updatePassword($share, $params) {
|
||||
|
||||
$itemSource = $share['item_source'];
|
||||
$itemType = $share['item_type'];
|
||||
|
||||
if( (int)$share['share_type'] !== \OCP\Share::SHARE_TYPE_LINK) {
|
||||
private static function updatePassword($shareId, $shareType, $password) {
|
||||
if($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
|
||||
return new \OC_OCS_Result(null, 400, "password protection is only supported for public shares");
|
||||
}
|
||||
|
||||
$shareWith = isset($params['_put']['password']) ? $params['_put']['password'] : null;
|
||||
|
||||
if($shareWith === '') {
|
||||
$shareWith = null;
|
||||
}
|
||||
|
||||
$items = \OCP\Share::getItemShared($itemType, $itemSource);
|
||||
|
||||
$checkExists = false;
|
||||
foreach ($items as $item) {
|
||||
if($item['share_type'] === \OCP\Share::SHARE_TYPE_LINK) {
|
||||
$checkExists = true;
|
||||
$permissions = $item['permissions'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$checkExists) {
|
||||
return new \OC_OCS_Result(null, 404, "share doesn't exists, can't change password");
|
||||
if($password === '') {
|
||||
$password = null;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = \OCP\Share::shareItem(
|
||||
$itemType,
|
||||
$itemSource,
|
||||
\OCP\Share::SHARE_TYPE_LINK,
|
||||
$shareWith,
|
||||
$permissions
|
||||
);
|
||||
$result = \OCP\Share::setPassword($shareId, $password);
|
||||
} catch (\Exception $e) {
|
||||
return new \OC_OCS_Result(null, 403, $e->getMessage());
|
||||
}
|
||||
|
||||
@@ -64,8 +64,6 @@ class Server2Server {
|
||||
$shareWith
|
||||
);
|
||||
|
||||
$name = \OCP\Files::buildNotExistingFileName('/', $name);
|
||||
|
||||
try {
|
||||
$externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<field>
|
||||
<name>remote_id</name>
|
||||
<type>integer</type>
|
||||
<default>-1</default>
|
||||
<notnull>true</notnull>
|
||||
<length>4</length>
|
||||
</field>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.6.0
|
||||
0.6.2
|
||||
|
||||
@@ -42,7 +42,7 @@ class Application extends App {
|
||||
$server->getAppConfig(),
|
||||
$server->getConfig(),
|
||||
$c->query('URLGenerator'),
|
||||
$server->getUserManager(),
|
||||
$c->query('UserManager'),
|
||||
$server->getLogger(),
|
||||
$server->getActivityManager()
|
||||
);
|
||||
@@ -65,6 +65,9 @@ class Application extends App {
|
||||
$container->registerService('URLGenerator', function(SimpleContainer $c) use ($server){
|
||||
return $server->getUrlGenerator();
|
||||
});
|
||||
$container->registerService('UserManager', function(SimpleContainer $c) use ($server){
|
||||
return $server->getUserManager();
|
||||
});
|
||||
$container->registerService('IsIncomingShareEnabled', function(SimpleContainer $c) {
|
||||
return Helper::isIncomingServer2serverShareEnabled();
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ thead {
|
||||
}
|
||||
|
||||
/* keep long file names in one line to not overflow download button on mobile */
|
||||
.directDownload #download {
|
||||
.directDownload #downloadFile {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
OCA.Sharing.showAddExternalDialog = function (share, passwordProtected, callback) {
|
||||
var remote = share.remote;
|
||||
var owner = share.owner;
|
||||
var owner = share.ownerDisplayName || share.owner;
|
||||
var name = share.name;
|
||||
var remoteClean = (remote.substr(0, 8) === 'https://') ? remote.substr(8) : remote.substr(7);
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
remote: share.remote,
|
||||
token: share.token,
|
||||
owner: share.owner,
|
||||
ownerDisplayName: share.ownerDisplayName || share.owner,
|
||||
name: share.name,
|
||||
password: password}, function(result) {
|
||||
if (result.status === 'error') {
|
||||
|
||||
@@ -88,8 +88,8 @@ OCA.Sharing.PublicApp = {
|
||||
|
||||
// dynamically load image previews
|
||||
var params = {
|
||||
x: $(document).width() * window.devicePixelRatio,
|
||||
y: $(document).height() * window.devicePixelRatio,
|
||||
x: Math.floor($(document).width() * window.devicePixelRatio),
|
||||
y: Math.floor($(document).height() * window.devicePixelRatio),
|
||||
a: 'true',
|
||||
file: encodeURIComponent(this.initialDir + $('#filename').val()),
|
||||
t: $('#sharingToken').val(),
|
||||
@@ -147,6 +147,8 @@ OCA.Sharing.PublicApp = {
|
||||
|
||||
this.fileList.generatePreviewUrl = function (urlSpec) {
|
||||
urlSpec.t = $('#dirToken').val();
|
||||
urlSpec.y = Math.floor(36 * window.devicePixelRatio);
|
||||
urlSpec.x = Math.floor(36 * window.devicePixelRatio);
|
||||
return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec);
|
||||
};
|
||||
|
||||
@@ -192,9 +194,10 @@ OCA.Sharing.PublicApp = {
|
||||
var remote = $(this).find('input[type="text"]').val();
|
||||
var token = $('#sharingToken').val();
|
||||
var owner = $('#save').data('owner');
|
||||
var ownerDisplayName = $('#save').data('owner-display-name');
|
||||
var name = $('#save').data('name');
|
||||
var isProtected = $('#save').data('protected') ? 1 : 0;
|
||||
OCA.Sharing.PublicApp._saveToOwnCloud(remote, token, owner, name, isProtected);
|
||||
OCA.Sharing.PublicApp._saveToOwnCloud(remote, token, owner, ownerDisplayName, name, isProtected);
|
||||
});
|
||||
|
||||
$('#save #save-button').click(function () {
|
||||
@@ -218,11 +221,11 @@ OCA.Sharing.PublicApp = {
|
||||
this.fileList.changeDirectory(params.path || params.dir, false, true);
|
||||
},
|
||||
|
||||
_saveToOwnCloud: function(remote, token, owner, name, isProtected) {
|
||||
_saveToOwnCloud: function (remote, token, owner, ownerDisplayName, name, isProtected) {
|
||||
var location = window.location.protocol + '//' + window.location.host + OC.webroot;
|
||||
|
||||
var url = remote + '/index.php/apps/files#' + 'remote=' + encodeURIComponent(location) // our location is the remote for the other server
|
||||
+ "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) + "&name=" + encodeURIComponent(name) + "&protected=" + isProtected;
|
||||
+ "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) +"&ownerDisplayName=" + encodeURIComponent(ownerDisplayName) + "&name=" + encodeURIComponent(name) + "&protected=" + isProtected;
|
||||
|
||||
|
||||
if (remote.indexOf('://') > 0) {
|
||||
|
||||
@@ -23,7 +23,7 @@ OC.L10N.register(
|
||||
"Add remote share" : "Entfernte Freigabe hinzufügen",
|
||||
"No ownCloud installation (7 or higher) found at {remote}" : "Keine OwnCloud-Installation (7 oder höher) auf {remote} gefunden",
|
||||
"Invalid ownCloud url" : "Ungültige OwnCloud-URL",
|
||||
"Share" : "Share",
|
||||
"Share" : "Teilen",
|
||||
"Shared by" : "Geteilt von ",
|
||||
"A file or folder was shared from <strong>another server</strong>" : "Eine Datei oder ein Ordner wurde von <strong>einem anderen Server</strong> geteilt",
|
||||
"A public shared file or folder was <strong>downloaded</strong>" : "Eine öffentliche geteilte Datei oder ein öffentlicher geteilter Ordner wurde <strong>heruntergeladen</strong>",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"Add remote share" : "Entfernte Freigabe hinzufügen",
|
||||
"No ownCloud installation (7 or higher) found at {remote}" : "Keine OwnCloud-Installation (7 oder höher) auf {remote} gefunden",
|
||||
"Invalid ownCloud url" : "Ungültige OwnCloud-URL",
|
||||
"Share" : "Share",
|
||||
"Share" : "Teilen",
|
||||
"Shared by" : "Geteilt von ",
|
||||
"A file or folder was shared from <strong>another server</strong>" : "Eine Datei oder ein Ordner wurde von <strong>einem anderen Server</strong> geteilt",
|
||||
"A public shared file or folder was <strong>downloaded</strong>" : "Eine öffentliche geteilte Datei oder ein öffentlicher geteilter Ordner wurde <strong>heruntergeladen</strong>",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
namespace OC\Files\Cache;
|
||||
|
||||
use OC\User\NoUserException;
|
||||
use OCP\Share_Backend_Collection;
|
||||
|
||||
/**
|
||||
@@ -53,7 +54,12 @@ class Shared_Cache extends Cache {
|
||||
}
|
||||
$source = \OC_Share_Backend_File::getSource($target, $this->storage->getMountPoint(), $this->storage->getItemType());
|
||||
if (isset($source['path']) && isset($source['fileOwner'])) {
|
||||
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
|
||||
try {
|
||||
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
|
||||
} catch(NoUserException $e) {
|
||||
\OC::$server->getLogger()->warning('The user \'' . $source['uid_owner'] . '\' of a share can\'t be retrieved.', array('app' => 'files_sharing'));
|
||||
return false;
|
||||
}
|
||||
$mounts = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
|
||||
if (is_array($mounts) and !empty($mounts)) {
|
||||
$fullPath = $mounts[0]->getMountPoint() . $source['path'];
|
||||
@@ -394,6 +400,28 @@ class Shared_Cache extends Cache {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* update the folder size and the size of all parent folders
|
||||
*
|
||||
* @param string|boolean $path
|
||||
* @param array $data (optional) meta data of the folder
|
||||
*/
|
||||
public function correctFolderSize($path, $data = null) {
|
||||
$this->calculateFolderSize($path, $data);
|
||||
if ($path !== '') {
|
||||
$parent = dirname($path);
|
||||
if ($parent === '.' or $parent === '/') {
|
||||
$parent = '';
|
||||
}
|
||||
$this->correctFolderSize($parent);
|
||||
} else {
|
||||
// bubble up to source cache
|
||||
$sourceCache = $this->getSourceCache($path);
|
||||
$parent = dirname($this->files[$path]);
|
||||
$sourceCache->correctFolderSize($parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the size of a folder and set it in the cache
|
||||
*
|
||||
|
||||
@@ -17,12 +17,12 @@ use OC_Files;
|
||||
use OC_Util;
|
||||
use OCP;
|
||||
use OCP\Template;
|
||||
use OCP\JSON;
|
||||
use OCP\Share;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\IRequest;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCP\AppFramework\Http\NotFoundResponse;
|
||||
use OC\URLGenerator;
|
||||
use OC\AppConfig;
|
||||
use OCP\ILogger;
|
||||
@@ -60,7 +60,7 @@ class ShareController extends Controller {
|
||||
* @param AppConfig $appConfig
|
||||
* @param OCP\IConfig $config
|
||||
* @param URLGenerator $urlGenerator
|
||||
* @param OC\User\Manager $userManager
|
||||
* @param OCP\IUserManager $userManager
|
||||
* @param ILogger $logger
|
||||
* @param OCP\Activity\IManager $activityManager
|
||||
*/
|
||||
@@ -70,7 +70,7 @@ class ShareController extends Controller {
|
||||
AppConfig $appConfig,
|
||||
OCP\IConfig $config,
|
||||
URLGenerator $urlGenerator,
|
||||
OC\User\Manager $userManager,
|
||||
OCP\IUserManager $userManager,
|
||||
ILogger $logger,
|
||||
OCP\Activity\IManager $activityManager) {
|
||||
parent::__construct($appName, $request);
|
||||
@@ -113,7 +113,7 @@ class ShareController extends Controller {
|
||||
public function authenticate($token, $password = '') {
|
||||
$linkItem = Share::getShareByToken($token, false);
|
||||
if($linkItem === false) {
|
||||
return new TemplateResponse('core', '404', array(), 'guest');
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
|
||||
$authenticate = Helper::authenticate($linkItem, $password);
|
||||
@@ -139,18 +139,11 @@ class ShareController extends Controller {
|
||||
// Check whether share exists
|
||||
$linkItem = Share::getShareByToken($token, false);
|
||||
if($linkItem === false) {
|
||||
return new TemplateResponse('core', '404', array(), 'guest');
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
|
||||
$shareOwner = $linkItem['uid_owner'];
|
||||
$originalSharePath = null;
|
||||
$rootLinkItem = OCP\Share::resolveReShare($linkItem);
|
||||
if (isset($rootLinkItem['uid_owner'])) {
|
||||
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
|
||||
OC_Util::tearDownFS();
|
||||
OC_Util::setupFS($rootLinkItem['uid_owner']);
|
||||
$originalSharePath = Filesystem::getPath($linkItem['file_source']);
|
||||
}
|
||||
$originalSharePath = $this->getPath($token);
|
||||
|
||||
// Share is password protected - check whether the user is permitted to access the share
|
||||
if (isset($linkItem['share_with']) && !Helper::authenticate($linkItem)) {
|
||||
@@ -161,12 +154,15 @@ class ShareController extends Controller {
|
||||
if (Filesystem::isReadable($originalSharePath . $path)) {
|
||||
$getPath = Filesystem::normalizePath($path);
|
||||
$originalSharePath .= $path;
|
||||
} else {
|
||||
throw new OCP\Files\NotFoundException();
|
||||
}
|
||||
|
||||
$file = basename($originalSharePath);
|
||||
|
||||
$shareTmpl = array();
|
||||
$shareTmpl = [];
|
||||
$shareTmpl['displayName'] = User::getDisplayName($shareOwner);
|
||||
$shareTmpl['owner'] = $shareOwner;
|
||||
$shareTmpl['filename'] = $file;
|
||||
$shareTmpl['directory_path'] = $linkItem['file_target'];
|
||||
$shareTmpl['mimetype'] = Filesystem::getMimeType($originalSharePath);
|
||||
@@ -204,6 +200,7 @@ class ShareController extends Controller {
|
||||
|
||||
$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', array('token' => $token));
|
||||
$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
|
||||
$shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
|
||||
|
||||
return new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
|
||||
}
|
||||
@@ -230,26 +227,48 @@ class ShareController extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$originalSharePath = self::getPath($token);
|
||||
|
||||
if (isset($originalSharePath) && Filesystem::isReadable($originalSharePath . $path)) {
|
||||
$originalSharePath = Filesystem::normalizePath($originalSharePath . $path);
|
||||
$type = \OC\Files\Filesystem::is_dir($originalSharePath) ? 'folder' : 'file';
|
||||
$args = $type === 'folder' ? array('dir' => $originalSharePath) : array('dir' => dirname($originalSharePath), 'scrollto' => basename($originalSharePath));
|
||||
$linkToFile = \OCP\Util::linkToAbsolute('files', 'index.php', $args);
|
||||
$subject = $type === 'folder' ? Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED : Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
|
||||
$this->activityManager->publishActivity(
|
||||
'files_sharing', $subject, array($originalSharePath), '', array(), $originalSharePath,
|
||||
$linkToFile, $linkItem['uid_owner'], Activity::TYPE_PUBLIC_LINKS, Activity::PRIORITY_MEDIUM);
|
||||
}
|
||||
|
||||
$files_list = null;
|
||||
if (!is_null($files)) { // download selected files
|
||||
$files_list = json_decode($files);
|
||||
// in case we get only a single file
|
||||
if ($files_list === NULL) {
|
||||
if ($files_list === null) {
|
||||
$files_list = array($files);
|
||||
}
|
||||
}
|
||||
|
||||
$originalSharePath = self::getPath($token);
|
||||
|
||||
// Create the activities
|
||||
if (isset($originalSharePath) && Filesystem::isReadable($originalSharePath . $path)) {
|
||||
$originalSharePath = Filesystem::normalizePath($originalSharePath . $path);
|
||||
$isDir = \OC\Files\Filesystem::is_dir($originalSharePath);
|
||||
|
||||
$activities = [];
|
||||
if (!$isDir) {
|
||||
// Single file public share
|
||||
$activities[$originalSharePath] = Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
|
||||
} else if (!empty($files_list)) {
|
||||
// Only some files are downloaded
|
||||
foreach ($files_list as $file) {
|
||||
$filePath = Filesystem::normalizePath($originalSharePath . '/' . $file);
|
||||
$isDir = \OC\Files\Filesystem::is_dir($filePath);
|
||||
$activities[$filePath] = ($isDir) ? Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED : Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
|
||||
}
|
||||
} else {
|
||||
// The folder is downloaded
|
||||
$activities[$originalSharePath] = Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
|
||||
}
|
||||
|
||||
foreach ($activities as $filePath => $subject) {
|
||||
$this->activityManager->publishActivity(
|
||||
'files_sharing', $subject, array($filePath), '', array(),
|
||||
$filePath, '', $linkItem['uid_owner'], Activity::TYPE_PUBLIC_LINKS, Activity::PRIORITY_MEDIUM
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// download selected files
|
||||
if (!is_null($files)) {
|
||||
// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
|
||||
// after dispatching the request which results in a "Cannot modify header information" notice.
|
||||
OC_Files::get($originalSharePath, $files_list, $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
||||
@@ -263,22 +282,29 @@ class ShareController extends Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $token
|
||||
* @return null|string
|
||||
* @param string $token
|
||||
* @return string Resolved file path of the token
|
||||
* @throws \Exception In case share could not get properly resolved
|
||||
*/
|
||||
private function getPath($token) {
|
||||
$linkItem = Share::getShareByToken($token, false);
|
||||
$path = null;
|
||||
if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
|
||||
// seems to be a valid share
|
||||
$rootLinkItem = Share::resolveReShare($linkItem);
|
||||
if (isset($rootLinkItem['uid_owner'])) {
|
||||
JSON::checkUserExists($rootLinkItem['uid_owner']);
|
||||
if(!$this->userManager->userExists($rootLinkItem['uid_owner'])) {
|
||||
throw new \Exception('Owner of the share does not exist anymore');
|
||||
}
|
||||
OC_Util::tearDownFS();
|
||||
OC_Util::setupFS($rootLinkItem['uid_owner']);
|
||||
$path = Filesystem::getPath($linkItem['file_source']);
|
||||
|
||||
if(!empty($path) && Filesystem::isReadable($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
|
||||
throw new \Exception('No file found belonging to file.');
|
||||
}
|
||||
}
|
||||
|
||||
+87
-30
@@ -9,6 +9,7 @@
|
||||
namespace OCA\Files_Sharing\External;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OCP\Files;
|
||||
|
||||
class Manager {
|
||||
const STORAGE = '\OCA\Files_Sharing\External\Storage';
|
||||
@@ -29,7 +30,7 @@ class Manager {
|
||||
private $mountManager;
|
||||
|
||||
/**
|
||||
* @var \OC\Files\Storage\StorageFactory
|
||||
* @var \OCP\Files\Storage\IStorageFactory
|
||||
*/
|
||||
private $storageLoader;
|
||||
|
||||
@@ -41,12 +42,12 @@ class Manager {
|
||||
/**
|
||||
* @param \OCP\IDBConnection $connection
|
||||
* @param \OC\Files\Mount\Manager $mountManager
|
||||
* @param \OC\Files\Storage\StorageFactory $storageLoader
|
||||
* @param \OCP\Files\Storage\IStorageFactory $storageLoader
|
||||
* @param \OC\HTTPHelper $httpHelper
|
||||
* @param string $uid
|
||||
*/
|
||||
public function __construct(\OCP\IDBConnection $connection, \OC\Files\Mount\Manager $mountManager,
|
||||
\OC\Files\Storage\StorageFactory $storageLoader, \OC\HTTPHelper $httpHelper, $uid) {
|
||||
\OCP\Files\Storage\IStorageFactory $storageLoader, \OC\HTTPHelper $httpHelper, $uid) {
|
||||
$this->connection = $connection;
|
||||
$this->mountManager = $mountManager;
|
||||
$this->storageLoader = $storageLoader;
|
||||
@@ -65,33 +66,64 @@ class Manager {
|
||||
* @param boolean $accepted
|
||||
* @param string $user
|
||||
* @param int $remoteId
|
||||
* @return mixed
|
||||
* @return Mount|null
|
||||
*/
|
||||
public function addShare($remote, $token, $password, $name, $owner, $accepted=false, $user = null, $remoteId = -1) {
|
||||
|
||||
$user = $user ? $user : $this->uid;
|
||||
$accepted = $accepted ? 1 : 0;
|
||||
$name = Filesystem::normalizePath('/' . $name);
|
||||
|
||||
$mountPoint = Filesystem::normalizePath('/' . $name);
|
||||
if (!$accepted) {
|
||||
// To avoid conflicts with the mount point generation later,
|
||||
// we only use a temporary mount point name here. The real
|
||||
// mount point name will be generated when accepting the share,
|
||||
// using the original share item name.
|
||||
$tmpMountPointName = '{{TemporaryMountPointName#' . $name . '}}';
|
||||
$mountPoint = $tmpMountPointName;
|
||||
$hash = md5($tmpMountPointName);
|
||||
$data = [
|
||||
'remote' => $remote,
|
||||
'share_token' => $token,
|
||||
'password' => $password,
|
||||
'name' => $name,
|
||||
'owner' => $owner,
|
||||
'user' => $user,
|
||||
'mountpoint' => $mountPoint,
|
||||
'mountpoint_hash' => $hash,
|
||||
'accepted' => $accepted,
|
||||
'remote_id' => $remoteId,
|
||||
];
|
||||
|
||||
$i = 1;
|
||||
while (!$this->connection->insertIfNotExist('*PREFIX*share_external', $data, ['user', 'mountpoint_hash'])) {
|
||||
// The external share already exists for the user
|
||||
$data['mountpoint'] = $tmpMountPointName . '-' . $i;
|
||||
$data['mountpoint_hash'] = md5($data['mountpoint']);
|
||||
$i++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
$mountPoint = Files::buildNotExistingFileName('/', $name);
|
||||
$mountPoint = Filesystem::normalizePath('/' . $mountPoint);
|
||||
$hash = md5($mountPoint);
|
||||
|
||||
$query = $this->connection->prepare('
|
||||
INSERT INTO `*PREFIX*share_external`
|
||||
(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
');
|
||||
$hash = md5($mountPoint);
|
||||
$query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId));
|
||||
|
||||
if ($accepted) {
|
||||
$options = array(
|
||||
'remote' => $remote,
|
||||
'token' => $token,
|
||||
'password' => $password,
|
||||
'mountpoint' => $mountPoint,
|
||||
'owner' => $owner
|
||||
);
|
||||
return $this->mountShare($options);
|
||||
}
|
||||
$options = array(
|
||||
'remote' => $remote,
|
||||
'token' => $token,
|
||||
'password' => $password,
|
||||
'mountpoint' => $mountPoint,
|
||||
'owner' => $owner
|
||||
);
|
||||
return $this->mountShare($options);
|
||||
}
|
||||
|
||||
private function setupMounts() {
|
||||
@@ -124,7 +156,7 @@ class Manager {
|
||||
*/
|
||||
private function getShare($id) {
|
||||
$getShare = $this->connection->prepare('
|
||||
SELECT `remote`, `share_token`
|
||||
SELECT `remote`, `remote_id`, `share_token`, `name`
|
||||
FROM `*PREFIX*share_external`
|
||||
WHERE `id` = ? AND `user` = ?');
|
||||
$result = $getShare->execute(array($id, $this->uid));
|
||||
@@ -142,12 +174,18 @@ class Manager {
|
||||
$share = $this->getShare($id);
|
||||
|
||||
if ($share) {
|
||||
$mountPoint = Files::buildNotExistingFileName('/', $share['name']);
|
||||
$mountPoint = Filesystem::normalizePath('/' . $mountPoint);
|
||||
$hash = md5($mountPoint);
|
||||
|
||||
$acceptShare = $this->connection->prepare('
|
||||
UPDATE `*PREFIX*share_external`
|
||||
SET `accepted` = ?
|
||||
SET `accepted` = ?,
|
||||
`mountpoint` = ?,
|
||||
`mountpoint_hash` = ?
|
||||
WHERE `id` = ? AND `user` = ?');
|
||||
$acceptShare->execute(array(1, $id, $this->uid));
|
||||
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $id, 'accept');
|
||||
$acceptShare->execute(array(1, $mountPoint, $hash, $id, $this->uid));
|
||||
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'accept');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +202,7 @@ class Manager {
|
||||
$removeShare = $this->connection->prepare('
|
||||
DELETE FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?');
|
||||
$removeShare->execute(array($id, $this->uid));
|
||||
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $id, 'decline');
|
||||
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,13 +211,13 @@ class Manager {
|
||||
*
|
||||
* @param string $remote
|
||||
* @param string $token
|
||||
* @param int $id
|
||||
* @param int $remoteId Share id on the remote host
|
||||
* @param string $feedback
|
||||
* @return boolean
|
||||
*/
|
||||
private function sendFeedbackToRemote($remote, $token, $id, $feedback) {
|
||||
private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) {
|
||||
|
||||
$url = $remote . \OCP\Share::BASE_PATH_TO_SHARE_API . '/' . $id . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT;
|
||||
$url = rtrim($remote, '/') . \OCP\Share::BASE_PATH_TO_SHARE_API . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT;
|
||||
$fields = array('token' => $token);
|
||||
|
||||
$result = $this->httpHelper->post($url, $fields);
|
||||
@@ -315,10 +353,29 @@ class Manager {
|
||||
* @return array list of open server-to-server shares
|
||||
*/
|
||||
public function getOpenShares() {
|
||||
$openShares = $this->connection->prepare('SELECT * FROM `*PREFIX*share_external` WHERE `accepted` = ? AND `user` = ?');
|
||||
$result = $openShares->execute(array(0, $this->uid));
|
||||
|
||||
return $result ? $openShares->fetchAll() : array();
|
||||
|
||||
return $this->getShares(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return a list of shares for the user
|
||||
*
|
||||
* @param bool|null $accepted True for accepted only,
|
||||
* false for not accepted,
|
||||
* null for all shares of the user
|
||||
* @return array list of open server-to-server shares
|
||||
*/
|
||||
private function getShares($accepted) {
|
||||
$query = 'SELECT * FROM `*PREFIX*share_external` WHERE `user` = ?';
|
||||
$parameters = [$this->uid];
|
||||
if (!is_null($accepted)) {
|
||||
$query .= ' AND `accepted` = ?';
|
||||
$parameters[] = (int) $accepted;
|
||||
}
|
||||
$query .= ' ORDER BY `id` ASC';
|
||||
|
||||
$shares = $this->connection->prepare($query);
|
||||
$result = $shares->execute($parameters);
|
||||
|
||||
return $result ? $shares->fetchAll() : [];
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -70,7 +70,7 @@ class Storage extends DAV implements ISharedStorage {
|
||||
'host' => $host,
|
||||
'root' => $root,
|
||||
'user' => $options['token'],
|
||||
'password' => $options['password']
|
||||
'password' => (string)$options['password']
|
||||
));
|
||||
}
|
||||
|
||||
@@ -237,7 +237,8 @@ class Storage extends DAV implements ISharedStorage {
|
||||
$errorMessage = curl_error($ch);
|
||||
curl_close($ch);
|
||||
if (!empty($errorMessage)) {
|
||||
throw new \Exception($errorMessage);
|
||||
\OCP\Util::writeLog('files_sharing', 'Error getting remote share info: ' . $errorMessage, \OCP\Util::ERROR);
|
||||
throw new StorageNotAvailableException($errorMessage);
|
||||
}
|
||||
|
||||
switch ($status) {
|
||||
|
||||
@@ -257,8 +257,21 @@ class Helper {
|
||||
*/
|
||||
public static function getShareFolder() {
|
||||
$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
|
||||
$shareFolder = \OC\Files\Filesystem::normalizePath($shareFolder);
|
||||
|
||||
if (!\OC\Files\Filesystem::file_exists($shareFolder)) {
|
||||
$dir = '';
|
||||
$subdirs = explode('/', $shareFolder);
|
||||
foreach ($subdirs as $subdir) {
|
||||
$dir = $dir . '/' . $subdir;
|
||||
if (!\OC\Files\Filesystem::is_dir($dir)) {
|
||||
\OC\Files\Filesystem::mkdir($dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $shareFolder;
|
||||
|
||||
return \OC\Files\Filesystem::normalizePath($shareFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace OCA\Files_Sharing\Middleware;
|
||||
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Http\NotFoundResponse;
|
||||
use OCP\AppFramework\Middleware;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\IConfig;
|
||||
@@ -59,7 +60,7 @@ class SharingCheckMiddleware extends Middleware {
|
||||
* @return TemplateResponse
|
||||
*/
|
||||
public function afterException($controller, $methodName, \Exception $exception){
|
||||
return new TemplateResponse('core', '404', array(), 'guest');
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Sharing;
|
||||
|
||||
use OC\Files\Cache\Cache;
|
||||
|
||||
class ReadOnlyCache extends Cache {
|
||||
public function get($path) {
|
||||
$data = parent::get($path);
|
||||
$data['permissions'] &= (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getFolderContents($path) {
|
||||
$content = parent::getFolderContents($path);
|
||||
foreach ($content as &$data) {
|
||||
$data['permissions'] &= (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_SHARE);
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
namespace OCA\Files_Sharing;
|
||||
|
||||
use OC\Files\Cache\Wrapper\CachePermissionsMask;
|
||||
use OC\Files\Storage\Wrapper\Wrapper;
|
||||
use OCP\Constants;
|
||||
|
||||
class ReadOnlyWrapper extends Wrapper {
|
||||
public function isUpdatable($path) {
|
||||
@@ -51,6 +53,7 @@ class ReadOnlyWrapper extends Wrapper {
|
||||
if (!$storage) {
|
||||
$storage = $this;
|
||||
}
|
||||
return new ReadOnlyCache($storage);
|
||||
$sourceCache = $this->storage->getCache($path, $storage);
|
||||
return new CachePermissionsMask($sourceCache, Constants::PERMISSION_READ | Constants::PERMISSION_SHARE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ class SharedMount extends MountPoint implements MoveableMount {
|
||||
$mountPoint = basename($share['file_target']);
|
||||
$parent = dirname($share['file_target']);
|
||||
|
||||
while (!\OC\Files\Filesystem::is_dir($parent)) {
|
||||
$parent = dirname($parent);
|
||||
if (!\OC\Files\Filesystem::is_dir($parent)) {
|
||||
$parent = Helper::getShareFolder();
|
||||
}
|
||||
|
||||
$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
|
||||
|
||||
@@ -293,26 +293,34 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
|
||||
// we need the paths relative to data/user/files
|
||||
$relPath1 = $this->getMountPoint() . '/' . $path1;
|
||||
$relPath2 = $this->getMountPoint() . '/' . $path2;
|
||||
$pathinfo = pathinfo($relPath1);
|
||||
|
||||
// check for update permissions on the share
|
||||
if ($this->isUpdatable('')) {
|
||||
|
||||
$pathinfo = pathinfo($relPath1);
|
||||
// for part files we need to ask for the owner and path from the parent directory because
|
||||
// the file cache doesn't return any results for part files
|
||||
if (isset($pathinfo['extension']) && $pathinfo['extension'] === 'part') {
|
||||
list($user1, $path1) = \OCA\Files_Sharing\Helper::getUidAndFilename($pathinfo['dirname']);
|
||||
$path1 = $path1 . '/' . $pathinfo['basename'];
|
||||
} else {
|
||||
list($user1, $path1) = \OCA\Files_Sharing\Helper::getUidAndFilename($relPath1);
|
||||
$isPartFile = (isset($pathinfo['extension']) && $pathinfo['extension'] === 'part');
|
||||
$targetExists = $this->file_exists($path2);
|
||||
$sameFolder = (dirname($relPath1) === dirname($relPath2));
|
||||
if ($targetExists || ($sameFolder && !$isPartFile)) {
|
||||
// note that renaming a share mount point is always allowed
|
||||
if (!$this->isUpdatable('')) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!$this->isCreatable('')) {
|
||||
return false;
|
||||
}
|
||||
$targetFilename = basename($relPath2);
|
||||
list($user2, $path2) = \OCA\Files_Sharing\Helper::getUidAndFilename(dirname($relPath2));
|
||||
$rootView = new \OC\Files\View('');
|
||||
return $rootView->rename('/' . $user1 . '/files/' . $path1, '/' . $user2 . '/files/' . $path2 . '/' . $targetFilename);
|
||||
}
|
||||
|
||||
return false;
|
||||
// for part files we need to ask for the owner and path from the parent directory because
|
||||
// the file cache doesn't return any results for part files
|
||||
if ($isPartFile) {
|
||||
list($user1, $path1) = \OCA\Files_Sharing\Helper::getUidAndFilename($pathinfo['dirname']);
|
||||
$path1 = $path1 . '/' . $pathinfo['basename'];
|
||||
} else {
|
||||
list($user1, $path1) = \OCA\Files_Sharing\Helper::getUidAndFilename($relPath1);
|
||||
}
|
||||
$targetFilename = basename($relPath2);
|
||||
list($user2, $path2) = \OCA\Files_Sharing\Helper::getUidAndFilename(dirname($relPath2));
|
||||
$rootView = new \OC\Files\View('');
|
||||
return $rootView->rename('/' . $user1 . '/files/' . $path1, '/' . $user2 . '/files/' . $path2 . '/' . $targetFilename);
|
||||
}
|
||||
|
||||
public function copy($path1, $path2) {
|
||||
@@ -343,13 +351,25 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
|
||||
case 'xb':
|
||||
case 'a':
|
||||
case 'ab':
|
||||
$exists = $this->file_exists($path);
|
||||
if ($exists && !$this->isUpdatable($path)) {
|
||||
$creatable = $this->isCreatable($path);
|
||||
$updatable = $this->isUpdatable($path);
|
||||
// if neither permissions given, no need to continue
|
||||
if (!$creatable && !$updatable) {
|
||||
return false;
|
||||
}
|
||||
if (!$exists && !$this->isCreatable(dirname($path))) {
|
||||
|
||||
$exists = $this->file_exists($path);
|
||||
// if a file exists, updatable permissions are required
|
||||
if ($exists && !$updatable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// part file is allowed if !$creatable but the final file is $updatable
|
||||
if (pathinfo($path, PATHINFO_EXTENSION) !== 'part') {
|
||||
if (!$exists && !$creatable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$info = array(
|
||||
'target' => $this->getMountPoint() . $path,
|
||||
|
||||
@@ -145,10 +145,10 @@ class Shared_Updater {
|
||||
$shareType = $params['shareType'];
|
||||
|
||||
if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
|
||||
self::correctUsersFolder($shareWith, '/');
|
||||
self::correctUsersFolder($shareWith, $params['fileTarget']);
|
||||
} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
|
||||
foreach (\OC_Group::usersInGroup($shareWith) as $user) {
|
||||
self::correctUsersFolder($user, '/');
|
||||
self::correctUsersFolder($user, $params['fileTarget']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ $server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
|
||||
// wait with registering these until auth is handled and the filesystem is setup
|
||||
$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $authBackend) {
|
||||
$share = $authBackend->getShare();
|
||||
$owner = $share['uid_owner'];
|
||||
$rootShare = \OCP\Share::resolveReShare($share);
|
||||
$owner = $rootShare['uid_owner'];
|
||||
$isWritable = $share['permissions'] & (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_CREATE);
|
||||
$fileId = $share['file_source'];
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
|
||||
if ($_['server2serversharing']) {
|
||||
?>
|
||||
<span id="save" data-protected="<?php p($_['protected']) ?>"
|
||||
data-owner="<?php p($_['displayName']) ?>" data-name="<?php p($_['filename']) ?>">
|
||||
data-owner-display-name="<?php p($_['displayName']) ?>" data-owner="<?php p($_['owner']) ?>" data-name="<?php p($_['filename']) ?>">
|
||||
<button id="save-button"><?php p($l->t('Add to your ownCloud')) ?></button>
|
||||
<form class="save-form hidden" action="#">
|
||||
<input type="text" id="remote_address" placeholder="example.com/owncloud"/>
|
||||
@@ -80,7 +80,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
|
||||
<?php if (isset($_['folder'])): ?>
|
||||
<?php print_unescaped($_['folder']); ?>
|
||||
<?php else: ?>
|
||||
<?php if (substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'video'): ?>
|
||||
<?php if ($_['previewEnabled'] && substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'video'): ?>
|
||||
<div id="imgframe">
|
||||
<video tabindex="0" controls="" preload="none">
|
||||
<source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" />
|
||||
@@ -91,7 +91,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
|
||||
<div id="imgframe"></div>
|
||||
<?php endif; ?>
|
||||
<div class="directDownload">
|
||||
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
|
||||
<a href="<?php p($_['downloadURL']); ?>" id="downloadFile" class="button">
|
||||
<img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
|
||||
<?php p($l->t('Download %s', array($_['filename'])))?> (<?php p($_['fileSize']) ?>)
|
||||
</a>
|
||||
|
||||
@@ -851,7 +851,6 @@ class Test_Files_Sharing_Api extends TestCase {
|
||||
$this->assertEquals('1', $newUserShare['permissions']);
|
||||
|
||||
// update password for link share
|
||||
|
||||
$this->assertTrue(empty($linkShare['share_with']));
|
||||
|
||||
$params = array();
|
||||
@@ -876,6 +875,29 @@ class Test_Files_Sharing_Api extends TestCase {
|
||||
$this->assertTrue(is_array($newLinkShare));
|
||||
$this->assertTrue(!empty($newLinkShare['share_with']));
|
||||
|
||||
// Remove password for link share
|
||||
$params = array();
|
||||
$params['id'] = $linkShare['id'];
|
||||
$params['_put'] = array();
|
||||
$params['_put']['password'] = '';
|
||||
|
||||
$result = \OCA\Files_Sharing\API\Local::updateShare($params);
|
||||
|
||||
$this->assertTrue($result->succeeded());
|
||||
|
||||
$items = \OCP\Share::getItemShared('file', $linkShare['file_source']);
|
||||
|
||||
$newLinkShare = null;
|
||||
foreach ($items as $item) {
|
||||
if ($item['share_type'] === \OCP\Share::SHARE_TYPE_LINK) {
|
||||
$newLinkShare = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertTrue(is_array($newLinkShare));
|
||||
$this->assertTrue(empty($newLinkShare['share_with']));
|
||||
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
@@ -1008,6 +1030,24 @@ class Test_Files_Sharing_Api extends TestCase {
|
||||
$this->assertTrue(is_array($updatedLinkShare));
|
||||
$this->assertEquals($dateWithinRange->format('Y-m-d') . ' 00:00:00', $updatedLinkShare['expiration']);
|
||||
|
||||
|
||||
// Try to remove expire date
|
||||
$params = array();
|
||||
$params['id'] = $linkShare['id'];
|
||||
$params['_put'] = ['expireDate' => ''];
|
||||
|
||||
$result = \OCA\Files_Sharing\API\Local::updateShare($params);
|
||||
|
||||
$this->assertFalse($result->succeeded());
|
||||
|
||||
$items = \OCP\Share::getItemShared('file', $linkShare['file_source']);
|
||||
|
||||
$updatedLinkShare = reset($items);
|
||||
|
||||
// date shouldn't be changed
|
||||
$this->assertTrue(is_array($updatedLinkShare));
|
||||
$this->assertEquals($dateWithinRange->format('Y-m-d') . ' 00:00:00', $updatedLinkShare['expiration']);
|
||||
|
||||
// cleanup
|
||||
$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
|
||||
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace OCA\Files_Sharing\Controllers;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OCA\Files_Sharing\Application;
|
||||
use OCP\AppFramework\Http\NotFoundResponse;
|
||||
use OCP\AppFramework\IAppContainer;
|
||||
use OCP\Files;
|
||||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
@@ -24,7 +25,7 @@ use OC\URLGenerator;
|
||||
/**
|
||||
* @package OCA\Files_Sharing\Controllers
|
||||
*/
|
||||
class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
class ShareControllerTest extends \Test\TestCase {
|
||||
|
||||
/** @var IAppContainer */
|
||||
private $container;
|
||||
@@ -40,6 +41,8 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
private $urlGenerator;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$app = new Application();
|
||||
$this->container = $app->getContainer();
|
||||
$this->container['Config'] = $this->getMockBuilder('\OCP\IConfig')
|
||||
@@ -49,6 +52,8 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->container['URLGenerator'] = $this->getMockBuilder('\OC\URLGenerator')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->container['UserManager'] = $this->getMockBuilder('\OCP\IUserManager')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->urlGenerator = $this->container['URLGenerator'];
|
||||
$this->shareController = $this->container['ShareController'];
|
||||
|
||||
@@ -89,6 +94,8 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
// Set old user
|
||||
\OC_User::setUserId($this->oldUser);
|
||||
\OC_Util::setupFS($this->oldUser);
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testShowAuthenticate() {
|
||||
@@ -115,7 +122,7 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
public function testAuthenticate() {
|
||||
// Test without a not existing token
|
||||
$response = $this->shareController->authenticate('ThisTokenShouldHopefullyNeverExistSoThatTheUnitTestWillAlwaysPass :)');
|
||||
$expectedResponse = new TemplateResponse('core', '404', array(), 'guest');
|
||||
$expectedResponse = new NotFoundResponse();
|
||||
$this->assertEquals($expectedResponse, $response);
|
||||
|
||||
// Test with a valid password
|
||||
@@ -130,9 +137,14 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
public function testShowShare() {
|
||||
$this->container['UserManager']->expects($this->exactly(2))
|
||||
->method('userExists')
|
||||
->with($this->user)
|
||||
->will($this->returnValue(true));
|
||||
|
||||
// Test without a not existing token
|
||||
$response = $this->shareController->showShare('ThisTokenShouldHopefullyNeverExistSoThatTheUnitTestWillAlwaysPass :)');
|
||||
$expectedResponse = new TemplateResponse('core', '404', array(), 'guest');
|
||||
$expectedResponse = new NotFoundResponse();
|
||||
$this->assertEquals($expectedResponse, $response);
|
||||
|
||||
// Test with a password protected share and no authentication
|
||||
@@ -146,6 +158,7 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
$response = $this->shareController->showShare($this->token);
|
||||
$sharedTmplParams = array(
|
||||
'displayName' => $this->user,
|
||||
'owner' => $this->user,
|
||||
'filename' => 'file1.txt',
|
||||
'directory_path' => '/file1.txt',
|
||||
'mimetype' => 'text/plain',
|
||||
@@ -158,6 +171,7 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
'fileSize' => '33 B',
|
||||
'nonHumanFileSize' => 33,
|
||||
'maxSizeAnimateGif' => 10,
|
||||
'previewEnabled' => true,
|
||||
);
|
||||
$expectedResponse = new TemplateResponse($this->container['AppName'], 'public', $sharedTmplParams, 'base');
|
||||
$this->assertEquals($expectedResponse, $response);
|
||||
@@ -170,4 +184,54 @@ class ShareControllerTest extends \PHPUnit_Framework_TestCase {
|
||||
array('token' => $this->token)));
|
||||
$this->assertEquals($expectedResponse, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage No file found belonging to file.
|
||||
*/
|
||||
public function testShowShareWithDeletedFile() {
|
||||
$this->container['UserManager']->expects($this->once())
|
||||
->method('userExists')
|
||||
->with($this->user)
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$view = new View('/'. $this->user . '/files');
|
||||
$view->unlink('file1.txt');
|
||||
$linkItem = Share::getShareByToken($this->token, false);
|
||||
\OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
|
||||
$this->shareController->showShare($this->token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage No file found belonging to file.
|
||||
*/
|
||||
public function testDownloadShareWithDeletedFile() {
|
||||
$this->container['UserManager']->expects($this->once())
|
||||
->method('userExists')
|
||||
->with($this->user)
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$view = new View('/'. $this->user . '/files');
|
||||
$view->unlink('file1.txt');
|
||||
$linkItem = Share::getShareByToken($this->token, false);
|
||||
\OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
|
||||
$this->shareController->downloadShare($this->token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage Owner of the share does not exist anymore
|
||||
*/
|
||||
public function testShowShareWithNotExistingUser() {
|
||||
$this->container['UserManager']->expects($this->once())
|
||||
->method('userExists')
|
||||
->with($this->user)
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$linkItem = Share::getShareByToken($this->token, false);
|
||||
\OC::$server->getSession()->set('public_link_authenticated', $linkItem['id']);
|
||||
$this->shareController->showShare($this->token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Joas Schilling
|
||||
* @copyright 2015 Joas Schilling <nickvergessen@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Sharing\Tests\External;
|
||||
|
||||
use OC\Files\Storage\StorageFactory;
|
||||
use OCA\Files_Sharing\External\Manager;
|
||||
use OCA\Files_Sharing\Tests\TestCase;
|
||||
|
||||
class ManagerTest extends TestCase {
|
||||
|
||||
/** @var Manager **/
|
||||
private $manager;
|
||||
|
||||
/** @var \OC\Files\Mount\Manager */
|
||||
private $mountManager;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $httpHelper;
|
||||
|
||||
private $uid;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->uid = $this->getUniqueID('user');
|
||||
$this->mountManager = new \OC\Files\Mount\Manager();
|
||||
$this->httpHelper = $httpHelper = $this->getMockBuilder('\OC\HTTPHelper')->disableOriginalConstructor()->getMock();
|
||||
/** @var \OC\HTTPHelper $httpHelper */
|
||||
$this->manager = new Manager(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
$this->mountManager,
|
||||
new StorageFactory(),
|
||||
$httpHelper,
|
||||
$this->uid
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddShare() {
|
||||
|
||||
$shareData1 = [
|
||||
'remote' => 'http://localhost',
|
||||
'token' => 'token1',
|
||||
'password' => '',
|
||||
'name' => '/SharedFolder',
|
||||
'owner' => 'foobar',
|
||||
'accepted' => false,
|
||||
'user' => $this->uid,
|
||||
];
|
||||
$shareData2 = $shareData1;
|
||||
$shareData2['token'] = 'token2';
|
||||
$shareData3 = $shareData1;
|
||||
$shareData3['token'] = 'token3';
|
||||
|
||||
// Add a share for "user"
|
||||
$this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData1));
|
||||
$openShares = $this->manager->getOpenShares();
|
||||
$this->assertCount(1, $openShares);
|
||||
$this->assertExternalShareEntry($shareData1, $openShares[0], 1, '{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
|
||||
\Test_Helper::invokePrivate($this->manager, 'setupMounts');
|
||||
$this->assertNotMount('SharedFolder');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
|
||||
// Add a second share for "user" with the same name
|
||||
$this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData2));
|
||||
$openShares = $this->manager->getOpenShares();
|
||||
$this->assertCount(2, $openShares);
|
||||
$this->assertExternalShareEntry($shareData1, $openShares[0], 1, '{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
// New share falls back to "-1" appendix, because the name is already taken
|
||||
$this->assertExternalShareEntry($shareData2, $openShares[1], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1');
|
||||
|
||||
\Test_Helper::invokePrivate($this->manager, 'setupMounts');
|
||||
$this->assertNotMount('SharedFolder');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1');
|
||||
|
||||
$this->httpHelper->expects($this->at(0))
|
||||
->method('post')
|
||||
->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[0]['remote_id']), $this->anything());
|
||||
|
||||
// Accept the first share
|
||||
$this->manager->acceptShare($openShares[0]['id']);
|
||||
|
||||
// Check remaining shares - Accepted
|
||||
$acceptedShares = \Test_Helper::invokePrivate($this->manager, 'getShares', [true]);
|
||||
$this->assertCount(1, $acceptedShares);
|
||||
$shareData1['accepted'] = true;
|
||||
$this->assertExternalShareEntry($shareData1, $acceptedShares[0], 1, $shareData1['name']);
|
||||
// Check remaining shares - Open
|
||||
$openShares = $this->manager->getOpenShares();
|
||||
$this->assertCount(1, $openShares);
|
||||
$this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1');
|
||||
|
||||
\Test_Helper::invokePrivate($this->manager, 'setupMounts');
|
||||
$this->assertMount($shareData1['name']);
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1');
|
||||
|
||||
// Add another share for "user" with the same name
|
||||
$this->assertSame(null, call_user_func_array([$this->manager, 'addShare'], $shareData3));
|
||||
$openShares = $this->manager->getOpenShares();
|
||||
$this->assertCount(2, $openShares);
|
||||
$this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1');
|
||||
// New share falls back to the original name (no "-\d", because the name is not taken)
|
||||
$this->assertExternalShareEntry($shareData3, $openShares[1], 3, '{{TemporaryMountPointName#' . $shareData3['name'] . '}}');
|
||||
|
||||
\Test_Helper::invokePrivate($this->manager, 'setupMounts');
|
||||
$this->assertMount($shareData1['name']);
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1');
|
||||
|
||||
$this->httpHelper->expects($this->at(0))
|
||||
->method('post')
|
||||
->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[1]['remote_id'] . '/decline'), $this->anything());
|
||||
|
||||
// Decline the third share
|
||||
$this->manager->declineShare($openShares[1]['id']);
|
||||
|
||||
\Test_Helper::invokePrivate($this->manager, 'setupMounts');
|
||||
$this->assertMount($shareData1['name']);
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1');
|
||||
|
||||
// Check remaining shares - Accepted
|
||||
$acceptedShares = \Test_Helper::invokePrivate($this->manager, 'getShares', [true]);
|
||||
$this->assertCount(1, $acceptedShares);
|
||||
$shareData1['accepted'] = true;
|
||||
$this->assertExternalShareEntry($shareData1, $acceptedShares[0], 1, $shareData1['name']);
|
||||
// Check remaining shares - Open
|
||||
$openShares = $this->manager->getOpenShares();
|
||||
$this->assertCount(1, $openShares);
|
||||
$this->assertExternalShareEntry($shareData2, $openShares[0], 2, '{{TemporaryMountPointName#' . $shareData2['name'] . '}}-1');
|
||||
|
||||
\Test_Helper::invokePrivate($this->manager, 'setupMounts');
|
||||
$this->assertMount($shareData1['name']);
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1');
|
||||
|
||||
$this->httpHelper->expects($this->at(0))
|
||||
->method('post')
|
||||
->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $openShares[0]['remote_id'] . '/decline'), $this->anything());
|
||||
$this->httpHelper->expects($this->at(1))
|
||||
->method('post')
|
||||
->with($this->stringStartsWith('http://localhost/ocs/v1.php/cloud/shares/' . $acceptedShares[0]['remote_id'] . '/decline'), $this->anything());
|
||||
|
||||
$this->manager->removeUserShares($this->uid);
|
||||
$this->assertEmpty(\Test_Helper::invokePrivate($this->manager, 'getShares', [null]), 'Asserting all shares for the user have been deleted');
|
||||
|
||||
$this->mountManager->clear();
|
||||
\Test_Helper::invokePrivate($this->manager, 'setupMounts');
|
||||
$this->assertNotMount($shareData1['name']);
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}');
|
||||
$this->assertNotMount('{{TemporaryMountPointName#' . $shareData1['name'] . '}}-1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $expected
|
||||
* @param array $actual
|
||||
* @param int $share
|
||||
* @param string $mountPoint
|
||||
*/
|
||||
protected function assertExternalShareEntry($expected, $actual, $share, $mountPoint) {
|
||||
$this->assertEquals($expected['remote'], $actual['remote'], 'Asserting remote of a share #' . $share);
|
||||
$this->assertEquals($expected['token'], $actual['share_token'], 'Asserting token of a share #' . $share);
|
||||
$this->assertEquals($expected['name'], $actual['name'], 'Asserting name of a share #' . $share);
|
||||
$this->assertEquals($expected['owner'], $actual['owner'], 'Asserting owner of a share #' . $share);
|
||||
$this->assertEquals($expected['accepted'], (int) $actual['accepted'], 'Asserting accept of a share #' . $share);
|
||||
$this->assertEquals($expected['user'], $actual['user'], 'Asserting user of a share #' . $share);
|
||||
$this->assertEquals($mountPoint, $actual['mountpoint'], 'Asserting mountpoint of a share #' . $share);
|
||||
}
|
||||
|
||||
private function assertMount($mountPoint) {
|
||||
$mountPoint = rtrim($mountPoint, '/');
|
||||
$mount = $this->mountManager->find($this->getFullPath($mountPoint));
|
||||
$this->assertInstanceOf('\OCA\Files_Sharing\External\Mount', $mount);
|
||||
$this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount);
|
||||
$this->assertEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/'));
|
||||
$storage = $mount->getStorage();
|
||||
$this->assertInstanceOf('\OCA\Files_Sharing\External\Storage', $storage);
|
||||
}
|
||||
|
||||
private function assertNotMount($mountPoint) {
|
||||
$mountPoint = rtrim($mountPoint, '/');
|
||||
$mount = $this->mountManager->find($this->getFullPath($mountPoint));
|
||||
if ($mount) {
|
||||
$this->assertInstanceOf('\OCP\Files\Mount\IMountPoint', $mount);
|
||||
$this->assertNotEquals($this->getFullPath($mountPoint), rtrim($mount->getMountPoint(), '/'));
|
||||
} else {
|
||||
$this->assertNull($mount);
|
||||
}
|
||||
}
|
||||
|
||||
private function getFullPath($path) {
|
||||
return '/' . $this->uid . '/files' . $path;
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,11 @@ class Test_Files_Sharing_Helper extends TestCase {
|
||||
function testSetGetShareFolder() {
|
||||
$this->assertSame('/', \OCA\Files_Sharing\Helper::getShareFolder());
|
||||
|
||||
\OCA\Files_Sharing\Helper::setShareFolder('/Shared');
|
||||
\OCA\Files_Sharing\Helper::setShareFolder('/Shared/Folder');
|
||||
|
||||
$this->assertSame('/Shared', \OCA\Files_Sharing\Helper::getShareFolder());
|
||||
$sharedFolder = \OCA\Files_Sharing\Helper::getShareFolder();
|
||||
$this->assertSame('/Shared/Folder', \OCA\Files_Sharing\Helper::getShareFolder());
|
||||
$this->assertTrue(\OC\Files\Filesystem::is_dir($sharedFolder));
|
||||
|
||||
// cleanup
|
||||
\OC::$server->getConfig()->deleteSystemValue('share_folder');
|
||||
|
||||
@@ -67,6 +67,7 @@ describe('OCA.Sharing external tests', function() {
|
||||
remote: 'http://example.com/owncloud',
|
||||
token: 'abcdefg',
|
||||
owner: 'theowner',
|
||||
ownerDisplayName: 'The Generous Owner',
|
||||
name: 'the share name'
|
||||
};
|
||||
});
|
||||
@@ -88,6 +89,7 @@ describe('OCA.Sharing external tests', function() {
|
||||
remote: 'http://example.com/owncloud',
|
||||
token: 'abcdefg',
|
||||
owner: 'theowner',
|
||||
ownerDisplayName: 'The Generous Owner',
|
||||
name: 'the share name',
|
||||
password: ''
|
||||
});
|
||||
@@ -104,6 +106,7 @@ describe('OCA.Sharing external tests', function() {
|
||||
remote: 'http://example.com/owncloud',
|
||||
token: 'abcdefg',
|
||||
owner: 'theowner',
|
||||
ownerDisplayName: 'The Generous Owner',
|
||||
name: 'the share name',
|
||||
password: 'thepassword'
|
||||
});
|
||||
@@ -148,6 +151,7 @@ describe('OCA.Sharing external tests', function() {
|
||||
remote: 'http://example.com/owncloud',
|
||||
token: 'abcdefg',
|
||||
owner: 'theowner',
|
||||
ownerDisplayName: 'The Generous Owner',
|
||||
name: 'the share name'
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Robin Appelman
|
||||
* @copyright 2015 Robin Appelman <icewind@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Files_sharing\Tests;
|
||||
|
||||
use OC\Files\View;
|
||||
|
||||
class Propagation extends TestCase {
|
||||
|
||||
public function testSizePropagationWhenOwnerChangesFile() {
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
|
||||
$recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
|
||||
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
|
||||
$ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
$ownerView->mkdir('/sharedfolder/subfolder');
|
||||
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar');
|
||||
|
||||
$sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false);
|
||||
\OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31);
|
||||
$ownerRootInfo = $ownerView->getFileInfo('', false);
|
||||
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
|
||||
$this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt'));
|
||||
$recipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
|
||||
// when file changed as owner
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
|
||||
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar');
|
||||
|
||||
// size of recipient's root stays the same
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
|
||||
$newRecipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
$this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize());
|
||||
|
||||
// size of owner's root increases
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
|
||||
$newOwnerRootInfo = $ownerView->getFileInfo('', false);
|
||||
$this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize());
|
||||
}
|
||||
|
||||
public function testSizePropagationWhenRecipientChangesFile() {
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
|
||||
$recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
|
||||
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
|
||||
$ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
$ownerView->mkdir('/sharedfolder/subfolder');
|
||||
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar');
|
||||
|
||||
$sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false);
|
||||
\OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31);
|
||||
$ownerRootInfo = $ownerView->getFileInfo('', false);
|
||||
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER1);
|
||||
$this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt'));
|
||||
$recipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
|
||||
// when file changed as recipient
|
||||
$recipientView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar');
|
||||
|
||||
// size of recipient's root stays the same
|
||||
$newRecipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
$this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize());
|
||||
|
||||
// size of owner's root increases
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
|
||||
$newOwnerRootInfo = $ownerView->getFileInfo('', false);
|
||||
$this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize());
|
||||
}
|
||||
}
|
||||
@@ -141,14 +141,20 @@ class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase {
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
\OC\Files\Filesystem::rename($this->filename, "newFileName");
|
||||
\OC\Files\Filesystem::rename($this->filename, $this->filename . '_renamed');
|
||||
|
||||
$this->assertTrue(\OC\Files\Filesystem::file_exists('newFileName'));
|
||||
$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename . '_renamed'));
|
||||
$this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename));
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
|
||||
$this->assertFalse(\OC\Files\Filesystem::file_exists("newFileName"));
|
||||
$this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename . '_renamed'));
|
||||
|
||||
// rename back to original name
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
\OC\Files\Filesystem::rename($this->filename . '_renamed', $this->filename);
|
||||
$this->assertFalse(\OC\Files\Filesystem::file_exists($this->filename . '_renamed'));
|
||||
$this->assertTrue(\OC\Files\Filesystem::file_exists($this->filename));
|
||||
|
||||
//cleanup
|
||||
\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
@@ -182,9 +182,8 @@ class Test_Files_Sharing_Storage extends OCA\Files_sharing\Tests\TestCase {
|
||||
// for the share root we expect:
|
||||
// the shared permissions (1)
|
||||
// the delete permission (8), to enable unshare
|
||||
// the update permission (2), to allow renaming of the mount point
|
||||
$rootInfo = \OC\Files\Filesystem::getFileInfo($this->folder);
|
||||
$this->assertSame(11, $rootInfo->getPermissions());
|
||||
$this->assertSame(9, $rootInfo->getPermissions());
|
||||
|
||||
// for the file within the shared folder we expect:
|
||||
// the shared permissions (1)
|
||||
@@ -199,6 +198,158 @@ class Test_Files_Sharing_Storage extends OCA\Files_sharing\Tests\TestCase {
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testFopenWithReadOnlyPermission() {
|
||||
$this->view->file_put_contents($this->folder . '/existing.txt', 'foo');
|
||||
$fileinfoFolder = $this->view->getFileInfo($this->folder);
|
||||
$result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ);
|
||||
$this->assertTrue($result);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
|
||||
// part file should be forbidden
|
||||
$handle = $user2View->fopen($this->folder . '/test.txt.part', 'w');
|
||||
$this->assertFalse($handle);
|
||||
|
||||
// regular file forbidden
|
||||
$handle = $user2View->fopen($this->folder . '/test.txt', 'w');
|
||||
$this->assertFalse($handle);
|
||||
|
||||
// rename forbidden
|
||||
$this->assertFalse($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing2.txt'));
|
||||
|
||||
// delete forbidden
|
||||
$this->assertFalse($user2View->unlink($this->folder . '/existing.txt'));
|
||||
|
||||
//cleanup
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testFopenWithCreateOnlyPermission() {
|
||||
$this->view->file_put_contents($this->folder . '/existing.txt', 'foo');
|
||||
$fileinfoFolder = $this->view->getFileInfo($this->folder);
|
||||
$result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE);
|
||||
$this->assertTrue($result);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
|
||||
// create part file allowed
|
||||
$handle = $user2View->fopen($this->folder . '/test.txt.part', 'w');
|
||||
$this->assertNotFalse($handle);
|
||||
fclose($handle);
|
||||
|
||||
// create regular file allowed
|
||||
$handle = $user2View->fopen($this->folder . '/test-create.txt', 'w');
|
||||
$this->assertNotFalse($handle);
|
||||
fclose($handle);
|
||||
|
||||
// rename file never allowed
|
||||
$this->assertFalse($user2View->rename($this->folder . '/test-create.txt', $this->folder . '/newtarget.txt'));
|
||||
$this->assertFalse($user2View->file_exists($this->folder . '/newtarget.txt'));
|
||||
|
||||
// rename file not allowed if target exists
|
||||
$this->assertFalse($user2View->rename($this->folder . '/newtarget.txt', $this->folder . '/existing.txt'));
|
||||
|
||||
// overwriting file not allowed
|
||||
$handle = $user2View->fopen($this->folder . '/existing.txt', 'w');
|
||||
$this->assertFalse($handle);
|
||||
|
||||
// overwrite forbidden (no update permission)
|
||||
$this->assertFalse($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/existing.txt'));
|
||||
|
||||
// delete forbidden
|
||||
$this->assertFalse($user2View->unlink($this->folder . '/existing.txt'));
|
||||
|
||||
//cleanup
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testFopenWithUpdateOnlyPermission() {
|
||||
$this->view->file_put_contents($this->folder . '/existing.txt', 'foo');
|
||||
$fileinfoFolder = $this->view->getFileInfo($this->folder);
|
||||
|
||||
$result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE);
|
||||
$this->assertTrue($result);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
|
||||
// create part file allowed
|
||||
$handle = $user2View->fopen($this->folder . '/test.txt.part', 'w');
|
||||
$this->assertNotFalse($handle);
|
||||
fclose($handle);
|
||||
|
||||
// create regular file not allowed
|
||||
$handle = $user2View->fopen($this->folder . '/test-create.txt', 'w');
|
||||
$this->assertFalse($handle);
|
||||
|
||||
// rename part file not allowed to non-existing file
|
||||
$this->assertFalse($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/nonexist.txt'));
|
||||
|
||||
// rename part file allowed to target existing file
|
||||
$this->assertTrue($user2View->rename($this->folder . '/test.txt.part', $this->folder . '/existing.txt'));
|
||||
$this->assertTrue($user2View->file_exists($this->folder . '/existing.txt'));
|
||||
|
||||
// rename regular file allowed
|
||||
$this->assertTrue($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing-renamed.txt'));
|
||||
$this->assertTrue($user2View->file_exists($this->folder . '/existing-renamed.txt'));
|
||||
|
||||
// overwriting file directly is allowed
|
||||
$handle = $user2View->fopen($this->folder . '/existing-renamed.txt', 'w');
|
||||
$this->assertNotFalse($handle);
|
||||
fclose($handle);
|
||||
|
||||
// delete forbidden
|
||||
$this->assertFalse($user2View->unlink($this->folder . '/existing-renamed.txt'));
|
||||
|
||||
//cleanup
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testFopenWithDeleteOnlyPermission() {
|
||||
$this->view->file_put_contents($this->folder . '/existing.txt', 'foo');
|
||||
$fileinfoFolder = $this->view->getFileInfo($this->folder);
|
||||
$result = \OCP\Share::shareItem('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_DELETE);
|
||||
$this->assertTrue($result);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
|
||||
// part file should be forbidden
|
||||
$handle = $user2View->fopen($this->folder . '/test.txt.part', 'w');
|
||||
$this->assertFalse($handle);
|
||||
|
||||
// regular file forbidden
|
||||
$handle = $user2View->fopen($this->folder . '/test.txt', 'w');
|
||||
$this->assertFalse($handle);
|
||||
|
||||
// rename forbidden
|
||||
$this->assertFalse($user2View->rename($this->folder . '/existing.txt', $this->folder . '/existing2.txt'));
|
||||
|
||||
// delete allowed
|
||||
$this->assertTrue($user2View->unlink($this->folder . '/existing.txt'));
|
||||
|
||||
//cleanup
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$result = \OCP\Share::unshare('folder', $fileinfoFolder['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
function testMountSharesOtherUser() {
|
||||
$folderInfo = $this->view->getFileInfo($this->folder);
|
||||
$fileInfo = $this->view->getFileInfo($this->filename);
|
||||
|
||||
@@ -115,14 +115,34 @@ class Test_Files_Sharing_Updater extends OCA\Files_sharing\Tests\TestCase {
|
||||
\OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin');
|
||||
}
|
||||
|
||||
public function shareFolderProvider() {
|
||||
return [
|
||||
['/'],
|
||||
['/my_shares'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* if a file gets shared the etag for the recipients root should change
|
||||
*
|
||||
* @dataProvider shareFolderProvider
|
||||
*
|
||||
* @param string $shareFolder share folder to use
|
||||
*/
|
||||
function testShareFile() {
|
||||
public function testShareFile($shareFolder) {
|
||||
$config = \OC::$server->getConfig();
|
||||
$oldShareFolder = $config->getSystemValue('share_folder');
|
||||
$config->setSystemValue('share_folder', $shareFolder);
|
||||
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$beforeShare = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagBeforeShare = $beforeShare->getEtag();
|
||||
$beforeShareRoot = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagBeforeShareRoot = $beforeShareRoot->getEtag();
|
||||
|
||||
\OC\Files\Filesystem::mkdir($shareFolder);
|
||||
|
||||
$beforeShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
|
||||
$etagBeforeShareDir = $beforeShareDir->getEtag();
|
||||
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder);
|
||||
@@ -131,17 +151,25 @@ class Test_Files_Sharing_Updater extends OCA\Files_sharing\Tests\TestCase {
|
||||
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$afterShare = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagAfterShare = $afterShare->getEtag();
|
||||
$afterShareRoot = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagAfterShareRoot = $afterShareRoot->getEtag();
|
||||
|
||||
$this->assertTrue(is_string($etagBeforeShare));
|
||||
$this->assertTrue(is_string($etagAfterShare));
|
||||
$this->assertTrue($etagBeforeShare !== $etagAfterShare);
|
||||
$afterShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
|
||||
$etagAfterShareDir = $afterShareDir->getEtag();
|
||||
|
||||
$this->assertTrue(is_string($etagBeforeShareRoot));
|
||||
$this->assertTrue(is_string($etagBeforeShareDir));
|
||||
$this->assertTrue(is_string($etagAfterShareRoot));
|
||||
$this->assertTrue(is_string($etagAfterShareDir));
|
||||
$this->assertTrue($etagBeforeShareRoot !== $etagAfterShareRoot);
|
||||
$this->assertTrue($etagBeforeShareDir !== $etagAfterShareDir);
|
||||
|
||||
// cleanup
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$result = \OCP\Share::unshare('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$config->setSystemValue('share_folder', $oldShareFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,5 +18,4 @@ To prevent a user from running out of disk space, the ownCloud Deleted files app
|
||||
<documentation>
|
||||
<user>user-trashbin</user>
|
||||
</documentation>
|
||||
<ocsid>166052</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.6.2
|
||||
0.6.3
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array("",""),
|
||||
"_%n file_::_%n files_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array("",""),
|
||||
"_%n file_::_%n files_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array("",""),
|
||||
"_%n file_::_%n files_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array("",""),
|
||||
"_%n file_::_%n files_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array(""),
|
||||
"_%n file_::_%n files_" => array("")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=1; plural=0;";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array("",""),
|
||||
"_%n file_::_%n files_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array(""),
|
||||
"_%n file_::_%n files_" => array("")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=1; plural=0;";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array("",""),
|
||||
"_%n file_::_%n files_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array(""),
|
||||
"_%n file_::_%n files_" => array("")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=1; plural=0;";
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n folder_::_%n folders_" => array("",""),
|
||||
"_%n file_::_%n files_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -61,14 +61,55 @@ class Storage extends Wrapper {
|
||||
self::$disableTrash = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename path1 to path2 by calling the wrapped storage.
|
||||
*
|
||||
* @param string $path1 first path
|
||||
* @param string $path2 second path
|
||||
*/
|
||||
public function rename($path1, $path2) {
|
||||
$result = $this->storage->rename($path1, $path2);
|
||||
if ($result === false) {
|
||||
// when rename failed, the post_rename hook isn't triggered,
|
||||
// but we still want to reenable the trash logic
|
||||
self::$disableTrash = false;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given file by moving it into the trashbin.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $path path of file or folder to delete
|
||||
*
|
||||
* @return bool true if the operation succeeded, false otherwise
|
||||
*/
|
||||
public function unlink($path) {
|
||||
return $this->doDelete($path, 'unlink');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given folder by moving it into the trashbin.
|
||||
*
|
||||
* @param string $path path of folder to delete
|
||||
*
|
||||
* @return bool true if the operation succeeded, false otherwise
|
||||
*/
|
||||
public function rmdir($path) {
|
||||
return $this->doDelete($path, 'rmdir');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the delete operation with the given method
|
||||
*
|
||||
* @param string $path path of file or folder to delete
|
||||
* @param string $method either "unlink" or "rmdir"
|
||||
*
|
||||
* @return bool true if the operation succeeded, false otherwise
|
||||
*/
|
||||
private function doDelete($path, $method) {
|
||||
if (self::$disableTrash) {
|
||||
return $this->storage->unlink($path);
|
||||
return call_user_func_array([$this->storage, $method], [$path]);
|
||||
}
|
||||
$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
|
||||
$result = true;
|
||||
@@ -81,14 +122,14 @@ class Storage extends Wrapper {
|
||||
// in cross-storage cases the file will be copied
|
||||
// but not deleted, so we delete it here
|
||||
if ($result) {
|
||||
$this->storage->unlink($path);
|
||||
call_user_func_array([$this->storage, $method], [$path]);
|
||||
}
|
||||
} else {
|
||||
$result = $this->storage->unlink($path);
|
||||
$result = call_user_func_array([$this->storage, $method], [$path]);
|
||||
}
|
||||
unset($this->deletedFiles[$normalized]);
|
||||
} else if ($this->storage->file_exists($path)) {
|
||||
$result = $this->storage->unlink($path);
|
||||
$result = call_user_func_array([$this->storage, $method], [$path]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
@@ -32,6 +32,13 @@ class Trashbin {
|
||||
// unit: percentage; 50% of available disk space/quota
|
||||
const DEFAULTMAXSIZE = 50;
|
||||
|
||||
/**
|
||||
* Whether versions have already be rescanned during this PHP request
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $scannedVersions = false;
|
||||
|
||||
public static function getUidAndFilename($filename) {
|
||||
$uid = \OC\Files\Filesystem::getOwner($filename);
|
||||
\OC\Files\Filesystem::initMountPoints($uid);
|
||||
@@ -151,6 +158,10 @@ class Trashbin {
|
||||
}
|
||||
|
||||
self::setUpTrash($user);
|
||||
if ($owner !== $user) {
|
||||
// also setup for owner
|
||||
self::setUpTrash($owner);
|
||||
}
|
||||
|
||||
$path_parts = pathinfo($file_path);
|
||||
|
||||
@@ -194,7 +205,7 @@ class Trashbin {
|
||||
\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_moveToTrash', array('filePath' => \OC\Files\Filesystem::normalizePath($file_path),
|
||||
'trashPath' => \OC\Files\Filesystem::normalizePath($filename . '.d' . $timestamp)));
|
||||
|
||||
$size += self::retainVersions($file_path, $filename, $timestamp);
|
||||
$size += self::retainVersions($file_path, $filename, $owner, $ownerPath, $timestamp);
|
||||
$size += self::retainEncryptionKeys($file_path, $filename, $timestamp);
|
||||
|
||||
// if owner !== user we need to also add a copy to the owners trash
|
||||
@@ -221,13 +232,15 @@ class Trashbin {
|
||||
*
|
||||
* @param string $file_path path to original file
|
||||
* @param string $filename of deleted file
|
||||
* @param string $owner owner user id
|
||||
* @param string $ownerPath path relative to the owner's home storage
|
||||
* @param integer $timestamp when the file was deleted
|
||||
*
|
||||
* @return int size of stored versions
|
||||
*/
|
||||
private static function retainVersions($file_path, $filename, $timestamp) {
|
||||
private static function retainVersions($file_path, $filename, $owner, $ownerPath, $timestamp) {
|
||||
$size = 0;
|
||||
if (\OCP\App::isEnabled('files_versions')) {
|
||||
if (\OCP\App::isEnabled('files_versions') && !empty($ownerPath)) {
|
||||
|
||||
// disable proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
@@ -236,12 +249,6 @@ class Trashbin {
|
||||
$user = \OCP\User::getUser();
|
||||
$rootView = new \OC\Files\View('/');
|
||||
|
||||
list($owner, $ownerPath) = self::getUidAndFilename($file_path);
|
||||
// file has been deleted in between
|
||||
if (empty($ownerPath)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
|
||||
$size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
|
||||
if ($owner !== $user) {
|
||||
@@ -292,7 +299,7 @@ class Trashbin {
|
||||
$util = new \OCA\Files_Encryption\Util($rootView, $user);
|
||||
|
||||
$baseDir = '/files_encryption/';
|
||||
if (!$util->isSystemWideMountPoint($ownerPath)) {
|
||||
if (!$util->isSystemWideMountPoint($ownerPath, $owner)) {
|
||||
$baseDir = $owner . $baseDir;
|
||||
}
|
||||
|
||||
@@ -466,7 +473,7 @@ class Trashbin {
|
||||
$util = new \OCA\Files_Encryption\Util($rootView, $user);
|
||||
|
||||
$baseDir = '/files_encryption/';
|
||||
if (!$util->isSystemWideMountPoint($ownerPath)) {
|
||||
if (!$util->isSystemWideMountPoint($ownerPath, $owner)) {
|
||||
$baseDir = $owner . $baseDir;
|
||||
}
|
||||
|
||||
@@ -825,9 +832,12 @@ class Trashbin {
|
||||
$versions = array();
|
||||
|
||||
//force rescan of versions, local storage may not have updated the cache
|
||||
/** @var \OC\Files\Storage\Storage $storage */
|
||||
list($storage, ) = $view->resolvePath('/');
|
||||
$storage->getScanner()->scan('files_trashbin');
|
||||
if (!self::$scannedVersions) {
|
||||
/** @var \OC\Files\Storage\Storage $storage */
|
||||
list($storage, ) = $view->resolvePath('/');
|
||||
$storage->getScanner()->scan('files_trashbin/versions');
|
||||
self::$scannedVersions = true;
|
||||
}
|
||||
|
||||
if ($timestamp) {
|
||||
// fetch for old versions
|
||||
|
||||
@@ -54,6 +54,8 @@ class Storage extends \Test\TestCase {
|
||||
$this->userView = new \OC\Files\View('/' . $this->user . '/files/');
|
||||
$this->userView->file_put_contents('test.txt', 'foo');
|
||||
|
||||
$this->userView->mkdir('folder');
|
||||
$this->userView->file_put_contents('folder/inside.txt', 'bar');
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
@@ -68,7 +70,7 @@ class Storage extends \Test\TestCase {
|
||||
/**
|
||||
* Test that deleting a file puts it into the trashbin.
|
||||
*/
|
||||
public function testSingleStorageDelete() {
|
||||
public function testSingleStorageDeleteFile() {
|
||||
$this->assertTrue($this->userView->file_exists('test.txt'));
|
||||
$this->userView->unlink('test.txt');
|
||||
list($storage,) = $this->userView->resolvePath('test.txt');
|
||||
@@ -82,13 +84,35 @@ class Storage extends \Test\TestCase {
|
||||
$this->assertEquals('test.txt', substr($name, 0, strrpos($name, '.')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that deleting a folder puts it into the trashbin.
|
||||
*/
|
||||
public function testSingleStorageDeleteFolder() {
|
||||
$this->assertTrue($this->userView->file_exists('folder/inside.txt'));
|
||||
$this->userView->rmdir('folder');
|
||||
list($storage,) = $this->userView->resolvePath('folder/inside.txt');
|
||||
$storage->getScanner()->scan(''); // make sure we check the storage
|
||||
$this->assertFalse($this->userView->getFileInfo('folder'));
|
||||
|
||||
// check if folder is in trashbin
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('folder', substr($name, 0, strrpos($name, '.')));
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/' . $name . '/');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('inside.txt', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that deleting a file from another mounted storage properly
|
||||
* lands in the trashbin. This is a cross-storage situation because
|
||||
* the trashbin folder is in the root storage while the mounted one
|
||||
* isn't.
|
||||
*/
|
||||
public function testCrossStorageDelete() {
|
||||
public function testCrossStorageDeleteFile() {
|
||||
$storage2 = new Temporary(array());
|
||||
\OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
|
||||
|
||||
@@ -108,10 +132,42 @@ class Storage extends \Test\TestCase {
|
||||
$this->assertEquals('subfile.txt', substr($name, 0, strrpos($name, '.')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that deleting a folder from another mounted storage properly
|
||||
* lands in the trashbin. This is a cross-storage situation because
|
||||
* the trashbin folder is in the root storage while the mounted one
|
||||
* isn't.
|
||||
*/
|
||||
public function testCrossStorageDeleteFolder() {
|
||||
$storage2 = new Temporary(array());
|
||||
\OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
|
||||
|
||||
$this->userView->mkdir('substorage/folder');
|
||||
$this->userView->file_put_contents('substorage/folder/subfile.txt', 'bar');
|
||||
$storage2->getScanner()->scan('');
|
||||
$this->assertTrue($storage2->file_exists('folder/subfile.txt'));
|
||||
$this->userView->rmdir('substorage/folder');
|
||||
|
||||
$storage2->getScanner()->scan('');
|
||||
$this->assertFalse($this->userView->getFileInfo('substorage/folder'));
|
||||
$this->assertFalse($storage2->file_exists('folder/subfile.txt'));
|
||||
|
||||
// check if folder is in trashbin
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('folder', substr($name, 0, strrpos($name, '.')));
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/' . $name . '/');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('subfile.txt', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that deleted versions properly land in the trashbin.
|
||||
*/
|
||||
public function testDeleteVersions() {
|
||||
public function testDeleteVersionsOfFile() {
|
||||
\OCA\Files_Versions\Hooks::connectHooks();
|
||||
|
||||
// trigger a version (multiple would not work because of the expire logic)
|
||||
@@ -130,7 +186,156 @@ class Storage extends \Test\TestCase {
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('test.txt', substr($name, 0, strlen('test.txt')));
|
||||
$this->assertEquals('test.txt.v', substr($name, 0, strlen('test.txt.v')));
|
||||
|
||||
// versions deleted
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/');
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that deleted versions properly land in the trashbin.
|
||||
*/
|
||||
public function testDeleteVersionsOfFolder() {
|
||||
\OCA\Files_Versions\Hooks::connectHooks();
|
||||
|
||||
// trigger a version (multiple would not work because of the expire logic)
|
||||
$this->userView->file_put_contents('folder/inside.txt', 'v1');
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/folder/');
|
||||
$this->assertEquals(1, count($results));
|
||||
|
||||
$this->userView->rmdir('folder');
|
||||
|
||||
// rescan trash storage
|
||||
list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
|
||||
$rootStorage->getScanner()->scan('');
|
||||
|
||||
// check if versions are in trashbin
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('folder.d', substr($name, 0, strlen('folder.d')));
|
||||
|
||||
// check if versions are in trashbin
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/' . $name . '/');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('inside.txt.v', substr($name, 0, strlen('inside.txt.v')));
|
||||
|
||||
// versions deleted
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/folder/');
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that deleted versions properly land in the trashbin when deleting as share recipient.
|
||||
*/
|
||||
public function testDeleteVersionsOfFileAsRecipient() {
|
||||
\OCA\Files_Versions\Hooks::connectHooks();
|
||||
\OCA\Files_Sharing\Helper::registerHooks();
|
||||
|
||||
$this->userView->mkdir('share');
|
||||
// trigger a version (multiple would not work because of the expire logic)
|
||||
$this->userView->file_put_contents('share/test.txt', 'v1');
|
||||
$this->userView->file_put_contents('share/test.txt', 'v2');
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/share/');
|
||||
$this->assertEquals(1, count($results));
|
||||
|
||||
$recipientUser = $this->getUniqueId('recipient_');
|
||||
\OC::$server->getUserManager()->createUser($recipientUser, $recipientUser);
|
||||
|
||||
$fileinfo = $this->userView->getFileInfo('share');
|
||||
$this->assertTrue(\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
$recipientUser, 31));
|
||||
|
||||
$this->loginAsUser($recipientUser);
|
||||
|
||||
// delete as recipient
|
||||
$recipientView = new \OC\Files\View('/' . $recipientUser . '/files');
|
||||
$recipientView->unlink('share/test.txt');
|
||||
|
||||
// rescan trash storage for both users
|
||||
list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
|
||||
$rootStorage->getScanner()->scan('');
|
||||
|
||||
// check if versions are in trashbin for both users
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions');
|
||||
$this->assertEquals(1, count($results), 'Versions in owner\'s trashbin');
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('test.txt.v', substr($name, 0, strlen('test.txt.v')));
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($recipientUser . '/files_trashbin/versions');
|
||||
$this->assertEquals(1, count($results), 'Versions in recipient\'s trashbin');
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('test.txt.v', substr($name, 0, strlen('test.txt.v')));
|
||||
|
||||
// versions deleted
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/share/');
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that deleted versions properly land in the trashbin when deleting as share recipient.
|
||||
*/
|
||||
public function testDeleteVersionsOfFolderAsRecipient() {
|
||||
\OCA\Files_Versions\Hooks::connectHooks();
|
||||
\OCA\Files_Sharing\Helper::registerHooks();
|
||||
|
||||
$this->userView->mkdir('share');
|
||||
$this->userView->mkdir('share/folder');
|
||||
// trigger a version (multiple would not work because of the expire logic)
|
||||
$this->userView->file_put_contents('share/folder/test.txt', 'v1');
|
||||
$this->userView->file_put_contents('share/folder/test.txt', 'v2');
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/share/folder/');
|
||||
$this->assertEquals(1, count($results));
|
||||
|
||||
$recipientUser = $this->getUniqueId('recipient_');
|
||||
\OC::$server->getUserManager()->createUser($recipientUser, $recipientUser);
|
||||
|
||||
$fileinfo = $this->userView->getFileInfo('share');
|
||||
$this->assertTrue(\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
$recipientUser, 31));
|
||||
|
||||
$this->loginAsUser($recipientUser);
|
||||
|
||||
// delete as recipient
|
||||
$recipientView = new \OC\Files\View('/' . $recipientUser . '/files');
|
||||
$recipientView->rmdir('share/folder');
|
||||
|
||||
// rescan trash storage
|
||||
list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
|
||||
$rootStorage->getScanner()->scan('');
|
||||
|
||||
// check if versions are in trashbin for owner
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('folder.d', substr($name, 0, strlen('folder.d')));
|
||||
|
||||
// check if file versions are in trashbin for owner
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/' . $name . '/');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('test.txt.v', substr($name, 0, strlen('test.txt.v')));
|
||||
|
||||
// check if versions are in trashbin for recipient
|
||||
$results = $this->rootView->getDirectoryContent($recipientUser . '/files_trashbin/versions');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('folder.d', substr($name, 0, strlen('folder.d')));
|
||||
|
||||
// check if file versions are in trashbin for recipient
|
||||
$results = $this->rootView->getDirectoryContent($recipientUser . '/files_trashbin/versions/' . $name . '/');
|
||||
$this->assertEquals(1, count($results));
|
||||
$name = $results[0]->getName();
|
||||
$this->assertEquals('test.txt.v', substr($name, 0, strlen('test.txt.v')));
|
||||
|
||||
// versions deleted
|
||||
$results = $this->rootView->getDirectoryContent($recipientUser . '/files_versions/share/folder/');
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +343,7 @@ class Storage extends \Test\TestCase {
|
||||
* storages. This is because rename() between storages would call
|
||||
* unlink() which should NOT trigger the version deletion logic.
|
||||
*/
|
||||
public function testKeepFileAndVersionsWhenMovingBetweenStorages() {
|
||||
public function testKeepFileAndVersionsWhenMovingFileBetweenStorages() {
|
||||
\OCA\Files_Versions\Hooks::connectHooks();
|
||||
|
||||
$storage2 = new Temporary(array());
|
||||
@@ -155,7 +360,7 @@ class Storage extends \Test\TestCase {
|
||||
|
||||
// move to another storage
|
||||
$this->userView->rename('test.txt', 'substorage/test.txt');
|
||||
$this->userView->file_exists('substorage/test.txt');
|
||||
$this->assertTrue($this->userView->file_exists('substorage/test.txt'));
|
||||
|
||||
// rescan trash storage
|
||||
list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
|
||||
@@ -174,10 +379,51 @@ class Storage extends \Test\TestCase {
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that versions are not auto-trashed when moving a file between
|
||||
* storages. This is because rename() between storages would call
|
||||
* unlink() which should NOT trigger the version deletion logic.
|
||||
*/
|
||||
public function testKeepFileAndVersionsWhenMovingFolderBetweenStorages() {
|
||||
\OCA\Files_Versions\Hooks::connectHooks();
|
||||
|
||||
$storage2 = new Temporary(array());
|
||||
\OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
|
||||
|
||||
// trigger a version (multiple would not work because of the expire logic)
|
||||
$this->userView->file_put_contents('folder/inside.txt', 'v1');
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
|
||||
$this->assertEquals(0, count($results));
|
||||
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/folder/');
|
||||
$this->assertEquals(1, count($results));
|
||||
|
||||
// move to another storage
|
||||
$this->userView->rename('folder', 'substorage/folder');
|
||||
$this->assertTrue($this->userView->file_exists('substorage/folder/inside.txt'));
|
||||
|
||||
// rescan trash storage
|
||||
list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
|
||||
$rootStorage->getScanner()->scan('');
|
||||
|
||||
// versions were moved too
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_versions/substorage/folder/');
|
||||
$this->assertEquals(1, count($results));
|
||||
|
||||
// check that nothing got trashed by the rename's unlink() call
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
|
||||
$this->assertEquals(0, count($results));
|
||||
|
||||
// check that versions were moved and not trashed
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/');
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete should fail is the source file cant be deleted
|
||||
*/
|
||||
public function testSingleStorageDeleteFail() {
|
||||
public function testSingleStorageDeleteFileFail() {
|
||||
/**
|
||||
* @var \OC\Files\Storage\Temporary | \PHPUnit_Framework_MockObject_MockObject $storage
|
||||
*/
|
||||
@@ -186,9 +432,6 @@ class Storage extends \Test\TestCase {
|
||||
->setMethods(['rename', 'unlink'])
|
||||
->getMock();
|
||||
|
||||
$storage->expects($this->any())
|
||||
->method('rename')
|
||||
->will($this->returnValue(false));
|
||||
$storage->expects($this->any())
|
||||
->method('unlink')
|
||||
->will($this->returnValue(false));
|
||||
@@ -206,4 +449,37 @@ class Storage extends \Test\TestCase {
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete should fail is the source folder cant be deleted
|
||||
*/
|
||||
public function testSingleStorageDeleteFolderFail() {
|
||||
/**
|
||||
* @var \OC\Files\Storage\Temporary | \PHPUnit_Framework_MockObject_MockObject $storage
|
||||
*/
|
||||
$storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
|
||||
->setConstructorArgs([[]])
|
||||
->setMethods(['rename', 'unlink', 'rmdir'])
|
||||
->getMock();
|
||||
|
||||
$storage->expects($this->any())
|
||||
->method('rmdir')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$cache = $storage->getCache();
|
||||
|
||||
Filesystem::mount($storage, [], '/' . $this->user . '/files');
|
||||
$this->userView->mkdir('folder');
|
||||
$this->userView->file_put_contents('folder/test.txt', 'foo');
|
||||
$this->assertTrue($storage->file_exists('folder/test.txt'));
|
||||
$this->assertFalse($this->userView->rmdir('folder'));
|
||||
$this->assertTrue($storage->file_exists('folder'));
|
||||
$this->assertTrue($storage->file_exists('folder/test.txt'));
|
||||
$this->assertTrue($cache->inCache('folder'));
|
||||
$this->assertTrue($cache->inCache('folder/test.txt'));
|
||||
|
||||
// file should not be in the trashbin
|
||||
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
|
||||
$this->assertEquals(0, count($results));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,14 +31,18 @@ if($maxX === 0 || $maxY === 0) {
|
||||
|
||||
try {
|
||||
list($user, $file) = \OCA\Files_Versions\Storage::getUidAndFilename($file);
|
||||
$preview = new \OC\Preview($user, 'files_versions', $file.'.v'.$version);
|
||||
$mimetype = \OC_Helper::getFileNameMimeType($file);
|
||||
$preview->setMimetype($mimetype);
|
||||
$preview->setMaxX($maxX);
|
||||
$preview->setMaxY($maxY);
|
||||
$preview->setScalingUp($scalingUp);
|
||||
if (is_null($file)) {
|
||||
\OC_Response::setStatus(404);
|
||||
} else {
|
||||
$preview = new \OC\Preview($user, 'files_versions', $file . '.v' . $version);
|
||||
$mimetype = \OC_Helper::getFileNameMimeType($file);
|
||||
$preview->setMimetype($mimetype);
|
||||
$preview->setMaxX($maxX);
|
||||
$preview->setMaxY($maxY);
|
||||
$preview->setScalingUp($scalingUp);
|
||||
|
||||
$preview->showPreview();
|
||||
$preview->showPreview();
|
||||
}
|
||||
}catch(\Exception $e) {
|
||||
\OC_Response::setStatus(500);
|
||||
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
|
||||
|
||||
@@ -18,5 +18,4 @@ In addition to the expiry of versions, ownCloud’s versions app makes certain n
|
||||
<user>user-versions</user>
|
||||
</documentation>
|
||||
<default_enable/>
|
||||
<ocsid>166053</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.0.5
|
||||
1.0.6
|
||||
|
||||
@@ -38,7 +38,7 @@ $ftype = $view->getMimeType('/'.$uid.'/files/'.$filename);
|
||||
header('Content-Type:'.$ftype);
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '.$view->filesize($versionName));
|
||||
OCP\Response::setContentLengthHeader($view->filesize($versionName));
|
||||
|
||||
OC_Util::obEnd();
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"History" => "Historique",
|
||||
"Files Versioning" => "Fichier's Versionéierung ",
|
||||
"Enable" => "Aschalten"
|
||||
);
|
||||
@@ -204,50 +204,75 @@ class Storage {
|
||||
}
|
||||
|
||||
/**
|
||||
* rename or copy versions of a file
|
||||
* @param string $old_path
|
||||
* @param string $new_path
|
||||
* Rename or copy versions of a file of the given paths
|
||||
*
|
||||
* @param string $sourcePath source path of the file to move, relative to
|
||||
* the currently logged in user's "files" folder
|
||||
* @param string $targetPath target path of the file to move, relative to
|
||||
* the currently logged in user's "files" folder
|
||||
* @param string $operation can be 'copy' or 'rename'
|
||||
*/
|
||||
public static function renameOrCopy($old_path, $new_path, $operation) {
|
||||
list($uid, $oldpath) = self::getSourcePathAndUser($old_path);
|
||||
public static function renameOrCopy($sourcePath, $targetPath, $operation) {
|
||||
list($sourceOwner, $sourcePath) = self::getSourcePathAndUser($sourcePath);
|
||||
|
||||
// it was a upload of a existing file if no old path exists
|
||||
// in this case the pre-hook already called the store method and we can
|
||||
// stop here
|
||||
if ($oldpath === false) {
|
||||
if ($sourcePath === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($uidn, $newpath) = self::getUidAndFilename($new_path);
|
||||
$versions_view = new \OC\Files\View('/'.$uid .'/files_versions');
|
||||
$files_view = new \OC\Files\View('/'.$uid .'/files');
|
||||
list($targetOwner, $targetPath) = self::getUidAndFilename($targetPath);
|
||||
|
||||
$sourcePath = ltrim($sourcePath, '/');
|
||||
$targetPath = ltrim($targetPath, '/');
|
||||
|
||||
$rootView = new \OC\Files\View('');
|
||||
|
||||
if ( $files_view->is_dir($oldpath) && $versions_view->is_dir($oldpath) ) {
|
||||
$versions_view->$operation($oldpath, $newpath);
|
||||
} else if ( ($versions = Storage::getVersions($uid, $oldpath)) ) {
|
||||
// did we move a directory ?
|
||||
if ($rootView->is_dir('/' . $targetOwner . '/files/' . $targetPath)) {
|
||||
// does the directory exists for versions too ?
|
||||
if ($rootView->is_dir('/' . $sourceOwner . '/files_versions/' . $sourcePath)) {
|
||||
// create missing dirs if necessary
|
||||
self::createMissingDirectories($targetPath, new \OC\Files\View('/'. $targetOwner));
|
||||
|
||||
// move the directory containing the versions
|
||||
$rootView->$operation(
|
||||
'/' . $sourceOwner . '/files_versions/' . $sourcePath,
|
||||
'/' . $targetOwner . '/files_versions/' . $targetPath
|
||||
);
|
||||
}
|
||||
} else if ($versions = Storage::getVersions($sourceOwner, '/' . $sourcePath)) {
|
||||
// create missing dirs if necessary
|
||||
self::createMissingDirectories($newpath, new \OC\Files\View('/'. $uidn));
|
||||
self::createMissingDirectories($targetPath, new \OC\Files\View('/'. $targetOwner));
|
||||
|
||||
foreach ($versions as $v) {
|
||||
$versions_view->$operation($oldpath.'.v'.$v['version'], $newpath.'.v'.$v['version']);
|
||||
// move each version one by one to the target directory
|
||||
$rootView->$operation(
|
||||
'/' . $sourceOwner . '/files_versions/' . $sourcePath.'.v' . $v['version'],
|
||||
'/' . $targetOwner . '/files_versions/' . $targetPath.'.v'.$v['version']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$files_view->is_dir($newpath)) {
|
||||
self::expire($newpath);
|
||||
// if we moved versions directly for a file, schedule expiration check for that file
|
||||
if (!$rootView->is_dir('/' . $targetOwner . '/files/' . $targetPath)) {
|
||||
self::expire($targetPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* rollback to an old version of a file.
|
||||
* Rollback to an old version of a file.
|
||||
*
|
||||
* @param string $file file name
|
||||
* @param int $revision revision timestamp
|
||||
*/
|
||||
public static function rollback($file, $revision) {
|
||||
|
||||
if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
|
||||
// add expected leading slash
|
||||
$file = '/' . ltrim($file, '/');
|
||||
list($uid, $filename) = self::getUidAndFilename($file);
|
||||
$users_view = new \OC\Files\View('/'.$uid);
|
||||
$files_view = new \OC\Files\View('/'.\OCP\User::getUser().'/files');
|
||||
@@ -270,12 +295,11 @@ class Storage {
|
||||
}
|
||||
|
||||
// rollback
|
||||
if( @$users_view->rename('files_versions'.$filename.'.v'.$revision, 'files'.$filename) ) {
|
||||
if (self::copyFileContents($users_view, 'files_versions' . $filename . '.v' . $revision, 'files' . $filename)) {
|
||||
$files_view->touch($file, $revision);
|
||||
Storage::expire($file);
|
||||
return true;
|
||||
|
||||
}else if ( $versionCreated ) {
|
||||
} else if ($versionCreated) {
|
||||
self::deleteVersion($users_view, $version);
|
||||
}
|
||||
}
|
||||
@@ -283,6 +307,36 @@ class Storage {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream copy file contents from $path1 to $path2
|
||||
*
|
||||
* @param \OC\Files\View $view view to use for copying
|
||||
* @param string $path1 source file to copy
|
||||
* @param string $path2 target file
|
||||
*
|
||||
* @return bool true for success, false otherwise
|
||||
*/
|
||||
private static function copyFileContents($view, $path1, $path2) {
|
||||
list($storage1, $internalPath1) = $view->resolvePath($path1);
|
||||
list($storage2, $internalPath2) = $view->resolvePath($path2);
|
||||
|
||||
if ($storage1 === $storage2) {
|
||||
return $storage1->rename($internalPath1, $internalPath2);
|
||||
}
|
||||
$source = $storage1->fopen($internalPath1, 'r');
|
||||
$target = $storage2->fopen($internalPath2, 'w');
|
||||
// FIXME: might need to use part file to avoid concurrent writes
|
||||
// (this would be an issue anyway when renaming/restoring cross-storage)
|
||||
list(, $result) = \OC_Helper::streamCopy($source, $target);
|
||||
fclose($source);
|
||||
fclose($target);
|
||||
|
||||
if ($result !== false) {
|
||||
$storage1->unlink($internalPath1);
|
||||
}
|
||||
|
||||
return ($result !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a list of all available versions of a file in descending chronological order
|
||||
@@ -574,8 +628,11 @@ class Storage {
|
||||
}
|
||||
|
||||
/**
|
||||
* create recursively missing directories
|
||||
* @param string $filename $path to a file
|
||||
* Create recursively missing directories inside of files_versions
|
||||
* that match the given path to a file.
|
||||
*
|
||||
* @param string $filename $path to a file, relative to the user's
|
||||
* "files" folder
|
||||
* @param \OC\Files\View $view view on data/user/
|
||||
*/
|
||||
private static function createMissingDirectories($filename, $view) {
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
|
||||
use OC\Files\Storage\Temporary;
|
||||
|
||||
/**
|
||||
* Class Test_Files_versions
|
||||
* this class provide basic files versions test
|
||||
@@ -70,7 +72,10 @@ class Test_Files_Versioning extends \Test\TestCase {
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
$this->rootView->deleteAll(self::USERS_VERSIONS_ROOT);
|
||||
$this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/');
|
||||
$this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/');
|
||||
$this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/');
|
||||
$this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/');
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
@@ -248,9 +253,6 @@ class Test_Files_Versioning extends \Test\TestCase {
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists($v1Renamed));
|
||||
$this->assertTrue($this->rootView->file_exists($v2Renamed));
|
||||
|
||||
//cleanup
|
||||
\OC\Files\Filesystem::unlink('test2.txt');
|
||||
}
|
||||
|
||||
public function testRenameInSharedFolder() {
|
||||
@@ -292,9 +294,131 @@ class Test_Files_Versioning extends \Test\TestCase {
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists($v1Renamed));
|
||||
$this->assertTrue($this->rootView->file_exists($v2Renamed));
|
||||
}
|
||||
|
||||
//cleanup
|
||||
\OC\Files\Filesystem::unlink('/folder1/folder2/test.txt');
|
||||
public function testMoveFolder() {
|
||||
|
||||
\OC\Files\Filesystem::mkdir('folder1');
|
||||
\OC\Files\Filesystem::mkdir('folder2');
|
||||
\OC\Files\Filesystem::file_put_contents('folder1/test.txt', 'test file');
|
||||
|
||||
$t1 = time();
|
||||
// second version is two weeks older, this way we make sure that no
|
||||
// version will be expired
|
||||
$t2 = $t1 - 60 * 60 * 24 * 14;
|
||||
|
||||
// create some versions
|
||||
$this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/folder1');
|
||||
$v1 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t1;
|
||||
$v2 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t2;
|
||||
$v1Renamed = self::USERS_VERSIONS_ROOT . '/folder2/folder1/test.txt.v' . $t1;
|
||||
$v2Renamed = self::USERS_VERSIONS_ROOT . '/folder2/folder1/test.txt.v' . $t2;
|
||||
|
||||
$this->rootView->file_put_contents($v1, 'version1');
|
||||
$this->rootView->file_put_contents($v2, 'version2');
|
||||
|
||||
// execute rename hook of versions app
|
||||
\OC\Files\Filesystem::rename('folder1', 'folder2/folder1');
|
||||
|
||||
$this->assertFalse($this->rootView->file_exists($v1));
|
||||
$this->assertFalse($this->rootView->file_exists($v2));
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists($v1Renamed));
|
||||
$this->assertTrue($this->rootView->file_exists($v2Renamed));
|
||||
}
|
||||
|
||||
|
||||
public function testMoveFileIntoSharedFolderAsRecipient() {
|
||||
|
||||
\OC\Files\Filesystem::mkdir('folder1');
|
||||
$fileInfo = \OC\Files\Filesystem::getFileInfo('folder1');
|
||||
|
||||
\OCP\Share::shareItem(
|
||||
'folder',
|
||||
$fileInfo['fileid'],
|
||||
\OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_VERSIONS_USER2,
|
||||
\OCP\Constants::PERMISSION_ALL
|
||||
);
|
||||
|
||||
self::loginHelper(self::TEST_VERSIONS_USER2);
|
||||
$versionsFolder2 = '/' . self::TEST_VERSIONS_USER2 . '/files_versions';
|
||||
\OC\Files\Filesystem::file_put_contents('test.txt', 'test file');
|
||||
|
||||
$t1 = time();
|
||||
// second version is two weeks older, this way we make sure that no
|
||||
// version will be expired
|
||||
$t2 = $t1 - 60 * 60 * 24 * 14;
|
||||
|
||||
$this->rootView->mkdir($versionsFolder2);
|
||||
// create some versions
|
||||
$v1 = $versionsFolder2 . '/test.txt.v' . $t1;
|
||||
$v2 = $versionsFolder2 . '/test.txt.v' . $t2;
|
||||
|
||||
$this->rootView->file_put_contents($v1, 'version1');
|
||||
$this->rootView->file_put_contents($v2, 'version2');
|
||||
|
||||
// move file into the shared folder as recipient
|
||||
\OC\Files\Filesystem::rename('/test.txt', '/folder1/test.txt');
|
||||
|
||||
$this->assertFalse($this->rootView->file_exists($v1));
|
||||
$this->assertFalse($this->rootView->file_exists($v2));
|
||||
|
||||
self::loginHelper(self::TEST_VERSIONS_USER);
|
||||
|
||||
$versionsFolder1 = '/' . self::TEST_VERSIONS_USER . '/files_versions';
|
||||
|
||||
$v1Renamed = $versionsFolder1 . '/folder1/test.txt.v' . $t1;
|
||||
$v2Renamed = $versionsFolder1 . '/folder1/test.txt.v' . $t2;
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists($v1Renamed));
|
||||
$this->assertTrue($this->rootView->file_exists($v2Renamed));
|
||||
}
|
||||
|
||||
public function testMoveFolderIntoSharedFolderAsRecipient() {
|
||||
|
||||
\OC\Files\Filesystem::mkdir('folder1');
|
||||
$fileInfo = \OC\Files\Filesystem::getFileInfo('folder1');
|
||||
|
||||
\OCP\Share::shareItem(
|
||||
'folder',
|
||||
$fileInfo['fileid'],
|
||||
\OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_VERSIONS_USER2,
|
||||
\OCP\Constants::PERMISSION_ALL
|
||||
);
|
||||
|
||||
self::loginHelper(self::TEST_VERSIONS_USER2);
|
||||
$versionsFolder2 = '/' . self::TEST_VERSIONS_USER2 . '/files_versions';
|
||||
\OC\Files\Filesystem::mkdir('folder2');
|
||||
\OC\Files\Filesystem::file_put_contents('folder2/test.txt', 'test file');
|
||||
|
||||
$t1 = time();
|
||||
// second version is two weeks older, this way we make sure that no
|
||||
// version will be expired
|
||||
$t2 = $t1 - 60 * 60 * 24 * 14;
|
||||
|
||||
$this->rootView->mkdir($versionsFolder2);
|
||||
$this->rootView->mkdir($versionsFolder2 . '/folder2');
|
||||
// create some versions
|
||||
$v1 = $versionsFolder2 . '/folder2/test.txt.v' . $t1;
|
||||
$v2 = $versionsFolder2 . '/folder2/test.txt.v' . $t2;
|
||||
|
||||
$this->rootView->file_put_contents($v1, 'version1');
|
||||
$this->rootView->file_put_contents($v2, 'version2');
|
||||
|
||||
// move file into the shared folder as recipient
|
||||
\OC\Files\Filesystem::rename('/folder2', '/folder1/folder2');
|
||||
|
||||
self::loginHelper(self::TEST_VERSIONS_USER);
|
||||
|
||||
$versionsFolder1 = '/' . self::TEST_VERSIONS_USER . '/files_versions';
|
||||
|
||||
$v1Renamed = $versionsFolder1 . '/folder1/folder2/test.txt.v' . $t1;
|
||||
$v2Renamed = $versionsFolder1 . '/folder1/folder2/test.txt.v' . $t2;
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists($v1Renamed));
|
||||
$this->assertTrue($this->rootView->file_exists($v2Renamed));
|
||||
}
|
||||
|
||||
public function testRenameSharedFile() {
|
||||
@@ -335,9 +459,6 @@ class Test_Files_Versioning extends \Test\TestCase {
|
||||
|
||||
$this->assertFalse($this->rootView->file_exists($v1Renamed));
|
||||
$this->assertFalse($this->rootView->file_exists($v2Renamed));
|
||||
|
||||
//cleanup
|
||||
\OC\Files\Filesystem::unlink('/test.txt');
|
||||
}
|
||||
|
||||
public function testCopy() {
|
||||
@@ -366,10 +487,6 @@ class Test_Files_Versioning extends \Test\TestCase {
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists($v1Copied));
|
||||
$this->assertTrue($this->rootView->file_exists($v2Copied));
|
||||
|
||||
//cleanup
|
||||
\OC\Files\Filesystem::unlink('test.txt');
|
||||
\OC\Files\Filesystem::unlink('test2.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,6 +523,100 @@ class Test_Files_Versioning extends \Test\TestCase {
|
||||
$this->rootView->deleteAll(self::USERS_VERSIONS_ROOT . '/subfolder');
|
||||
}
|
||||
|
||||
public function testRestoreSameStorage() {
|
||||
\OC\Files\Filesystem::mkdir('sub');
|
||||
$this->doTestRestore();
|
||||
}
|
||||
|
||||
public function testRestoreCrossStorage() {
|
||||
$storage2 = new Temporary(array());
|
||||
\OC\Files\Filesystem::mount($storage2, array(), self::TEST_VERSIONS_USER . '/files/sub');
|
||||
|
||||
$this->doTestRestore();
|
||||
}
|
||||
|
||||
private function doTestRestore() {
|
||||
$filePath = self::TEST_VERSIONS_USER . '/files/sub/test.txt';
|
||||
$this->rootView->file_put_contents($filePath, 'test file');
|
||||
|
||||
$t0 = $this->rootView->filemtime($filePath);
|
||||
|
||||
// not exactly the same timestamp as the file
|
||||
$t1 = time() - 60;
|
||||
// second version is two weeks older
|
||||
$t2 = $t1 - 60 * 60 * 24 * 14;
|
||||
|
||||
// create some versions
|
||||
$v1 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t1;
|
||||
$v2 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t2;
|
||||
|
||||
$this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/sub');
|
||||
$this->rootView->file_put_contents($v1, 'version1');
|
||||
$this->rootView->file_put_contents($v2, 'version2');
|
||||
|
||||
$oldVersions = \OCA\Files_Versions\Storage::getVersions(
|
||||
self::TEST_VERSIONS_USER, '/sub/test.txt'
|
||||
);
|
||||
|
||||
$this->assertCount(2, $oldVersions);
|
||||
|
||||
$this->assertEquals('test file', $this->rootView->file_get_contents($filePath));
|
||||
$info1 = $this->rootView->getFileInfo($filePath);
|
||||
|
||||
\OCA\Files_Versions\Storage::rollback('sub/test.txt', $t2);
|
||||
|
||||
$this->assertEquals('version2', $this->rootView->file_get_contents($filePath));
|
||||
$info2 = $this->rootView->getFileInfo($filePath);
|
||||
|
||||
$this->assertNotEquals(
|
||||
$info2['etag'],
|
||||
$info1['etag'],
|
||||
'Etag must change after rolling back version'
|
||||
);
|
||||
$this->assertEquals(
|
||||
$info2['fileid'],
|
||||
$info1['fileid'],
|
||||
'File id must not change after rolling back version'
|
||||
);
|
||||
$this->assertEquals(
|
||||
$info2['mtime'],
|
||||
$t2,
|
||||
'Restored file has mtime from version'
|
||||
);
|
||||
|
||||
$newVersions = \OCA\Files_Versions\Storage::getVersions(
|
||||
self::TEST_VERSIONS_USER, '/sub/test.txt'
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->rootView->file_exists(self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t0),
|
||||
'A version file was created for the file before restoration'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$this->rootView->file_exists($v1),
|
||||
'Untouched version file is still there'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$this->rootView->file_exists($v2),
|
||||
'Restored version file gone from files_version folder'
|
||||
);
|
||||
|
||||
$this->assertCount(2, $newVersions, 'Additional version created');
|
||||
|
||||
$this->assertTrue(
|
||||
isset($newVersions[$t0 . '#' . 'test.txt']),
|
||||
'A version was created for the file before restoration'
|
||||
);
|
||||
$this->assertTrue(
|
||||
isset($newVersions[$t1 . '#' . 'test.txt']),
|
||||
'Untouched version is still there'
|
||||
);
|
||||
$this->assertFalse(
|
||||
isset($newVersions[$t2 . '#' . 'test.txt']),
|
||||
'Restored version is not in the list any more'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $user
|
||||
* @param bool $create
|
||||
|
||||
@@ -296,6 +296,10 @@ class Users {
|
||||
if(strtolower($group) == 'admin') {
|
||||
return new OC_OCS_Result(null, 103, 'Cannot create subadmins for admin group');
|
||||
}
|
||||
// We cannot be subadmin twice
|
||||
if (OC_Subadmin::isSubAdminOfGroup($user, $group)) {
|
||||
return new OC_OCS_Result(null, 100);
|
||||
}
|
||||
// Go
|
||||
if(OC_Subadmin::createSubAdmin($user, $group)) {
|
||||
return new OC_OCS_Result(null, 100);
|
||||
|
||||
@@ -767,4 +767,29 @@ class UsersTest extends TestCase {
|
||||
$this->assertFalse($result->succeeded());
|
||||
$this->assertEquals(101, $result->getStatusCode());
|
||||
}
|
||||
|
||||
public function testSubAdminOfGroupAlreadySubAdmin() {
|
||||
$user1 = $this->generateUsers();
|
||||
$user2 = $this->generateUsers();
|
||||
\OC_User::setUserId($user1);
|
||||
\OC_Group::addToGroup($user1, 'admin');
|
||||
$group1 = $this->getUniqueID();
|
||||
\OC_Group::createGroup($group1);
|
||||
|
||||
//Make user2 subadmin of group1
|
||||
$_POST['groupid'] = $group1;
|
||||
$result = \OCA\provisioning_api\Users::addSubAdmin([
|
||||
'userid' => $user2,
|
||||
]);
|
||||
$this->assertInstanceOf('OC_OCS_Result', $result);
|
||||
$this->assertTrue($result->succeeded());
|
||||
|
||||
//Make user2 subadmin of group1 again
|
||||
$_POST['groupid'] = $group1;
|
||||
$result = \OCA\provisioning_api\Users::addSubAdmin([
|
||||
'userid' => $user2,
|
||||
]);
|
||||
$this->assertInstanceOf('OC_OCS_Result', $result);
|
||||
$this->assertTrue($result->succeeded());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ switch($action) {
|
||||
exit;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\OCP\JSON::error(array('message' => $e->getMessage()));
|
||||
\OCP\JSON::error(array('message' => $e->getMessage(), 'code' => $e->getCode()));
|
||||
exit;
|
||||
}
|
||||
\OCP\JSON::error();
|
||||
|
||||
@@ -17,7 +17,6 @@ A user logs into ownCloud with their LDAP or AD credentials, and is granted acce
|
||||
<documentation>
|
||||
<admin>admin-ldap</admin>
|
||||
</documentation>
|
||||
<ocsid>166061</ocsid>
|
||||
<dependencies>
|
||||
<lib>ldap</lib>
|
||||
</dependencies>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
*
|
||||
* @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/>
|
||||
*
|
||||
*/
|
||||
|
||||
$config = \OC::$server->getConfig();
|
||||
$installedVersion = $config->getAppValue('user_ldap', 'installed_version');
|
||||
|
||||
if (version_compare($installedVersion, '0.5.2', '<')) {
|
||||
$config->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', false);
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
0.5.0
|
||||
0.5.2
|
||||
|
||||
@@ -49,13 +49,15 @@
|
||||
}
|
||||
|
||||
#ldapWizard1 .hostPortCombinator div span {
|
||||
width: 7%;
|
||||
display: table-cell;
|
||||
width: 14.5%;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#ldapWizard1 .host {
|
||||
width: 96.5% !important;
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.tableCellInput {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user