Merge pull request #657 from nextcloud/share-by-mail
New share provider: Share by mail
This commit is contained in:
commit
7da3ba3f91
|
@ -16,6 +16,7 @@
|
|||
!/apps/files
|
||||
!/apps/federation
|
||||
!/apps/federatedfilesharing
|
||||
!/apps/sharebymail
|
||||
!/apps/encryption
|
||||
!/apps/files_external
|
||||
!/apps/files_sharing
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
|
@ -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"> </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"> </td></tr>
|
||||
<tr>
|
||||
<td width="20px"> </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"> </td></tr>
|
||||
<tr>
|
||||
<td width="20px"> </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"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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 |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -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...');
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"password_policy",
|
||||
"provisioning_api",
|
||||
"serverinfo",
|
||||
"sharebymail",
|
||||
"survey_client",
|
||||
"systemtags",
|
||||
"templateeditor",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Reference in New Issue