Compare commits
356 Commits
fix/taskpr
...
v8.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fcab24e59 | ||
|
|
d1f99f1003 | ||
|
|
e56fb7e368 | ||
|
|
1854c7f590 | ||
|
|
30bc7a7418 | ||
|
|
72e576e529 | ||
|
|
7b5493ea21 | ||
|
|
6867d45ffc | ||
|
|
a035198f4b | ||
|
|
52d09386d4 | ||
|
|
2c56909604 | ||
|
|
2396ddf9e9 | ||
|
|
bf69107c25 | ||
|
|
080b837bc8 | ||
|
|
8b635cd7b7 | ||
|
|
2d24ad53c6 | ||
|
|
cd311c1ac1 | ||
|
|
d5d3cbd50d | ||
|
|
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.4
|
||||
<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
|
||||
|
||||
2
3rdparty
2
3rdparty
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);
|
||||
|
||||
@@ -102,7 +102,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 );
|
||||
|
||||
@@ -947,7 +947,7 @@
|
||||
mime: mime,
|
||||
etag: fileData.etag,
|
||||
callback: function(url) {
|
||||
iconDiv.css('background-image', 'url(' + url + ')');
|
||||
iconDiv.css('background-image', 'url("' + url + '")');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -959,7 +959,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);
|
||||
}
|
||||
|
||||
243
apps/files/tests/controller/apicontrollertest.php
Normal file
243
apps/files/tests/controller/apicontrollertest.php
Normal file
@@ -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(
|
||||
|
||||
@@ -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);";
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -72,8 +72,14 @@ 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);
|
||||
foreach ($arguments as $key => $value) {
|
||||
if($value[0] === '@') {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments);
|
||||
// $httpHeaders['Content-Length']=strlen($arguments);
|
||||
} else {
|
||||
|
||||
5
apps/files_external/3rdparty/smb4php/smb.php
vendored
5
apps/files_external/3rdparty/smb4php/smb.php
vendored
@@ -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
|
||||
|
||||
@@ -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 = '';
|
||||
|
||||
@@ -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/',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,6 @@ $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'))));
|
||||
|
||||
@@ -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.1
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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>",
|
||||
|
||||
@@ -394,6 +394,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,11 +154,13 @@ 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['filename'] = $file;
|
||||
$shareTmpl['directory_path'] = $linkItem['file_target'];
|
||||
@@ -230,26 +225,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 +280,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.');
|
||||
}
|
||||
}
|
||||
|
||||
117
apps/files_sharing/lib/external/manager.php
vendored
117
apps/files_sharing/lib/external/manager.php
vendored
@@ -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() : [];
|
||||
}
|
||||
}
|
||||
|
||||
5
apps/files_sharing/lib/external/storage.php
vendored
5
apps/files_sharing/lib/external/storage.php
vendored
@@ -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,
|
||||
|
||||
@@ -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'];
|
||||
|
||||
|
||||
@@ -1008,6 +1008,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;
|
||||
@@ -49,6 +50,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'];
|
||||
|
||||
@@ -115,7 +118,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 +133,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
|
||||
@@ -170,4 +178,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
apps/files_sharing/tests/external/managertest.php
vendored
Normal file
216
apps/files_sharing/tests/external/managertest.php
vendored
Normal file
@@ -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');
|
||||
|
||||
90
apps/files_sharing/tests/propagation.php
Normal file
90
apps/files_sharing/tests/propagation.php
Normal file
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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,38 @@ 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')));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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')));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +225,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 +242,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 +261,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 +314,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 +331,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
@@ -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();
|
||||
|
||||
@@ -630,7 +630,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
}
|
||||
$maxGroups = 100000; // limit max results (just for safety reasons)
|
||||
if ($limit > -1) {
|
||||
$overallLimit = min($limit, $maxGroups);
|
||||
$overallLimit = min($limit + $offset, $maxGroups);
|
||||
} else {
|
||||
$overallLimit = $maxGroups;
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ var LdapWizard = {
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.showSpinner(spinnerID);
|
||||
var request = LdapWizard.ajax(param,
|
||||
LdapWizard.ajax(param,
|
||||
function(result) {
|
||||
LdapWizard.applyChanges(result);
|
||||
LdapWizard.hideSpinner(spinnerID);
|
||||
@@ -360,7 +360,7 @@ var LdapWizard = {
|
||||
}
|
||||
},
|
||||
function (result) {
|
||||
OC.Notification.show('Counting the entries failed with, ' + result.message);
|
||||
OC.Notification.showTemporary('Counting the entries failed with: ' + result.message);
|
||||
LdapWizard.hideSpinner(spinnerID);
|
||||
if(!_.isUndefined(doneCallback)) {
|
||||
doneCallback(method);
|
||||
@@ -371,11 +371,17 @@ var LdapWizard = {
|
||||
},
|
||||
|
||||
countGroups: function(doneCallback) {
|
||||
LdapWizard._countThings('countGroups', '#ldap_group_count', doneCallback);
|
||||
var groupFilter = $('#ldap_group_filter').val();
|
||||
if(!_.isEmpty(groupFilter)) {
|
||||
LdapWizard._countThings('countGroups', '#ldap_group_count', doneCallback);
|
||||
}
|
||||
},
|
||||
|
||||
countUsers: function(doneCallback) {
|
||||
LdapWizard._countThings('countUsers', '#ldap_user_count', doneCallback);
|
||||
var userFilter = $('#ldap_userlist_filter').val();
|
||||
if(!_.isEmpty(userFilter)) {
|
||||
LdapWizard._countThings('countUsers', '#ldap_user_count', doneCallback);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%s group found_::_%s groups found_" => array("",""),
|
||||
"_%s user found_::_%s users found_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -1372,7 +1372,8 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
* @return void
|
||||
*/
|
||||
private function setPagedResultCookie($base, $filter, $limit, $offset, $cookie) {
|
||||
if(!empty($cookie)) {
|
||||
// allow '0' for 389ds
|
||||
if(!empty($cookie) || $cookie === '0') {
|
||||
$cacheKey = 'lc' . crc32($base) . '-' . crc32($filter) . '-' .intval($limit) . '-' . intval($offset);
|
||||
$this->cookies[$cacheKey] = $cookie;
|
||||
$this->lastCookie = $cookie;
|
||||
@@ -1410,11 +1411,12 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
foreach($bases as $base) {
|
||||
|
||||
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
|
||||
if(empty($cookie) && ($offset > 0)) {
|
||||
if(empty($cookie) && $cookie !== "0" && ($offset > 0)) {
|
||||
// no cookie known, although the offset is not 0. Maybe cache run out. We need
|
||||
// to start all over *sigh* (btw, Dear Reader, did you know LDAP paged
|
||||
// searching was designed by MSFT?)
|
||||
// Lukas: No, but thanks to reading that source I finally know!
|
||||
// '0' is valid, because 389ds
|
||||
$reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit;
|
||||
//a bit recursive, $offset of 0 is the exit
|
||||
\OCP\Util::writeLog('user_ldap', 'Looking for cookie L/O '.$limit.'/'.$reOffset, \OCP\Util::INFO);
|
||||
@@ -1422,7 +1424,8 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
|
||||
//still no cookie? obviously, the server does not like us. Let's skip paging efforts.
|
||||
//TODO: remember this, probably does not change in the next request...
|
||||
if(empty($cookie)) {
|
||||
if(empty($cookie) && $cookie !== '0') {
|
||||
// '0' is valid, because 389ds
|
||||
$cookie = null;
|
||||
}
|
||||
}
|
||||
@@ -1443,6 +1446,17 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
}
|
||||
|
||||
}
|
||||
} else if($this->connection->hasPagedResultSupport && $limit === 0) {
|
||||
// a search without limit was requested. However, if we do use
|
||||
// Paged Search once, we always must do it. This requires us to
|
||||
// initialize it with the configured page size.
|
||||
$this->abandonPagedSearch();
|
||||
// in case someone set it to 0 … use 500, otherwise no results will
|
||||
// be returned.
|
||||
$pageSize = intval($this->connection->ldapPagingSize) > 0 ? intval($this->connection->ldapPagingSize) : 500;
|
||||
$pagedSearchOK = $this->ldap->controlPagedResult(
|
||||
$this->connection->getConnectionResource(), $pageSize, false, ''
|
||||
);
|
||||
}
|
||||
|
||||
return $pagedSearchOK;
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
|
||||
namespace OCA\user_ldap\lib;
|
||||
|
||||
//magic properties (incomplete)
|
||||
use OC\ServerNotAvailableException;
|
||||
|
||||
/**
|
||||
* magic properties (incomplete)
|
||||
* responsible for LDAP connections in context with the provided configuration
|
||||
*
|
||||
* @property string ldapUserFilter
|
||||
@@ -46,7 +48,7 @@ class Connection extends LDAPUtility {
|
||||
//cache handler
|
||||
protected $cache;
|
||||
|
||||
//settings handler
|
||||
/** @var Configuration settings handler **/
|
||||
protected $configuration;
|
||||
|
||||
protected $doNotValidate = false;
|
||||
@@ -159,7 +161,8 @@ class Connection extends LDAPUtility {
|
||||
$this->establishConnection();
|
||||
}
|
||||
if(is_null($this->ldapConnectionRes)) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Connection could not be established', \OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
|
||||
throw new ServerNotAvailableException('Connection to LDAP server could not be established');
|
||||
}
|
||||
return $this->ldapConnectionRes;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
namespace OCA\user_ldap\lib;
|
||||
|
||||
use OC\ServerNotAvailableException;
|
||||
|
||||
class LDAP implements ILDAPWrapper {
|
||||
protected $curFunc = '';
|
||||
protected $curArgs = array();
|
||||
@@ -280,6 +282,8 @@ class LDAP implements ILDAPWrapper {
|
||||
//for now
|
||||
} else if ($errorCode === 10) {
|
||||
//referrals, we switch them off, but then there is AD :)
|
||||
} else if ($errorCode === -1) {
|
||||
throw new ServerNotAvailableException('Lost connection to LDAP server.');
|
||||
} else {
|
||||
\OCP\Util::writeLog('user_ldap',
|
||||
'LDAP error '.$errorMsg.' (' .
|
||||
|
||||
@@ -150,6 +150,11 @@ class Manager {
|
||||
$this->access->getUserMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns a User object by it's ownCloud username
|
||||
* @param string the DN or username of the user
|
||||
* @return \OCA\user_ldap\lib\user\User|\OCA\user_ldap\lib\user\OfflineUser|null
|
||||
*/
|
||||
protected function createInstancyByUserName($id) {
|
||||
//most likely a uid. Check whether it is a deleted user
|
||||
if($this->isDeletedUser($id)) {
|
||||
@@ -159,13 +164,14 @@ class Manager {
|
||||
if($dn !== false) {
|
||||
return $this->createAndCache($dn, $id);
|
||||
}
|
||||
throw new \Exception('Could not create User instance');
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns a User object by it's DN or ownCloud username
|
||||
* @param string the DN or username of the user
|
||||
* @return \OCA\user_ldap\lib\user\User|\OCA\user_ldap\lib\user\OfflineUser|null
|
||||
* @throws \Exception when connection could not be established
|
||||
*/
|
||||
public function get($id) {
|
||||
$this->checkAccess();
|
||||
@@ -182,12 +188,7 @@ class Manager {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$user = $this->createInstancyByUserName($id);
|
||||
return $user;
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
return $this->createInstancyByUserName($id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -293,4 +293,18 @@ class Test_Group_Ldap extends \Test\TestCase {
|
||||
$groupBackend->inGroup($uid, $gid);
|
||||
}
|
||||
|
||||
public function testGetGroupsWithOffset() {
|
||||
$access = $this->getAccessMock();
|
||||
$this->enableGroups($access);
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('ownCloudGroupNames')
|
||||
->will($this->returnValue(array('group1', 'group2')));
|
||||
|
||||
$groupBackend = new GroupLDAP($access);
|
||||
$groups = $groupBackend->getGroups('', 2, 2);
|
||||
|
||||
$this->assertSame(2, count($groups));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -411,21 +411,53 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for existing user
|
||||
$result = $backend->userExists('gunslinger');
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testUserExistsForDeleted() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for deleted user
|
||||
$result = $backend->userExists('formerUser');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testUserExistsForNeverExisting() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for never-existing user
|
||||
$result = $backend->userExists('mallory');
|
||||
@@ -439,21 +471,55 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for existing user
|
||||
$result = \OCP\User::userExists('gunslinger');
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testUserExistsPublicAPIForDeleted() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
|
||||
$this->prepareMockForUserExists($access);
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for deleted user
|
||||
$result = \OCP\User::userExists('formerUser');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testUserExistsPublicAPIForNeverExisting() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
|
||||
$this->prepareMockForUserExists($access);
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for never-existing user
|
||||
$result = \OCP\User::userExists('mallory');
|
||||
@@ -469,54 +535,105 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testGetHome() {
|
||||
public function testGetHomeAbsolutePath() {
|
||||
$access = $this->getAccessMock();
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$backend = new UserLDAP($access, $config);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
case 'dnOfRoland,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('/tmp/rolandshome/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
case 'dnOfLadyOfShadows,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('susannah/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
case 'dnOfRoland,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('/tmp/rolandshome/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
//absolut path
|
||||
$result = $backend->getHome('gunslinger');
|
||||
$this->assertEquals('/tmp/rolandshome/', $result);
|
||||
}
|
||||
|
||||
public function testGetHomeRelative() {
|
||||
$access = $this->getAccessMock();
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$backend = new UserLDAP($access, $config);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
case 'dnOfLadyOfShadows,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('susannah/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
//datadir-relativ path
|
||||
$datadir = '/my/data/dir';
|
||||
$config->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->will($this->returnValue($datadir));
|
||||
|
||||
//absolut path
|
||||
$result = $backend->getHome('gunslinger');
|
||||
$this->assertEquals('/tmp/rolandshome/', $result);
|
||||
|
||||
//datadir-relativ path
|
||||
$result = $backend->getHome('ladyofshadows');
|
||||
$this->assertEquals($datadir.'/susannah/', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testGetHomeNoPath() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
//no path at all – triggers OC default behaviour
|
||||
$result = $backend->getHome('newyorker');
|
||||
@@ -556,6 +673,12 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
|
||||
$backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('getConnectionResource')
|
||||
->will($this->returnCallback(function() {
|
||||
return true;
|
||||
}));
|
||||
|
||||
//with displayName
|
||||
$result = $backend->getDisplayName('gunslinger');
|
||||
$this->assertEquals('Roland Deschain', $result);
|
||||
@@ -567,9 +690,36 @@ class Test_User_Ldap_Direct extends \Test\TestCase {
|
||||
|
||||
public function testGetDisplayNamePublicAPI() {
|
||||
$access = $this->getAccessMock();
|
||||
$access->expects($this->any())
|
||||
->method('username2dn')
|
||||
->will($this->returnCallback(function($uid) {
|
||||
switch ($uid) {
|
||||
case 'gunslinger':
|
||||
return 'dnOfRoland,dc=test';
|
||||
break;
|
||||
case 'formerUser':
|
||||
return 'dnOfFormerUser,dc=test';
|
||||
break;
|
||||
case 'newyorker':
|
||||
return 'dnOfNewYorker,dc=test';
|
||||
break;
|
||||
case 'ladyofshadows':
|
||||
return 'dnOfLadyOfShadows,dc=test';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
$this->prepareAccessForGetDisplayName($access);
|
||||
$backend = new UserLDAP($access, $this->getMock('\OCP\IConfig'));
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('getConnectionResource')
|
||||
->will($this->returnCallback(function() {
|
||||
return true;
|
||||
}));
|
||||
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
//with displayName
|
||||
|
||||
@@ -188,6 +188,7 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
|
||||
* check if a user exists
|
||||
* @param string $uid the username
|
||||
* @return boolean
|
||||
* @throws \Exception when connection could not be established
|
||||
*/
|
||||
public function userExists($uid) {
|
||||
if($this->access->connection->isCached('userExists'.$uid)) {
|
||||
@@ -206,17 +207,12 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->userExistsOnLDAP($user);
|
||||
$this->access->connection->writeToCache('userExists'.$uid, $result);
|
||||
if($result === true) {
|
||||
$user->update();
|
||||
}
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
\OCP\Util::writeLog('user_ldap', $e->getMessage(), \OCP\Util::WARN);
|
||||
return false;
|
||||
$result = $this->userExistsOnLDAP($user);
|
||||
$this->access->connection->writeToCache('userExists'.$uid, $result);
|
||||
if($result === true) {
|
||||
$user->update();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -229,9 +229,9 @@ $CONFIG = array(
|
||||
'skeletondirectory' => '',
|
||||
|
||||
/**
|
||||
* The ``user_backends`` app allows you to configure alternate authentication
|
||||
* backends. Supported backends are IMAP (OC_User_IMAP), SMB (OC_User_SMB), and
|
||||
* FTP (OC_User_FTP).
|
||||
* The ``user_backends`` app (which needs to be enabled first) allows you to
|
||||
* configure alternate authentication backends. Supported backends are:
|
||||
* IMAP (OC_User_IMAP), SMB (OC_User_SMB), and FTP (OC_User_FTP).
|
||||
*/
|
||||
'user_backends' => array(
|
||||
array(
|
||||
@@ -420,8 +420,9 @@ $CONFIG = array(
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check 3rd party apps to make sure they are using the private API and not the
|
||||
* public API. If the app uses the private API it cannot be installed.
|
||||
* Checks an app before install whether it uses private APIs instead of the
|
||||
* proper public APIs. If this is set to true it will only allow to install or
|
||||
* enable apps that pass this check.
|
||||
*/
|
||||
'appcodechecker' => true,
|
||||
|
||||
@@ -669,6 +670,10 @@ $CONFIG = array(
|
||||
* - OC\Preview\StarOffice
|
||||
* - OC\Preview\SVG
|
||||
* - OC\Preview\TIFF
|
||||
*
|
||||
* .. note:: Troubleshooting steps for the MS Word previews are available
|
||||
* at the :doc:`../configuration_files/collaborative_documents_configuration`
|
||||
* section of the Administrators Manual.
|
||||
*
|
||||
* The following providers are not available in Microsoft Windows:
|
||||
*
|
||||
|
||||
@@ -11,6 +11,9 @@ use Symfony\Component\Console\Application;
|
||||
try {
|
||||
require_once 'lib/base.php';
|
||||
|
||||
// set to run indefinitely if needed
|
||||
set_time_limit(0);
|
||||
|
||||
// Don't do anything if ownCloud has not been installed yet
|
||||
if (!\OC::$server->getConfig()->getSystemValue('installed', false)) {
|
||||
echo "Console can only be used once ownCloud has been installed" . PHP_EOL;
|
||||
|
||||
@@ -105,7 +105,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
|
||||
// don't send a mail to the user who shared the file
|
||||
$recipientList = array_diff($recipientList, array(\OCP\User::getUser()));
|
||||
|
||||
$mailNotification = new OC\Share\MailNotifications();
|
||||
$mailNotification = new OC\Share\MailNotifications(\OCP\User::getUser());
|
||||
$result = $mailNotification->sendInternalShareMail($recipientList, $itemSource, $itemType);
|
||||
|
||||
\OCP\Share::setSendMailStatus($itemType, $itemSource, $shareType, $recipient, true);
|
||||
@@ -137,7 +137,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
|
||||
$file = $_POST['file'];
|
||||
$to_address = $_POST['toaddress'];
|
||||
|
||||
$mailNotification = new \OC\Share\MailNotifications();
|
||||
$mailNotification = new \OC\Share\MailNotifications(\OCP\User::getUser());
|
||||
|
||||
$expiration = null;
|
||||
if (isset($_POST['expiration']) && $_POST['expiration'] !== '') {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
set_time_limit(0);
|
||||
require_once '../../lib/base.php';
|
||||
|
||||
\OCP\JSON::callCheck();
|
||||
|
||||
if (OC::checkUpgrade(false)) {
|
||||
// if a user is currently logged in, their session must be ignored to
|
||||
// avoid side effects
|
||||
@@ -11,9 +13,12 @@ if (OC::checkUpgrade(false)) {
|
||||
$eventSource = \OC::$server->createEventSource();
|
||||
$updater = new \OC\Updater(
|
||||
\OC::$server->getHTTPHelper(),
|
||||
\OC::$server->getAppConfig(),
|
||||
\OC::$server->getConfig(),
|
||||
\OC_Log::$object
|
||||
);
|
||||
$incompatibleApps = [];
|
||||
$disabledThirdPartyApps = [];
|
||||
|
||||
$updater->listen('\OC\Updater', 'maintenanceStart', function () use ($eventSource, $l) {
|
||||
$eventSource->send('success', (string)$l->t('Turned on maintenance mode'));
|
||||
});
|
||||
@@ -32,13 +37,17 @@ if (OC::checkUpgrade(false)) {
|
||||
$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) {
|
||||
$eventSource->send('success', (string)$l->t('Updated "%s" to %s', array($app, $version)));
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'disabledApps', function ($appList) use ($eventSource, $l) {
|
||||
$list = array();
|
||||
foreach ($appList as $appId) {
|
||||
$info = OC_App::getAppInfo($appId);
|
||||
$list[] = $info['name'] . ' (' . $info['id'] . ')';
|
||||
}
|
||||
$eventSource->send('success', (string)$l->t('Disabled incompatible apps: %s', implode(', ', $list)));
|
||||
$updater->listen('\OC\Updater', 'repairWarning', function ($description) use ($eventSource, $l) {
|
||||
$eventSource->send('notice', (string)$l->t('Repair warning: ') . $description);
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'repairError', function ($description) use ($eventSource, $l) {
|
||||
$eventSource->send('notice', (string)$l->t('Repair error: ') . $description);
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) {
|
||||
$incompatibleApps[]= $app;
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use (&$disabledThirdPartyApps) {
|
||||
$disabledThirdPartyApps[]= $app;
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource) {
|
||||
$eventSource->send('failure', $message);
|
||||
@@ -48,6 +57,15 @@ if (OC::checkUpgrade(false)) {
|
||||
|
||||
$updater->upgrade();
|
||||
|
||||
if (!empty($incompatibleApps)) {
|
||||
$eventSource->send('notice',
|
||||
(string)$l->t('Following incompatible apps have been disabled: %s', implode(', ', $incompatibleApps)));
|
||||
}
|
||||
if (!empty($disabledThirdPartyApps)) {
|
||||
$eventSource->send('notice',
|
||||
(string)$l->t('Following 3rd party apps have been disabled: %s', implode(', ', $disabledThirdPartyApps)));
|
||||
}
|
||||
|
||||
$eventSource->send('done', '');
|
||||
$eventSource->close();
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ class Repair extends Command {
|
||||
$this->repair->listen('\OC\Repair', 'info', function ($description) use ($output) {
|
||||
$output->writeln(' - ' . $description);
|
||||
});
|
||||
$this->repair->listen('\OC\Repair', 'warning', function ($description) use ($output) {
|
||||
$output->writeln(' - WARNING: ' . $description);
|
||||
});
|
||||
$this->repair->listen('\OC\Repair', 'error', function ($description) use ($output) {
|
||||
$output->writeln(' - ERROR: ' . $description);
|
||||
});
|
||||
|
||||
@@ -53,6 +53,12 @@ class Upgrade extends Command {
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'only runs the database schema migration simulation, do not actually update'
|
||||
)
|
||||
->addOption(
|
||||
'--no-app-disable',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'skips the disable of third party apps'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,6 +72,7 @@ class Upgrade extends Command {
|
||||
|
||||
$simulateStepEnabled = true;
|
||||
$updateStepEnabled = true;
|
||||
$skip3rdPartyAppsDisable = false;
|
||||
|
||||
if ($input->getOption('skip-migration-test')) {
|
||||
$simulateStepEnabled = false;
|
||||
@@ -73,6 +80,9 @@ class Upgrade extends Command {
|
||||
if ($input->getOption('dry-run')) {
|
||||
$updateStepEnabled = false;
|
||||
}
|
||||
if ($input->getOption('no-app-disable')) {
|
||||
$skip3rdPartyAppsDisable = true;
|
||||
}
|
||||
|
||||
if (!$simulateStepEnabled && !$updateStepEnabled) {
|
||||
$output->writeln(
|
||||
@@ -84,10 +94,12 @@ class Upgrade extends Command {
|
||||
|
||||
if(\OC::checkUpgrade(false)) {
|
||||
$self = $this;
|
||||
$updater = new Updater(\OC::$server->getHTTPHelper(), \OC::$server->getAppConfig());
|
||||
$updater = new Updater(\OC::$server->getHTTPHelper(),
|
||||
\OC::$server->getConfig());
|
||||
|
||||
$updater->setSimulateStepEnabled($simulateStepEnabled);
|
||||
$updater->setUpdateStepEnabled($updateStepEnabled);
|
||||
$updater->setSkip3rdPartyAppsDisable($skip3rdPartyAppsDisable);
|
||||
|
||||
$updater->listen('\OC\Updater', 'maintenanceStart', function () use($output) {
|
||||
$output->writeln('<info>Turned on maintenance mode</info>');
|
||||
@@ -106,10 +118,24 @@ class Upgrade extends Command {
|
||||
$updater->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($output) {
|
||||
$output->writeln('<info>Checked database schema update</info>');
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'disabledApps', function ($appList) use($output) {
|
||||
$output->writeln('<info>Disabled incompatible apps: ' . implode(', ', $appList) . '</info>');
|
||||
$updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($output) {
|
||||
$output->writeln('<info>Disabled incompatible app: ' . $app . '</info>');
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($output) {
|
||||
$output->writeln('<info>Disabled 3rd-party app: ' . $app . '</info>');
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'repairWarning', function ($app) use($output) {
|
||||
$output->writeln('<error>Repair warning: ' . $app . '</error>');
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'repairError', function ($app) use($output) {
|
||||
$output->writeln('<error>Repair error: ' . $app . '</error>');
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'appUpgradeCheck', function () use ($output) {
|
||||
$output->writeln('<info>Checked database schema update for apps</info>');
|
||||
});
|
||||
$updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($output) {
|
||||
$output->writeln("<info>Updated <$app> to $version</info>");
|
||||
});
|
||||
|
||||
$updater->listen('\OC\Updater', 'failure', function ($message) use($output, $self) {
|
||||
$output->writeln("<error>$message</error>");
|
||||
$self->upgradeFailed = true;
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
display: block;
|
||||
width: 100%;
|
||||
line-height: 44px;
|
||||
min-height: 44px;
|
||||
padding: 0 12px;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box; box-sizing: border-box;
|
||||
|
||||
@@ -62,6 +62,7 @@ select {
|
||||
|
||||
/* fix installation screen rendering issue for IE8+9 */
|
||||
.lte9 #body-login {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* do not show update notification on mobile */
|
||||
#update-notification {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* position share dropdown */
|
||||
#dropdown {
|
||||
margin-right: 10% !important;
|
||||
|
||||
@@ -1213,7 +1213,7 @@ $.fn.filterAttr = function(attr_name, attr_value) {
|
||||
function humanFileSize(size, skipSmallSizes) {
|
||||
var humanList = ['B', 'kB', 'MB', 'GB', 'TB'];
|
||||
// Calculate Log with base 1024: size = 1024 ** order
|
||||
var order = size?Math.floor(Math.log(size) / Math.log(1024)):0;
|
||||
var order = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0;
|
||||
// Stay in range of the byte sizes that are defined
|
||||
order = Math.min(humanList.length - 1, order);
|
||||
var readableFormat = humanList[order];
|
||||
|
||||
@@ -138,7 +138,7 @@ var OCdialogs = {
|
||||
* @param title dialog title
|
||||
* @param callback which will be triggered when user presses Choose
|
||||
* @param multiselect whether it should be possible to select multiple files
|
||||
* @param mimetypeFilter mimetype to filter by
|
||||
* @param mimetypeFilter mimetype to filter by - directories will always be included
|
||||
* @param modal make the dialog modal
|
||||
*/
|
||||
filepicker:function(title, callback, multiselect, mimetypeFilter, modal) {
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
t('core', 'Your data directory and your files are probably accessible from the internet. The .htaccess file is not working. We strongly suggest that you configure your webserver in a way that the data directory is no longer accessible or you move the data directory outside the webserver document root.')
|
||||
);
|
||||
}
|
||||
if(!data.hasCurlInstalled) {
|
||||
messages.push(
|
||||
t('core', 'cURL is not installed, some functionality might not work. Please install the PHP cURL extension. Future versions will require installed cURL.')
|
||||
);
|
||||
}
|
||||
} else {
|
||||
messages.push(t('core', 'Error occurred while checking server setup'));
|
||||
}
|
||||
|
||||
@@ -473,6 +473,10 @@ OC.Share={
|
||||
} else {
|
||||
response();
|
||||
}
|
||||
}).fail(function(){
|
||||
$('#dropdown').find('.shareWithLoading').addClass('hidden');
|
||||
OC.Notification.show(t('core', 'An error occured. Please try again'));
|
||||
window.setTimeout(OC.Notification.hide, 5000);
|
||||
});
|
||||
},
|
||||
focus: function(event, focused) {
|
||||
@@ -798,6 +802,24 @@ OC.Share={
|
||||
$('#defaultExpireMessage').show('blind');
|
||||
}
|
||||
$.datepicker.setDefaults(datePickerOptions);
|
||||
},
|
||||
/**
|
||||
* Get the default Expire date
|
||||
*
|
||||
* @return {String} The expire date
|
||||
*/
|
||||
getDefaultExpirationDate:function() {
|
||||
var expireDateString = '';
|
||||
if (oc_appconfig.core.defaultExpireDateEnabled) {
|
||||
var date = new Date().getTime();
|
||||
var expireAfterMs = oc_appconfig.core.defaultExpireDate * 24 * 60 * 60 * 1000;
|
||||
var expireDate = new Date(date + expireAfterMs);
|
||||
var month = expireDate.getMonth() + 1;
|
||||
var year = expireDate.getFullYear();
|
||||
var day = expireDate.getDate();
|
||||
expireDateString = year + "-" + month + '-' + day + ' 00:00:00';
|
||||
}
|
||||
return expireDateString;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -942,17 +964,9 @@ $(document).ready(function() {
|
||||
|
||||
if (this.checked) {
|
||||
var expireDateString = '';
|
||||
if (oc_appconfig.core.defaultExpireDateEnabled) {
|
||||
var date = new Date().getTime();
|
||||
var expireAfterMs = oc_appconfig.core.defaultExpireDate * 24 * 60 * 60 * 1000;
|
||||
var expireDate = new Date(date + expireAfterMs);
|
||||
var month = expireDate.getMonth() + 1;
|
||||
var year = expireDate.getFullYear();
|
||||
var day = expireDate.getDate();
|
||||
expireDateString = year + "-" + month + '-' + day + ' 00:00:00';
|
||||
}
|
||||
// Create a link
|
||||
if (oc_appconfig.core.enforcePasswordForPublicLink === false) {
|
||||
expireDateString = OC.Share.getDefaultExpirationDate();
|
||||
$loading.removeClass('hidden');
|
||||
$button.addClass('hidden');
|
||||
$button.prop('disabled', true);
|
||||
@@ -1086,8 +1100,10 @@ $(document).ready(function() {
|
||||
permissions = OC.PERMISSION_READ;
|
||||
}
|
||||
|
||||
var expireDateString = OC.Share.getDefaultExpirationDate();
|
||||
|
||||
$loading.removeClass('hidden');
|
||||
OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, function(data) {
|
||||
OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, expireDateString, function(data) {
|
||||
$loading.addClass('hidden');
|
||||
linkPassText.val('');
|
||||
linkPassText.attr('placeholder', t('core', 'Password protected'));
|
||||
@@ -1096,8 +1112,12 @@ $(document).ready(function() {
|
||||
OC.Share.showLink(data.token, "password set", itemSource);
|
||||
OC.Share.updateIcon(itemType, itemSource);
|
||||
}
|
||||
$('#dropdown').trigger(new $.Event('sharesChanged', {shares: OC.Share.currentShares}));
|
||||
});
|
||||
|
||||
if (expireDateString !== '') {
|
||||
OC.Share.showExpirationDate(expireDateString);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -465,6 +465,8 @@ describe('Core base tests', function() {
|
||||
it('renders file sizes with the correct unit', function() {
|
||||
var data = [
|
||||
[0, '0 B'],
|
||||
["0", '0 B'],
|
||||
["A", 'NaN B'],
|
||||
[125, '125 B'],
|
||||
[128000, '125 kB'],
|
||||
[128000000, '122.1 MB'],
|
||||
|
||||
@@ -309,6 +309,7 @@ describe('OC.Share tests', function() {
|
||||
};
|
||||
loadItemStub.returns(shareData);
|
||||
oc_appconfig.core.defaultExpireDate = 7;
|
||||
oc_appconfig.core.enforcePasswordForPublicLink = false;
|
||||
oc_appconfig.core.defaultExpireDateEnabled = false;
|
||||
oc_appconfig.core.defaultExpireDateEnforced = false;
|
||||
});
|
||||
@@ -364,6 +365,32 @@ describe('OC.Share tests', function() {
|
||||
$('#dropdown [name=expirationCheckbox]').click();
|
||||
expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
|
||||
});
|
||||
it('enforces default date when enforced date setting is enabled and password is enforced', function() {
|
||||
/* jshint camelcase:false */
|
||||
oc_appconfig.core.enforcePasswordForPublicLink = true;
|
||||
oc_appconfig.core.defaultExpireDateEnabled = true;
|
||||
oc_appconfig.core.defaultExpireDateEnforced = true;
|
||||
showDropDown();
|
||||
$('#dropdown [name=linkCheckbox]').click();
|
||||
|
||||
//Enter password
|
||||
$('#dropdown #linkPassText').val('foo');
|
||||
$('#dropdown #linkPassText').trigger(new $.Event('keyup', {keyCode: 13}));
|
||||
fakeServer.requests[0].respond(
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({data: {token: 'xyz'}, status: 'success'})
|
||||
);
|
||||
|
||||
expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
|
||||
// TODO: those zeros must go...
|
||||
expect($('#dropdown #expirationDate').val()).toEqual('2014-1-27 00:00:00');
|
||||
|
||||
// disabling is not allowed
|
||||
expect($('#dropdown [name=expirationCheckbox]').prop('disabled')).toEqual(true);
|
||||
$('#dropdown [name=expirationCheckbox]').click();
|
||||
expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
|
||||
});
|
||||
it('displayes email form when sending emails is enabled', function() {
|
||||
$('input[name=mailPublicNotificationEnabled]').val('yes');
|
||||
showDropDown();
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
updateEventSource.listen('success', function(message) {
|
||||
$('<span>').append(message).append('<br />').appendTo($el);
|
||||
});
|
||||
updateEventSource.listen('notice', function(message) {
|
||||
$('<span>').addClass('error').append(message).append('<br />').appendTo($el);
|
||||
});
|
||||
updateEventSource.listen('error', function(message) {
|
||||
$('<span>').addClass('error').append(message).append('<br />').appendTo($el);
|
||||
message = t('core', 'Please reload the page.');
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n minute ago_::_%n minutes ago_" => array("",""),
|
||||
"_%n hour ago_::_%n hours ago_" => array("",""),
|
||||
"_%n day ago_::_%n days ago_" => array("",""),
|
||||
"_%n month ago_::_%n months ago_" => array("",""),
|
||||
"_{count} file conflict_::_{count} file conflicts_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
@@ -337,7 +337,7 @@
|
||||
var $row = $(this);
|
||||
var item = $row.data('result');
|
||||
if(self.hasHandler(item.type)){
|
||||
var result = self.getHandler(item.type)($row, result, event);
|
||||
var result = self.getHandler(item.type)($row, item, event);
|
||||
$searchBox.val('');
|
||||
if(self.hasFilter(getCurrentApp())) {
|
||||
self.getFilter(getCurrentApp())('');
|
||||
@@ -360,10 +360,17 @@
|
||||
})();
|
||||
|
||||
$(document).ready(function() {
|
||||
var $searchResults = $('<div id="searchresults" class="hidden"/>');
|
||||
$('#app-content')
|
||||
.append($searchResults)
|
||||
.find('.viewcontainer').css('min-height', 'initial');
|
||||
var $searchResults = $('#searchresults');
|
||||
if ($searchResults.length) {
|
||||
$searchResults.addClass('hidden');
|
||||
$('#app-content')
|
||||
.find('.viewcontainer').css('min-height', 'initial');
|
||||
} else {
|
||||
$searchResults = $('<div id="searchresults" class="hidden"/>');
|
||||
$('#app-content')
|
||||
.append($searchResults)
|
||||
.find('.viewcontainer').css('min-height', 'initial');
|
||||
}
|
||||
$searchResults.load(OC.webroot + '/core/search/templates/part.results.html', function () {
|
||||
OC.Search = new OCA.Search($('#searchbox'), $('#searchresults'));
|
||||
});
|
||||
|
||||
@@ -24,6 +24,12 @@ script('core', [
|
||||
<?php p($message); ?><br>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php if (isset($_['internalexception']) && ($_['internalexception'])): ?>
|
||||
<div class="warning">
|
||||
<?php p($l->t('An internal error occured.')); ?><br>
|
||||
<small><?php p($l->t('Please try again or contact your administrator.')); ?></small>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<p id="message" class="hidden">
|
||||
<img class="float-spinner" alt=""
|
||||
src="<?php p(\OCP\Util::imagePath('core', 'loading-dark.gif'));?>" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<ul>
|
||||
<li class='update'>
|
||||
<?php p($l->t('This %s instance is currently being updated, which may take a while.', array($theme->getName()))) ?><br/><br/>
|
||||
<?php p($l->t('This %s instance is currently in maintenance mode, which may take a while.', array($theme->getName()))) ?><br/><br/>
|
||||
<?php p($l->t('This page will refresh itself when the %s instance is available again.', array($theme->getName()))) ?><br/><br/>
|
||||
<?php p($l->t('Contact your system administrator if this message persists or appeared unexpectedly.')) ?><br/><br/>
|
||||
<?php p($l->t('Thank you for your patience.')); ?><br/><br/>
|
||||
|
||||
27
cron.php
27
cron.php
@@ -50,7 +50,16 @@ try {
|
||||
|
||||
if (\OCP\Util::needUpgrade()) {
|
||||
\OCP\Util::writeLog('cron', 'Update required, skipping cron', \OCP\Util::DEBUG);
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
|
||||
\OCP\Util::writeLog('cron', 'We are in maintenance mode, skipping cron', \OCP\Util::DEBUG);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (\OC::$server->getSystemConfig()->getValue('singleuser', false)) {
|
||||
\OCP\Util::writeLog('cron', 'We are in admin only mode, skipping cron', \OCP\Util::DEBUG);
|
||||
exit;
|
||||
}
|
||||
|
||||
// load all apps to get all api routes properly setup
|
||||
@@ -86,6 +95,22 @@ try {
|
||||
}
|
||||
|
||||
if (OC::$CLI) {
|
||||
// the cron job must be executed with the right user
|
||||
if (!OC_Util::runningOnWindows()) {
|
||||
if (!function_exists('posix_getuid')) {
|
||||
echo "The posix extensions are required - see http://php.net/manual/en/book.posix.php" . PHP_EOL;
|
||||
exit(0);
|
||||
}
|
||||
$user = posix_getpwuid(posix_getuid());
|
||||
$configUser = posix_getpwuid(fileowner(OC::$SERVERROOT . '/config/config.php'));
|
||||
if ($user['name'] !== $configUser['name']) {
|
||||
echo "Console has to be executed with the same user as the web server is operated" . PHP_EOL;
|
||||
echo "Current user: " . $user['name'] . PHP_EOL;
|
||||
echo "Web server user: " . $configUser['name'] . PHP_EOL;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Create lock file first
|
||||
TemporaryCronClass::$lockfile = OC_Config::getValue("datadirectory", OC::$SERVERROOT . '/data') . '/cron.lock';
|
||||
|
||||
|
||||
82
lib/base.php
82
lib/base.php
@@ -263,27 +263,37 @@ class OC {
|
||||
header('Retry-After: 120');
|
||||
|
||||
// render error page
|
||||
$tmpl = new OC_Template('', 'update.user', 'guest');
|
||||
$template = new OC_Template('', 'update.user', 'guest');
|
||||
OC_Util::addscript('maintenance-check');
|
||||
$tmpl->printPage();
|
||||
$template->printPage();
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
public static function checkSingleUserMode() {
|
||||
$user = OC_User::getUserSession()->getUser();
|
||||
$group = OC_Group::getManager()->get('admin');
|
||||
if ($user && \OC::$server->getSystemConfig()->getValue('singleuser', false) && !$group->inGroup($user)) {
|
||||
// send http status 503
|
||||
header('HTTP/1.1 503 Service Temporarily Unavailable');
|
||||
header('Status: 503 Service Temporarily Unavailable');
|
||||
header('Retry-After: 120');
|
||||
|
||||
// render error page
|
||||
$tmpl = new OC_Template('', 'singleuser.user', 'guest');
|
||||
$tmpl->printPage();
|
||||
die();
|
||||
public static function checkSingleUserMode($lockIfNoUserLoggedIn = false) {
|
||||
if (!\OC::$server->getSystemConfig()->getValue('singleuser', false)) {
|
||||
return;
|
||||
}
|
||||
$user = OC_User::getUserSession()->getUser();
|
||||
if ($user) {
|
||||
$group = \OC::$server->getGroupManager()->get('admin');
|
||||
if ($group->inGroup($user)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(!$lockIfNoUserLoggedIn) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// send http status 503
|
||||
header('HTTP/1.1 503 Service Temporarily Unavailable');
|
||||
header('Status: 503 Service Temporarily Unavailable');
|
||||
header('Retry-After: 120');
|
||||
|
||||
// render error page
|
||||
$template = new OC_Template('', 'singleuser.user', 'guest');
|
||||
$template->printPage();
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -478,7 +488,10 @@ class OC {
|
||||
require_once $vendorAutoLoad;
|
||||
} else {
|
||||
OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
|
||||
OC_Template::printErrorPage('Composer autoloader not found, unable to continue.');
|
||||
// we can't use the template error page here, because this needs the
|
||||
// DI container which isn't available yet
|
||||
print('Composer autoloader not found, unable to continue. Check the folder "3rdparty".');
|
||||
exit();
|
||||
}
|
||||
|
||||
// setup the basic server
|
||||
@@ -486,12 +499,11 @@ class OC {
|
||||
\OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
|
||||
\OC::$server->getEventLogger()->start('boot', 'Initialize');
|
||||
|
||||
// set some stuff
|
||||
//ob_start();
|
||||
// Don't display errors and log them
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
if (defined('DEBUG') && DEBUG) {
|
||||
ini_set('display_errors', 1);
|
||||
}
|
||||
@ini_set('display_errors', 0);
|
||||
@ini_set('log_errors', 1);
|
||||
|
||||
self::$CLI = (php_sapi_name() == 'cli');
|
||||
|
||||
date_default_timezone_set('UTC');
|
||||
@@ -550,15 +562,30 @@ class OC {
|
||||
$errors = OC_Util::checkServer(\OC::$server->getConfig());
|
||||
if (count($errors) > 0) {
|
||||
if (self::$CLI) {
|
||||
// Convert l10n string into regular string for usage in database
|
||||
$staticErrors = [];
|
||||
foreach ($errors as $error) {
|
||||
echo $error['error'] . "\n";
|
||||
echo $error['hint'] . "\n\n";
|
||||
$staticErrors[] = [
|
||||
'error' => (string) $error['error'],
|
||||
'hint' => (string) $error['hint'],
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
\OC::$server->getConfig()->setAppValue('core', 'cronErrors', json_encode($staticErrors));
|
||||
} catch(\Exception $e) {
|
||||
echo('Writing to database failed');
|
||||
}
|
||||
exit();
|
||||
} else {
|
||||
OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
|
||||
OC_Template::printGuestPage('', 'error', array('errors' => $errors));
|
||||
exit;
|
||||
}
|
||||
exit;
|
||||
} elseif(self::$CLI && \OC::$server->getConfig()->getSystemValue('installed', false)) {
|
||||
\OC::$server->getConfig()->deleteAppValue('core', 'cronErrors');
|
||||
}
|
||||
|
||||
//try to set the session lifetime
|
||||
@@ -736,6 +763,9 @@ class OC {
|
||||
self::checkUpgrade();
|
||||
}
|
||||
|
||||
// Always load authentication apps
|
||||
OC_App::loadApps(['authentication']);
|
||||
|
||||
// Load minimum set of apps
|
||||
if (!self::checkUpgrade(false)
|
||||
&& !$systemConfig->getValue('maintenance', false)
|
||||
@@ -744,8 +774,7 @@ class OC {
|
||||
if(OC_User::isLoggedIn()) {
|
||||
OC_App::loadApps();
|
||||
} else {
|
||||
// For guests: Load only authentication, filesystem and logging
|
||||
OC_App::loadApps(array('authentication'));
|
||||
// For guests: Load only filesystem and logging
|
||||
OC_App::loadApps(array('filesystem', 'logging'));
|
||||
\OC_User::tryBasicAuthLogin();
|
||||
}
|
||||
@@ -754,7 +783,6 @@ class OC {
|
||||
if (!self::$CLI and (!isset($_GET["logout"]) or ($_GET["logout"] !== 'true'))) {
|
||||
try {
|
||||
if (!$systemConfig->getValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
|
||||
OC_App::loadApps(array('authentication'));
|
||||
OC_App::loadApps(array('filesystem', 'logging'));
|
||||
OC_App::loadApps();
|
||||
}
|
||||
@@ -861,6 +889,10 @@ class OC {
|
||||
}
|
||||
} catch (\OC\User\LoginException $e) {
|
||||
$messages[] = $e->getMessage();
|
||||
} catch (\Exception $ex) {
|
||||
\OCP\Util::logException('handleLogin', $ex);
|
||||
// do not disclose information. show generic error
|
||||
$error[] = 'internalexception';
|
||||
}
|
||||
|
||||
OC_Util::displayLoginPage(array_unique($error), $messages);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n minute ago_::_%n minutes ago_" => array("",""),
|
||||
"_%n hour ago_::_%n hours ago_" => array("",""),
|
||||
"_%n day go_::_%n days ago_" => array("",""),
|
||||
"_%n month ago_::_%n months ago_" => array("","")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user