Merge pull request #657 from nextcloud/share-by-mail

New share provider: Share by mail
This commit is contained in:
Joas Schilling 2016-11-02 11:04:33 +01:00 committed by GitHub
commit 7da3ba3f91
25 changed files with 2124 additions and 294 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@
!/apps/files
!/apps/federation
!/apps/federatedfilesharing
!/apps/sharebymail
!/apps/encryption
!/apps/files_external
!/apps/files_sharing

View File

@ -200,7 +200,8 @@ class ApiController extends Controller {
\OCP\Share::SHARE_TYPE_USER,
\OCP\Share::SHARE_TYPE_GROUP,
\OCP\Share::SHARE_TYPE_LINK,
\OCP\Share::SHARE_TYPE_REMOTE
\OCP\Share::SHARE_TYPE_REMOTE,
\OCP\Share::SHARE_TYPE_EMAIL
];
foreach ($requestedShareTypes as $requestedShareType) {
// one of each type is enough to find out about the types

View File

@ -36,7 +36,6 @@ use OCP\IL10N;
use OCP\IUserManager;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Files\IRootFolder;
use OCP\Lock\LockedException;
use OCP\Share\IManager;
@ -186,7 +185,11 @@ class ShareAPIController extends OCSController {
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $share->getSharedWith();
$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
$result['token'] = $share->getToken();
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
$result['token'] = $share->getToken();
}
@ -195,6 +198,28 @@ class ShareAPIController extends OCSController {
return $result;
}
/**
* Check if one of the users address books knows the exact property, if
* yes we return the full name.
*
* @param string $query
* @param string $property
* @return string
*/
private function getDisplayNameFromAddressBook($query, $property) {
// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
$result = \OC::$server->getContactsManager()->search($query, [$property]);
foreach ($result as $r) {
foreach($r[$property] as $value) {
if ($value === $query) {
return $r['FN'];
}
}
}
return $query;
}
/**
* Get a specific share by id
*
@ -400,6 +425,17 @@ class ShareAPIController extends OCSController {
$share->setSharedWith($shareWith);
$share->setPermissions($permissions);
} else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
if ($share->getNodeType() === 'file') {
$share->setPermissions(\OCP\Constants::PERMISSION_READ);
} else {
$share->setPermissions(
\OCP\Constants::PERMISSION_READ |
\OCP\Constants::PERMISSION_CREATE |
\OCP\Constants::PERMISSION_UPDATE |
\OCP\Constants::PERMISSION_DELETE);
}
$share->setSharedWith($shareWith);
} else {
throw new OCSBadRequestException($this->l->t('Unknown share type'));
}
@ -466,6 +502,9 @@ class ShareAPIController extends OCSController {
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
if($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $node, false, -1, 0));
}
if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
$shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
}
@ -541,7 +580,12 @@ class ShareAPIController extends OCSController {
$userShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
$groupShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
$linkShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
$shares = array_merge($userShares, $groupShares, $linkShares);
if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
$mailShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
} else {
$mailShares = [];
}
$shares = array_merge($userShares, $groupShares, $linkShares, $mailShares);
if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
$federatedShares = $this->shareManager->getSharesBy($this->currentUser, \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
@ -774,14 +818,25 @@ class ShareAPIController extends OCSController {
// First check if it is an internal share.
try {
$share = $this->shareManager->getShareById('ocinternal:' . $id);
return $share;
} catch (ShareNotFound $e) {
if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
throw new ShareNotFound();
}
$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
// Do nothing, just try the other share type
}
try {
if ($this->shareManager->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
$share = $this->shareManager->getShareById('ocMailShare:' . $id);
return $share;
}
} catch (ShareNotFound $e) {
// Do nothing, just try the other share type
}
if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
throw new ShareNotFound();
}
$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id);
return $share;
}

View File

@ -273,15 +273,15 @@ class ShareesAPIController extends OCSController {
/**
* @param string $search
* @return array possible sharees
* @return array
*/
protected function getRemote($search) {
$this->result['remotes'] = [];
$result = ['results' => [], 'exact' => []];
// Search in contacts
//@todo Pagination missing
$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
$foundRemoteById = false;
$result['exactIdMatch'] = false;
foreach ($addressBookContacts as $contact) {
if (isset($contact['isLocalSystemBook'])) {
continue;
@ -295,10 +295,10 @@ class ShareesAPIController extends OCSController {
list(, $serverUrl) = $this->splitUserRemote($cloudId);
if (strtolower($contact['FN']) === strtolower($search) || strtolower($cloudId) === strtolower($search)) {
if (strtolower($cloudId) === strtolower($search)) {
$foundRemoteById = true;
$result['exactIdMatch'] = true;
}
$this->result['exact']['remotes'][] = [
'label' => $contact['FN'],
$result['exact'][] = [
'label' => $contact['FN'] . " ($cloudId)",
'value' => [
'shareType' => Share::SHARE_TYPE_REMOTE,
'shareWith' => $cloudId,
@ -306,8 +306,8 @@ class ShareesAPIController extends OCSController {
],
];
} else {
$this->result['remotes'][] = [
'label' => $contact['FN'],
$result['results'][] = [
'label' => $contact['FN'] . " ($cloudId)",
'value' => [
'shareType' => Share::SHARE_TYPE_REMOTE,
'shareWith' => $cloudId,
@ -320,11 +320,11 @@ class ShareesAPIController extends OCSController {
}
if (!$this->shareeEnumeration) {
$this->result['remotes'] = [];
$result['results'] = [];
}
if (!$foundRemoteById && substr_count($search, '@') >= 1 && $this->offset === 0) {
$this->result['exact']['remotes'][] = [
if (!$result['exactIdMatch'] && substr_count($search, '@') >= 1 && $this->offset === 0) {
$result['exact'][] = [
'label' => $search,
'value' => [
'shareType' => Share::SHARE_TYPE_REMOTE,
@ -334,6 +334,8 @@ class ShareesAPIController extends OCSController {
}
$this->reachedEndFor[] = 'remotes';
return $result;
}
/**
@ -404,68 +406,6 @@ class ShareesAPIController extends OCSController {
return $remote;
}
/**
* @param string $search
*/
protected function getEmails($search) {
$this->result['emails'] = [];
$this->result['exact']['emails'] = [];
$foundEmail = false;
// Search in contacts
//@todo Pagination missing
$addressBookContacts = $this->contactsManager->search($search, ['FN', 'EMAIL']);
foreach ($addressBookContacts as $contact) {
if (!isset($contact['EMAIL'])) {
continue;
}
$emails = $contact['EMAIL'];
if (!is_array($emails)) {
$emails = [$emails];
}
foreach ($emails as $email) {
if (strtolower($search) === strtolower($contact['FN']) ||
strtolower($search) === strtolower($email)
) {
if (strtolower($search) === strtolower($email)) {
$foundEmail = true;
}
$this->result['exact']['emails'][] = [
'label' => $contact['FN'],
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $email,
],
];
} else if ($this->shareeEnumeration) {
$this->result['emails'][] = [
'label' => $contact['FN'],
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $email,
],
];
}
}
}
if (!$foundEmail && substr_count($search, '@') >= 1 && $this->offset === 0) {
$this->result['exact']['emails'][] = [
'label' => $search,
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $search,
],
];
}
$this->reachedEndFor[] = 'emails';
}
/**
* @NoAdminRequired
*
@ -487,17 +427,16 @@ class ShareesAPIController extends OCSController {
$shareTypes = [
Share::SHARE_TYPE_USER,
Share::SHARE_TYPE_REMOTE,
Share::SHARE_TYPE_EMAIL
];
if ($this->shareManager->allowGroupSharing()) {
$shareTypes[] = Share::SHARE_TYPE_GROUP;
}
$shareTypes[] = Share::SHARE_TYPE_EMAIL;
$shareTypes[] = Share::SHARE_TYPE_REMOTE;
if (is_array($shareType)) {
$shareTypes = array_intersect($shareTypes, $shareType);
if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
sort($shareTypes);
} else if (is_numeric($shareType)) {
$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
@ -509,6 +448,11 @@ class ShareesAPIController extends OCSController {
$shareTypes = array_diff($shareTypes, [Share::SHARE_TYPE_REMOTE]);
}
if (!$this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
// Remove mail shares from type array, because the share provider is not loaded
$shareTypes = array_diff($shareTypes, [Share::SHARE_TYPE_EMAIL]);
}
$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
$this->limit = (int) $perPage;
@ -560,13 +504,30 @@ class ShareesAPIController extends OCSController {
}
// Get remote
$remoteResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
$this->getRemote($search);
$remoteResults = $this->getRemote($search);
}
// Get email
$mailResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
if (in_array(Share::SHARE_TYPE_EMAIL, $shareTypes)) {
$this->getEmails($search);
$mailResults = $this->getEmail($search);
}
// if we have a exact match, either for the federated cloud id or for the
// email address we only return the exact match. It is highly unlikely
// that the exact same email address and federated cloud id exists
if ($mailResults['exactIdMatch'] && !$remoteResults['exactIdMatch']) {
$this->result['emails'] = $mailResults['results'];
$this->result['exact']['emails'] = $mailResults['exact'];
} else if (!$mailResults['exactIdMatch'] && $remoteResults['exactIdMatch']) {
$this->result['remotes'] = $remoteResults['results'];
$this->result['exact']['remotes'] = $remoteResults['exact'];
} else {
$this->result['remotes'] = $remoteResults['results'];
$this->result['exact']['remotes'] = $remoteResults['exact'];
$this->result['emails'] = $mailResults['results'];
$this->result['exact']['emails'] = $mailResults['exact'];
}
$response = new Http\DataResponse($this->result);
@ -583,6 +544,70 @@ class ShareesAPIController extends OCSController {
return $response;
}
/**
* @param string $search
* @return array
*/
protected function getEmail($search) {
$result = ['results' => [], 'exact' => []];
// Search in contacts
//@todo Pagination missing
$addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN']);
$result['exactIdMatch'] = false;
foreach ($addressBookContacts as $contact) {
if (isset($contact['isLocalSystemBook'])) {
continue;
}
if (isset($contact['EMAIL'])) {
$emailAddresses = $contact['EMAIL'];
if (!is_array($emailAddresses)) {
$emailAddresses = [$emailAddresses];
}
foreach ($emailAddresses as $emailAddress) {
if (strtolower($contact['FN']) === strtolower($search) || strtolower($emailAddress) === strtolower($search)) {
if (strtolower($emailAddress) === strtolower($search)) {
$result['exactIdMatch'] = true;
}
$result['exact'][] = [
'label' => $contact['FN'] . " ($emailAddress)",
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $emailAddress,
],
];
} else {
$result['results'][] = [
'label' => $contact['FN'] . " ($emailAddress)",
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $emailAddress,
],
];
}
}
}
}
if (!$this->shareeEnumeration) {
$result['results'] = [];
}
if (!$result['exactIdMatch'] && filter_var($search, FILTER_VALIDATE_EMAIL)) {
$result['exact'][] = [
'label' => $search,
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $search,
],
];
}
$this->reachedEndFor[] = 'emails';
return $result;
}
/**
* Generates a bunch of pagination links for the current page
*

View File

@ -234,6 +234,7 @@ class ApiTest extends TestCase {
function testEnfoceLinkPassword() {
$password = md5(time());
$appConfig = \OC::$server->getAppConfig();
$appConfig->setValue('core', 'shareapi_enforce_links_password', 'yes');
@ -257,14 +258,14 @@ class ApiTest extends TestCase {
// share with password should succeed
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
$result = $ocs->createShare($this->folder, \OCP\Constants::PERMISSION_ALL, \OCP\Share::SHARE_TYPE_LINK, null, 'false', 'bar');
$result = $ocs->createShare($this->folder, \OCP\Constants::PERMISSION_ALL, \OCP\Share::SHARE_TYPE_LINK, null, 'false', $password);
$ocs->cleanup();
$data = $result->getData();
// setting new password should succeed
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
$ocs->updateShare($data['id'], null, 'bar');
$ocs->updateShare($data['id'], null, $password);
$ocs->cleanup();
// removing password should fail
@ -887,6 +888,9 @@ class ApiTest extends TestCase {
* @depends testCreateShareLink
*/
function testUpdateShare() {
$password = md5(time());
$node1 = $this->userFolder->get($this->filename);
$share1 = $this->shareManager->newShare();
$share1->setNode($node1)
@ -915,7 +919,7 @@ class ApiTest extends TestCase {
$this->assertNull($share2->getPassword());
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
$ocs->updateShare($share2->getId(), null, 'foo');
$ocs->updateShare($share2->getId(), null, $password);
$ocs->cleanup();
$share2 = $this->shareManager->getShareById('ocinternal:' . $share2->getId());

View File

@ -23,8 +23,10 @@
*/
namespace OCA\Files_Sharing\Tests\Controller;
use OC\ContactsManager;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\Contacts;
use OCP\Files\Folder;
use OCP\IL10N;
use OCA\Files_Sharing\Controller\ShareAPIController;

View File

@ -771,28 +771,44 @@ class ShareesAPIControllerTest extends TestCase {
$this->assertCount((int) $reachedEnd, $this->invokePrivate($this->sharees, 'reachedEndFor'));
}
/**
* @dataProvider dataGetRemote
*
* @param string $searchTerm
* @param array $contacts
* @param bool $shareeEnumeration
* @param array $expected
* @param bool $reachedEnd
*/
public function testGetRemote($searchTerm, $contacts, $shareeEnumeration, $expected, $reachedEnd) {
$this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]);
$this->contactsManager->expects($this->any())
->method('search')
->with($searchTerm, ['CLOUD', 'FN'])
->willReturn($contacts);
$result = $this->invokePrivate($this->sharees, 'getRemote', [$searchTerm]);
$this->assertEquals($expected, $result);
$this->assertCount((int) $reachedEnd, $this->invokePrivate($this->sharees, 'reachedEndFor'));
}
public function dataGetRemote() {
return [
['test', [], true, [], [], true],
['test', [], false, [], [], true],
['test', [], true, ['results' => [], 'exact' => [], 'exactIdMatch' => false], true],
['test', [], false, ['results' => [], 'exact' => [], 'exactIdMatch' => false], true],
[
'test@remote',
[],
true,
[
['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
],
[],
['results' => [], 'exact' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]], 'exactIdMatch' => false],
true,
],
[
'test@remote',
[],
false,
[
['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
],
[],
['results' => [], 'exact' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]], 'exactIdMatch' => false],
true,
],
[
@ -814,10 +830,7 @@ class ShareesAPIControllerTest extends TestCase {
],
],
true,
[],
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']],
],
['results' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => [], 'exactIdMatch' => false],
true,
],
[
@ -839,8 +852,7 @@ class ShareesAPIControllerTest extends TestCase {
],
],
false,
[],
[],
['results' => [], 'exact' => [], 'exactIdMatch' => false],
true,
],
[
@ -862,12 +874,7 @@ class ShareesAPIControllerTest extends TestCase {
],
],
true,
[
['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
],
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']],
],
['results' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]], 'exactIdMatch' => false],
true,
],
[
@ -889,10 +896,7 @@ class ShareesAPIControllerTest extends TestCase {
],
],
false,
[
['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']],
],
[],
['results' => [], 'exact' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]], 'exactIdMatch' => false],
true,
],
[
@ -914,10 +918,7 @@ class ShareesAPIControllerTest extends TestCase {
],
],
true,
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']],
],
[],
['results' => [], 'exact' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exactIdMatch' => true],
true,
],
[
@ -939,10 +940,7 @@ class ShareesAPIControllerTest extends TestCase {
],
],
false,
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']],
],
[],
['results' => [], 'exact' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exactIdMatch' => true],
true,
],
// contact with space
@ -965,10 +963,7 @@ class ShareesAPIControllerTest extends TestCase {
],
],
false,
[
['label' => 'User Name @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user name@localhost', 'server' => 'localhost']],
],
[],
['results' => [], 'exact' => [['label' => 'User Name @ Localhost (user name@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user name@localhost', 'server' => 'localhost']]], 'exactIdMatch' => true],
true,
],
// remote with space, no contact
@ -991,62 +986,57 @@ class ShareesAPIControllerTest extends TestCase {
],
],
false,
[
['label' => 'user space@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user space@remote']],
],
[],
['results' => [], 'exact' => [['label' => 'user space@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user space@remote']]], 'exactIdMatch' => false],
true,
],
];
}
/**
* @dataProvider dataGetRemote
* @dataProvider dataGetEmail
*
* @param string $searchTerm
* @param array $contacts
* @param bool $shareeEnumeration
* @param array $exactExpected
* @param array $expected
* @param bool $reachedEnd
*/
public function testGetRemote($searchTerm, $contacts, $shareeEnumeration, $exactExpected, $expected, $reachedEnd) {
public function testGetEmail($searchTerm, $contacts, $shareeEnumeration, $expected, $reachedEnd) {
$this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]);
$this->contactsManager->expects($this->any())
->method('search')
->with($searchTerm, ['CLOUD', 'FN'])
->with($searchTerm, ['EMAIL', 'FN'])
->willReturn($contacts);
$this->invokePrivate($this->sharees, 'getRemote', [$searchTerm]);
$result = $this->invokePrivate($this->sharees, 'result');
$result = $this->invokePrivate($this->sharees, 'getEmail', [$searchTerm]);
$this->assertEquals($exactExpected, $result['exact']['remotes']);
$this->assertEquals($expected, $result['remotes']);
$this->assertEquals($expected, $result);
$this->assertCount((int) $reachedEnd, $this->invokePrivate($this->sharees, 'reachedEndFor'));
}
public function dataGetEmails() {
public function dataGetEmail() {
return [
['test', [], true, [], [], true],
['test', [], false, [], [], true],
['test', [], true, ['results' => [], 'exact' => [], 'exactIdMatch' => false], true],
['test', [], false, ['results' => [], 'exact' => [], 'exactIdMatch' => false], true],
[
'test@remote.com',
[],
true,
[
['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']],
],
['results' => [], 'exact' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]], 'exactIdMatch' => false],
true,
],
[ // no valid email address
'test@remote',
[],
true,
['results' => [], 'exact' => [], 'exactIdMatch' => false],
true,
],
[
'test@remote.com',
[],
false,
[
['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']],
],
[],
['results' => [], 'exact' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]], 'exactIdMatch' => false],
true,
],
[
@ -1063,15 +1053,12 @@ class ShareesAPIControllerTest extends TestCase {
[
'FN' => 'User @ Localhost',
'EMAIL' => [
'username@localhost.com',
'username@localhost',
],
],
],
true,
[],
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost.com']],
],
['results' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => [], 'exactIdMatch' => false],
true,
],
[
@ -1088,13 +1075,12 @@ class ShareesAPIControllerTest extends TestCase {
[
'FN' => 'User @ Localhost',
'EMAIL' => [
'username@localhost.com',
'username@localhost',
],
],
],
false,
[],
[],
['results' => [], 'exact' => [], 'exactIdMatch' => false],
true,
],
[
@ -1111,17 +1097,12 @@ class ShareesAPIControllerTest extends TestCase {
[
'FN' => 'User @ Localhost',
'EMAIL' => [
'username@localhost.com',
'username@localhost',
],
],
],
true,
[
['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']],
],
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost.com']],
],
['results' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]], 'exactIdMatch' => false],
true,
],
[
@ -1138,19 +1119,16 @@ class ShareesAPIControllerTest extends TestCase {
[
'FN' => 'User @ Localhost',
'EMAIL' => [
'username@localhost.com',
'username@localhost',
],
],
],
false,
[
['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']],
],
[],
['results' => [], 'exact' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]], 'exactIdMatch' => false],
true,
],
[
'username@localhost.com',
'username@localhost',
[
[
'FN' => 'User3 @ Localhost',
@ -1163,19 +1141,16 @@ class ShareesAPIControllerTest extends TestCase {
[
'FN' => 'User @ Localhost',
'EMAIL' => [
'username@localhost.com',
'username@localhost',
],
],
],
true,
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost.com']],
],
[],
['results' => [], 'exact' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exactIdMatch' => true],
true,
],
[
'username@localhost.com',
'username@localhost',
[
[
'FN' => 'User3 @ Localhost',
@ -1188,20 +1163,40 @@ class ShareesAPIControllerTest extends TestCase {
[
'FN' => 'User @ Localhost',
'EMAIL' => [
'username@localhost.com',
'username@localhost',
],
],
],
false,
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost.com']],
],
[],
['results' => [], 'exact' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exactIdMatch' => true],
true,
],
// Test single email
// contact with space
[
'username@localhost.com',
'user name@localhost',
[
[
'FN' => 'User3 @ Localhost',
],
[
'FN' => 'User2 @ Localhost',
'EMAIL' => [
],
],
[
'FN' => 'User Name @ Localhost',
'EMAIL' => [
'user name@localhost',
],
],
],
false,
['results' => [], 'exact' => [['label' => 'User Name @ Localhost (user name@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'user name@localhost']]], 'exactIdMatch' => true],
true,
],
// remote with space, no contact
[
'user space@remote.com',
[
[
'FN' => 'User3 @ Localhost',
@ -1213,137 +1208,106 @@ class ShareesAPIControllerTest extends TestCase {
],
[
'FN' => 'User @ Localhost',
'EMAIL' => 'username@localhost.com',
'EMAIL' => [
'username@localhost',
],
],
],
false,
[
['label' => 'User @ Localhost', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost.com']],
],
[],
['results' => [], 'exact' => [], 'exactIdMatch' => false],
true,
],
];
}
/**
* @dataProvider dataGetEmails
*
* @param string $searchTerm
* @param array $contacts
* @param bool $shareeEnumeration
* @param array $exactExpected
* @param array $expected
* @param bool $reachedEnd
*/
public function testGetEmails($searchTerm, $contacts, $shareeEnumeration, $exactExpected, $expected, $reachedEnd) {
$this->invokePrivate($this->sharees, 'shareeEnumeration', [$shareeEnumeration]);
$this->contactsManager->expects($this->any())
->method('search')
->with($searchTerm, ['FN', 'EMAIL'])
->willReturn($contacts);
$this->invokePrivate($this->sharees, 'getEmails', [$searchTerm]);
$result = $this->invokePrivate($this->sharees, 'result');
$this->assertEquals($exactExpected, $result['exact']['emails']);
$this->assertEquals($expected, $result['emails']);
$this->assertCount((int) $reachedEnd, $this->invokePrivate($this->sharees, 'reachedEndFor'));
}
public function dataSearch() {
$allTypes = [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_EMAIL, Share::SHARE_TYPE_REMOTE];
$allTypes = [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE, Share::SHARE_TYPE_EMAIL];
return [
[[], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
[[], '', 'yes', true, true, $allTypes, false, true, true],
// Test itemType
[[
'search' => '',
], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'search' => 'foobar',
], '', 'yes', true, 'foobar', null, $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'search' => 0,
], '', 'yes', true, '0', null, $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
// Test itemType
[[
'itemType' => '',
], '', 'yes', true, '', '', $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'itemType' => 'folder',
], '', 'yes', true, '', 'folder', $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'itemType' => 0,
], '', 'yes', true, '', '0', $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
// Test shareType
[[
], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'shareType' => 0,
], '', 'yes', true, '', null, [0], 1, 200, false, true, true],
], '', 'yes', true, false, [0], false, true, true],
[[
'shareType' => '0',
], '', 'yes', true, '', null, [0], 1, 200, false, true, true],
], '', 'yes', true, false, [0], false, true, true],
[[
'shareType' => 1,
], '', 'yes', true, '', null, [1], 1, 200, false, true, true],
], '', 'yes', true, false, [1], false, true, true],
[[
'shareType' => 12,
], '', 'yes', true, '', null, [], 1, 200, false, true, true],
], '', 'yes', true, false, [], false, true, true],
[[
'shareType' => 'foobar',
], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'shareType' => [0, 1, 2],
], '', 'yes', true, '', null, [0, 1], 1, 200, false, true, true],
], '', 'yes', false, false, [0, 1], false, true, true],
[[
'shareType' => [0, 1],
], '', 'yes', true, '', null, [0, 1], 1, 200, false, true, true],
], '', 'yes', false, false, [0, 1], false, true, true],
[[
'shareType' => $allTypes,
], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'shareType' => $allTypes,
], '', 'yes', false, '', null, [0, 1, 4], 1, 200, false, true, true],
], '', 'yes', false, false, [0, 1], false, true, true],
[[
'shareType' => $allTypes,
], '', 'yes', true, '', null, [0, 4, 6], 1, 200, false, true, false],
], '', 'yes', true, false, [0, 6], false, true, false],
[[
'shareType' => $allTypes,
], '', 'yes', false, '', null, [0, 4], 1, 200, false, true, false],
], '', 'yes', false, true, [0, 4], false, true, false],
// Test pagination
[[
'page' => 1,
], '', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'page' => 10,
], '', 'yes', true, '', null, $allTypes, 10, 200, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
// Test perPage
[[
'perPage' => 1,
], '', 'yes', true, '', null, $allTypes, 1, 1, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
[[
'perPage' => 10,
], '', 'yes', true, '', null, $allTypes, 1, 10, false, true, true],
], '', 'yes', true, true, $allTypes, false, true, true],
// Test $shareWithGroupOnly setting
[[], 'no', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
[[], 'yes', 'yes', true, '', null, $allTypes, 1, 200, true, true, true],
[[], 'no', 'yes', true, true, $allTypes, false, true, true],
[[], 'yes', 'yes', true, true, $allTypes, true, true, true],
// Test $shareeEnumeration setting
[[], 'no', 'yes', true, '', null, $allTypes, 1, 200, false, true, true],
[[], 'no', 'no', true, '', null, $allTypes, 1, 200, false, false, true],
// Test keep case for search
[[
'search' => 'foo@example.com/ownCloud',
], '', 'yes', true, 'foo@example.com/ownCloud', null, $allTypes, 1, 200, false, true, true],
[[], 'no', 'yes', true, true, $allTypes, false, true, true],
[[], 'no', 'no', true, true, $allTypes, false, false, true],
];
}
@ -1354,16 +1318,12 @@ class ShareesAPIControllerTest extends TestCase {
* @param string $apiSetting
* @param string $enumSetting
* @param bool $remoteSharingEnabled
* @param string $search
* @param string $itemType
* @param array $shareTypes
* @param int $page
* @param int $perPage
* @param bool $shareWithGroupOnly
* @param bool $shareeEnumeration
* @param bool $allowGroupSharing
*/
public function testSearch($getData, $apiSetting, $enumSetting, $remoteSharingEnabled, $search, $itemType, $shareTypes, $page, $perPage, $shareWithGroupOnly, $shareeEnumeration, $allowGroupSharing) {
public function testSearch($getData, $apiSetting, $enumSetting, $remoteSharingEnabled, $emailSharingEnabled, $shareTypes, $shareWithGroupOnly, $shareeEnumeration, $allowGroupSharing) {
$search = isset($getData['search']) ? $getData['search'] : '';
$itemType = isset($getData['itemType']) ? $getData['itemType'] : null;
$page = isset($getData['page']) ? $getData['page'] : 1;
@ -1399,11 +1359,10 @@ class ShareesAPIControllerTest extends TestCase {
$this->getMockBuilder('OCP\ILogger')->disableOriginalConstructor()->getMock(),
$this->shareManager
])
->setMethods(array('searchSharees', 'isRemoteSharingAllowed'))
->setMethods(array('searchSharees', 'isRemoteSharingAllowed', 'shareProviderExists'))
->getMock();
$sharees->expects($this->once())
->method('searchSharees')
->with($search, $itemType, $shareTypes, $page, $perPage)
->willReturnCallback(function
($isearch, $iitemType, $ishareTypes, $ipage, $iperPage)
use ($search, $itemType, $shareTypes, $page, $perPage) {
@ -1411,7 +1370,10 @@ class ShareesAPIControllerTest extends TestCase {
// We are doing strict comparisons here, so we can differ 0/'' and null on shareType/itemType
$this->assertSame($search, $isearch);
$this->assertSame($itemType, $iitemType);
$this->assertSame($shareTypes, $ishareTypes);
$this->assertSame(count($shareTypes), count($ishareTypes));
foreach($shareTypes as $expected) {
$this->assertTrue(in_array($expected, $ishareTypes));
}
$this->assertSame($page, $ipage);
$this->assertSame($perPage, $iperPage);
return new Http\DataResponse();
@ -1421,6 +1383,11 @@ class ShareesAPIControllerTest extends TestCase {
->with($itemType)
->willReturn($remoteSharingEnabled);
$this->shareManager->expects($this->any())
->method('shareProviderExists')
->with(\OCP\Share::SHARE_TYPE_EMAIL)
->willReturn($emailSharingEnabled);
$this->assertInstanceOf(Http\DataResponse::class, $sharees->search($search, $itemType, $page, $perPage, $shareType));
$this->assertSame($shareWithGroupOnly, $this->invokePrivate($sharees, 'shareWithGroupOnly'));
@ -1519,7 +1486,7 @@ class ShareesAPIControllerTest extends TestCase {
public function dataSearchSharees() {
return [
['test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, false, [], [], [],
['test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, false, [], [], ['results' => [], 'exact' => [], 'exactIdMatch' => false],
[
'exact' => ['users' => [], 'groups' => [], 'remotes' => [], 'emails' => []],
'users' => [],
@ -1527,7 +1494,7 @@ class ShareesAPIControllerTest extends TestCase {
'remotes' => [],
'emails' => [],
], false],
['test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, false, [], [], [],
['test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, false, [], [], ['results' => [], 'exact' => [], 'exactIdMatch' => false],
[
'exact' => ['users' => [], 'groups' => [], 'remotes' => [], 'emails' => []],
'users' => [],
@ -1541,7 +1508,7 @@ class ShareesAPIControllerTest extends TestCase {
], [
['label' => 'testgroup1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'testgroup1']],
], [
['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']],
'results' => [['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']]], 'exact' => [], 'exactIdMatch' => false,
],
[
'exact' => ['users' => [], 'groups' => [], 'remotes' => [], 'emails' => []],
@ -1562,7 +1529,7 @@ class ShareesAPIControllerTest extends TestCase {
'test', 'folder', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_REMOTE], 1, 2, false, [
['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
], null, [
['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']],
'results' => [['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']]], 'exact' => [], 'exactIdMatch' => false
],
[
'exact' => ['users' => [], 'groups' => [], 'remotes' => [], 'emails' => []],
@ -1660,14 +1627,11 @@ class ShareesAPIControllerTest extends TestCase {
$result['groups'] = $mockedGroupsResult;
$this->invokePrivate($sharees, 'result', [$result]);
});
$sharees->expects(($mockedRemotesResult === null) ? $this->never() : $this->once())
->method('getRemote')
->with($searchTerm)
->willReturnCallback(function() use ($sharees, $mockedRemotesResult) {
$result = $this->invokePrivate($sharees, 'result');
$result['remotes'] = $mockedRemotesResult;
$this->invokePrivate($sharees, 'result', [$result]);
});
->willReturn($mockedRemotesResult);
$ocs = $this->invokePrivate($sharees, 'searchSharees', [$searchTerm, $itemType, $shareTypes, $page, $perPage, $shareWithGroupOnly]);
$this->assertInstanceOf('\OCP\AppFramework\Http\DataResponse', $ocs);

View File

@ -0,0 +1,24 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
$settings = new \OCA\ShareByMail\Settings();
\OCP\Util::connectHook('\OCP\Config', 'js', $settings, 'announceShareProvider');

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<info>
<id>sharebymail</id>
<name>Share by mail</name>
<description>Share provider which allows you to share files by mail</description>
<licence>AGPL</licence>
<author>Bjoern Schiessle</author>
<version>1.0.0</version>
<namespace>ShareByMail</namespace>
<category>other</category>
<dependencies>
<owncloud min-version="9.2" max-version="9.2" />
</dependencies>
<default_enable/>
</info>

View File

@ -0,0 +1,38 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ShareByMail;
class Settings {
/**
* announce that the share-by-mail share provider is enabled
*
* @param array $settings
*/
public function announceShareProvider(array $settings) {
$array = json_decode($settings['array']['oc_appconfig'], true);
$array['shareByMailEnabled'] = true;
$settings['array']['oc_appconfig'] = json_encode($array);
}
}

View File

@ -0,0 +1,709 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ShareByMail;
use OC\HintException;
use OC\Share20\Exception\InvalidShare;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\Mail\IMailer;
use OCP\Security\ISecureRandom;
use OC\Share20\Share;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
/**
* Class ShareByMail
*
* @package OCA\ShareByMail
*/
class ShareByMailProvider implements IShareProvider {
/** @var IDBConnection */
private $dbConnection;
/** @var ILogger */
private $logger;
/** @var ISecureRandom */
private $secureRandom;
/** @var IUserManager */
private $userManager;
/** @var IRootFolder */
private $rootFolder;
/** @var IL10N */
private $l;
/** @var IMailer */
private $mailer;
/** @var IURLGenerator */
private $urlGenerator;
/**
* Return the identifier of this provider.
*
* @return string Containing only [a-zA-Z0-9]
*/
public function identifier() {
return 'ocShareByMail';
}
/**
* DefaultShareProvider constructor.
*
* @param IDBConnection $connection
* @param ISecureRandom $secureRandom
* @param IUserManager $userManager
* @param IRootFolder $rootFolder
* @param IL10N $l
* @param ILogger $logger
* @param IMailer $mailer
* @param IURLGenerator $urlGenerator
*/
public function __construct(
IDBConnection $connection,
ISecureRandom $secureRandom,
IUserManager $userManager,
IRootFolder $rootFolder,
IL10N $l,
ILogger $logger,
IMailer $mailer,
IURLGenerator $urlGenerator
) {
$this->dbConnection = $connection;
$this->secureRandom = $secureRandom;
$this->userManager = $userManager;
$this->rootFolder = $rootFolder;
$this->l = $l;
$this->logger = $logger;
$this->mailer = $mailer;
$this->urlGenerator = $urlGenerator;
}
/**
* Share a path
*
* @param IShare $share
* @return IShare The share object
* @throws ShareNotFound
* @throws \Exception
*/
public function create(IShare $share) {
$shareWith = $share->getSharedWith();
/*
* Check if file is not already shared with the remote user
*/
$alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0);
if (!empty($alreadyShared)) {
$message = 'Sharing %s failed, this item is already shared with %s';
$message_t = $this->l->t('Sharing %s failed, this item is already shared with %s', array($share->getNode()->getName(), $shareWith));
$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
throw new \Exception($message_t);
}
$shareId = $this->createMailShare($share);
$data = $this->getRawShare($shareId);
return $this->createShareObject($data);
}
/**
* @param IShare $share
* @return int
* @throws \Exception
*/
protected function createMailShare(IShare $share) {
$share->setToken($this->generateToken());
$shareId = $this->addShareToDB(
$share->getNodeId(),
$share->getNodeType(),
$share->getSharedWith(),
$share->getSharedBy(),
$share->getShareOwner(),
$share->getPermissions(),
$share->getToken()
);
try {
$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
['token' => $share->getToken()]);
$this->sendMailNotification($share->getNode()->getName(),
$link,
$share->getShareOwner(),
$share->getSharedBy(), $share->getSharedWith());
} catch (HintException $hintException) {
$this->logger->error('Failed to send share by mail: ' . $hintException->getMessage());
$this->removeShareFromTable($shareId);
throw $hintException;
} catch (\Exception $e) {
$this->logger->error('Failed to send share by mail: ' . $e->getMessage());
$this->removeShareFromTable($shareId);
throw new HintException('Failed to send share by mail',
$this->l->t('Failed to send share by E-mail'));
}
return $shareId;
}
protected function sendMailNotification($filename, $link, $owner, $initiator, $shareWith) {
if ($owner === $initiator) {
$subject = (string)$this->l->t('%s shared »%s« with you', array($owner, $filename));
} else {
$subject = (string)$this->l->t('%s shared »%s« with you on behalf of %s', array($owner, $filename, $initiator));
}
$message = $this->mailer->createMessage();
$htmlBody = $this->createMailBody('mail', $filename, $link, $owner, $initiator);
$textBody = $this->createMailBody('altmail', $filename, $link, $owner, $initiator);
$message->setTo([$shareWith]);
$message->setSubject($subject);
$message->setBody($textBody, 'text/plain');
$message->setHtmlBody($htmlBody);
$this->mailer->send($message);
}
/**
* create mail body
*
* @param $filename
* @param $link
* @param $owner
* @param $initiator
* @return string plain text mail
* @throws HintException
*/
protected function createMailBody($template, $filename, $link, $owner, $initiator) {
$mailBodyTemplate = new \OC_Template('sharebymail', $template, '');
$mailBodyTemplate->assign ('filename', $filename);
$mailBodyTemplate->assign ('link', $link);
$mailBodyTemplate->assign ('owner', $owner);
$mailBodyTemplate->assign ('initiator', $initiator);
$mailBodyTemplate->assign ('onBehalfOf', $initiator !== $owner);
$mailBody = $mailBodyTemplate->fetchPage();
if (is_string($mailBody)) {
return $mailBody;
}
throw new HintException('Failed to create the E-mail',
$this->l->t('Failed to create the E-mail'));
}
/**
* generate share token
*
* @return string
*/
protected function generateToken() {
$token = $this->secureRandom->generate(
15, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
return $token;
}
/**
* Get all children of this share
*
* @param IShare $parent
* @return IShare[]
*/
public function getChildren(IShare $parent) {
$children = [];
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share')
->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
->orderBy('id');
$cursor = $qb->execute();
while($data = $cursor->fetch()) {
$children[] = $this->createShareObject($data);
}
$cursor->closeCursor();
return $children;
}
/**
* add share to the database and return the ID
*
* @param int $itemSource
* @param string $itemType
* @param string $shareWith
* @param string $sharedBy
* @param string $uidOwner
* @param int $permissions
* @param string $token
* @return int
*/
protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->insert('share')
->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
->setValue('item_type', $qb->createNamedParameter($itemType))
->setValue('item_source', $qb->createNamedParameter($itemSource))
->setValue('file_source', $qb->createNamedParameter($itemSource))
->setValue('share_with', $qb->createNamedParameter($shareWith))
->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
->setValue('permissions', $qb->createNamedParameter($permissions))
->setValue('token', $qb->createNamedParameter($token))
->setValue('stime', $qb->createNamedParameter(time()));
/*
* Added to fix https://github.com/owncloud/core/issues/22215
* Can be removed once we get rid of ajax/share.php
*/
$qb->setValue('file_target', $qb->createNamedParameter(''));
$qb->execute();
$id = $qb->getLastInsertId();
return (int)$id;
}
/**
* Update a share
*
* @param IShare $share
* @return IShare The share object
*/
public function update(IShare $share) {
/*
* We allow updating the permissions of mail shares
*/
$qb = $this->dbConnection->getQueryBuilder();
$qb->update('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
->set('permissions', $qb->createNamedParameter($share->getPermissions()))
->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
->execute();
return $share;
}
/**
* @inheritdoc
*/
public function move(IShare $share, $recipient) {
/**
* nothing to do here, mail shares are only outgoing shares
*/
return $share;
}
/**
* Delete a share (owner unShares the file)
*
* @param IShare $share
*/
public function delete(IShare $share) {
$this->removeShareFromTable($share->getId());
}
/**
* @inheritdoc
*/
public function deleteFromSelf(IShare $share, $recipient) {
// nothing to do here, mail shares are only outgoing shares
return;
}
/**
* @inheritdoc
*/
public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share');
$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
/**
* Reshares for this user are shares where they are the owner.
*/
if ($reshares === false) {
//Special case for old shares created via the web UI
$or1 = $qb->expr()->andX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->isNull('uid_initiator')
);
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
$or1
)
);
} else {
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
)
);
}
if ($node !== null) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
}
if ($limit !== -1) {
$qb->setMaxResults($limit);
}
$qb->setFirstResult($offset);
$qb->orderBy('id');
$cursor = $qb->execute();
$shares = [];
while($data = $cursor->fetch()) {
$shares[] = $this->createShareObject($data);
}
$cursor->closeCursor();
return $shares;
}
/**
* @inheritdoc
*/
public function getShareById($id, $recipientId = null) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
$cursor = $qb->execute();
$data = $cursor->fetch();
$cursor->closeCursor();
if ($data === false) {
throw new ShareNotFound();
}
try {
$share = $this->createShareObject($data);
} catch (InvalidShare $e) {
throw new ShareNotFound();
}
return $share;
}
/**
* Get shares for a given path
*
* @param \OCP\Files\Node $path
* @return IShare[]
*/
public function getSharesByPath(Node $path) {
$qb = $this->dbConnection->getQueryBuilder();
$cursor = $qb->select('*')
->from('share')
->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
->execute();
$shares = [];
while($data = $cursor->fetch()) {
$shares[] = $this->createShareObject($data);
}
$cursor->closeCursor();
return $shares;
}
/**
* @inheritdoc
*/
public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
/** @var IShare[] $shares */
$shares = [];
//Get shares directly with this user
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share');
// Order by id
$qb->orderBy('id');
// Set limit and offset
if ($limit !== -1) {
$qb->setMaxResults($limit);
}
$qb->setFirstResult($offset);
$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)));
$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
// Filter by node if provided
if ($node !== null) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
}
$cursor = $qb->execute();
while($data = $cursor->fetch()) {
$shares[] = $this->createShareObject($data);
}
$cursor->closeCursor();
return $shares;
}
/**
* Get a share by token
*
* @param string $token
* @return IShare
* @throws ShareNotFound
*/
public function getShareByToken($token) {
$qb = $this->dbConnection->getQueryBuilder();
$cursor = $qb->select('*')
->from('share')
->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
->execute();
$data = $cursor->fetch();
if ($data === false) {
throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
}
try {
$share = $this->createShareObject($data);
} catch (InvalidShare $e) {
throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
}
return $share;
}
/**
* remove share from table
*
* @param string $shareId
*/
protected function removeShareFromTable($shareId) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
$qb->execute();
}
/**
* Create a share object from an database row
*
* @param array $data
* @return IShare
* @throws InvalidShare
* @throws ShareNotFound
*/
protected function createShareObject($data) {
$share = new Share($this->rootFolder, $this->userManager);
$share->setId((int)$data['id'])
->setShareType((int)$data['share_type'])
->setPermissions((int)$data['permissions'])
->setTarget($data['file_target'])
->setMailSend((bool)$data['mail_send'])
->setToken($data['token']);
$shareTime = new \DateTime();
$shareTime->setTimestamp((int)$data['stime']);
$share->setShareTime($shareTime);
$share->setSharedWith($data['share_with']);
if ($data['uid_initiator'] !== null) {
$share->setShareOwner($data['uid_owner']);
$share->setSharedBy($data['uid_initiator']);
} else {
//OLD SHARE
$share->setSharedBy($data['uid_owner']);
$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
$owner = $path->getOwner();
$share->setShareOwner($owner->getUID());
}
$share->setNodeId((int)$data['file_source']);
$share->setNodeType($data['item_type']);
$share->setProviderId($this->identifier());
return $share;
}
/**
* Get the node with file $id for $user
*
* @param string $userId
* @param int $id
* @return \OCP\Files\File|\OCP\Files\Folder
* @throws InvalidShare
*/
private function getNode($userId, $id) {
try {
$userFolder = $this->rootFolder->getUserFolder($userId);
} catch (NotFoundException $e) {
throw new InvalidShare();
}
$nodes = $userFolder->getById($id);
if (empty($nodes)) {
throw new InvalidShare();
}
return $nodes[0];
}
/**
* A user is deleted from the system
* So clean up the relevant shares.
*
* @param string $uid
* @param int $shareType
*/
public function userDeleted($uid, $shareType) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)))
->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
->execute();
}
/**
* This provider does not support group shares
*
* @param string $gid
*/
public function groupDeleted($gid) {
return;
}
/**
* This provider does not support group shares
*
* @param string $uid
* @param string $gid
*/
public function userDeletedFromGroup($uid, $gid) {
return;
}
/**
* get database row of a give share
*
* @param $id
* @return array
* @throws ShareNotFound
*/
protected function getRawShare($id) {
// Now fetch the inserted share and create a complete share object
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
$cursor = $qb->execute();
$data = $cursor->fetch();
$cursor->closeCursor();
if ($data === false) {
throw new ShareNotFound;
}
return $data;
}
public function getSharesInFolder($userId, Folder $node, $reshares) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share', 's')
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
))
->andWhere(
$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))
);
/**
* Reshares for this user are shares where they are the owner.
*/
if ($reshares === false) {
$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
} else {
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
)
);
}
$qb->innerJoin('s', 'filecache' ,'f', 's.file_source = f.fileid');
$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
$qb->orderBy('id');
$cursor = $qb->execute();
$shares = [];
while ($data = $cursor->fetch()) {
$shares[$data['fileid']][] = $this->createShareObject($data);
}
$cursor->closeCursor();
return $shares;
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** @var OC_Theme $theme */
/** @var array $_ */
if ($_['onBehalfOf']) {
print_unescaped($l->t("Hey there,\n\n%s shared »%s« with you on behalf of %s.\n\n%s\n\n", [$_['owner'], $_['filename'], $_['initiator'], $_['link']]));
} else {
print_unescaped($l->t("Hey there,\n\n%s shared »%s« with you.\n\n%s\n\n", [$_['owner'], $_['filename'], $_['link']]));
}
// TRANSLATORS term at the end of a mail
p($l->t("Cheers!"));
print_unescaped("\n");
?>
--
<?php p($theme->getName() . ' - ' . $theme->getSlogan()); ?>
<?php print_unescaped("\n".$theme->getBaseUrl());

View File

@ -0,0 +1,64 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** @var OC_Theme $theme */
/** @var array $_ */
?>
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr><td>
<table cellspacing="0" cellpadding="0" border="0" width="600px">
<tr>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>" width="20px">&nbsp;</td>
<td bgcolor="<?php p($theme->getMailHeaderColor());?>">
<img src="<?php p(\OC::$server->getURLGenerator()->getAbsoluteURL(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/>
</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
<tr>
<td width="20px">&nbsp;</td>
<td style="font-weight:normal; font-size:0.8em; line-height:1.2em; font-family:verdana,'arial',sans;">
<?php
if ($_['onBehalfOf']) {
print_unescaped($l->t('Hey there,<br><br>%s shared <a href="%s">%s</a> with you on behalf of %s.<br><br>', [$_['owner'], $_['link'], $_['filename'], $_['initiator']]));
} else {
print_unescaped($l->t('Hey there,<br><br>%s shared <a href="%s">%s</a> with you.<br><br>', [$_['owner'], $_['link'], $_['filename']]));
}
// TRANSLATORS term at the end of a mail
p($l->t('Cheers!'));
?>
</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
<tr>
<td width="20px">&nbsp;</td>
<td style="font-weight:normal; font-size:0.8em; line-height:1.2em; font-family:verdana,'arial',sans;">--<br>
<?php p($theme->getName()); ?> -
<?php p($theme->getSlogan()); ?>
<br><a href="<?php p($theme->getBaseUrl()); ?>"><?php p($theme->getBaseUrl());?></a>
</td>
</tr>
<tr>
<td colspan="2">&nbsp;</td>
</tr>
</table>
</td></tr>
</table>

View File

@ -0,0 +1,64 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ShareByMail\Tests;
use OCA\ShareByMail\Settings;
use Test\TestCase;
class SettingsTest extends TestCase {
/** @var Settings */
private $instance;
public function setUp() {
parent::setUp();
$this->instance = new Settings();
}
public function testAnnounceShareProvider() {
$before = [
'oc_appconfig' =>
json_encode([
'key1' => 'value1',
'key2' => 'value2'
]),
'oc_foo' => 'oc_bar'
];
$after = [
'oc_appconfig' =>
json_encode([
'key1' => 'value1',
'key2' => 'value2',
'shareByMailEnabled' => true
]),
'oc_foo' => 'oc_bar'
];
$this->instance->announceShareProvider(['array' => &$before]);
$this->assertSame($after, $before);
}
}

View File

@ -0,0 +1,655 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ShareByMail\Tests;
use OC\HintException;
use OCA\ShareByMail\ShareByMailProvider;
use OCP\Files\IRootFolder;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\Mail\IMailer;
use OCP\Security\ISecureRandom;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
use OCP\Share\IShare;
use Test\TestCase;
/**
* Class ShareByMailProviderTest
*
* @package OCA\ShareByMail\Tests
* @group DB
*/
class ShareByMailProviderTest extends TestCase {
/** @var IDBConnection */
private $connection;
/** @var IManager */
private $shareManager;
/** @var IL10N | \PHPUnit_Framework_MockObject_MockObject */
private $l;
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject */
private $logger;
/** @var IRootFolder | \PHPUnit_Framework_MockObject_MockObject */
private $rootFolder;
/** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */
private $userManager;
/** @var ISecureRandom | \PHPUnit_Framework_MockObject_MockObject */
private $secureRandom;
/** @var IMailer | \PHPUnit_Framework_MockObject_MockObject */
private $mailer;
/** @var IURLGenerator | \PHPUnit_Framework_MockObject_MockObject */
private $urlGenerator;
/** @var IShare | \PHPUnit_Framework_MockObject_MockObject */
private $share;
public function setUp() {
parent::setUp();
$this->shareManager = \OC::$server->getShareManager();
$this->connection = \OC::$server->getDatabaseConnection();
$this->l = $this->getMockBuilder('OCP\IL10N')->getMock();
$this->l->method('t')
->will($this->returnCallback(function($text, $parameters = []) {
return vsprintf($text, $parameters);
}));
$this->logger = $this->getMockBuilder('OCP\ILogger')->getMock();
$this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->getMock();
$this->userManager = $this->getMockBuilder('OCP\IUserManager')->getMock();
$this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom')->getMock();
$this->mailer = $this->getMockBuilder('\OCP\Mail\IMailer')->getMock();
$this->urlGenerator = $this->getMockBuilder('\OCP\IUrlGenerator')->getMock();
$this->share = $this->getMockBuilder('\OCP\Share\IShare')->getMock();
$this->userManager->expects($this->any())->method('userExists')->willReturn(true);
}
/**
* get instance of Mocked ShareByMailProvider
*
* @param array $mockedMethods internal methods which should be mocked
* @return \PHPUnit_Framework_MockObject_MockObject | ShareByMailProvider
*/
private function getInstance(array $mockedMethods = []) {
$instance = $this->getMockBuilder('OCA\ShareByMail\ShareByMailProvider')
->setConstructorArgs(
[
$this->connection,
$this->secureRandom,
$this->userManager,
$this->rootFolder,
$this->l,
$this->logger,
$this->mailer,
$this->urlGenerator
]
);
if (!empty($mockedMethods)) {
$instance->setMethods($mockedMethods);
return $instance->getMock();
}
return new ShareByMailProvider(
$this->connection,
$this->secureRandom,
$this->userManager,
$this->rootFolder,
$this->l,
$this->logger,
$this->mailer,
$this->urlGenerator
);
}
public function tearDown() {
$this->connection->getQueryBuilder()->delete('share')->execute();
return parent::tearDown();
}
public function testCreate() {
$share = $this->getMockBuilder('\OCP\Share\IShare')->getMock();
$share->expects($this->once())->method('getSharedWith')->willReturn('user1');
$instance = $this->getInstance(['getSharedWith', 'createMailShare', 'getRawShare', 'createShareObject']);
$instance->expects($this->once())->method('getSharedWith')->willReturn([]);
$instance->expects($this->once())->method('createMailShare')->with($share)->willReturn(42);
$instance->expects($this->once())->method('getRawShare')->with(42)->willReturn('rawShare');
$instance->expects($this->once())->method('createShareObject')->with('rawShare')->willReturn('shareObject');
$this->assertSame('shareObject',
$instance->create($share)
);
}
/**
* @expectedException \Exception
*/
public function testCreateFailed() {
$this->share->expects($this->once())->method('getSharedWith')->willReturn('user1');
$node = $this->getMockBuilder('OCP\Files\Node')->getMock();
$node->expects($this->any())->method('getName')->willReturn('fileName');
$this->share->expects($this->any())->method('getNode')->willReturn($node);
$instance = $this->getInstance(['getSharedWith', 'createMailShare', 'getRawShare', 'createShareObject']);
$instance->expects($this->once())->method('getSharedWith')->willReturn(['found']);
$instance->expects($this->never())->method('createMailShare');
$instance->expects($this->never())->method('getRawShare');
$instance->expects($this->never())->method('createShareObject');
$this->assertSame('shareObject',
$instance->create($this->share)
);
}
public function testCreateMailShare() {
$this->share->expects($this->any())->method('getToken')->willReturn('token');
$this->share->expects($this->once())->method('setToken')->with('token');
$node = $this->getMockBuilder('OCP\Files\Node')->getMock();
$node->expects($this->any())->method('getName')->willReturn('fileName');
$this->share->expects($this->any())->method('getNode')->willReturn($node);
$instance = $this->getInstance(['generateToken', 'addShareToDB', 'sendMailNotification']);
$instance->expects($this->once())->method('generateToken')->willReturn('token');
$instance->expects($this->once())->method('addShareToDB')->willReturn(42);
$instance->expects($this->once())->method('sendMailNotification');
$this->urlGenerator->expects($this->once())->method('linkToRouteAbsolute')
->with('files_sharing.sharecontroller.showShare', ['token' => 'token']);
$instance->expects($this->once())->method('sendMailNotification');
$this->assertSame(42,
$this->invokePrivate($instance, 'createMailShare', [$this->share])
);
}
/**
* @expectedException \OC\HintException
*/
public function testCreateMailShareFailed() {
$this->share->expects($this->any())->method('getToken')->willReturn('token');
$this->share->expects($this->once())->method('setToken')->with('token');
$node = $this->getMockBuilder('OCP\Files\Node')->getMock();
$node->expects($this->any())->method('getName')->willReturn('fileName');
$this->share->expects($this->any())->method('getNode')->willReturn($node);
$instance = $this->getInstance(['generateToken', 'addShareToDB', 'sendMailNotification']);
$instance->expects($this->once())->method('generateToken')->willReturn('token');
$instance->expects($this->once())->method('addShareToDB')->willReturn(42);
$instance->expects($this->once())->method('sendMailNotification');
$this->urlGenerator->expects($this->once())->method('linkToRouteAbsolute')
->with('files_sharing.sharecontroller.showShare', ['token' => 'token']);
$instance->expects($this->once())->method('sendMailNotification')
->willReturnCallback(
function() {
throw new \Exception('should be converted to a hint exception');
}
);
$this->assertSame(42,
$this->invokePrivate($instance, 'createMailShare', [$this->share])
);
}
public function testGenerateToken() {
$instance = $this->getInstance();
$this->secureRandom->expects($this->once())->method('generate')->willReturn('token');
$this->assertSame('token',
$this->invokePrivate($instance, 'generateToken')
);
}
public function testAddShareToDB() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$instance = $this->getInstance();
$id = $this->invokePrivate(
$instance,
'addShareToDB',
[
$itemSource,
$itemType,
$shareWith,
$sharedBy,
$uidOwner,
$permissions,
$token
]
);
$qb = $this->connection->getQueryBuilder();
$result = $qb->select('*')
->from('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->execute()->fetchAll();
$this->assertSame(1, count($result));
$this->assertSame($itemSource, (int)$result[0]['item_source']);
$this->assertSame($itemType, $result[0]['item_type']);
$this->assertSame($shareWith, $result[0]['share_with']);
$this->assertSame($sharedBy, $result[0]['uid_initiator']);
$this->assertSame($uidOwner, $result[0]['uid_owner']);
$this->assertSame($permissions, (int)$result[0]['permissions']);
$this->assertSame($token, $result[0]['token']);
}
public function testUpdate() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$instance = $this->getInstance();
$id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$this->share->expects($this->once())->method('getPermissions')->willReturn($permissions + 1);
$this->share->expects($this->once())->method('getShareOwner')->willReturn($uidOwner);
$this->share->expects($this->once())->method('getSharedBy')->willReturn($sharedBy);
$this->share->expects($this->once())->method('getId')->willReturn($id);
$this->assertSame($this->share,
$instance->update($this->share)
);
$qb = $this->connection->getQueryBuilder();
$result = $qb->select('*')
->from('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->execute()->fetchAll();
$this->assertSame(1, count($result));
$this->assertSame($itemSource, (int)$result[0]['item_source']);
$this->assertSame($itemType, $result[0]['item_type']);
$this->assertSame($shareWith, $result[0]['share_with']);
$this->assertSame($sharedBy, $result[0]['uid_initiator']);
$this->assertSame($uidOwner, $result[0]['uid_owner']);
$this->assertSame($permissions + 1, (int)$result[0]['permissions']);
$this->assertSame($token, $result[0]['token']);
}
public function testDelete() {
$instance = $this->getInstance(['removeShareFromTable']);
$this->share->expects($this->once())->method('getId')->willReturn(42);
$instance->expects($this->once())->method('removeShareFromTable')->with(42);
$instance->delete($this->share);
}
public function testGetShareById() {
$instance = $this->getInstance(['createShareObject']);
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$this->createDummyShare($itemType, $itemSource, $shareWith, "user1wrong", "user2wrong", $permissions, $token);
$id2 = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$instance->expects($this->once())->method('createShareObject')
->willReturnCallback(
function ($data) use ($uidOwner, $sharedBy, $id2) {
$this->assertSame($uidOwner, $data['uid_owner']);
$this->assertSame($sharedBy, $data['uid_initiator']);
$this->assertSame($id2, (int)$data['id']);
return $this->share;
}
);
$result = $instance->getShareById($id2);
$this->assertInstanceOf('OCP\Share\IShare', $result);
}
/**
* @expectedException \OCP\Share\Exceptions\ShareNotFound
*/
public function testGetShareByIdFailed() {
$instance = $this->getInstance(['createShareObject']);
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$instance->getShareById($id+1);
}
public function testGetShareByPath() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$node = $this->getMockBuilder('OCP\Files\Node')->getMock();
$node->expects($this->once())->method('getId')->willReturn($itemSource);
$instance = $this->getInstance(['createShareObject']);
$this->createDummyShare($itemType, 111, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$instance->expects($this->once())->method('createShareObject')
->willReturnCallback(
function ($data) use ($uidOwner, $sharedBy, $id) {
$this->assertSame($uidOwner, $data['uid_owner']);
$this->assertSame($sharedBy, $data['uid_initiator']);
$this->assertSame($id, (int)$data['id']);
return $this->share;
}
);
$result = $instance->getSharesByPath($node);
$this->assertTrue(is_array($result));
$this->assertSame(1, count($result));
$this->assertInstanceOf('OCP\Share\IShare', $result[0]);
}
public function testGetShareByToken() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$instance = $this->getInstance(['createShareObject']);
$idMail = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$idPublic = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token, \OCP\Share::SHARE_TYPE_LINK);
$this->assertTrue($idMail !== $idPublic);
$instance->expects($this->once())->method('createShareObject')
->willReturnCallback(
function ($data) use ($idMail) {
$this->assertSame($idMail, (int)$data['id']);
return $this->share;
}
);
$this->assertInstanceOf('OCP\Share\IShare',
$instance->getShareByToken('token')
);
}
/**
* @expectedException \OCP\Share\Exceptions\ShareNotFound
*/
public function testGetShareByTokenFailed() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$instance = $this->getInstance(['createShareObject']);
$idMail = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$idPublic = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, "token2", \OCP\Share::SHARE_TYPE_LINK);
$this->assertTrue($idMail !== $idPublic);
$this->assertInstanceOf('OCP\Share\IShare',
$instance->getShareByToken('token2')
);
}
public function testRemoveShareFromTable() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$instance = $this->getInstance();
$id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$query = $this->connection->getQueryBuilder();
$query->select('*')->from('share')
->where($query->expr()->eq('id', $query->createNamedParameter($id)));
$before = $query->execute()->fetchAll();
$this->assertTrue(is_array($before));
$this->assertSame(1, count($before));
$this->invokePrivate($instance, 'removeShareFromTable', [$id]);
$query = $this->connection->getQueryBuilder();
$query->select('*')->from('share')
->where($query->expr()->eq('id', $query->createNamedParameter($id)));
$after = $query->execute()->fetchAll();
$this->assertTrue(is_array($after));
$this->assertEmpty($after);
}
public function testUserDeleted() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, 'user2Wrong', $permissions, $token);
$query = $this->connection->getQueryBuilder();
$query->select('*')->from('share');
$before = $query->execute()->fetchAll();
$this->assertTrue(is_array($before));
$this->assertSame(2, count($before));
$instance = $this->getInstance();
$instance->userDeleted($uidOwner, \OCP\Share::SHARE_TYPE_EMAIL);
$query = $this->connection->getQueryBuilder();
$query->select('*')->from('share');
$after = $query->execute()->fetchAll();
$this->assertTrue(is_array($after));
$this->assertSame(1, count($after));
$this->assertSame($id, (int)$after[0]['id']);
}
public function testGetRawShare() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$instance = $this->getInstance();
$id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$result = $this->invokePrivate($instance, 'getRawShare', [$id]);
$this->assertTrue(is_array($result));
$this->assertSame($itemSource, (int)$result['item_source']);
$this->assertSame($itemType, $result['item_type']);
$this->assertSame($shareWith, $result['share_with']);
$this->assertSame($sharedBy, $result['uid_initiator']);
$this->assertSame($uidOwner, $result['uid_owner']);
$this->assertSame($permissions, (int)$result['permissions']);
$this->assertSame($token, $result['token']);
}
/**
* @expectedException \OCP\Share\Exceptions\ShareNotFound
*/
public function testGetRawShareFailed() {
$itemSource = 11;
$itemType = 'file';
$shareWith = 'user@server.com';
$sharedBy = 'user1';
$uidOwner = 'user2';
$permissions = 1;
$token = 'token';
$instance = $this->getInstance();
$id = $this->createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token);
$this->invokePrivate($instance, 'getRawShare', [$id+1]);
}
private function createDummyShare($itemType, $itemSource, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType = \OCP\Share::SHARE_TYPE_EMAIL) {
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->setValue('share_type', $qb->createNamedParameter($shareType))
->setValue('item_type', $qb->createNamedParameter($itemType))
->setValue('item_source', $qb->createNamedParameter($itemSource))
->setValue('file_source', $qb->createNamedParameter($itemSource))
->setValue('share_with', $qb->createNamedParameter($shareWith))
->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
->setValue('permissions', $qb->createNamedParameter($permissions))
->setValue('token', $qb->createNamedParameter($token))
->setValue('stime', $qb->createNamedParameter(time()));
/*
* Added to fix https://github.com/owncloud/core/issues/22215
* Can be removed once we get rid of ajax/share.php
*/
$qb->setValue('file_target', $qb->createNamedParameter(''));
$qb->execute();
$id = $qb->getLastInsertId();
return (int)$id;
}
public function testGetSharesInFolder() {
$userManager = \OC::$server->getUserManager();
$rootFolder = \OC::$server->getRootFolder();
$provider = $this->getInstance(['sendMailNotification']);
$u1 = $userManager->createUser('testFed', md5(time()));
$u2 = $userManager->createUser('testFed2', md5(time()));
$folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo');
$file1 = $folder1->newFile('bar1');
$file2 = $folder1->newFile('bar2');
$share1 = $this->shareManager->newShare();
$share1->setSharedWith('user@server.com')
->setSharedBy($u1->getUID())
->setShareOwner($u1->getUID())
->setPermissions(\OCP\Constants::PERMISSION_READ)
->setNode($file1);
$provider->create($share1);
$share2 = $this->shareManager->newShare();
$share2->setSharedWith('user@server.com')
->setSharedBy($u2->getUID())
->setShareOwner($u1->getUID())
->setPermissions(\OCP\Constants::PERMISSION_READ)
->setNode($file2);
$provider->create($share2);
$result = $provider->getSharesInFolder($u1->getUID(), $folder1, false);
$this->assertCount(1, $result);
$this->assertCount(1, $result[$file1->getId()]);
$result = $provider->getSharesInFolder($u1->getUID(), $folder1, true);
$this->assertCount(2, $result);
$this->assertCount(1, $result[$file1->getId()]);
$this->assertCount(1, $result[$file2->getId()]);
$u1->delete();
$u2->delete();
}
}

View File

@ -255,7 +255,7 @@ Feature: provisioning
Scenario: Delete a user
Given As an "admin"
And user "brand-new-user" exists
When sending "DELETE" to "/cloud/users/brand-new-user"
When sending "DELETE" to "/cloud/users/brand-new-user"
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And user "brand-new-user" does not exist
@ -291,6 +291,7 @@ Feature: provisioning
| files_trashbin |
| files_versions |
| provisioning_api |
| sharebymail |
| systemtags |
| theming |
| twofactor_backupcodes |

View File

@ -25,6 +25,7 @@
isDefaultExpireDateEnforced: oc_appconfig.core.defaultExpireDateEnforced === true,
isDefaultExpireDateEnabled: oc_appconfig.core.defaultExpireDateEnabled === true,
isRemoteShareAllowed: oc_appconfig.core.remoteShareAllowed,
isMailShareAllowed: oc_appconfig.shareByMailEnabled !== undefined,
defaultExpireDate: oc_appconfig.core.defaultExpireDate,
isResharingAllowed: oc_appconfig.core.resharingAllowed,
allowGroupSharing: oc_appconfig.core.allowGroupSharing

View File

@ -24,25 +24,28 @@
'{{#if avatarEnabled}}' +
'<div class="avatar {{#if modSeed}}imageplaceholderseed{{/if}}" data-username="{{shareWith}}" {{#if modSeed}}data-seed="{{shareWith}} {{shareType}}"{{/if}}></div>' +
'{{/if}}' +
'<span class="has-tooltip username" title="{{shareWith}}">{{shareWithDisplayName}}</span>' +
'<span class="has-tooltip username" title="{{shareWithTitle}}">{{shareWithDisplayName}}</span>' +
'<span class="sharingOptionsGroup">' +
'{{#if editPermissionPossible}}' +
'{{#unless isFileSharedByMail}}' +
'<span class="shareOption">' +
'<input id="canEdit-{{cid}}-{{shareWith}}" type="checkbox" name="edit" class="permissions checkbox" {{#if hasEditPermission}}checked="checked"{{/if}} />' +
'<label for="canEdit-{{cid}}-{{shareWith}}">{{canEditLabel}}</label>' +
'</span>' +
'{{/unless}}' +
'{{/if}}' +
'{{#unless isMailShare}}' +
'<a href="#"><span class="icon icon-more"></span></a>' +
'<div class="popovermenu bubble hidden menu">' +
'<ul>' +
'{{#if isResharingAllowed}} {{#if sharePermissionPossible}}' +
'{{#if isResharingAllowed}} {{#if sharePermissionPossible}} {{#unless isMailShare}}' +
'<li>' +
'<span class="shareOption">' +
'<input id="canShare-{{cid}}-{{shareWith}}" type="checkbox" name="share" class="permissions checkbox" {{#if hasSharePermission}}checked="checked"{{/if}} data-permissions="{{sharePermission}}" />' +
'<label for="canShare-{{cid}}-{{shareWith}}">{{canShareLabel}}</label>' +
'</span>' +
'</li>' +
'{{/if}} {{/if}}' +
'{{/unless}} {{/if}} {{/if}}' +
'{{#if isFolder}}' +
'{{#if createPermissionPossible}}' +
'<li>' +
@ -74,7 +77,9 @@
'</li>' +
'</ul>' +
'</div>' +
'</span>' +
'{{/unless}}' +
'<a href="#" class="unshare"><span class="icon-loading-small hidden"></span><span class="icon icon-delete"></span><span class="hidden-visually">{{unshareLabel}}</span></a>' +
'</span>' +
'</li>' +
'{{/each}}' +
'{{#each linkReshares}}' +
@ -141,6 +146,7 @@
getShareeObject: function(shareIndex) {
var shareWith = this.model.getShareWith(shareIndex);
var shareWithDisplayName = this.model.getShareWithDisplayName(shareIndex);
var shareWithTitle = '';
var shareType = this.model.getShareType(shareIndex);
var hasPermissionOverride = {};
@ -148,6 +154,16 @@
shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'group') + ')';
} else if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'remote') + ')';
} else if (shareType === OC.Share.SHARE_TYPE_EMAIL) {
shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'email') + ')';
}
if (shareType === OC.Share.SHARE_TYPE_GROUP) {
shareWithTitle = shareWith + " (" + t('core', 'group') + ')';
} else if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
shareWithTitle = shareWith + " (" + t('core', 'remote') + ')';
} else if (shareType === OC.Share.SHARE_TYPE_EMAIL) {
shareWithTitle = shareWith + " (" + t('core', 'email') + ')';
}
return _.extend(hasPermissionOverride, {
@ -160,10 +176,13 @@
wasMailSent: this.model.notificationMailWasSent(shareIndex),
shareWith: shareWith,
shareWithDisplayName: shareWithDisplayName,
shareWithTitle: shareWithTitle,
shareType: shareType,
shareId: this.model.get('shares')[shareIndex].id,
modSeed: shareType !== OC.Share.SHARE_TYPE_USER,
isRemoteShare: shareType === OC.Share.SHARE_TYPE_REMOTE
isRemoteShare: shareType === OC.Share.SHARE_TYPE_REMOTE,
isMailShare: shareType === OC.Share.SHARE_TYPE_EMAIL,
isFileSharedByMail: shareType === OC.Share.SHARE_TYPE_EMAIL && !this.model.isFolder()
});
},

View File

@ -154,10 +154,16 @@
var users = result.ocs.data.exact.users.concat(result.ocs.data.users);
var groups = result.ocs.data.exact.groups.concat(result.ocs.data.groups);
var remotes = result.ocs.data.exact.remotes.concat(result.ocs.data.remotes);
if (typeof(result.ocs.data.emails) !== 'undefined') {
var emails = result.ocs.data.exact.emails.concat(result.ocs.data.emails);
} else {
var emails = [];
}
var usersLength;
var groupsLength;
var remotesLength;
var emailsLength;
var i, j;
@ -212,10 +218,18 @@
break;
}
}
} else if (share.share_type === OC.Share.SHARE_TYPE_EMAIL) {
emailsLength = emails.length;
for (j = 0; j < emailsLength; j++) {
if (emails[j].value.shareWith === share.share_with) {
emails.splice(j, 1);
break;
}
}
}
}
var suggestions = users.concat(groups).concat(remotes);
var suggestions = users.concat(groups).concat(remotes).concat(emails);
if (suggestions.length > 0) {
$('.shareWithField').removeClass('error')
@ -258,16 +272,13 @@
sharee: text
});
} else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
if (item.value.server) {
text = t('core', '{sharee} (at {server})', {
sharee: text,
server: item.value.server
});
} else {
text = t('core', '{sharee} (remote)', {
sharee: text
});
}
} else if (item.value.shareType === OC.Share.SHARE_TYPE_EMAIL) {
text = t('core', '{sharee} (email)', {
sharee: text
});
}
var insert = $("<div class='share-autocomplete-item'/>");
var avatar = $("<div class='avatardiv'></div>").appendTo(insert);
@ -397,7 +408,7 @@
var infoTemplate = this._getRemoteShareInfoTemplate();
remoteShareInfo = infoTemplate({
docLink: this.configModel.getFederatedShareDocLink(),
tooltip: t('core', 'Share with people on other Nextclouds using the syntax username@example.com/nextcloud')
tooltip: t('core', 'Share with people on other servers using the syntax username@example.com/nextcloud')
});
}
@ -405,19 +416,33 @@
},
_renderSharePlaceholderPart: function () {
var sharePlaceholder = t('core', 'Share with users…');
var allowGroupSharing = this.configModel.get('allowGroupSharing');
var allowRemoteSharing = this.configModel.get('isRemoteShareAllowed');
var allowMailSharing = this.configModel.get('isMailShareAllowed');
if (this.configModel.get('allowGroupSharing')) {
if (this.configModel.get('isRemoteShareAllowed')) {
sharePlaceholder = t('core', 'Share with users, groups or remote users…');
} else {
sharePlaceholder = t('core', 'Share with users or groups…');
}
} else if (this.configModel.get('isRemoteShareAllowed')) {
sharePlaceholder = t('core', 'Share with users or remote users…');
if (!allowGroupSharing && !allowRemoteSharing && allowMailSharing) {
return t('core', 'Share with users or by mail...');
}
if (!allowGroupSharing && allowRemoteSharing && !allowMailSharing) {
return t('core', 'Share with users or remote users...');
}
if (!allowGroupSharing && allowRemoteSharing && allowMailSharing) {
return t('core', 'Share with users, remote users or by mail...');
}
if (allowGroupSharing && !allowRemoteSharing && !allowMailSharing) {
return t('core', 'Share with users or groups...');
}
if (allowGroupSharing && !allowRemoteSharing && allowMailSharing) {
return t('core', 'Share with users, groups or by mail...');
}
if (allowGroupSharing && allowRemoteSharing && !allowMailSharing) {
return t('core', 'Share with users, groups or remote users...');
}
if (allowGroupSharing && allowRemoteSharing && allowMailSharing) {
return t('core', 'Share with users, groups, remote users or by mail...');
}
return sharePlaceholder;
return t('core', 'Share with users...');
},
/**

View File

@ -25,6 +25,7 @@
"password_policy",
"provisioning_api",
"serverinfo",
"sharebymail",
"survey_client",
"systemtags",
"templateeditor",

View File

@ -29,9 +29,9 @@ class Constants {
const SHARE_TYPE_USER = 0;
const SHARE_TYPE_GROUP = 1;
const SHARE_TYPE_LINK = 3;
const SHARE_TYPE_EMAIL = 4; // ToDo Check if it is still in use otherwise remove it
const SHARE_TYPE_EMAIL = 4;
const SHARE_TYPE_CONTACT = 5; // ToDo Check if it is still in use otherwise remove it
const SHARE_TYPE_REMOTE = 6; // ToDo Check if it is still in use otherwise remove it
const SHARE_TYPE_REMOTE = 6;
const FORMAT_NONE = -1;
const FORMAT_STATUSES = -2;

View File

@ -30,6 +30,7 @@ namespace OC\Share20;
use OC\Cache\CappedMemoryCache;
use OC\Files\Mount\MoveableMount;
use OC\HintException;
use OC\Share20\Exception\ProviderException;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
@ -185,6 +186,10 @@ class Manager implements IManager {
if ($share->getSharedWith() === null) {
throw new \InvalidArgumentException('SharedWith should not be empty');
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
if ($share->getSharedWith() === null) {
throw new \InvalidArgumentException('SharedWith should not be empty');
}
} else {
// We can't handle other types yet
throw new \InvalidArgumentException('unkown share type');
@ -580,6 +585,16 @@ class Manager implements IManager {
if ($share->getPassword() !== null) {
$share->setPassword($this->hasher->hash($share->getPassword()));
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
$this->linkCreateChecks($share);
$share->setToken(
$this->secureRandom->generate(
\OC\Share\Constants::TOKEN_LENGTH,
\OCP\Security\ISecureRandom::CHAR_LOWER.
\OCP\Security\ISecureRandom::CHAR_UPPER.
\OCP\Security\ISecureRandom::CHAR_DIGITS
)
);
}
// Cannot share with the owner
@ -1034,6 +1049,16 @@ class Manager implements IManager {
// If it is not a link share try to fetch a federated share by token
if ($share === null) {
$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
try {
$share = $provider->getShareByToken($token);
} catch (ShareNotFound $e) {
$share = null;
}
}
// If it is not a link share try to fetch a federated share by token
if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
$share = $provider->getShareByToken($token);
}
@ -1277,4 +1302,17 @@ class Manager implements IManager {
return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
}
/**
* @inheritdoc
*/
public function shareProviderExists($shareType) {
try {
$this->factory->getProviderForType($shareType);
} catch (ProviderException $e) {
return false;
}
return true;
}
}

View File

@ -28,6 +28,7 @@ use OCA\FederatedFileSharing\DiscoveryManager;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\FederatedFileSharing\Notifications;
use OCA\FederatedFileSharing\TokenHandler;
use OCA\ShareByMail\ShareByMailProvider;
use OCP\Share\IProviderFactory;
use OC\Share20\Exception\ProviderException;
use OCP\IServerContainer;
@ -45,6 +46,8 @@ class ProviderFactory implements IProviderFactory {
private $defaultProvider = null;
/** @var FederatedShareProvider */
private $federatedProvider = null;
/** @var ShareByMailProvider */
private $shareByMailProvider;
/**
* IProviderFactory constructor.
@ -125,6 +128,39 @@ class ProviderFactory implements IProviderFactory {
return $this->federatedProvider;
}
/**
* Create the federated share provider
*
* @return FederatedShareProvider
*/
protected function getShareByMailProvider() {
if ($this->shareByMailProvider === null) {
/*
* Check if the app is enabled
*/
$appManager = $this->serverContainer->getAppManager();
if (!$appManager->isEnabledForUser('sharebymail')) {
return null;
}
$l = $this->serverContainer->getL10N('sharebymail');
$this->shareByMailProvider = new ShareByMailProvider(
$this->serverContainer->getDatabaseConnection(),
$this->serverContainer->getSecureRandom(),
$this->serverContainer->getUserManager(),
$this->serverContainer->getLazyRootFolder(),
$l,
$this->serverContainer->getLogger(),
$this->serverContainer->getMailer(),
$this->serverContainer->getURLGenerator()
);
}
return $this->shareByMailProvider;
}
/**
* @inheritdoc
*/
@ -134,6 +170,8 @@ class ProviderFactory implements IProviderFactory {
$provider = $this->defaultShareProvider();
} else if ($id === 'ocFederatedSharing') {
$provider = $this->federatedShareProvider();
} else if ($id = 'ocMailShare') {
$provider = $this->getShareByMailProvider();
}
if ($provider === null) {
@ -155,6 +193,8 @@ class ProviderFactory implements IProviderFactory {
$provider = $this->defaultShareProvider();
} else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
$provider = $this->federatedShareProvider();
} else if ($shareType === \OCP\Share::SHARE_TYPE_EMAIL) {
$provider = $this->getShareByMailProvider();
}
if ($provider === null) {

View File

@ -286,4 +286,12 @@ interface IManager {
*/
public function outgoingServer2ServerSharesAllowed();
/**
* Check if a given share provider exists
* @param int $shareType
* @return bool
* @since 9.2.0
*/
public function shareProviderExists($shareType);
}

View File

@ -2530,6 +2530,46 @@ class ManagerTest extends \Test\TestCase {
$this->manager->moveShare($share, 'recipient');
}
/**
* @dataProvider dataTestShareProviderExists
*/
public function testShareProviderExists($shareType, $expected) {
$factory = $this->getMockBuilder('OCP\Share\IProviderFactory')->getMock();
$factory->expects($this->any())->method('getProviderForType')
->willReturnCallback(function ($id) {
if ($id === \OCP\Share::SHARE_TYPE_USER) {
return true;
}
throw new Exception\ProviderException();
});
$manager = new Manager(
$this->logger,
$this->config,
$this->secureRandom,
$this->hasher,
$this->mountManager,
$this->groupManager,
$this->l,
$factory,
$this->userManager,
$this->rootFolder,
$this->eventDispatcher
);
$this->assertSame($expected,
$manager->shareProviderExists($shareType)
);
}
public function dataTestShareProviderExists() {
return [
[\OCP\Share::SHARE_TYPE_USER, true],
[42, false],
];
}
public function testGetSharesInFolder() {
$factory = new DummyFactory2($this->createMock(IServerContainer::class));