Merge pull request #12452 from owncloud/server2server-ng-ocs
OCS API for server-to-server sharingremotes/origin/fix-10825
commit
1362c0b67a
@ -0,0 +1,224 @@ |
||||
<?php |
||||
/** |
||||
* ownCloud - OCS API for server-to-server shares |
||||
* |
||||
* @copyright (C) 2014 ownCloud, Inc. |
||||
* |
||||
* @author Bjoern Schiessle <schiessle@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\API; |
||||
|
||||
class Server2Server { |
||||
|
||||
/** |
||||
* create a new share |
||||
* |
||||
* @param array $params |
||||
* @return \OC_OCS_Result |
||||
*/ |
||||
public function createShare($params) { |
||||
|
||||
if (!$this->isS2SEnabled(true)) { |
||||
return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); |
||||
} |
||||
|
||||
$remote = isset($_POST['remote']) ? $_POST['remote'] : null; |
||||
$token = isset($_POST['token']) ? $_POST['token'] : null; |
||||
$name = isset($_POST['name']) ? $_POST['name'] : null; |
||||
$owner = isset($_POST['owner']) ? $_POST['owner'] : null; |
||||
$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; |
||||
$remoteId = isset($_POST['remote_id']) ? (int)$_POST['remote_id'] : null; |
||||
|
||||
if ($remote && $token && $name && $owner && $remoteId && $shareWith) { |
||||
|
||||
if(!\OCP\Util::isValidFileName($name)) { |
||||
return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.'); |
||||
} |
||||
|
||||
if (!\OCP\User::userExists($shareWith)) { |
||||
return new \OC_OCS_Result(null, 400, 'User does not exists'); |
||||
} |
||||
|
||||
\OC_Util::setupFS($shareWith); |
||||
|
||||
$mountPoint = \OC\Files\Filesystem::normalizePath('/' . $name); |
||||
$name = \OCP\Files::buildNotExistingFileName('/', $name); |
||||
|
||||
try { |
||||
\OCA\Files_Sharing\Helper::addServer2ServerShare($remote, $token, $name, $mountPoint, $owner, $shareWith, '', $remoteId); |
||||
|
||||
\OC::$server->getActivityManager()->publishActivity( |
||||
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($owner), '', array(), |
||||
'', '', $shareWith, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); |
||||
|
||||
return new \OC_OCS_Result(); |
||||
} catch (\Exception $e) { |
||||
return new \OC_OCS_Result(null, 500, 'server can not add remote share, ' . $e->getMessage()); |
||||
} |
||||
} |
||||
|
||||
return new \OC_OCS_Result(null, 400, 'server can not add remote share, missing parameter'); |
||||
} |
||||
|
||||
/** |
||||
* accept server-to-server share |
||||
* |
||||
* @param array $params |
||||
* @return \OC_OCS_Result |
||||
*/ |
||||
public function acceptShare($params) { |
||||
|
||||
if (!$this->isS2SEnabled()) { |
||||
return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); |
||||
} |
||||
|
||||
$id = $params['id']; |
||||
$token = isset($_POST['token']) ? $_POST['token'] : null; |
||||
$share = self::getShare($id, $token); |
||||
|
||||
if ($share) { |
||||
list($file, $link) = self::getFile($share['uid_owner'], $share['file_source']); |
||||
|
||||
\OC::$server->getActivityManager()->publishActivity( |
||||
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, array($share['share_with'], basename($file)), '', array(), |
||||
$file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); |
||||
} |
||||
|
||||
return new \OC_OCS_Result(); |
||||
} |
||||
|
||||
/** |
||||
* decline server-to-server share |
||||
* |
||||
* @param array $params |
||||
* @return \OC_OCS_Result |
||||
*/ |
||||
public function declineShare($params) { |
||||
|
||||
if (!$this->isS2SEnabled()) { |
||||
return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); |
||||
} |
||||
|
||||
$id = $params['id']; |
||||
$token = isset($_POST['token']) ? $_POST['token'] : null; |
||||
|
||||
$share = $this->getShare($id, $token); |
||||
|
||||
if ($share) { |
||||
// userId must be set to the user who unshares |
||||
\OCP\Share::unshare($share['item_type'], $share['item_source'], $share['share_type'], null, $share['uid_owner']); |
||||
|
||||
list($file, $link) = $this->getFile($share['uid_owner'], $share['file_source']); |
||||
|
||||
\OC::$server->getActivityManager()->publishActivity( |
||||
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($share['share_with'], basename($file)), '', array(), |
||||
$file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); |
||||
} |
||||
|
||||
return new \OC_OCS_Result(); |
||||
} |
||||
|
||||
/** |
||||
* remove server-to-server share if it was unshared by the owner |
||||
* |
||||
* @param array $params |
||||
* @return \OC_OCS_Result |
||||
*/ |
||||
public function unshare($params) { |
||||
|
||||
if (!$this->isS2SEnabled()) { |
||||
return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing'); |
||||
} |
||||
|
||||
$id = $params['id']; |
||||
$token = isset($_POST['token']) ? $_POST['token'] : null; |
||||
|
||||
$query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?'); |
||||
$query->execute(array($id, $token)); |
||||
$share = $query->fetchRow(); |
||||
|
||||
if ($token && $id && !empty($share)) { |
||||
|
||||
$owner = $share['owner'] . '@' . $share['remote']; |
||||
$mountpoint = $share['mountpoint']; |
||||
$user = $share['user']; |
||||
|
||||
$query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?'); |
||||
$query->execute(array($id, $token)); |
||||
|
||||
\OC::$server->getActivityManager()->publishActivity( |
||||
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($owner, $mountpoint), '', array(), |
||||
'', '', $user, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_MEDIUM); |
||||
} |
||||
|
||||
return new \OC_OCS_Result(); |
||||
} |
||||
|
||||
/** |
||||
* get share |
||||
* |
||||
* @param int $id |
||||
* @param string $token |
||||
* @return array |
||||
*/ |
||||
private function getShare($id, $token) { |
||||
$query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ? AND `token` = ? AND `share_type` = ?'); |
||||
$query->execute(array($id, $token, \OCP\Share::SHARE_TYPE_REMOTE)); |
||||
$share = $query->fetchRow(); |
||||
|
||||
return $share; |
||||
} |
||||
|
||||
/** |
||||
* get file |
||||
* |
||||
* @param string $user |
||||
* @param int $fileSource |
||||
* @return array with internal path of the file and a absolute link to it |
||||
*/ |
||||
private function getFile($user, $fileSource) { |
||||
\OC_Util::setupFS($user); |
||||
|
||||
$file = \OC\Files\Filesystem::getPath($fileSource); |
||||
$args = \OC\Files\Filesystem::is_dir($file) ? array('dir' => $file) : array('dir' => dirname($file), 'scrollto' => $file); |
||||
$link = \OCP\Util::linkToAbsolute('files', 'index.php', $args); |
||||
|
||||
return array($file, $link); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* check if server-to-server sharing is enabled |
||||
* |
||||
* @param bool $incoming |
||||
* @return bool |
||||
*/ |
||||
private function isS2SEnabled($incoming = false) { |
||||
|
||||
$result = \OCP\App::isEnabled('files_sharing'); |
||||
|
||||
if ($incoming) { |
||||
$result = $result && \OCA\Files_Sharing\Helper::isIncomingServer2serverShareEnabled(); |
||||
} else { |
||||
$result = $result && \OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled(); |
||||
} |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
} |
@ -1 +1 @@ |
||||
0.5.3 |
||||
0.5.4 |
||||
|
@ -0,0 +1,165 @@ |
||||
<?php |
||||
/** |
||||
* ownCloud - publish activities |
||||
* |
||||
* @copyright (c) 2014, ownCloud Inc. |
||||
* |
||||
* @author Bjoern Schiessle <schiessle@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; |
||||
|
||||
class Activity implements \OCP\Activity\IExtension { |
||||
|
||||
const TYPE_REMOTE_SHARE = 'remote_share'; |
||||
const SUBJECT_REMOTE_SHARE_RECEIVED = 'remote_share_received'; |
||||
const SUBJECT_REMOTE_SHARE_ACCEPTED = 'remote_share_accepted'; |
||||
const SUBJECT_REMOTE_SHARE_DECLINED = 'remote_share_declined'; |
||||
const SUBJECT_REMOTE_SHARE_UNSHARED = 'remote_share_unshared'; |
||||
|
||||
/** |
||||
* The extension can return an array of additional notification types. |
||||
* If no additional types are to be added false is to be returned |
||||
* |
||||
* @param string $languageCode |
||||
* @return array|false |
||||
*/ |
||||
public function getNotificationTypes($languageCode) { |
||||
$l = \OC::$server->getL10N('files_sharing', $languageCode); |
||||
return array(self::TYPE_REMOTE_SHARE => $l->t('A file or folder was shared from <strong>another server</strong>')); |
||||
} |
||||
|
||||
/** |
||||
* The extension can filter the types based on the filter if required. |
||||
* In case no filter is to be applied false is to be returned unchanged. |
||||
* |
||||
* @param array $types |
||||
* @param string $filter |
||||
* @return array|false |
||||
*/ |
||||
public function filterNotificationTypes($types, $filter) { |
||||
return $types; |
||||
} |
||||
|
||||
/** |
||||
* For a given method additional types to be displayed in the settings can be returned. |
||||
* In case no additional types are to be added false is to be returned. |
||||
* |
||||
* @param string $method |
||||
* @return array|false |
||||
*/ |
||||
public function getDefaultTypes($method) { |
||||
if ($method === 'stream') { |
||||
return array(self::TYPE_REMOTE_SHARE); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* The extension can translate a given message to the requested languages. |
||||
* If no translation is available false is to be returned. |
||||
* |
||||
* @param string $app |
||||
* @param string $text |
||||
* @param array $params |
||||
* @param boolean $stripPath |
||||
* @param boolean $highlightParams |
||||
* @param string $languageCode |
||||
* @return string|false |
||||
*/ |
||||
public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) { |
||||
|
||||
$l = \OC::$server->getL10N('files_sharing', $languageCode); |
||||
|
||||
if (!$text) { |
||||
return ''; |
||||
} |
||||
|
||||
if ($app === 'files_sharing') { |
||||
switch ($text) { |
||||
case self::SUBJECT_REMOTE_SHARE_RECEIVED: |
||||
return $l->t('You received a new remote share from %s', $params)->__toString(); |
||||
case self::SUBJECT_REMOTE_SHARE_ACCEPTED: |
||||
return $l->t('%1$s accepted remote share <strong>%2$s</strong>', $params)->__toString(); |
||||
case self::SUBJECT_REMOTE_SHARE_DECLINED: |
||||
return $l->t('%1$s declined remote share <strong>%2$s</strong>', $params)->__toString(); |
||||
case self::SUBJECT_REMOTE_SHARE_UNSHARED: |
||||
return $l->t('%1$s unshared <strong>%2$s</strong>', $params)->__toString(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* A string naming the css class for the icon to be used can be returned. |
||||
* If no icon is known for the given type false is to be returned. |
||||
* |
||||
* @param string $type |
||||
* @return string|false |
||||
*/ |
||||
public function getTypeIcon($type) { |
||||
return 'icon-share'; |
||||
} |
||||
|
||||
/** |
||||
* The extension can define the parameter grouping by returning the index as integer. |
||||
* In case no grouping is required false is to be returned. |
||||
* |
||||
* @param array $activity |
||||
* @return integer|false |
||||
*/ |
||||
public function getGroupParameter($activity) { |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* The extension can define additional navigation entries. The array returned has to contain two keys 'top' |
||||
* and 'apps' which hold arrays with the relevant entries. |
||||
* If no further entries are to be added false is no be returned. |
||||
* |
||||
* @return array|false |
||||
*/ |
||||
public function getNavigation() { |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* The extension can check if a customer filter (given by a query string like filter=abc) is valid or not. |
||||
* |
||||
* @param string $filterValue |
||||
* @return boolean |
||||
*/ |
||||
public function isFilterValid($filterValue) { |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* For a given filter the extension can specify the sql query conditions including parameters for that query. |
||||
* In case the extension does not know the filter false is to be returned. |
||||
* The query condition and the parameters are to be returned as array with two elements. |
||||
* E.g. return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%')); |
||||
* |
||||
* @param string $filter |
||||
* @return array|false |
||||
*/ |
||||
public function getQueryForFilter($filter) { |
||||
if ($filter === 'shares') { |
||||
return array('`app` = ? and `type` = ?', array('files_sharing', self::TYPE_REMOTE_SHARE)); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,102 @@ |
||||
<?php |
||||
/** |
||||
* ownCloud - test server-to-server OCS API |
||||
* |
||||
* @copyright (c) ownCloud, Inc. |
||||
* |
||||
* @author Bjoern Schiessle <schiessle@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/>. |
||||
* |
||||
*/ |
||||
|
||||
use OCA\Files_Sharing\Tests\TestCase; |
||||
|
||||
/** |
||||
* Class Test_Files_Sharing_Api |
||||
*/ |
||||
class Test_Files_Sharing_S2S_OCS_API extends TestCase { |
||||
|
||||
const TEST_FOLDER_NAME = '/folder_share_api_test'; |
||||
|
||||
private $s2s; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1); |
||||
\OCP\Share::registerBackend('test', 'Test_Share_Backend'); |
||||
|
||||
$this->s2s = new \OCA\Files_Sharing\API\Server2Server(); |
||||
} |
||||
|
||||
protected function tearDown() { |
||||
$query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external`'); |
||||
$query->execute(); |
||||
|
||||
parent::tearDown(); |
||||
} |
||||
|
||||
/** |
||||
* @medium |
||||
*/ |
||||
function testCreateShare() { |
||||
// simulate a post request |
||||
$_POST['remote'] = 'localhost'; |
||||
$_POST['token'] = 'token'; |
||||
$_POST['name'] = 'name'; |
||||
$_POST['owner'] = 'owner'; |
||||
$_POST['shareWith'] = self::TEST_FILES_SHARING_API_USER2; |
||||
$_POST['remote_id'] = 1; |
||||
|
||||
$result = $this->s2s->createShare(null); |
||||
|
||||
$this->assertTrue($result->succeeded()); |
||||
|
||||
$query = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share_external` WHERE `remote_id` = ?'); |
||||
$result = $query->execute(array('1')); |
||||
$data = $result->fetchRow(); |
||||
|
||||
$this->assertSame('localhost', $data['remote']); |
||||
$this->assertSame('token', $data['share_token']); |
||||
$this->assertSame('/name', $data['name']); |
||||
$this->assertSame('owner', $data['owner']); |
||||
$this->assertSame(self::TEST_FILES_SHARING_API_USER2, $data['user']); |
||||
$this->assertSame(1, (int)$data['remote_id']); |
||||
$this->assertSame(0, (int)$data['accepted']); |
||||
} |
||||
|
||||
|
||||
function testDeclineShare() { |
||||
$dummy = \OCP\DB::prepare(' |
||||
INSERT INTO `*PREFIX*share` |
||||
(`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`) |
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) |
||||
'); |
||||
$dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token')); |
||||
|
||||
$verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); |
||||
$result = $verify->execute(); |
||||
$data = $result->fetchAll(); |
||||
$this->assertSame(1, count($data)); |
||||
|
||||
$_POST['token'] = 'token'; |
||||
$this->s2s->declineShare(array('id' => $data[0]['id'])); |
||||
|
||||
$verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`'); |
||||
$result = $verify->execute(); |
||||
$data = $result->fetchAll(); |
||||
$this->assertEmpty($data); |
||||
} |
||||
} |
Loading…
Reference in new issue