diff options
Diffstat (limited to 'apps')
26 files changed, 379 insertions, 189 deletions
diff --git a/apps/files/appinfo/application.php b/apps/files/appinfo/application.php index 5203946f827..17637d6447c 100644 --- a/apps/files/appinfo/application.php +++ b/apps/files/appinfo/application.php @@ -8,7 +8,6 @@ namespace OCA\Files\Appinfo; -use OC\AppFramework\Utility\SimpleContainer; use OCA\Files\Controller\ApiController; use OCP\AppFramework\App; use \OCA\Files\Service\TagService; @@ -18,15 +17,17 @@ class Application extends App { public function __construct(array $urlParams=array()) { parent::__construct('files', $urlParams); $container = $this->getContainer(); + $server = $container->getServer(); /** * Controllers */ - $container->registerService('APIController', function (IContainer $c) { + $container->registerService('APIController', function (IContainer $c) use ($server) { return new ApiController( $c->query('AppName'), $c->query('Request'), - $c->query('TagService') + $c->query('TagService'), + $server->getPreviewManager() ); }); diff --git a/apps/files/controller/apicontroller.php b/apps/files/controller/apicontroller.php index de9fa20dde0..d6e62180df3 100644 --- a/apps/files/controller/apicontroller.php +++ b/apps/files/controller/apicontroller.php @@ -11,11 +11,11 @@ namespace OCA\Files\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Controller; use OCP\IRequest; -use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\DataDisplayResponse; use OCP\AppFramework\Http\DownloadResponse; -use OC\Preview; use OCA\Files\Service\TagService; +use OCP\IPreview; /** * Class ApiController @@ -25,17 +25,22 @@ use OCA\Files\Service\TagService; class ApiController extends Controller { /** @var TagService */ private $tagService; + /** @var IPreview */ + private $previewManager; /** * @param string $appName * @param IRequest $request * @param TagService $tagService + * @param IPreview $previewManager */ public function __construct($appName, IRequest $request, - TagService $tagService){ + TagService $tagService, + IPreview $previewManager){ parent::__construct($appName, $request); $this->tagService = $tagService; + $this->previewManager = $previewManager; } /** @@ -49,19 +54,18 @@ class ApiController extends Controller { * @param int $x * @param int $y * @param string $file URL-encoded filename - * @return JSONResponse|DownloadResponse + * @return DataResponse|DataDisplayResponse */ public function getThumbnail($x, $y, $file) { if($x < 1 || $y < 1) { - return new JSONResponse('Requested size must be numeric and a positive value.', Http::STATUS_BAD_REQUEST); + return new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST); } - try { - $preview = new Preview('', 'files', urldecode($file), $x, $y, true); - echo($preview->showPreview('image/png')); - return new DownloadResponse(urldecode($file).'.png', 'image/png'); - } catch (\Exception $e) { - return new JSONResponse('File not found.', Http::STATUS_NOT_FOUND); + $preview = $this->previewManager->createPreview('files/'.urldecode($file), $x, $y, true); + if ($preview->valid()) { + return new DataDisplayResponse($preview->data(), Http::STATUS_OK, ['Content-Type' => 'image/png']); + } else { + return new DataResponse(['message' => 'File not found.'], Http::STATUS_NOT_FOUND); } } diff --git a/apps/files/css/files.css b/apps/files/css/files.css index d546f346ce0..d34013db499 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -105,8 +105,14 @@ /* move Deleted Files to bottom of sidebar */ .nav-trashbin { - position: absolute !important; - bottom: 0; + position: fixed !important; + bottom: 44px; + width: inherit !important; + background-color: #f5f5f5; +} +/* double padding to account for Deleted files entry, issue with Firefox */ +.app-files #app-navigation > ul li:nth-last-child(2) { + margin-bottom: 44px; } #filestable tbody tr { background-color:#fff; height:40px; } @@ -582,6 +588,9 @@ table tr.summary td { .summary .info { margin-left: 40px; } +.has-favorites .summary .info { + margin-left: 90px; +} #scanning-message{ top:40%; left:40%; position:absolute; display:none; } diff --git a/apps/files/l10n/az.js b/apps/files/l10n/az.js index 18458119942..426038f4af7 100644 --- a/apps/files/l10n/az.js +++ b/apps/files/l10n/az.js @@ -91,6 +91,7 @@ OC.L10N.register( "Maximum upload size" : "Maksimal yükləmə həcmi", "max. possible: " : "maks. ola bilər: ", "Save" : "Saxlamaq", + "Can not be edited from here due to insufficient permissions." : "Yetki çatışmamazlığına görə, burdan başlayaraq dəyişiklik edə bilməzsiniz.", "Settings" : "Quraşdırmalar", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Bu ünvanı <a href=\"%s\" target=\"_blank\">WebDAV vasitəsilə fayllarınızı əldə etmək üçün</a> istifadə edə bilərsiniz. ", diff --git a/apps/files/l10n/az.json b/apps/files/l10n/az.json index a3efcef7dfc..c29461618a5 100644 --- a/apps/files/l10n/az.json +++ b/apps/files/l10n/az.json @@ -89,6 +89,7 @@ "Maximum upload size" : "Maksimal yükləmə həcmi", "max. possible: " : "maks. ola bilər: ", "Save" : "Saxlamaq", + "Can not be edited from here due to insufficient permissions." : "Yetki çatışmamazlığına görə, burdan başlayaraq dəyişiklik edə bilməzsiniz.", "Settings" : "Quraşdırmalar", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Bu ünvanı <a href=\"%s\" target=\"_blank\">WebDAV vasitəsilə fayllarınızı əldə etmək üçün</a> istifadə edə bilərsiniz. ", diff --git a/apps/files/l10n/en_GB.js b/apps/files/l10n/en_GB.js index 513f5f2f7d7..d243b859b5a 100644 --- a/apps/files/l10n/en_GB.js +++ b/apps/files/l10n/en_GB.js @@ -91,6 +91,7 @@ OC.L10N.register( "Maximum upload size" : "Maximum upload size", "max. possible: " : "max. possible: ", "Save" : "Save", + "Can not be edited from here due to insufficient permissions." : "Can not be edited from here due to insufficient permissions.", "Settings" : "Settings", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>", diff --git a/apps/files/l10n/en_GB.json b/apps/files/l10n/en_GB.json index 1523209bb97..a199bc0fdf1 100644 --- a/apps/files/l10n/en_GB.json +++ b/apps/files/l10n/en_GB.json @@ -89,6 +89,7 @@ "Maximum upload size" : "Maximum upload size", "max. possible: " : "max. possible: ", "Save" : "Save", + "Can not be edited from here due to insufficient permissions." : "Can not be edited from here due to insufficient permissions.", "Settings" : "Settings", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>", diff --git a/apps/files/l10n/ja.js b/apps/files/l10n/ja.js index 6f86088c49a..f6f055aa911 100644 --- a/apps/files/l10n/ja.js +++ b/apps/files/l10n/ja.js @@ -91,6 +91,7 @@ OC.L10N.register( "Maximum upload size" : "最大アップロードサイズ", "max. possible: " : "最大容量: ", "Save" : "保存", + "Can not be edited from here due to insufficient permissions." : "権限不足のため直接編集することはできません。", "Settings" : "設定", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">WebDAV経由でのファイルアクセス</a>にはこのアドレスを利用してください", diff --git a/apps/files/l10n/ja.json b/apps/files/l10n/ja.json index 18ce4dfbe3a..c73bb902ced 100644 --- a/apps/files/l10n/ja.json +++ b/apps/files/l10n/ja.json @@ -89,6 +89,7 @@ "Maximum upload size" : "最大アップロードサイズ", "max. possible: " : "最大容量: ", "Save" : "保存", + "Can not be edited from here due to insufficient permissions." : "権限不足のため直接編集することはできません。", "Settings" : "設定", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\">access your Files via WebDAV</a>" : "<a href=\"%s\" target=\"_blank\">WebDAV経由でのファイルアクセス</a>にはこのアドレスを利用してください", diff --git a/apps/files/tests/controller/apicontrollertest.php b/apps/files/tests/controller/apicontrollertest.php index 1be7a749a1b..1d4317f0bca 100644 --- a/apps/files/tests/controller/apicontrollertest.php +++ b/apps/files/tests/controller/apicontrollertest.php @@ -17,6 +17,8 @@ use Test\TestCase; use OCP\IRequest; use OCA\Files\Service\TagService; use OCP\AppFramework\Http\DataResponse; +use OCP\IPreview; +use OCP\Image; /** * Class ApiController @@ -30,6 +32,8 @@ class ApiControllerTest extends TestCase { private $request; /** @var TagService */ private $tagService; + /** @var IPreview */ + private $preview; /** @var ApiController */ private $apiController; @@ -40,11 +44,15 @@ class ApiControllerTest extends TestCase { $this->tagService = $this->getMockBuilder('\OCA\Files\Service\TagService') ->disableOriginalConstructor() ->getMock(); + $this->preview = $this->getMockBuilder('\OCP\IPreview') + ->disableOriginalConstructor() + ->getMock(); $this->apiController = new ApiController( $this->appName, $this->request, - $this->tagService + $this->tagService, + $this->preview ); } @@ -240,4 +248,29 @@ class ApiControllerTest extends TestCase { $expected = new DataResponse(['message' => 'My error message'], Http::STATUS_NOT_FOUND); $this->assertEquals($expected, $this->apiController->updateFileTags('/path.txt', ['Tag1', 'Tag2'])); } + + public function testGetThumbnailInvalidSize() { + $expected = new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST); + $this->assertEquals($expected, $this->apiController->getThumbnail(0, 0, '')); + } + + public function testGetThumbnailInvaidImage() { + $this->preview->expects($this->once()) + ->method('createPreview') + ->with('files/unknown.jpg', 10, 10, true) + ->willReturn(new Image); + $expected = new DataResponse(['message' => 'File not found.'], Http::STATUS_NOT_FOUND); + $this->assertEquals($expected, $this->apiController->getThumbnail(10, 10, 'unknown.jpg')); + } + + public function testGetThumbnail() { + $this->preview->expects($this->once()) + ->method('createPreview') + ->with('files/known.jpg', 10, 10, true) + ->willReturn(new Image(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + + $ret = $this->apiController->getThumbnail(10, 10, 'known.jpg'); + + $this->assertEquals(Http::STATUS_OK, $ret->getStatus()); + } } diff --git a/apps/files_external/l10n/az.js b/apps/files_external/l10n/az.js index 0db76d96278..4e1e0a9dccd 100644 --- a/apps/files_external/l10n/az.js +++ b/apps/files_external/l10n/az.js @@ -44,6 +44,9 @@ OC.L10N.register( "URL" : "URL", "Secure https://" : "Təhlükəsiz https://", "Public key" : "İctimai açar", + "Storage with id \"%i\" not found" : "\"%i\"-li depo tapılmadı", + "Invalid mount point" : "Yalnış mount nöqtəsi", + "Invalid storage backend \"%s\"" : "Yalnış depo arxasonu \"%s\"", "Access granted" : "Yetki verildi", "Error configuring Dropbox storage" : "Dropbox deposunun konfiqurasiyasında səhv baş verdi", "Grant access" : "Yetkinin verilməsi", diff --git a/apps/files_external/l10n/az.json b/apps/files_external/l10n/az.json index 267f30908a0..890c9d5424f 100644 --- a/apps/files_external/l10n/az.json +++ b/apps/files_external/l10n/az.json @@ -42,6 +42,9 @@ "URL" : "URL", "Secure https://" : "Təhlükəsiz https://", "Public key" : "İctimai açar", + "Storage with id \"%i\" not found" : "\"%i\"-li depo tapılmadı", + "Invalid mount point" : "Yalnış mount nöqtəsi", + "Invalid storage backend \"%s\"" : "Yalnış depo arxasonu \"%s\"", "Access granted" : "Yetki verildi", "Error configuring Dropbox storage" : "Dropbox deposunun konfiqurasiyasında səhv baş verdi", "Grant access" : "Yetkinin verilməsi", diff --git a/apps/files_external/l10n/en_GB.js b/apps/files_external/l10n/en_GB.js index 2ccf775f0be..85e58c8770f 100644 --- a/apps/files_external/l10n/en_GB.js +++ b/apps/files_external/l10n/en_GB.js @@ -44,6 +44,9 @@ OC.L10N.register( "URL" : "URL", "Secure https://" : "Secure https://", "Public key" : "Public key", + "Storage with id \"%i\" not found" : "Storage with id \"%i\" not found", + "Invalid mount point" : "Invalid mount point", + "Invalid storage backend \"%s\"" : "Invalid storage backend \"%s\"", "Access granted" : "Access granted", "Error configuring Dropbox storage" : "Error configuring Dropbox storage", "Grant access" : "Grant access", diff --git a/apps/files_external/l10n/en_GB.json b/apps/files_external/l10n/en_GB.json index 7e4415dbf7f..54e42a7a742 100644 --- a/apps/files_external/l10n/en_GB.json +++ b/apps/files_external/l10n/en_GB.json @@ -42,6 +42,9 @@ "URL" : "URL", "Secure https://" : "Secure https://", "Public key" : "Public key", + "Storage with id \"%i\" not found" : "Storage with id \"%i\" not found", + "Invalid mount point" : "Invalid mount point", + "Invalid storage backend \"%s\"" : "Invalid storage backend \"%s\"", "Access granted" : "Access granted", "Error configuring Dropbox storage" : "Error configuring Dropbox storage", "Grant access" : "Grant access", diff --git a/apps/files_sharing/ajax/external.php b/apps/files_sharing/ajax/external.php index 30c1f38801e..153285e11ff 100644 --- a/apps/files_sharing/ajax/external.php +++ b/apps/files_sharing/ajax/external.php @@ -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')))); diff --git a/apps/files_sharing/api/local.php b/apps/files_sharing/api/local.php index 87a8fbbb21f..3cf541b3fab 100644 --- a/apps/files_sharing/api/local.php +++ b/apps/files_sharing/api/local.php @@ -303,8 +303,7 @@ class Local { break; } } - $url = \OCP\Util::linkToPublic('files&t='.$token); - $data['url'] = $url; // '&' gets encoded to $amp; + $data['url'] = \OC::$server->getURLGenerator()->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]); $data['token'] = $token; } else { diff --git a/apps/files_sharing/api/server2server.php b/apps/files_sharing/api/server2server.php index f2f7561598f..89a0262481c 100644 --- a/apps/files_sharing/api/server2server.php +++ b/apps/files_sharing/api/server2server.php @@ -64,8 +64,6 @@ class Server2Server { $shareWith ); - $name = \OCP\Files::buildNotExistingFileName('/', $name); - try { $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); diff --git a/apps/files_sharing/lib/activity.php b/apps/files_sharing/lib/activity.php index 0cd874d69f0..50ec2f297d7 100644 --- a/apps/files_sharing/lib/activity.php +++ b/apps/files_sharing/lib/activity.php @@ -202,6 +202,7 @@ class Activity implements IExtension { } else if ($app === 'files') { switch ($text) { case self::SUBJECT_SHARED_LINK_SELF: + return [0 => 'file']; case self::SUBJECT_SHARED_USER_SELF: case self::SUBJECT_SHARED_WITH_BY: return [0 => 'file', 1 => 'username']; @@ -225,6 +226,19 @@ class Activity implements IExtension { * @return integer|false */ public function getGroupParameter($activity) { + if ($activity['app'] === 'files') { + switch ($activity['subject']) { + case self::SUBJECT_SHARED_LINK_SELF: + case self::SUBJECT_SHARED_WITH_BY: + // Group by file name + return 0; + case self::SUBJECT_SHARED_USER_SELF: + case self::SUBJECT_SHARED_GROUP_SELF: + // Group by user/group + return 1; + } + } + return false; } diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php index 490e5e5003d..1d937c29043 100644 --- a/apps/files_sharing/lib/external/manager.php +++ b/apps/files_sharing/lib/external/manager.php @@ -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); + + 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 = Filesystem::normalizePath('/' . $name); + $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`, `share_token`, `name` FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?'); $result = $getShare->execute(array($id, $this->uid)); @@ -142,11 +174,17 @@ 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)); + $acceptShare->execute(array(1, $mountPoint, $hash, $id, $this->uid)); $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $id, 'accept'); } } @@ -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 $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'; - return $result ? $openShares->fetchAll() : array(); + $shares = $this->connection->prepare($query); + $result = $shares->execute($parameters); + return $result ? $shares->fetchAll() : []; } } diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php index 371c94a8c88..4f9041ae27a 100644 --- a/apps/files_sharing/tests/api.php +++ b/apps/files_sharing/tests/api.php @@ -103,6 +103,11 @@ class Test_Files_Sharing_Api extends TestCase { // check if we have a token $this->assertTrue(is_string($data['token'])); + // check for correct link + $url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']); + $this->assertEquals($url, $data['url']); + + $share = $this->getShareFromId($data['id']); $items = \OCP\Share::getItemShared('file', $share['item_source']); diff --git a/apps/files_sharing/tests/external/manager.php b/apps/files_sharing/tests/external/manager.php deleted file mode 100644 index dcb3dfba692..00000000000 --- a/apps/files_sharing/tests/external/manager.php +++ /dev/null @@ -1,142 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -namespace OCA\Files_sharing\Tests\External; - -use OC\Files\Storage\StorageFactory; -use Test\TestCase; - -class Manager extends TestCase { - private $uid; - - /** - * @var \OC\Files\Mount\Manager - */ - private $mountManager; - - /** - * @var \OCA\Files_Sharing\External\Manager - */ - private $instance; - - public function setUp() { - $this->uid = uniqid(); - $this->mountManager = new \OC\Files\Mount\Manager(); - $this->instance = new \OCA\Files_Sharing\External\Manager(\OC::$server->getDatabaseConnection(), - $this->mountManager, new StorageFactory(), \OC::$server->getHTTPHelper(), $this->uid); - } - - public function tearDown() { - $this->instance->removeUserShares($this->uid); - } - - private function getFullPath($path) { - return '/' . $this->uid . '/files' . $path; - } - - private function assertMount($mountPoint) { - $mountPoint = rtrim($mountPoint, '/'); - $mount = $this->mountManager->find($this->getFullPath($mountPoint)); - $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); - } - } - - public function testAddBasic() { - $this->instance->addShare('http://example.com', 'foo', 'bar', 'example', 'me', true); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertMount('/example'); - } - - public function testAddBasicEmptyPassword() { - $this->instance->addShare('http://example.com', 'foo', '', 'example', 'me', true); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertMount('/example'); - } - - public function testAddNotAcceptedShare() { - $this->instance->addShare('http://example.com', 'foo', 'bar', 'example', 'me', false); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertNotMount('/example'); - } - - public function testAcceptMount() { - $this->instance->addShare('http://example.com', 'foo', 'bar', 'example', 'me', false); - $open = $this->instance->getOpenShares(); - $this->assertCount(1, $open); - $this->instance->acceptShare($open[0]['id']); - $this->assertEquals([], $this->instance->getOpenShares()); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertMount('/example'); - } - - public function testDeclineMount() { - $this->instance->addShare('http://example.com', 'foo', 'bar', 'example', 'me', false); - $open = $this->instance->getOpenShares(); - $this->assertCount(1, $open); - $this->instance->declineShare($open[0]['id']); - $this->assertEquals([], $this->instance->getOpenShares()); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertNotMount('/example'); - } - - public function testSetMountPoint() { - $this->instance->addShare('http://example.com', 'foo', 'bar', 'example', 'me', true); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertMount('/example'); - $this->instance->setMountPoint($this->getFullPath('/example'), $this->getFullPath('/renamed')); - $this->mountManager->clear(); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertMount('/renamed'); - $this->assertNotMount('/example'); - } - - public function testRemoveShare() { - $this->instance->addShare('http://example.com', 'foo', 'bar', 'example', 'me', true); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertMount('/example'); - $this->instance->removeShare($this->getFullPath('/example')); - $this->mountManager->clear(); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertNotMount('/example'); - } - - public function testRemoveShareForUser() { - $this->instance->addShare('http://example.com', 'foo', 'bar', 'example', 'me', true); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertMount('/example'); - $this->instance->removeUserShares($this->uid); - $this->mountManager->clear(); - \Test_Helper::invokePrivate($this->instance, 'setupMounts'); - $this->assertNotMount('/example'); - } -} diff --git a/apps/files_sharing/tests/external/managertest.php b/apps/files_sharing/tests/external/managertest.php new file mode 100644 index 00000000000..4158b1bf445 --- /dev/null +++ b/apps/files_sharing/tests/external/managertest.php @@ -0,0 +1,194 @@ +<?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\Tests\TestCase; + +class ManagerTest extends TestCase { + + /** @var \OCA\Files_Sharing\External\Manager **/ + private $manager; + + /** @var \OC\Files\Mount\Manager */ + private $mountManager; + + private $uid; + + protected function setUp() { + parent::setUp(); + + $this->uid = $this->getUniqueID('user'); + $this->mountManager = new \OC\Files\Mount\Manager(); + $this->manager = new \OCA\Files_Sharing\External\Manager( + \OC::$server->getDatabaseConnection(), + $this->mountManager, + new StorageFactory(), + $this->getMockBuilder('\OC\HTTPHelper')->disableOriginalConstructor()->getMock(), + $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'); + + // 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'); + + // 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->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; + } +} diff --git a/apps/user_ldap/l10n/el.js b/apps/user_ldap/l10n/el.js index cf6cdc061ef..f19d0023cd4 100644 --- a/apps/user_ldap/l10n/el.js +++ b/apps/user_ldap/l10n/el.js @@ -127,6 +127,7 @@ OC.L10N.register( "UUID Attribute for Users:" : "Χαρακτηριστικό UUID για Χρήστες:", "UUID Attribute for Groups:" : "Χαρακτηριστικό UUID για Ομάδες:", "Username-LDAP User Mapping" : "Αντιστοίχιση Χρηστών Όνομα Χρήστη-LDAP", + "Usernames are used to store and assign (meta) data. In order to precisely identify and recognize users, each LDAP user will have an internal username. This requires a mapping from username to LDAP user. The created username is mapped to the UUID of the LDAP user. Additionally the DN is cached as well to reduce LDAP interaction, but it is not used for identification. If the DN changes, the changes will be found. The internal username is used all over. Clearing the mappings will have leftovers everywhere. Clearing the mappings is not configuration sensitive, it affects all LDAP configurations! Never clear the mappings in a production environment, only in a testing or experimental stage." : "Τα ονόματα χρηστών χρησιμοποιούνται για την αποθήκευση και τον προσδιορισμό των (μετα) δεδομένων. Προκειμένου να προσδιοριστούν με ακρίβεια και να αναγνωριστούν οι χρήστες, κάθε χρήστης LDAP θα έχει ένα εσωτερικό όνομα. Αυτό απαιτεί μια αντιστοίχιση του ονόματος χρήστη με το χρήστη LDAP. Το όνομα χρήστη που δημιουργήθηκαν αντιστοιχίζεται στην UUID του χρήστη LDAP. Επιπροσθέτως, το DN αποθηκεύεται προσωρινά (cache) ώστε να μειωθεί η αλληλεπίδραση LDAP, αλλά δεν χρησιμοποιείται για την ταυτοποίηση. Αν το DN αλλάξει, οι αλλαγές θα εντοπιστούν. Το εσωτερικό όνομα χρήστη χρησιμοποιείται παντού. Η εκκαθάριση των αντιστοιχίσεων θα αφήσει υπολείμματα παντού. Η εκκαθάριση των αντιστοιχίσεων δεν επηρεάζεται από τη διαμόρφωση, επηρεάζει όλες τις διαμορφώσεις LDAP! Μην διαγράψετε ποτέ τις αντιστοιχίσεις σε ένα λειτουργικό περιβάλλον παρά μόνο σε δοκιμές ή σε πειραματικό στάδιο.", "Clear Username-LDAP User Mapping" : "Διαγραφή αντιστοίχησης Ονόματος Χρήστη LDAP-Χρήστη", "Clear Groupname-LDAP Group Mapping" : "Διαγραφή αντιστοίχησης Ονόματος Ομάδας-LDAP Ομάδας" }, diff --git a/apps/user_ldap/l10n/el.json b/apps/user_ldap/l10n/el.json index 59aac4319ee..49a4813b0a4 100644 --- a/apps/user_ldap/l10n/el.json +++ b/apps/user_ldap/l10n/el.json @@ -125,6 +125,7 @@ "UUID Attribute for Users:" : "Χαρακτηριστικό UUID για Χρήστες:", "UUID Attribute for Groups:" : "Χαρακτηριστικό UUID για Ομάδες:", "Username-LDAP User Mapping" : "Αντιστοίχιση Χρηστών Όνομα Χρήστη-LDAP", + "Usernames are used to store and assign (meta) data. In order to precisely identify and recognize users, each LDAP user will have an internal username. This requires a mapping from username to LDAP user. The created username is mapped to the UUID of the LDAP user. Additionally the DN is cached as well to reduce LDAP interaction, but it is not used for identification. If the DN changes, the changes will be found. The internal username is used all over. Clearing the mappings will have leftovers everywhere. Clearing the mappings is not configuration sensitive, it affects all LDAP configurations! Never clear the mappings in a production environment, only in a testing or experimental stage." : "Τα ονόματα χρηστών χρησιμοποιούνται για την αποθήκευση και τον προσδιορισμό των (μετα) δεδομένων. Προκειμένου να προσδιοριστούν με ακρίβεια και να αναγνωριστούν οι χρήστες, κάθε χρήστης LDAP θα έχει ένα εσωτερικό όνομα. Αυτό απαιτεί μια αντιστοίχιση του ονόματος χρήστη με το χρήστη LDAP. Το όνομα χρήστη που δημιουργήθηκαν αντιστοιχίζεται στην UUID του χρήστη LDAP. Επιπροσθέτως, το DN αποθηκεύεται προσωρινά (cache) ώστε να μειωθεί η αλληλεπίδραση LDAP, αλλά δεν χρησιμοποιείται για την ταυτοποίηση. Αν το DN αλλάξει, οι αλλαγές θα εντοπιστούν. Το εσωτερικό όνομα χρήστη χρησιμοποιείται παντού. Η εκκαθάριση των αντιστοιχίσεων θα αφήσει υπολείμματα παντού. Η εκκαθάριση των αντιστοιχίσεων δεν επηρεάζεται από τη διαμόρφωση, επηρεάζει όλες τις διαμορφώσεις LDAP! Μην διαγράψετε ποτέ τις αντιστοιχίσεις σε ένα λειτουργικό περιβάλλον παρά μόνο σε δοκιμές ή σε πειραματικό στάδιο.", "Clear Username-LDAP User Mapping" : "Διαγραφή αντιστοίχησης Ονόματος Χρήστη LDAP-Χρήστη", "Clear Groupname-LDAP Group Mapping" : "Διαγραφή αντιστοίχησης Ονόματος Ομάδας-LDAP Ομάδας" },"pluralForm" :"nplurals=2; plural=(n != 1);" diff --git a/apps/user_webdavauth/l10n/sr.js b/apps/user_webdavauth/l10n/sr.js index df3c00a5585..a68c0e94395 100644 --- a/apps/user_webdavauth/l10n/sr.js +++ b/apps/user_webdavauth/l10n/sr.js @@ -1,7 +1,7 @@ OC.L10N.register( "user_webdavauth", { - "WebDAV Authentication" : "ВебДАВ провера идентитета", + "WebDAV Authentication" : "ВебДАВ аутентификација", "Address:" : "Адреса:", "Save" : "Сачувај", "The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." : "Кориснички акредитиви биће послати на ову адресу. Прикључак проверава одговор и ХТТП кодове 401 и 403 тумачиће као неисправне акредитиве а све остале одговоре као исправне." diff --git a/apps/user_webdavauth/l10n/sr.json b/apps/user_webdavauth/l10n/sr.json index 037fd2929b1..5a999a10e71 100644 --- a/apps/user_webdavauth/l10n/sr.json +++ b/apps/user_webdavauth/l10n/sr.json @@ -1,5 +1,5 @@ { "translations": { - "WebDAV Authentication" : "ВебДАВ провера идентитета", + "WebDAV Authentication" : "ВебДАВ аутентификација", "Address:" : "Адреса:", "Save" : "Сачувај", "The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." : "Кориснички акредитиви биће послати на ову адресу. Прикључак проверава одговор и ХТТП кодове 401 и 403 тумачиће као неисправне акредитиве а све остале одговоре као исправне." |