Merge pull request #6328 from nextcloud/split-sharees-api-logic
Splits off the logic from sharees endpoint thus making it available from within Nc/via PHP.
This commit is contained in:
commit
2d62f97f1b
|
@ -6,6 +6,7 @@
|
|||
* @author Joas Schilling <coding@schilljs.com>
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
|
@ -27,52 +28,23 @@ namespace OCA\Files_Sharing\Controller;
|
|||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCS\OCSBadRequestException;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\Contacts\IManager;
|
||||
use OCP\Federation\ICloudIdManager;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\ILogger;
|
||||
use OCP\Collaboration\Collaborators\ISearch;
|
||||
use OCP\IRequest;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\IUserSession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\Share;
|
||||
use OCP\Share\IManager;
|
||||
|
||||
class ShareesAPIController extends OCSController {
|
||||
|
||||
/** @var IGroupManager */
|
||||
protected $groupManager;
|
||||
|
||||
/** @var IUserManager */
|
||||
protected $userManager;
|
||||
|
||||
/** @var IManager */
|
||||
protected $contactsManager;
|
||||
|
||||
/** @var IConfig */
|
||||
protected $config;
|
||||
|
||||
/** @var IUserSession */
|
||||
protected $userSession;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
protected $urlGenerator;
|
||||
|
||||
/** @var ILogger */
|
||||
protected $logger;
|
||||
|
||||
/** @var \OCP\Share\IManager */
|
||||
/** @var IManager */
|
||||
protected $shareManager;
|
||||
|
||||
/** @var IClientService */
|
||||
protected $clientService;
|
||||
|
||||
/** @var ICloudIdManager */
|
||||
protected $cloudIdManager;
|
||||
|
||||
/** @var bool */
|
||||
protected $shareWithGroupOnly = false;
|
||||
|
||||
|
@ -103,326 +75,31 @@ class ShareesAPIController extends OCSController {
|
|||
];
|
||||
|
||||
protected $reachedEndFor = [];
|
||||
/** @var ISearch */
|
||||
private $collaboratorSearch;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
* @param IRequest $request
|
||||
* @param IGroupManager $groupManager
|
||||
* @param IUserManager $userManager
|
||||
* @param IManager $contactsManager
|
||||
* @param IConfig $config
|
||||
* @param IUserSession $userSession
|
||||
* @param IURLGenerator $urlGenerator
|
||||
* @param ILogger $logger
|
||||
* @param \OCP\Share\IManager $shareManager
|
||||
* @param IClientService $clientService
|
||||
* @param ICloudIdManager $cloudIdManager
|
||||
* @param IManager $shareManager
|
||||
* @param ISearch $collaboratorSearch
|
||||
*/
|
||||
public function __construct($appName,
|
||||
IRequest $request,
|
||||
IGroupManager $groupManager,
|
||||
IUserManager $userManager,
|
||||
IManager $contactsManager,
|
||||
IConfig $config,
|
||||
IUserSession $userSession,
|
||||
IURLGenerator $urlGenerator,
|
||||
ILogger $logger,
|
||||
\OCP\Share\IManager $shareManager,
|
||||
IClientService $clientService,
|
||||
ICloudIdManager $cloudIdManager
|
||||
public function __construct(
|
||||
$appName,
|
||||
IRequest $request,
|
||||
IConfig $config,
|
||||
IURLGenerator $urlGenerator,
|
||||
IManager $shareManager,
|
||||
ISearch $collaboratorSearch
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
|
||||
$this->groupManager = $groupManager;
|
||||
$this->userManager = $userManager;
|
||||
$this->contactsManager = $contactsManager;
|
||||
$this->config = $config;
|
||||
$this->userSession = $userSession;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->logger = $logger;
|
||||
$this->shareManager = $shareManager;
|
||||
$this->clientService = $clientService;
|
||||
$this->cloudIdManager = $cloudIdManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
*/
|
||||
protected function getUsers($search) {
|
||||
$this->result['users'] = $this->result['exact']['users'] = $users = [];
|
||||
|
||||
$userGroups = [];
|
||||
if ($this->shareWithGroupOnly) {
|
||||
// Search in all the groups this user is part of
|
||||
$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
|
||||
foreach ($userGroups as $userGroup) {
|
||||
$usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $this->limit, $this->offset);
|
||||
foreach ($usersTmp as $uid => $userDisplayName) {
|
||||
$users[$uid] = $userDisplayName;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Search in all users
|
||||
$usersTmp = $this->userManager->searchDisplayName($search, $this->limit, $this->offset);
|
||||
|
||||
foreach ($usersTmp as $user) {
|
||||
$users[$user->getUID()] = $user->getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
|
||||
$this->reachedEndFor[] = 'users';
|
||||
}
|
||||
|
||||
$foundUserById = false;
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($users as $uid => $userDisplayName) {
|
||||
if (strtolower($uid) === $lowerSearch || strtolower($userDisplayName) === $lowerSearch) {
|
||||
if (strtolower($uid) === $lowerSearch) {
|
||||
$foundUserById = true;
|
||||
}
|
||||
$this->result['exact']['users'][] = [
|
||||
'label' => $userDisplayName,
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $uid,
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$this->result['users'][] = [
|
||||
'label' => $userDisplayName,
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $uid,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->offset === 0 && !$foundUserById) {
|
||||
// On page one we try if the search result has a direct hit on the
|
||||
// user id and if so, we add that to the exact match list
|
||||
$user = $this->userManager->get($search);
|
||||
if ($user instanceof IUser) {
|
||||
$addUser = true;
|
||||
|
||||
if ($this->shareWithGroupOnly) {
|
||||
// Only add, if we have a common group
|
||||
$commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
|
||||
$addUser = !empty($commonGroups);
|
||||
}
|
||||
|
||||
if ($addUser) {
|
||||
array_push($this->result['exact']['users'], [
|
||||
'label' => $user->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $user->getUID(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration) {
|
||||
$this->result['users'] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
*/
|
||||
protected function getGroups($search) {
|
||||
$this->result['groups'] = $this->result['exact']['groups'] = [];
|
||||
|
||||
$groups = $this->groupManager->search($search, $this->limit, $this->offset);
|
||||
$groupIds = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
|
||||
|
||||
if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
|
||||
$this->reachedEndFor[] = 'groups';
|
||||
}
|
||||
|
||||
$userGroups = [];
|
||||
if (!empty($groups) && $this->shareWithGroupOnly) {
|
||||
// Intersect all the groups that match with the groups this user is a member of
|
||||
$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
|
||||
$userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
|
||||
$groupIds = array_intersect($groupIds, $userGroups);
|
||||
}
|
||||
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($groups as $group) {
|
||||
// FIXME: use a more efficient approach
|
||||
$gid = $group->getGID();
|
||||
if (!in_array($gid, $groupIds)) {
|
||||
continue;
|
||||
}
|
||||
if (strtolower($gid) === $lowerSearch || strtolower($group->getDisplayName()) === $lowerSearch) {
|
||||
$this->result['exact']['groups'][] = [
|
||||
'label' => $group->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_GROUP,
|
||||
'shareWith' => $gid,
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$this->result['groups'][] = [
|
||||
'label' => $group->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_GROUP,
|
||||
'shareWith' => $gid,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->offset === 0 && empty($this->result['exact']['groups'])) {
|
||||
// On page one we try if the search result has a direct hit on the
|
||||
// user id and if so, we add that to the exact match list
|
||||
$group = $this->groupManager->get($search);
|
||||
if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
|
||||
array_push($this->result['exact']['groups'], [
|
||||
'label' => $group->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_GROUP,
|
||||
'shareWith' => $group->getGID(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration) {
|
||||
$this->result['groups'] = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
* @suppress PhanUndeclaredClassMethod
|
||||
*/
|
||||
protected function getCircles($search) {
|
||||
$this->result['circles'] = $this->result['exact']['circles'] = [];
|
||||
|
||||
$result = \OCA\Circles\Api\Sharees::search($search, $this->limit, $this->offset);
|
||||
if (array_key_exists('circles', $result['exact'])) {
|
||||
$this->result['exact']['circles'] = $result['exact']['circles'];
|
||||
}
|
||||
if (array_key_exists('circles', $result)) {
|
||||
$this->result['circles'] = $result['circles'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
* @return array
|
||||
*/
|
||||
protected function getRemote($search) {
|
||||
$result = ['results' => [], 'exact' => []];
|
||||
|
||||
// Search in contacts
|
||||
//@todo Pagination missing
|
||||
$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
|
||||
$result['exactIdMatch'] = false;
|
||||
foreach ($addressBookContacts as $contact) {
|
||||
if (isset($contact['isLocalSystemBook'])) {
|
||||
continue;
|
||||
}
|
||||
if (isset($contact['CLOUD'])) {
|
||||
$cloudIds = $contact['CLOUD'];
|
||||
if (!is_array($cloudIds)) {
|
||||
$cloudIds = [$cloudIds];
|
||||
}
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($cloudIds as $cloudId) {
|
||||
try {
|
||||
list(, $serverUrl) = $this->splitUserRemote($cloudId);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
|
||||
if (strtolower($cloudId) === $lowerSearch) {
|
||||
$result['exactIdMatch'] = true;
|
||||
}
|
||||
$result['exact'][] = [
|
||||
'label' => $contact['FN'] . " ($cloudId)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $cloudId,
|
||||
'server' => $serverUrl,
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$result['results'][] = [
|
||||
'label' => $contact['FN'] . " ($cloudId)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $cloudId,
|
||||
'server' => $serverUrl,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration) {
|
||||
$result['results'] = [];
|
||||
}
|
||||
|
||||
if (!$result['exactIdMatch'] && $this->cloudIdManager->isValidCloudId($search) && $this->offset === 0) {
|
||||
$result['exact'][] = [
|
||||
'label' => $search,
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $search,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$this->reachedEndFor[] = 'remotes';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* split user and remote from federated cloud id
|
||||
*
|
||||
* @param string $address federated share address
|
||||
* @return array [user, remoteURL]
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function splitUserRemote($address) {
|
||||
try {
|
||||
$cloudId = $this->cloudIdManager->resolveCloudId($address);
|
||||
return [$cloudId->getUser(), $cloudId->getRemote()];
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips away a potential file names and trailing slashes:
|
||||
* - http://localhost
|
||||
* - http://localhost/
|
||||
* - http://localhost/index.php
|
||||
* - http://localhost/index.php/s/{shareToken}
|
||||
*
|
||||
* all return: http://localhost
|
||||
*
|
||||
* @param string $remote
|
||||
* @return string
|
||||
*/
|
||||
protected function fixRemoteURL($remote) {
|
||||
$remote = str_replace('\\', '/', $remote);
|
||||
if ($fileNamePosition = strpos($remote, '/index.php')) {
|
||||
$remote = substr($remote, 0, $fileNamePosition);
|
||||
}
|
||||
$remote = rtrim($remote, '/');
|
||||
|
||||
return $remote;
|
||||
$this->collaboratorSearch = $collaboratorSearch;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -461,7 +138,9 @@ class ShareesAPIController extends OCSController {
|
|||
Share::SHARE_TYPE_USER,
|
||||
];
|
||||
|
||||
if ($itemType === 'file' || $itemType === 'folder') {
|
||||
if ($itemType === null) {
|
||||
throw new OCSBadRequestException('Missing itemType');
|
||||
} elseif ($itemType === 'file' || $itemType === 'folder') {
|
||||
if ($this->shareManager->allowGroupSharing()) {
|
||||
$shareTypes[] = Share::SHARE_TYPE_GROUP;
|
||||
}
|
||||
|
@ -478,6 +157,7 @@ class ShareesAPIController extends OCSController {
|
|||
$shareTypes[] = Share::SHARE_TYPE_EMAIL;
|
||||
}
|
||||
|
||||
// FIXME: DI
|
||||
if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
|
||||
$shareTypes[] = Share::SHARE_TYPE_CIRCLE;
|
||||
}
|
||||
|
@ -495,94 +175,16 @@ class ShareesAPIController extends OCSController {
|
|||
$this->limit = (int) $perPage;
|
||||
$this->offset = $perPage * ($page - 1);
|
||||
|
||||
return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage, $lookup);
|
||||
}
|
||||
list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
|
||||
|
||||
/**
|
||||
* Method to get out the static call for better testing
|
||||
*
|
||||
* @param string $itemType
|
||||
* @return bool
|
||||
*/
|
||||
protected function isRemoteSharingAllowed($itemType) {
|
||||
try {
|
||||
$backend = \OC\Share\Share::getBackend($itemType);
|
||||
return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
// extra treatment for 'exact' subarray, with a single merge expected keys might be lost
|
||||
if(isset($result['exact'])) {
|
||||
$result['exact'] = array_merge($this->result['exact'], $result['exact']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testable search function that does not need globals
|
||||
*
|
||||
* @param string $search
|
||||
* @param string $itemType
|
||||
* @param array $shareTypes
|
||||
* @param int $page
|
||||
* @param int $perPage
|
||||
* @param bool $lookup
|
||||
* @return DataResponse
|
||||
* @throws OCSBadRequestException
|
||||
*/
|
||||
protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage, $lookup) {
|
||||
// Verify arguments
|
||||
if ($itemType === null) {
|
||||
throw new OCSBadRequestException('Missing itemType');
|
||||
}
|
||||
|
||||
// Get users
|
||||
if (in_array(Share::SHARE_TYPE_USER, $shareTypes)) {
|
||||
$this->getUsers($search);
|
||||
}
|
||||
|
||||
// Get groups
|
||||
if (in_array(Share::SHARE_TYPE_GROUP, $shareTypes)) {
|
||||
$this->getGroups($search);
|
||||
}
|
||||
|
||||
// Get circles
|
||||
if (in_array(Share::SHARE_TYPE_CIRCLE, $shareTypes)) {
|
||||
$this->getCircles($search);
|
||||
}
|
||||
|
||||
|
||||
// Get remote
|
||||
$remoteResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
|
||||
if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
|
||||
$remoteResults = $this->getRemote($search);
|
||||
}
|
||||
|
||||
// Get emails
|
||||
$mailResults = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
|
||||
if (in_array(Share::SHARE_TYPE_EMAIL, $shareTypes)) {
|
||||
$mailResults = $this->getEmail($search);
|
||||
}
|
||||
|
||||
// Get from lookup server
|
||||
if ($lookup) {
|
||||
$this->getLookup($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'];
|
||||
}
|
||||
|
||||
$this->result = array_merge($this->result, $result);
|
||||
$response = new DataResponse($this->result);
|
||||
|
||||
if (sizeof($this->reachedEndFor) < 3) {
|
||||
if ($hasMoreResults) {
|
||||
$response->addHeader('Link', $this->getPaginationLink($page, [
|
||||
'search' => $search,
|
||||
'itemType' => $itemType,
|
||||
|
@ -595,166 +197,22 @@ class ShareesAPIController extends OCSController {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
* @return array
|
||||
*/
|
||||
protected function getEmail($search) {
|
||||
$result = ['results' => [], 'exact' => [], 'exactIdMatch' => false];
|
||||
|
||||
// Search in contacts
|
||||
//@todo Pagination missing
|
||||
$addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN']);
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($addressBookContacts as $contact) {
|
||||
if (isset($contact['EMAIL'])) {
|
||||
$emailAddresses = $contact['EMAIL'];
|
||||
if (!is_array($emailAddresses)) {
|
||||
$emailAddresses = [$emailAddresses];
|
||||
}
|
||||
foreach ($emailAddresses as $emailAddress) {
|
||||
$exactEmailMatch = strtolower($emailAddress) === $lowerSearch;
|
||||
|
||||
if (isset($contact['isLocalSystemBook'])) {
|
||||
if ($exactEmailMatch) {
|
||||
try {
|
||||
$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->hasUserInResult($cloud->getUser())) {
|
||||
$this->result['exact']['users'][] = [
|
||||
'label' => $contact['FN'] . " ($emailAddress)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $cloud->getUser(),
|
||||
],
|
||||
];
|
||||
}
|
||||
return ['results' => [], 'exact' => [], 'exactIdMatch' => true];
|
||||
}
|
||||
|
||||
if ($this->shareeEnumeration) {
|
||||
try {
|
||||
$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->hasUserInResult($cloud->getUser())) {
|
||||
$this->result['users'][] = [
|
||||
'label' => $contact['FN'] . " ($emailAddress)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $cloud->getUser(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($exactEmailMatch || strtolower($contact['FN']) === $lowerSearch) {
|
||||
if ($exactEmailMatch) {
|
||||
$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;
|
||||
}
|
||||
|
||||
protected function getLookup($search) {
|
||||
$isEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no');
|
||||
$lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
|
||||
$lookupServerUrl = rtrim($lookupServerUrl, '/');
|
||||
$result = [];
|
||||
|
||||
if($isEnabled === 'yes') {
|
||||
try {
|
||||
$client = $this->clientService->newClient();
|
||||
$response = $client->get(
|
||||
$lookupServerUrl . '/users?search=' . urlencode($search),
|
||||
[
|
||||
'timeout' => 10,
|
||||
'connect_timeout' => 3,
|
||||
]
|
||||
);
|
||||
|
||||
$body = json_decode($response->getBody(), true);
|
||||
|
||||
$result = [];
|
||||
foreach ($body as $lookup) {
|
||||
$result[] = [
|
||||
'label' => $lookup['federationId'],
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $lookup['federationId'],
|
||||
],
|
||||
'extra' => $lookup,
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
$this->result['lookup'] = $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given user is already part of the result
|
||||
* Method to get out the static call for better testing
|
||||
*
|
||||
* @param string $userId
|
||||
* @param string $itemType
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasUserInResult($userId) {
|
||||
foreach ($this->result['exact']['users'] as $result) {
|
||||
if ($result['value']['shareWith'] === $userId) {
|
||||
return true;
|
||||
}
|
||||
protected function isRemoteSharingAllowed($itemType) {
|
||||
try {
|
||||
// FIXME: static foo makes unit testing unnecessarily difficult
|
||||
$backend = \OC\Share\Share::getBackend($itemType);
|
||||
return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->result['users'] as $result) {
|
||||
if ($result['value']['shareWith'] === $userId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a bunch of pagination links for the current page
|
||||
*
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -68,6 +68,10 @@ return array(
|
|||
'OCP\\BackgroundJob\\IJobList' => $baseDir . '/lib/public/BackgroundJob/IJobList.php',
|
||||
'OCP\\Capabilities\\ICapability' => $baseDir . '/lib/public/Capabilities/ICapability.php',
|
||||
'OCP\\Capabilities\\IPublicCapability' => $baseDir . '/lib/public/Capabilities/IPublicCapability.php',
|
||||
'OCP\\Collaboration\\Collaborators\\ISearch' => $baseDir . '/lib/public/Collaboration/Collaborators/ISearch.php',
|
||||
'OCP\\Collaboration\\Collaborators\\ISearchPlugin' => $baseDir . '/lib/public/Collaboration/Collaborators/ISearchPlugin.php',
|
||||
'OCP\\Collaboration\\Collaborators\\ISearchResult' => $baseDir . '/lib/public/Collaboration/Collaborators/ISearchResult.php',
|
||||
'OCP\\Collaboration\\Collaborators\\SearchResultType' => $baseDir . '/lib/public/Collaboration/Collaborators/SearchResultType.php',
|
||||
'OCP\\Command\\IBus' => $baseDir . '/lib/public/Command/IBus.php',
|
||||
'OCP\\Command\\ICommand' => $baseDir . '/lib/public/Command/ICommand.php',
|
||||
'OCP\\Comments\\CommentsEntityEvent' => $baseDir . '/lib/public/Comments/CommentsEntityEvent.php',
|
||||
|
@ -384,6 +388,13 @@ return array(
|
|||
'OC\\Cache\\CappedMemoryCache' => $baseDir . '/lib/private/Cache/CappedMemoryCache.php',
|
||||
'OC\\Cache\\File' => $baseDir . '/lib/private/Cache/File.php',
|
||||
'OC\\CapabilitiesManager' => $baseDir . '/lib/private/CapabilitiesManager.php',
|
||||
'OC\\Collaboration\\Collaborators\\GroupPlugin' => $baseDir . '/lib/private/Collaboration/Collaborators/GroupPlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\LookupPlugin' => $baseDir . '/lib/private/Collaboration/Collaborators/LookupPlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\MailPlugin' => $baseDir . '/lib/private/Collaboration/Collaborators/MailPlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\RemotePlugin' => $baseDir . '/lib/private/Collaboration/Collaborators/RemotePlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\Search' => $baseDir . '/lib/private/Collaboration/Collaborators/Search.php',
|
||||
'OC\\Collaboration\\Collaborators\\SearchResult' => $baseDir . '/lib/private/Collaboration/Collaborators/SearchResult.php',
|
||||
'OC\\Collaboration\\Collaborators\\UserPlugin' => $baseDir . '/lib/private/Collaboration/Collaborators/UserPlugin.php',
|
||||
'OC\\Command\\AsyncBus' => $baseDir . '/lib/private/Command/AsyncBus.php',
|
||||
'OC\\Command\\CallableJob' => $baseDir . '/lib/private/Command/CallableJob.php',
|
||||
'OC\\Command\\ClosureJob' => $baseDir . '/lib/private/Command/ClosureJob.php',
|
||||
|
|
|
@ -98,6 +98,10 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OCP\\BackgroundJob\\IJobList' => __DIR__ . '/../../..' . '/lib/public/BackgroundJob/IJobList.php',
|
||||
'OCP\\Capabilities\\ICapability' => __DIR__ . '/../../..' . '/lib/public/Capabilities/ICapability.php',
|
||||
'OCP\\Capabilities\\IPublicCapability' => __DIR__ . '/../../..' . '/lib/public/Capabilities/IPublicCapability.php',
|
||||
'OCP\\Collaboration\\Collaborators\\ISearch' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/ISearch.php',
|
||||
'OCP\\Collaboration\\Collaborators\\ISearchPlugin' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/ISearchPlugin.php',
|
||||
'OCP\\Collaboration\\Collaborators\\ISearchResult' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/ISearchResult.php',
|
||||
'OCP\\Collaboration\\Collaborators\\SearchResultType' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/SearchResultType.php',
|
||||
'OCP\\Command\\IBus' => __DIR__ . '/../../..' . '/lib/public/Command/IBus.php',
|
||||
'OCP\\Command\\ICommand' => __DIR__ . '/../../..' . '/lib/public/Command/ICommand.php',
|
||||
'OCP\\Comments\\CommentsEntityEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/CommentsEntityEvent.php',
|
||||
|
@ -414,6 +418,13 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Cache\\CappedMemoryCache' => __DIR__ . '/../../..' . '/lib/private/Cache/CappedMemoryCache.php',
|
||||
'OC\\Cache\\File' => __DIR__ . '/../../..' . '/lib/private/Cache/File.php',
|
||||
'OC\\CapabilitiesManager' => __DIR__ . '/../../..' . '/lib/private/CapabilitiesManager.php',
|
||||
'OC\\Collaboration\\Collaborators\\GroupPlugin' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/GroupPlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\LookupPlugin' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/LookupPlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\MailPlugin' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/MailPlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\RemotePlugin' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/RemotePlugin.php',
|
||||
'OC\\Collaboration\\Collaborators\\Search' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/Search.php',
|
||||
'OC\\Collaboration\\Collaborators\\SearchResult' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/SearchResult.php',
|
||||
'OC\\Collaboration\\Collaborators\\UserPlugin' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/UserPlugin.php',
|
||||
'OC\\Command\\AsyncBus' => __DIR__ . '/../../..' . '/lib/private/Command/AsyncBus.php',
|
||||
'OC\\Command\\CallableJob' => __DIR__ . '/../../..' . '/lib/private/Command/CallableJob.php',
|
||||
'OC\\Command\\ClosureJob' => __DIR__ . '/../../..' . '/lib/private/Command/ClosureJob.php',
|
||||
|
|
|
@ -165,6 +165,12 @@ class InfoParser {
|
|||
if (isset($array['activity']['providers']['provider']) && is_array($array['activity']['providers']['provider'])) {
|
||||
$array['activity']['providers'] = $array['activity']['providers']['provider'];
|
||||
}
|
||||
if (isset($array['collaboration']['collaborators']['searchPlugins']['searchPlugin'])
|
||||
&& is_array($array['collaboration']['collaborators']['searchPlugins']['searchPlugin'])
|
||||
&& !isset($array['collaboration']['collaborators']['searchPlugins']['searchPlugin']['class'])
|
||||
) {
|
||||
$array['collaboration']['collaborators']['searchPlugins'] = $array['collaboration']['collaborators']['searchPlugins']['searchPlugin'];
|
||||
}
|
||||
|
||||
if(!is_null($this->cache)) {
|
||||
$this->cache->set($fileCacheKey, json_encode($array));
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OC\Collaboration\Collaborators;
|
||||
|
||||
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\IConfig;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Share;
|
||||
|
||||
class GroupPlugin implements ISearchPlugin {
|
||||
protected $shareeEnumeration;
|
||||
protected $shareWithGroupOnly;
|
||||
|
||||
/** @var IGroupManager */
|
||||
private $groupManager;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
|
||||
public function __construct(IConfig $config, IGroupManager $groupManager, IUserSession $userSession) {
|
||||
$this->groupManager = $groupManager;
|
||||
$this->config = $config;
|
||||
$this->userSession = $userSession;
|
||||
|
||||
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
|
||||
$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
|
||||
}
|
||||
|
||||
public function search($search, $limit, $offset, ISearchResult $searchResult) {
|
||||
$hasMoreResults = false;
|
||||
$result = ['wide' => [], 'exact' => []];
|
||||
|
||||
$groups = $this->groupManager->search($search, $limit, $offset);
|
||||
$groupIds = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
|
||||
|
||||
if (!$this->shareeEnumeration || sizeof($groups) < $limit) {
|
||||
$hasMoreResults = true;
|
||||
}
|
||||
|
||||
$userGroups = [];
|
||||
if (!empty($groups) && $this->shareWithGroupOnly) {
|
||||
// Intersect all the groups that match with the groups this user is a member of
|
||||
$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
|
||||
$userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
|
||||
$groupIds = array_intersect($groupIds, $userGroups);
|
||||
}
|
||||
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($groups as $group) {
|
||||
// FIXME: use a more efficient approach
|
||||
$gid = $group->getGID();
|
||||
if (!in_array($gid, $groupIds)) {
|
||||
continue;
|
||||
}
|
||||
if (strtolower($gid) === $lowerSearch || strtolower($group->getDisplayName()) === $lowerSearch) {
|
||||
$result['exact'][] = [
|
||||
'label' => $group->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_GROUP,
|
||||
'shareWith' => $gid,
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$result['wide'][] = [
|
||||
'label' => $group->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_GROUP,
|
||||
'shareWith' => $gid,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($offset === 0 && empty($result['exact'])) {
|
||||
// On page one we try if the search result has a direct hit on the
|
||||
// user id and if so, we add that to the exact match list
|
||||
$group = $this->groupManager->get($search);
|
||||
if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
|
||||
array_push($result['exact'], [
|
||||
'label' => $group->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_GROUP,
|
||||
'shareWith' => $group->getGID(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration) {
|
||||
$result['wide'] = [];
|
||||
}
|
||||
|
||||
$type = new SearchResultType('groups');
|
||||
$searchResult->addResultSet($type, $result['wide'], $result['exact']);
|
||||
|
||||
return $hasMoreResults;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OC\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\IConfig;
|
||||
use OCP\Share;
|
||||
|
||||
class LookupPlugin implements ISearchPlugin {
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var IClientService */
|
||||
private $clientService;
|
||||
|
||||
public function __construct(IConfig $config, IClientService $clientService) {
|
||||
$this->config = $config;
|
||||
$this->clientService = $clientService;
|
||||
}
|
||||
|
||||
public function search($search, $limit, $offset, ISearchResult $searchResult) {
|
||||
if ($this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no') !== 'yes') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
|
||||
$lookupServerUrl = rtrim($lookupServerUrl, '/');
|
||||
$result = [];
|
||||
|
||||
try {
|
||||
$client = $this->clientService->newClient();
|
||||
$response = $client->get(
|
||||
$lookupServerUrl . '/users?search=' . urlencode($search),
|
||||
[
|
||||
'timeout' => 10,
|
||||
'connect_timeout' => 3,
|
||||
]
|
||||
);
|
||||
|
||||
$body = json_decode($response->getBody(), true);
|
||||
|
||||
foreach ($body as $lookup) {
|
||||
$result[] = [
|
||||
'label' => $lookup['federationId'],
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $lookup['federationId'],
|
||||
],
|
||||
'extra' => $lookup,
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
$type = new SearchResultType('lookup');
|
||||
$searchResult->addResultSet($type, $result, []);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OC\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\Contacts\IManager;
|
||||
use OCP\Federation\ICloudIdManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\Share;
|
||||
|
||||
class MailPlugin implements ISearchPlugin {
|
||||
protected $shareeEnumeration;
|
||||
|
||||
/** @var IManager */
|
||||
private $contactsManager;
|
||||
/** @var ICloudIdManager */
|
||||
private $cloudIdManager;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config) {
|
||||
$this->contactsManager = $contactsManager;
|
||||
$this->cloudIdManager = $cloudIdManager;
|
||||
$this->config = $config;
|
||||
|
||||
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $search
|
||||
* @param $limit
|
||||
* @param $offset
|
||||
* @param ISearchResult $searchResult
|
||||
* @return bool
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function search($search, $limit, $offset, ISearchResult $searchResult) {
|
||||
$result = ['wide' => [], 'exact' => []];
|
||||
$userType = new SearchResultType('users');
|
||||
$emailType = new SearchResultType('emails');
|
||||
|
||||
// Search in contacts
|
||||
//@todo Pagination missing
|
||||
$addressBookContacts = $this->contactsManager->search($search, ['EMAIL', 'FN']);
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($addressBookContacts as $contact) {
|
||||
if (isset($contact['EMAIL'])) {
|
||||
$emailAddresses = $contact['EMAIL'];
|
||||
if (!is_array($emailAddresses)) {
|
||||
$emailAddresses = [$emailAddresses];
|
||||
}
|
||||
foreach ($emailAddresses as $emailAddress) {
|
||||
$exactEmailMatch = strtolower($emailAddress) === $lowerSearch;
|
||||
|
||||
if (isset($contact['isLocalSystemBook'])) {
|
||||
if ($exactEmailMatch) {
|
||||
try {
|
||||
$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$searchResult->hasResult($userType, $cloud->getUser())) {
|
||||
$singleResult = [[
|
||||
'label' => $contact['FN'] . " ($emailAddress)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $cloud->getUser(),
|
||||
],
|
||||
]];
|
||||
$searchResult->addResultSet($userType, [], $singleResult);
|
||||
$searchResult->markExactIdMatch($emailType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->shareeEnumeration) {
|
||||
try {
|
||||
$cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$searchResult->hasResult($userType, $cloud->getUser())) {
|
||||
$singleResult = [[
|
||||
'label' => $contact['FN'] . " ($emailAddress)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $cloud->getUser(),
|
||||
]],
|
||||
];
|
||||
$searchResult->addResultSet($userType, $singleResult, []);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($exactEmailMatch || strtolower($contact['FN']) === $lowerSearch) {
|
||||
if ($exactEmailMatch) {
|
||||
$searchResult->markExactIdMatch($emailType);
|
||||
}
|
||||
$result['exact'][] = [
|
||||
'label' => $contact['FN'] . " ($emailAddress)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_EMAIL,
|
||||
'shareWith' => $emailAddress,
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$result['wide'][] = [
|
||||
'label' => $contact['FN'] . " ($emailAddress)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_EMAIL,
|
||||
'shareWith' => $emailAddress,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration) {
|
||||
$result['wide'] = [];
|
||||
}
|
||||
|
||||
if (!$searchResult->hasExactIdMatch($emailType) && filter_var($search, FILTER_VALIDATE_EMAIL)) {
|
||||
$result['exact'][] = [
|
||||
'label' => $search,
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_EMAIL,
|
||||
'shareWith' => $search,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$searchResult->addResultSet($emailType, $result['wide'], $result['exact']);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OC\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\Contacts\IManager;
|
||||
use OCP\Federation\ICloudIdManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\Share;
|
||||
|
||||
class RemotePlugin implements ISearchPlugin {
|
||||
protected $shareeEnumeration;
|
||||
|
||||
/** @var IManager */
|
||||
private $contactsManager;
|
||||
/** @var ICloudIdManager */
|
||||
private $cloudIdManager;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config) {
|
||||
$this->contactsManager = $contactsManager;
|
||||
$this->cloudIdManager = $cloudIdManager;
|
||||
$this->config = $config;
|
||||
|
||||
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
|
||||
}
|
||||
|
||||
public function search($search, $limit, $offset, ISearchResult $searchResult) {
|
||||
$result = ['wide' => [], 'exact' => []];
|
||||
$resultType = new SearchResultType('remotes');
|
||||
|
||||
// Search in contacts
|
||||
//@todo Pagination missing
|
||||
$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
|
||||
foreach ($addressBookContacts as $contact) {
|
||||
if (isset($contact['isLocalSystemBook'])) {
|
||||
continue;
|
||||
}
|
||||
if (isset($contact['CLOUD'])) {
|
||||
$cloudIds = $contact['CLOUD'];
|
||||
if (!is_array($cloudIds)) {
|
||||
$cloudIds = [$cloudIds];
|
||||
}
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($cloudIds as $cloudId) {
|
||||
try {
|
||||
list(, $serverUrl) = $this->splitUserRemote($cloudId);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
|
||||
if (strtolower($cloudId) === $lowerSearch) {
|
||||
$searchResult->markExactIdMatch($resultType);
|
||||
}
|
||||
$result['exact'][] = [
|
||||
'label' => $contact['FN'] . " ($cloudId)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $cloudId,
|
||||
'server' => $serverUrl,
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$result['wide'][] = [
|
||||
'label' => $contact['FN'] . " ($cloudId)",
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $cloudId,
|
||||
'server' => $serverUrl,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration) {
|
||||
$result['wide'] = [];
|
||||
}
|
||||
|
||||
if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
|
||||
$result['exact'][] = [
|
||||
'label' => $search,
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $search,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* split user and remote from federated cloud id
|
||||
*
|
||||
* @param string $address federated share address
|
||||
* @return array [user, remoteURL]
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function splitUserRemote($address) {
|
||||
try {
|
||||
$cloudId = $this->cloudIdManager->resolveCloudId($address);
|
||||
return [$cloudId->getUser(), $cloudId->getRemote()];
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OC\Collaboration\Collaborators;
|
||||
|
||||
use OCP\Collaboration\Collaborators\ISearch;
|
||||
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\IContainer;
|
||||
use OCP\Share;
|
||||
|
||||
class Search implements ISearch {
|
||||
/** @var IContainer */
|
||||
private $c;
|
||||
|
||||
protected $pluginList = [];
|
||||
|
||||
public function __construct(IContainer $c) {
|
||||
$this->c = $c;
|
||||
}
|
||||
|
||||
public function search($search, array $shareTypes, $lookup, $limit, $offset) {
|
||||
$hasMoreResults = false;
|
||||
|
||||
/** @var ISearchResult $searchResult */
|
||||
$searchResult = $this->c->resolve(SearchResult::class);
|
||||
|
||||
foreach ($shareTypes as $type) {
|
||||
if(!isset($this->pluginList[$type])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($this->pluginList[$type] as $plugin) {
|
||||
/** @var ISearchPlugin $searchPlugin */
|
||||
$searchPlugin = $this->c->resolve($plugin);
|
||||
$hasMoreResults |= $searchPlugin->search($search, $limit, $offset, $searchResult);
|
||||
}
|
||||
}
|
||||
|
||||
// Get from lookup server, not a separate share type
|
||||
if ($lookup) {
|
||||
$searchPlugin = $this->c->resolve(LookupPlugin::class);
|
||||
$hasMoreResults |= $searchPlugin->search($search, $limit, $offset, $searchResult);
|
||||
}
|
||||
|
||||
// sanitizing, could go into the plugins as well
|
||||
|
||||
// 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
|
||||
$emailType = new SearchResultType('emails');
|
||||
$remoteType = new SearchResultType('remotes');
|
||||
if($searchResult->hasExactIdMatch($emailType) && !$searchResult->hasExactIdMatch($remoteType)) {
|
||||
$searchResult->unsetResult($remoteType);
|
||||
} elseif (!$searchResult->hasExactIdMatch($emailType) && $searchResult->hasExactIdMatch($remoteType)) {
|
||||
$searchResult->unsetResult($emailType);
|
||||
}
|
||||
|
||||
return [$searchResult->asArray(), (bool)$hasMoreResults];
|
||||
}
|
||||
|
||||
public function registerPlugin(array $pluginInfo) {
|
||||
$shareType = constant(Share::class . '::' . $pluginInfo['shareType']);
|
||||
if($shareType === null) {
|
||||
throw new \InvalidArgumentException('Provided ShareType is invalid');
|
||||
}
|
||||
$this->pluginList[$shareType][] = $pluginInfo['class'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OC\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
|
||||
class SearchResult implements ISearchResult {
|
||||
|
||||
protected $result = [
|
||||
'exact' => [],
|
||||
];
|
||||
|
||||
protected $exactIdMatches = [];
|
||||
|
||||
public function addResultSet(SearchResultType $type, array $matches, array $exactMatches = null) {
|
||||
$type = $type->getLabel();
|
||||
if(!isset($this->result[$type])) {
|
||||
$this->result[$type] = [];
|
||||
$this->result['exact'][$type] = [];
|
||||
}
|
||||
|
||||
$this->result[$type] = array_merge($this->result[$type], $matches);
|
||||
if(is_array($exactMatches)) {
|
||||
$this->result['exact'][$type] = array_merge($this->result['exact'][$type], $exactMatches);
|
||||
}
|
||||
}
|
||||
|
||||
public function markExactIdMatch(SearchResultType $type) {
|
||||
$this->exactIdMatches[$type->getLabel()] = 1;
|
||||
}
|
||||
|
||||
public function hasExactIdMatch(SearchResultType$type) {
|
||||
return isset($this->exactIdMatches[$type->getLabel()]);
|
||||
}
|
||||
|
||||
public function hasResult(SearchResultType $type, $collaboratorId) {
|
||||
$type = $type->getLabel();
|
||||
if(!isset($this->result[$type])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$resultArrays = [$this->result['exact'][$type], $this->result[$type]];
|
||||
foreach($resultArrays as $resultArray) {
|
||||
if ($resultArray['value']['shareWith'] === $collaboratorId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function asArray() {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public function unsetResult(SearchResultType $type) {
|
||||
$type = $type->getLabel();
|
||||
$this->result[$type] = [];
|
||||
if(isset($this->result['exact'][$type])) {
|
||||
$this->result['exact'][$type] = [];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OC\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Share;
|
||||
|
||||
class UserPlugin implements ISearchPlugin {
|
||||
/* @var bool */
|
||||
protected $shareWithGroupOnly;
|
||||
protected $shareeEnumeration;
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var IGroupManager */
|
||||
private $groupManager;
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
|
||||
public function __construct(IConfig $config, IUserManager $userManager, IGroupManager $groupManager, IUserSession $userSession) {
|
||||
$this->config = $config;
|
||||
|
||||
$this->groupManager = $groupManager;
|
||||
$this->userSession = $userSession;
|
||||
$this->userManager = $userManager;
|
||||
|
||||
$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';
|
||||
}
|
||||
|
||||
public function search($search, $limit, $offset, ISearchResult $searchResult) {
|
||||
$result = ['wide' => [], 'exact' => []];
|
||||
$users = [];
|
||||
$hasMoreResults = false;
|
||||
|
||||
$userGroups = [];
|
||||
if ($this->shareWithGroupOnly) {
|
||||
// Search in all the groups this user is part of
|
||||
$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
|
||||
foreach ($userGroups as $userGroup) {
|
||||
$usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $limit, $offset);
|
||||
foreach ($usersTmp as $uid => $userDisplayName) {
|
||||
$users[$uid] = $userDisplayName;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Search in all users
|
||||
$usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
|
||||
|
||||
foreach ($usersTmp as $user) {
|
||||
$users[$user->getUID()] = $user->getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration || sizeof($users) < $limit) {
|
||||
$hasMoreResults = true;
|
||||
}
|
||||
|
||||
$foundUserById = false;
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($users as $uid => $userDisplayName) {
|
||||
if (strtolower($uid) === $lowerSearch || strtolower($userDisplayName) === $lowerSearch) {
|
||||
if (strtolower($uid) === $lowerSearch) {
|
||||
$foundUserById = true;
|
||||
}
|
||||
$result['exact'][] = [
|
||||
'label' => $userDisplayName,
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $uid,
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$result['wide'][] = [
|
||||
'label' => $userDisplayName,
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $uid,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($offset === 0 && !$foundUserById) {
|
||||
// On page one we try if the search result has a direct hit on the
|
||||
// user id and if so, we add that to the exact match list
|
||||
$user = $this->userManager->get($search);
|
||||
if ($user instanceof IUser) {
|
||||
$addUser = true;
|
||||
|
||||
if ($this->shareWithGroupOnly) {
|
||||
// Only add, if we have a common group
|
||||
$commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
|
||||
$addUser = !empty($commonGroups);
|
||||
}
|
||||
|
||||
if ($addUser) {
|
||||
array_push($result['exact'], [
|
||||
'label' => $user->getDisplayName(),
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_USER,
|
||||
'shareWith' => $user->getUID(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->shareeEnumeration) {
|
||||
$result['wide'] = [];
|
||||
}
|
||||
|
||||
$type = new SearchResultType('users');
|
||||
$searchResult->addResultSet($type, $result['wide'], $result['exact']);
|
||||
|
||||
return $hasMoreResults;
|
||||
}
|
||||
}
|
|
@ -52,6 +52,10 @@ use OC\AppFramework\Http\Request;
|
|||
use OC\AppFramework\Utility\SimpleContainer;
|
||||
use OC\AppFramework\Utility\TimeFactory;
|
||||
use OC\Authentication\LoginCredentials\Store;
|
||||
use OC\Collaboration\Collaborators\GroupPlugin;
|
||||
use OC\Collaboration\Collaborators\MailPlugin;
|
||||
use OC\Collaboration\Collaborators\RemotePlugin;
|
||||
use OC\Collaboration\Collaborators\UserPlugin;
|
||||
use OC\Command\CronBus;
|
||||
use OC\Contacts\ContactsMenu\ActionFactory;
|
||||
use OC\Diagnostics\EventLogger;
|
||||
|
@ -115,6 +119,7 @@ use OCP\Contacts\ContactsMenu\IActionFactory;
|
|||
use OCP\Lock\ILockingProvider;
|
||||
use OCP\RichObjectStrings\IValidator;
|
||||
use OCP\Security\IContentSecurityPolicyManager;
|
||||
use OCP\Share;
|
||||
use OCP\Share\IShareHelper;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
@ -993,6 +998,19 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
});
|
||||
$this->registerAlias('ShareManager', \OCP\Share\IManager::class);
|
||||
|
||||
$this->registerService(\OCP\Collaboration\Collaborators\ISearch::class, function(Server $c) {
|
||||
$instance = new Collaboration\Collaborators\Search($c);
|
||||
|
||||
// register default plugins
|
||||
$instance->registerPlugin(['shareType' => 'SHARE_TYPE_USER', 'class' => UserPlugin::class]);
|
||||
$instance->registerPlugin(['shareType' => 'SHARE_TYPE_GROUP', 'class' => GroupPlugin::class]);
|
||||
$instance->registerPlugin(['shareType' => 'SHARE_TYPE_EMAIL', 'class' => MailPlugin::class]);
|
||||
$instance->registerPlugin(['shareType' => 'SHARE_TYPE_REMOTE', 'class' => RemotePlugin::class]);
|
||||
|
||||
return $instance;
|
||||
});
|
||||
$this->registerAlias('CollaboratorSearch', \OCP\Collaboration\Collaborators\ISearch::class);
|
||||
|
||||
$this->registerService('SettingsManager', function (Server $c) {
|
||||
$manager = new \OC\Settings\Manager(
|
||||
$c->getLogger(),
|
||||
|
@ -1776,6 +1794,13 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
return $this->query('ShareManager');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \OCP\Collaboration\Collaborators\ISearch
|
||||
*/
|
||||
public function getCollaboratorSearch() {
|
||||
return $this->query('CollaboratorSearch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP Provider
|
||||
*
|
||||
|
|
|
@ -174,6 +174,20 @@ class OC_App {
|
|||
\OC::$server->getActivityManager()->registerProvider($provider);
|
||||
}
|
||||
}
|
||||
if (!empty($info['collaboration']['plugins'])) {
|
||||
// deal with one or many plugin entries
|
||||
$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
|
||||
[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
|
||||
foreach ($plugins as $plugin) {
|
||||
if($plugin['@attributes']['type'] === 'collaborator-search') {
|
||||
$pluginInfo = [
|
||||
'shareType' => $plugin['@attributes']['share-type'],
|
||||
'class' => $plugin['@value'],
|
||||
];
|
||||
\OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OCP\Collaboration\Collaborators;
|
||||
|
||||
/**
|
||||
* Interface ISearch
|
||||
*
|
||||
* @package OCP\Collaboration\Collaborators
|
||||
* @since 13.0.0
|
||||
*/
|
||||
interface ISearch {
|
||||
/**
|
||||
* @param string $search
|
||||
* @param array $shareTypes
|
||||
* @param bool $lookup
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return array with two elements, 1st ISearchResult as array, 2nd a bool indicating whether more result are available
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function search($search, array $shareTypes, $lookup, $limit, $offset);
|
||||
|
||||
/**
|
||||
* @param array $pluginInfo with keys 'shareType' containing the name of a corresponding constant in \OCP\Share and
|
||||
* 'class' with the class name of the plugin
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function registerPlugin(array $pluginInfo);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OCP\Collaboration\Collaborators;
|
||||
|
||||
/**
|
||||
* Interface ISearchPlugin
|
||||
*
|
||||
* @package OCP\Collaboration\Collaborators
|
||||
* @since 13.0.0
|
||||
*/
|
||||
interface ISearchPlugin {
|
||||
/**
|
||||
* @param string $search
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @param ISearchResult $searchResult
|
||||
* @return bool whether the plugin has more results
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function search($search, $limit, $offset, ISearchResult $searchResult);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OCP\Collaboration\Collaborators;
|
||||
|
||||
/**
|
||||
* Interface ISearchResult
|
||||
*
|
||||
* @package OCP\Collaboration\Collaborators
|
||||
* @since 13.0.0
|
||||
*/
|
||||
interface ISearchResult {
|
||||
/**
|
||||
* @param SearchResultType $type
|
||||
* @param array $matches
|
||||
* @param array|null $exactMatches
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function addResultSet(SearchResultType $type, array $matches, array $exactMatches = null);
|
||||
|
||||
/**
|
||||
* @param SearchResultType $type
|
||||
* @param string $collaboratorId
|
||||
* @return bool
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function hasResult(SearchResultType $type, $collaboratorId);
|
||||
|
||||
/**
|
||||
* @param SearchResultType $type
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function unsetResult(SearchResultType $type);
|
||||
|
||||
/**
|
||||
* @param SearchResultType $type
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function markExactIdMatch(SearchResultType $type);
|
||||
|
||||
/**
|
||||
* @param SearchResultType $type
|
||||
* @return bool
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function hasExactIdMatch(SearchResultType $type);
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function asArray();
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 OCP\Collaboration\Collaborators;
|
||||
|
||||
/**
|
||||
* Class SearchResultType
|
||||
*
|
||||
* @package OCP\Collaboration\Collaborators
|
||||
* @since 13.0.0
|
||||
*/
|
||||
class SearchResultType {
|
||||
/** @var string */
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* SearchResultType constructor.
|
||||
*
|
||||
* @param string $label
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function __construct($label) {
|
||||
$this->label = $this->getValidatedType($label);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 13.0.0
|
||||
*/
|
||||
public function getLabel() {
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
* @since 13.0.0
|
||||
*/
|
||||
protected function getValidatedType($type) {
|
||||
$type = trim(strval($type));
|
||||
|
||||
if($type === '') {
|
||||
throw new \InvalidArgumentException('Type must not be empty');
|
||||
}
|
||||
|
||||
if($type === 'exact') {
|
||||
throw new \InvalidArgumentException('Provided type is a reserved word');
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,491 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 Test\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OC\Collaboration\Collaborators\GroupPlugin;
|
||||
use OC\Collaboration\Collaborators\SearchResult;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\IConfig;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Share;
|
||||
use Test\TestCase;
|
||||
|
||||
class GroupPluginTest extends TestCase {
|
||||
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $config;
|
||||
|
||||
/** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $groupManager;
|
||||
|
||||
/** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $session;
|
||||
|
||||
/** @var ISearchResult */
|
||||
protected $searchResult;
|
||||
|
||||
/** @var GroupPlugin */
|
||||
protected $plugin;
|
||||
|
||||
/** @var int */
|
||||
protected $limit = 2;
|
||||
|
||||
/** @var int */
|
||||
protected $offset = 0;
|
||||
|
||||
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $user;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
|
||||
$this->groupManager = $this->createMock(IGroupManager::class);
|
||||
|
||||
$this->session = $this->createMock(IUserSession::class);
|
||||
|
||||
$this->searchResult = new SearchResult();
|
||||
|
||||
$this->user = $this->getUserMock('admin', 'Administrator');
|
||||
}
|
||||
|
||||
public function instantiatePlugin() {
|
||||
// cannot be done within setUp, because dependent mocks needs to be set
|
||||
// up with configuration etc. first
|
||||
$this->plugin = new GroupPlugin(
|
||||
$this->config,
|
||||
$this->groupManager,
|
||||
$this->session
|
||||
);
|
||||
}
|
||||
|
||||
public function getUserMock($uid, $displayName) {
|
||||
$user = $this->createMock(IUser::class);
|
||||
|
||||
$user->expects($this->any())
|
||||
->method('getUID')
|
||||
->willReturn($uid);
|
||||
|
||||
$user->expects($this->any())
|
||||
->method('getDisplayName')
|
||||
->willReturn($displayName);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $gid
|
||||
* @param null $displayName
|
||||
* @return IGroup|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected function getGroupMock($gid, $displayName = null) {
|
||||
$group = $this->createMock(IGroup::class);
|
||||
|
||||
$group->expects($this->any())
|
||||
->method('getGID')
|
||||
->willReturn($gid);
|
||||
|
||||
if (is_null($displayName)) {
|
||||
// note: this is how the Group class behaves
|
||||
$displayName = $gid;
|
||||
}
|
||||
|
||||
$group->expects($this->any())
|
||||
->method('getDisplayName')
|
||||
->willReturn($displayName);
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
public function dataGetGroups() {
|
||||
return [
|
||||
['test', false, true, [], [], [], [], true, false],
|
||||
['test', false, false, [], [], [], [], true, false],
|
||||
// group without display name
|
||||
[
|
||||
'test', false, true,
|
||||
[$this->getGroupMock('test1')],
|
||||
[],
|
||||
[],
|
||||
[['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
// group with display name, search by id
|
||||
[
|
||||
'test', false, true,
|
||||
[$this->getGroupMock('test1', 'Test One')],
|
||||
[],
|
||||
[],
|
||||
[['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
// group with display name, search by display name
|
||||
[
|
||||
'one', false, true,
|
||||
[$this->getGroupMock('test1', 'Test One')],
|
||||
[],
|
||||
[],
|
||||
[['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
// group with display name, search by display name, exact expected
|
||||
[
|
||||
'Test One', false, true,
|
||||
[$this->getGroupMock('test1', 'Test One')],
|
||||
[],
|
||||
[['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', false, false,
|
||||
[$this->getGroupMock('test1')],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', false, true,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[],
|
||||
[['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
|
||||
[['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', false, false,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[],
|
||||
[['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', false, true,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']],
|
||||
['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']],
|
||||
],
|
||||
false,
|
||||
null,
|
||||
],
|
||||
[
|
||||
'test', false, false,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
null,
|
||||
],
|
||||
[
|
||||
'test', false, true,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[],
|
||||
[
|
||||
['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']],
|
||||
],
|
||||
[
|
||||
['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']],
|
||||
['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']],
|
||||
],
|
||||
false,
|
||||
$this->getGroupMock('test'),
|
||||
],
|
||||
[
|
||||
'test', false, false,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[],
|
||||
[
|
||||
['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']],
|
||||
],
|
||||
[],
|
||||
true,
|
||||
$this->getGroupMock('test'),
|
||||
],
|
||||
['test', true, true, [], [], [], [], true, false],
|
||||
['test', true, false, [], [], [], [], true, false],
|
||||
[
|
||||
'test', true, true,
|
||||
[
|
||||
$this->getGroupMock('test1'),
|
||||
$this->getGroupMock('test2'),
|
||||
],
|
||||
[$this->getGroupMock('test1')],
|
||||
[],
|
||||
[['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, false,
|
||||
[
|
||||
$this->getGroupMock('test1'),
|
||||
$this->getGroupMock('test2'),
|
||||
],
|
||||
[$this->getGroupMock('test1')],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, true,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test')],
|
||||
[['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, false,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test')],
|
||||
[['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, true,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test1')],
|
||||
[],
|
||||
[['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, false,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test1')],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, true,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
|
||||
[['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
|
||||
[['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']]],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, false,
|
||||
[
|
||||
$this->getGroupMock('test'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
|
||||
[['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']]],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test', true, true,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
|
||||
[],
|
||||
[
|
||||
['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']],
|
||||
['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']],
|
||||
],
|
||||
false,
|
||||
null,
|
||||
],
|
||||
[
|
||||
'test', true, false,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
null,
|
||||
],
|
||||
[
|
||||
'test', true, true,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
|
||||
[
|
||||
['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']],
|
||||
],
|
||||
[
|
||||
['label' => 'test0', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test0']],
|
||||
['label' => 'test1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test1']],
|
||||
],
|
||||
false,
|
||||
$this->getGroupMock('test'),
|
||||
],
|
||||
[
|
||||
'test', true, false,
|
||||
[
|
||||
$this->getGroupMock('test0'),
|
||||
$this->getGroupMock('test1'),
|
||||
],
|
||||
[$this->getGroupMock('test'), $this->getGroupMock('test0'), $this->getGroupMock('test1')],
|
||||
[
|
||||
['label' => 'test', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'test']],
|
||||
],
|
||||
[],
|
||||
true,
|
||||
$this->getGroupMock('test'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataGetGroups
|
||||
*
|
||||
* @param string $searchTerm
|
||||
* @param bool $shareWithGroupOnly
|
||||
* @param bool $shareeEnumeration
|
||||
* @param array $groupResponse
|
||||
* @param array $userGroupsResponse
|
||||
* @param array $exactExpected
|
||||
* @param array $expected
|
||||
* @param bool $reachedEnd
|
||||
* @param bool|IGroup $singleGroup
|
||||
*/
|
||||
public function testSearch(
|
||||
$searchTerm,
|
||||
$shareWithGroupOnly,
|
||||
$shareeEnumeration,
|
||||
array $groupResponse,
|
||||
array $userGroupsResponse,
|
||||
array $exactExpected,
|
||||
array $expected,
|
||||
$reachedEnd,
|
||||
$singleGroup
|
||||
) {
|
||||
$this->config->expects($this->any())
|
||||
->method('getAppValue')
|
||||
->willReturnCallback(
|
||||
function($appName, $key, $default)
|
||||
use ($shareWithGroupOnly, $shareeEnumeration)
|
||||
{
|
||||
if ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
|
||||
return $shareWithGroupOnly ? 'yes' : 'no';
|
||||
} else if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
|
||||
return $shareeEnumeration ? 'yes' : 'no';
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
);
|
||||
|
||||
$this->instantiatePlugin();
|
||||
|
||||
$this->groupManager->expects($this->once())
|
||||
->method('search')
|
||||
->with($searchTerm, $this->limit, $this->offset)
|
||||
->willReturn($groupResponse);
|
||||
|
||||
if ($singleGroup !== false) {
|
||||
$this->groupManager->expects($this->once())
|
||||
->method('get')
|
||||
->with($searchTerm)
|
||||
->willReturn($singleGroup);
|
||||
}
|
||||
|
||||
if ($shareWithGroupOnly) {
|
||||
$this->session->expects($this->any())
|
||||
->method('getUser')
|
||||
->willReturn($this->user);
|
||||
|
||||
$numGetUserGroupsCalls = empty($groupResponse) ? 0 : 1;
|
||||
$this->groupManager->expects($this->exactly($numGetUserGroupsCalls))
|
||||
->method('getUserGroups')
|
||||
->with($this->user)
|
||||
->willReturn($userGroupsResponse);
|
||||
}
|
||||
|
||||
$moreResults = $this->plugin->search($searchTerm, $this->limit, $this->offset, $this->searchResult);
|
||||
$result = $this->searchResult->asArray();
|
||||
|
||||
$this->assertEquals($exactExpected, $result['exact']['groups']);
|
||||
$this->assertEquals($expected, $result['groups']);
|
||||
$this->assertSame($reachedEnd, $moreResults);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 Test\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OC\Collaboration\Collaborators\LookupPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\Http\Client\IResponse;
|
||||
use OCP\IConfig;
|
||||
use OCP\Share;
|
||||
use Test\TestCase;
|
||||
|
||||
class LookupPluginTest extends TestCase {
|
||||
|
||||
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $config;
|
||||
/** @var IClientService|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $clientService;
|
||||
/** @var LookupPlugin */
|
||||
protected $plugin;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->clientService = $this->createMock(IClientService::class);
|
||||
|
||||
$this->plugin = new LookupPlugin($this->config, $this->clientService);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider searchDataProvider
|
||||
* @param array $searchParams
|
||||
*/
|
||||
public function testSearch(array $searchParams) {
|
||||
$type = new SearchResultType('lookup');
|
||||
|
||||
/** @var ISearchResult|\PHPUnit_Framework_MockObject_MockObject $searchResult */
|
||||
$searchResult = $this->createMock(ISearchResult::class);
|
||||
$searchResult->expects($this->once())
|
||||
->method('addResultSet')
|
||||
->with($type, $searchParams['expectedResult'], []);
|
||||
|
||||
$this->config->expects($this->once())
|
||||
->method('getAppValue')
|
||||
->with('files_sharing', 'lookupServerEnabled', 'no')
|
||||
->willReturn('yes');
|
||||
$this->config->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with('lookup_server', 'https://lookup.nextcloud.com')
|
||||
->willReturn($searchParams['server']);
|
||||
|
||||
$response = $this->createMock(IResponse::class);
|
||||
$response->expects($this->once())
|
||||
->method('getBody')
|
||||
->willReturn(json_encode($searchParams['resultBody']));
|
||||
|
||||
$client = $this->createMock(IClient::class);
|
||||
$client->expects($this->once())
|
||||
->method('get')
|
||||
->willReturnCallback(function($url) use ($searchParams, $response) {
|
||||
$this->assertSame(strpos($url, $searchParams['server'] . '/users?search='), 0);
|
||||
$this->assertNotFalse(strpos($url, urlencode($searchParams['search'])));
|
||||
return $response;
|
||||
});
|
||||
|
||||
$this->clientService->expects($this->once())
|
||||
->method('newClient')
|
||||
->willReturn($client);
|
||||
|
||||
$moreResults = $this->plugin->search(
|
||||
$searchParams['search'],
|
||||
$searchParams['limit'],
|
||||
$searchParams['offset'],
|
||||
$searchResult
|
||||
);
|
||||
|
||||
|
||||
|
||||
$this->assertFalse($moreResults);
|
||||
}
|
||||
|
||||
public function testSearchLookupServerDisabled() {
|
||||
$this->config->expects($this->once())
|
||||
->method('getAppValue')
|
||||
->with('files_sharing', 'lookupServerEnabled', 'no')
|
||||
->willReturn('no');
|
||||
|
||||
/** @var ISearchResult|\PHPUnit_Framework_MockObject_MockObject $searchResult */
|
||||
$searchResult = $this->createMock(ISearchResult::class);
|
||||
$searchResult->expects($this->never())
|
||||
->method('addResultSet');
|
||||
$searchResult->expects($this->never())
|
||||
->method('markExactIdMatch');
|
||||
|
||||
$this->assertFalse($this->plugin->search('irr', 10, 0, $searchResult));
|
||||
}
|
||||
|
||||
public function searchDataProvider() {
|
||||
$fedIDs = [
|
||||
'foo@enceladus.moon',
|
||||
'foobar@enceladus.moon',
|
||||
'foongus@enceladus.moon',
|
||||
];
|
||||
|
||||
return [
|
||||
// #0, standard search with results
|
||||
[[
|
||||
'search' => 'foo',
|
||||
'limit' => 10,
|
||||
'offset' => 0,
|
||||
'server' => 'https://lookup.example.io',
|
||||
'resultBody' => [
|
||||
[ 'federationId' => $fedIDs[0] ],
|
||||
[ 'federationId' => $fedIDs[1] ],
|
||||
[ 'federationId' => $fedIDs[2] ],
|
||||
],
|
||||
'expectedResult' => [
|
||||
[
|
||||
'label' => $fedIDs[0],
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $fedIDs[0]
|
||||
],
|
||||
'extra' => ['federationId' => $fedIDs[0]],
|
||||
],
|
||||
[
|
||||
'label' => $fedIDs[1],
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $fedIDs[1]
|
||||
],
|
||||
'extra' => ['federationId' => $fedIDs[1]],
|
||||
],
|
||||
[
|
||||
'label' => $fedIDs[2],
|
||||
'value' => [
|
||||
'shareType' => Share::SHARE_TYPE_REMOTE,
|
||||
'shareWith' => $fedIDs[2]
|
||||
],
|
||||
'extra' => ['federationId' => $fedIDs[2]],
|
||||
],
|
||||
]
|
||||
]],
|
||||
// #1, search without results
|
||||
[[
|
||||
'search' => 'foo',
|
||||
'limit' => 10,
|
||||
'offset' => 0,
|
||||
'server' => 'https://lookup.example.io',
|
||||
'resultBody' => [],
|
||||
'expectedResult' => [],
|
||||
]],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,336 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 Test\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OC\Collaboration\Collaborators\MailPlugin;
|
||||
use OC\Collaboration\Collaborators\SearchResult;
|
||||
use OC\Federation\CloudIdManager;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\Contacts\IManager;
|
||||
use OCP\Federation\ICloudIdManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\Share;
|
||||
use Test\TestCase;
|
||||
|
||||
class MailPluginTest extends TestCase {
|
||||
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $config;
|
||||
|
||||
/** @var IManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $contactsManager;
|
||||
|
||||
/** @var ICloudIdManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $cloudIdManager;
|
||||
|
||||
/** @var MailPlugin */
|
||||
protected $plugin;
|
||||
|
||||
/** @var SearchResult */
|
||||
protected $searchResult;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->contactsManager = $this->createMock(IManager::class);
|
||||
$this->cloudIdManager = new CloudIdManager();
|
||||
$this->searchResult = new SearchResult();
|
||||
}
|
||||
|
||||
public function instantiatePlugin() {
|
||||
$this->plugin = new MailPlugin($this->contactsManager, $this->cloudIdManager, $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataGetEmail
|
||||
*
|
||||
* @param string $searchTerm
|
||||
* @param array $contacts
|
||||
* @param bool $shareeEnumeration
|
||||
* @param array $expected
|
||||
* @param bool $reachedEnd
|
||||
*/
|
||||
public function testSearch($searchTerm, $contacts, $shareeEnumeration, $expected, $exactIdMatch, $reachedEnd) {
|
||||
$this->config->expects($this->any())
|
||||
->method('getAppValue')
|
||||
->willReturnCallback(
|
||||
function($appName, $key, $default)
|
||||
use ($shareeEnumeration)
|
||||
{
|
||||
if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
|
||||
return $shareeEnumeration ? 'yes' : 'no';
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
);
|
||||
|
||||
$this->instantiatePlugin();
|
||||
|
||||
$this->contactsManager->expects($this->any())
|
||||
->method('search')
|
||||
->with($searchTerm, ['EMAIL', 'FN'])
|
||||
->willReturn($contacts);
|
||||
|
||||
$moreResults = $this->plugin->search($searchTerm, 0, 0, $this->searchResult);
|
||||
$result = $this->searchResult->asArray();
|
||||
|
||||
$this->assertSame($exactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
|
||||
$this->assertEquals($expected, $result);
|
||||
$this->assertSame($reachedEnd, $moreResults);
|
||||
}
|
||||
|
||||
public function dataGetEmail() {
|
||||
return [
|
||||
['test', [], true, ['emails' => [], 'exact' => ['emails' => []]], false, true],
|
||||
['test', [], false, ['emails' => [], 'exact' => ['emails' => []]], false, true],
|
||||
[
|
||||
'test@remote.com',
|
||||
[],
|
||||
true,
|
||||
['emails' => [], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[ // no valid email address
|
||||
'test@remote',
|
||||
[],
|
||||
true,
|
||||
['emails' => [], 'exact' => ['emails' => []]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test@remote.com',
|
||||
[],
|
||||
false,
|
||||
['emails' => [], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'EMAIL' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
true,
|
||||
['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => ['emails' => []]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'EMAIL' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['emails' => [], 'exact' => ['emails' => []]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test@remote.com',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'EMAIL' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
true,
|
||||
['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test@remote.com',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'EMAIL' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['emails' => [], 'exact' => ['emails' => [['label' => 'test@remote.com', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'test@remote.com']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'username@localhost',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'EMAIL' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
true,
|
||||
['emails' => [], 'exact' => ['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]]]],
|
||||
true,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'username@localhost',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'EMAIL' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['emails' => [], 'exact' => ['emails' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'username@localhost']]]]],
|
||||
true,
|
||||
true,
|
||||
],
|
||||
// contact with space
|
||||
[
|
||||
'user name@localhost',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User Name @ Localhost',
|
||||
'EMAIL' => [
|
||||
'user name@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['emails' => [], 'exact' => ['emails' => [['label' => 'User Name @ Localhost (user name@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => 'user name@localhost']]]]],
|
||||
true,
|
||||
true,
|
||||
],
|
||||
// remote with space, no contact
|
||||
[
|
||||
'user space@remote.com',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'EMAIL' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'EMAIL' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['emails' => [], 'exact' => ['emails' => []]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
// Local user found by email
|
||||
[
|
||||
'test@example.com',
|
||||
[
|
||||
[
|
||||
'FN' => 'User',
|
||||
'EMAIL' => ['test@example.com'],
|
||||
'CLOUD' => ['test@localhost'],
|
||||
'isLocalSystemBook' => true,
|
||||
]
|
||||
],
|
||||
false,
|
||||
['users' => [], 'exact' => ['users' => [['label' => 'User (test@example.com)','value' => ['shareType' => 0, 'shareWith' => 'test'],]]]],
|
||||
true,
|
||||
false,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,388 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 Test\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OC\Collaboration\Collaborators\RemotePlugin;
|
||||
use OC\Collaboration\Collaborators\SearchResult;
|
||||
use OC\Federation\CloudIdManager;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\Contacts\IManager;
|
||||
use OCP\Federation\ICloudIdManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\Share;
|
||||
use Test\TestCase;
|
||||
|
||||
class RemotePluginTest extends TestCase {
|
||||
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $config;
|
||||
|
||||
/** @var IManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $contactsManager;
|
||||
|
||||
/** @var ICloudIdManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $cloudIdManager;
|
||||
|
||||
/** @var RemotePlugin */
|
||||
protected $plugin;
|
||||
|
||||
/** @var SearchResult */
|
||||
protected $searchResult;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->contactsManager = $this->createMock(IManager::class);
|
||||
$this->cloudIdManager = new CloudIdManager();
|
||||
$this->searchResult = new SearchResult();
|
||||
}
|
||||
|
||||
public function instantiatePlugin() {
|
||||
$this->plugin = new RemotePlugin($this->contactsManager, $this->cloudIdManager, $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataGetRemote
|
||||
*
|
||||
* @param string $searchTerm
|
||||
* @param array $contacts
|
||||
* @param bool $shareeEnumeration
|
||||
* @param array $expected
|
||||
* @param bool $exactIdMatch
|
||||
* @param bool $reachedEnd
|
||||
*/
|
||||
public function testSearch($searchTerm, array $contacts, $shareeEnumeration, array $expected, $exactIdMatch, $reachedEnd) {
|
||||
$this->config->expects($this->any())
|
||||
->method('getAppValue')
|
||||
->willReturnCallback(
|
||||
function($appName, $key, $default)
|
||||
use ($shareeEnumeration)
|
||||
{
|
||||
if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
|
||||
return $shareeEnumeration ? 'yes' : 'no';
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
);
|
||||
|
||||
$this->instantiatePlugin();
|
||||
|
||||
$this->contactsManager->expects($this->any())
|
||||
->method('search')
|
||||
->with($searchTerm, ['CLOUD', 'FN'])
|
||||
->willReturn($contacts);
|
||||
|
||||
$moreResults = $this->plugin->search($searchTerm, 0, 0, $this->searchResult);
|
||||
$result = $this->searchResult->asArray();
|
||||
|
||||
$this->assertSame($exactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('remotes')));
|
||||
$this->assertEquals($expected, $result);
|
||||
$this->assertSame($reachedEnd, $moreResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestSplitUserRemote
|
||||
*
|
||||
* @param string $remote
|
||||
* @param string $expectedUser
|
||||
* @param string $expectedUrl
|
||||
*/
|
||||
public function testSplitUserRemote($remote, $expectedUser, $expectedUrl) {
|
||||
$this->instantiatePlugin();
|
||||
|
||||
list($remoteUser, $remoteUrl) = $this->plugin->splitUserRemote($remote);
|
||||
$this->assertSame($expectedUser, $remoteUser);
|
||||
$this->assertSame($expectedUrl, $remoteUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestSplitUserRemoteError
|
||||
*
|
||||
* @param string $id
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testSplitUserRemoteError($id) {
|
||||
$this->instantiatePlugin();
|
||||
$this->plugin->splitUserRemote($id);
|
||||
}
|
||||
|
||||
public function dataGetRemote() {
|
||||
return [
|
||||
['test', [], true, ['remotes' => [], 'exact' => ['remotes' => []]], false, true],
|
||||
['test', [], false, ['remotes' => [], 'exact' => ['remotes' => []]], false, true],
|
||||
[
|
||||
'test@remote',
|
||||
[],
|
||||
true,
|
||||
['remotes' => [], 'exact' => ['remotes' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test@remote',
|
||||
[],
|
||||
false,
|
||||
['remotes' => [], 'exact' => ['remotes' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'CLOUD' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
true,
|
||||
['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => []]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'CLOUD' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['remotes' => [], 'exact' => ['remotes' => []]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test@remote',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'CLOUD' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
true,
|
||||
['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]], 'exact' => ['remotes' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'test@remote',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'CLOUD' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['remotes' => [], 'exact' => ['remotes' => [['label' => 'test@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'test@remote']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'username@localhost',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'CLOUD' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
true,
|
||||
['remotes' => [], 'exact' => ['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]],
|
||||
true,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'username@localhost',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'CLOUD' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['remotes' => [], 'exact' => ['remotes' => [['label' => 'User @ Localhost (username@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'username@localhost', 'server' => 'localhost']]]]],
|
||||
true,
|
||||
true,
|
||||
],
|
||||
// contact with space
|
||||
[
|
||||
'user name@localhost',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User Name @ Localhost',
|
||||
'CLOUD' => [
|
||||
'user name@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['remotes' => [], 'exact' => ['remotes' => [['label' => 'User Name @ Localhost (user name@localhost)', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user name@localhost', 'server' => 'localhost']]]]],
|
||||
true,
|
||||
true,
|
||||
],
|
||||
// remote with space, no contact
|
||||
[
|
||||
'user space@remote',
|
||||
[
|
||||
[
|
||||
'FN' => 'User3 @ Localhost',
|
||||
],
|
||||
[
|
||||
'FN' => 'User2 @ Localhost',
|
||||
'CLOUD' => [
|
||||
],
|
||||
],
|
||||
[
|
||||
'FN' => 'User @ Localhost',
|
||||
'CLOUD' => [
|
||||
'username@localhost',
|
||||
],
|
||||
],
|
||||
],
|
||||
false,
|
||||
['remotes' => [], 'exact' => ['remotes' => [['label' => 'user space@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'user space@remote']]]]],
|
||||
false,
|
||||
true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function dataTestSplitUserRemote() {
|
||||
$userPrefix = ['user@name', 'username'];
|
||||
$protocols = ['', 'http://', 'https://'];
|
||||
$remotes = [
|
||||
'localhost',
|
||||
'local.host',
|
||||
'dev.local.host',
|
||||
'dev.local.host/path',
|
||||
'dev.local.host/at@inpath',
|
||||
'127.0.0.1',
|
||||
'::1',
|
||||
'::192.0.2.128',
|
||||
'::192.0.2.128/at@inpath',
|
||||
];
|
||||
|
||||
$testCases = [];
|
||||
foreach ($userPrefix as $user) {
|
||||
foreach ($remotes as $remote) {
|
||||
foreach ($protocols as $protocol) {
|
||||
$baseUrl = $user . '@' . $protocol . $remote;
|
||||
|
||||
$testCases[] = [$baseUrl, $user, $protocol . $remote];
|
||||
$testCases[] = [$baseUrl . '/', $user, $protocol . $remote];
|
||||
$testCases[] = [$baseUrl . '/index.php', $user, $protocol . $remote];
|
||||
$testCases[] = [$baseUrl . '/index.php/s/token', $user, $protocol . $remote];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $testCases;
|
||||
}
|
||||
|
||||
public function dataTestSplitUserRemoteError() {
|
||||
return array(
|
||||
// Invalid path
|
||||
array('user@'),
|
||||
|
||||
// Invalid user
|
||||
array('@server'),
|
||||
array('us/er@server'),
|
||||
array('us:er@server'),
|
||||
|
||||
// Invalid splitting
|
||||
array('user'),
|
||||
array(''),
|
||||
array('us/erserver'),
|
||||
array('us:erserver'),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 Test\Collaboration\Collaborators;
|
||||
|
||||
|
||||
use OC\Collaboration\Collaborators\Search;
|
||||
use OC\Collaboration\Collaborators\SearchResult;
|
||||
use OCP\Collaboration\Collaborators\ISearch;
|
||||
use OCP\Collaboration\Collaborators\ISearchPlugin;
|
||||
use OCP\Collaboration\Collaborators\SearchResultType;
|
||||
use OCP\IContainer;
|
||||
use OCP\Share;
|
||||
use Test\TestCase;
|
||||
|
||||
class SearchTest extends TestCase {
|
||||
/** @var IContainer|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $container;
|
||||
/** @var ISearch */
|
||||
protected $search;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->container = $this->createMock(IContainer::class);
|
||||
|
||||
$this->search = new Search($this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataSearchSharees
|
||||
*
|
||||
* @param string $searchTerm
|
||||
* @param array $shareTypes
|
||||
* @param int $page
|
||||
* @param int $perPage
|
||||
* @param array $mockedUserResult
|
||||
* @param array $mockedGroupsResult
|
||||
* @param array $mockedRemotesResult
|
||||
* @param array $expected
|
||||
* @param bool $expectedMoreResults
|
||||
*/
|
||||
public function testSearch(
|
||||
$searchTerm,
|
||||
array $shareTypes,
|
||||
$page,
|
||||
$perPage,
|
||||
array $mockedUserResult,
|
||||
array $mockedGroupsResult,
|
||||
array $mockedRemotesResult,
|
||||
array $expected,
|
||||
$expectedMoreResults
|
||||
) {
|
||||
$searchResult = new SearchResult();
|
||||
|
||||
$userPlugin = $this->createMock(ISearchPlugin::class);
|
||||
$userPlugin->expects($this->any())
|
||||
->method('search')
|
||||
->willReturnCallback(function() use ($searchResult, $mockedUserResult, $expectedMoreResults) {
|
||||
$type = new SearchResultType('users');
|
||||
$searchResult->addResultSet($type, $mockedUserResult);
|
||||
return $expectedMoreResults;
|
||||
});
|
||||
|
||||
$groupPlugin = $this->createMock(ISearchPlugin::class);
|
||||
$groupPlugin->expects($this->any())
|
||||
->method('search')
|
||||
->willReturnCallback(function() use ($searchResult, $mockedGroupsResult, $expectedMoreResults) {
|
||||
$type = new SearchResultType('groups');
|
||||
$searchResult->addResultSet($type, $mockedGroupsResult);
|
||||
return $expectedMoreResults;
|
||||
});
|
||||
|
||||
$remotePlugin = $this->createMock(ISearchPlugin::class);
|
||||
$remotePlugin->expects($this->any())
|
||||
->method('search')
|
||||
->willReturnCallback(function() use ($searchResult, $mockedRemotesResult, $expectedMoreResults) {
|
||||
if($mockedRemotesResult !== null) {
|
||||
$type = new SearchResultType('remotes');
|
||||
$searchResult->addResultSet($type, $mockedRemotesResult['results'], $mockedRemotesResult['exact']);
|
||||
if($mockedRemotesResult['exactIdMatch'] === true) {
|
||||
$searchResult->markExactIdMatch($type);
|
||||
}
|
||||
}
|
||||
return $expectedMoreResults;
|
||||
});
|
||||
|
||||
$this->container->expects($this->any())
|
||||
->method('resolve')
|
||||
->willReturnCallback(function($class) use ($searchResult, $userPlugin, $groupPlugin, $remotePlugin) {
|
||||
if($class === SearchResult::class) {
|
||||
return $searchResult;
|
||||
} elseif ($class === $userPlugin) {
|
||||
return $userPlugin;
|
||||
} elseif ($class === $groupPlugin) {
|
||||
return $groupPlugin;
|
||||
} elseif ($class === $remotePlugin) {
|
||||
return $remotePlugin;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
$this->search->registerPlugin(['shareType' => 'SHARE_TYPE_USER', 'class' => $userPlugin]);
|
||||
$this->search->registerPlugin(['shareType' => 'SHARE_TYPE_GROUP', 'class' => $groupPlugin]);
|
||||
$this->search->registerPlugin(['shareType' => 'SHARE_TYPE_REMOTE', 'class' => $remotePlugin]);
|
||||
|
||||
list($results, $moreResults) = $this->search->search($searchTerm, $shareTypes, false, $perPage, $perPage * ($page - 1));
|
||||
|
||||
$this->assertEquals($expected, $results);
|
||||
$this->assertSame($expectedMoreResults, $moreResults);
|
||||
}
|
||||
|
||||
public function dataSearchSharees() {
|
||||
return [
|
||||
[
|
||||
'test', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, [], [], ['results' => [], 'exact' => [], 'exactIdMatch' => false],
|
||||
[
|
||||
'exact' => ['users' => [], 'groups' => [], 'remotes' => []],
|
||||
'users' => [],
|
||||
'groups' => [],
|
||||
'remotes' => [],
|
||||
], false
|
||||
],
|
||||
[
|
||||
'test', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, [], [], ['results' => [], 'exact' => [], 'exactIdMatch' => false],
|
||||
[
|
||||
'exact' => ['users' => [], 'groups' => [], 'remotes' => []],
|
||||
'users' => [],
|
||||
'groups' => [],
|
||||
'remotes' => [],
|
||||
], false
|
||||
],
|
||||
[
|
||||
'test', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_GROUP, Share::SHARE_TYPE_REMOTE], 1, 2, [
|
||||
['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
], [
|
||||
['label' => 'testgroup1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'testgroup1']],
|
||||
], [
|
||||
'results' => [['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']]], 'exact' => [], 'exactIdMatch' => false,
|
||||
],
|
||||
[
|
||||
'exact' => ['users' => [], 'groups' => [], 'remotes' => []],
|
||||
'users' => [
|
||||
['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
],
|
||||
'groups' => [
|
||||
['label' => 'testgroup1', 'value' => ['shareType' => Share::SHARE_TYPE_GROUP, 'shareWith' => 'testgroup1']],
|
||||
],
|
||||
'remotes' => [
|
||||
['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']],
|
||||
],
|
||||
], true,
|
||||
],
|
||||
// No groups requested
|
||||
[
|
||||
'test', [Share::SHARE_TYPE_USER, Share::SHARE_TYPE_REMOTE], 1, 2, [
|
||||
['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
], [], [
|
||||
'results' => [['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']]], 'exact' => [], 'exactIdMatch' => false
|
||||
],
|
||||
[
|
||||
'exact' => ['users' => [], 'remotes' => []],
|
||||
'users' => [
|
||||
['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
],
|
||||
'remotes' => [
|
||||
['label' => 'testz@remote', 'value' => ['shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => 'testz@remote']],
|
||||
],
|
||||
], false,
|
||||
],
|
||||
// Share type restricted to user - Only one user
|
||||
[
|
||||
'test', [Share::SHARE_TYPE_USER], 1, 2, [
|
||||
['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
], [], [],
|
||||
[
|
||||
'exact' => ['users' => []],
|
||||
'users' => [
|
||||
['label' => 'test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
],
|
||||
], false,
|
||||
],
|
||||
// Share type restricted to user - Multipage result
|
||||
[
|
||||
'test', [Share::SHARE_TYPE_USER], 1, 2, [
|
||||
['label' => 'test 1', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
['label' => 'test 2', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']],
|
||||
], [], [],
|
||||
[
|
||||
'exact' => ['users' => []],
|
||||
'users' => [
|
||||
['label' => 'test 1', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
['label' => 'test 2', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']],
|
||||
],
|
||||
], true,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,445 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
||||
*
|
||||
* @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 Test\Collaboration\Collaborators;
|
||||
|
||||
use OC\Collaboration\Collaborators\SearchResult;
|
||||
use OC\Collaboration\Collaborators\UserPlugin;
|
||||
use OCP\Collaboration\Collaborators\ISearchResult;
|
||||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Share;
|
||||
use Test\TestCase;
|
||||
|
||||
class UserPluginTest extends TestCase {
|
||||
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $config;
|
||||
|
||||
/** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $userManager;
|
||||
|
||||
/** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $groupManager;
|
||||
|
||||
/** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $session;
|
||||
|
||||
/** @var UserPlugin */
|
||||
protected $plugin;
|
||||
|
||||
/** @var ISearchResult */
|
||||
protected $searchResult;
|
||||
|
||||
/** @var int */
|
||||
protected $limit = 2;
|
||||
|
||||
/** @var int */
|
||||
protected $offset = 0;
|
||||
|
||||
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $user;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
|
||||
$this->groupManager = $this->createMock(IGroupManager::class);
|
||||
|
||||
$this->session = $this->createMock(IUserSession::class);
|
||||
|
||||
$this->searchResult = new SearchResult();
|
||||
|
||||
$this->user = $this->getUserMock('admin', 'Administrator');
|
||||
}
|
||||
|
||||
public function instantiatePlugin() {
|
||||
// cannot be done within setUp, because dependent mocks needs to be set
|
||||
// up with configuration etc. first
|
||||
$this->plugin = new UserPlugin(
|
||||
$this->config,
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->session
|
||||
);
|
||||
}
|
||||
|
||||
public function getUserMock($uid, $displayName) {
|
||||
$user = $this->createMock(IUser::class);
|
||||
|
||||
$user->expects($this->any())
|
||||
->method('getUID')
|
||||
->willReturn($uid);
|
||||
|
||||
$user->expects($this->any())
|
||||
->method('getDisplayName')
|
||||
->willReturn($displayName);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function dataGetUsers() {
|
||||
return [
|
||||
['test', false, true, [], [], [], [], true, false],
|
||||
['test', false, false, [], [], [], [], true, false],
|
||||
['test', true, true, [], [], [], [], true, false],
|
||||
['test', true, false, [], [], [], [], true, false],
|
||||
[
|
||||
'test', false, true, [], [],
|
||||
[
|
||||
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
|
||||
], [], true, $this->getUserMock('test', 'Test')
|
||||
],
|
||||
[
|
||||
'test', false, false, [], [],
|
||||
[
|
||||
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
|
||||
], [], true, $this->getUserMock('test', 'Test')
|
||||
],
|
||||
[
|
||||
'test', true, true, [], [],
|
||||
[], [], true, $this->getUserMock('test', 'Test')
|
||||
],
|
||||
[
|
||||
'test', true, false, [], [],
|
||||
[], [], true, $this->getUserMock('test', 'Test')
|
||||
],
|
||||
[
|
||||
'test', true, true, ['test-group'], [['test-group', 'test', 2, 0, []]],
|
||||
[
|
||||
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
|
||||
], [], true, $this->getUserMock('test', 'Test')
|
||||
],
|
||||
[
|
||||
'test', true, false, ['test-group'], [['test-group', 'test', 2, 0, []]],
|
||||
[
|
||||
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
|
||||
], [], true, $this->getUserMock('test', 'Test')
|
||||
],
|
||||
[
|
||||
'test',
|
||||
false,
|
||||
true,
|
||||
[],
|
||||
[
|
||||
$this->getUserMock('test1', 'Test One'),
|
||||
],
|
||||
[],
|
||||
[
|
||||
['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
[
|
||||
$this->getUserMock('test1', 'Test One'),
|
||||
],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
false,
|
||||
true,
|
||||
[],
|
||||
[
|
||||
$this->getUserMock('test1', 'Test One'),
|
||||
$this->getUserMock('test2', 'Test Two'),
|
||||
],
|
||||
[],
|
||||
[
|
||||
['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']],
|
||||
],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
[
|
||||
$this->getUserMock('test1', 'Test One'),
|
||||
$this->getUserMock('test2', 'Test Two'),
|
||||
],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
false,
|
||||
true,
|
||||
[],
|
||||
[
|
||||
$this->getUserMock('test0', 'Test'),
|
||||
$this->getUserMock('test1', 'Test One'),
|
||||
$this->getUserMock('test2', 'Test Two'),
|
||||
],
|
||||
[
|
||||
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test0']],
|
||||
],
|
||||
[
|
||||
['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']],
|
||||
],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
[
|
||||
$this->getUserMock('test0', 'Test'),
|
||||
$this->getUserMock('test1', 'Test One'),
|
||||
$this->getUserMock('test2', 'Test Two'),
|
||||
],
|
||||
[
|
||||
['label' => 'Test', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test0']],
|
||||
],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
true,
|
||||
true,
|
||||
['abc', 'xyz'],
|
||||
[
|
||||
['abc', 'test', 2, 0, ['test1' => 'Test One']],
|
||||
['xyz', 'test', 2, 0, []],
|
||||
],
|
||||
[],
|
||||
[
|
||||
['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
true,
|
||||
false,
|
||||
['abc', 'xyz'],
|
||||
[
|
||||
['abc', 'test', 2, 0, ['test1' => 'Test One']],
|
||||
['xyz', 'test', 2, 0, []],
|
||||
],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
true,
|
||||
true,
|
||||
['abc', 'xyz'],
|
||||
[
|
||||
['abc', 'test', 2, 0, [
|
||||
'test1' => 'Test One',
|
||||
'test2' => 'Test Two',
|
||||
]],
|
||||
['xyz', 'test', 2, 0, [
|
||||
'test1' => 'Test One',
|
||||
'test2' => 'Test Two',
|
||||
]],
|
||||
],
|
||||
[],
|
||||
[
|
||||
['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test1']],
|
||||
['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']],
|
||||
],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
true,
|
||||
false,
|
||||
['abc', 'xyz'],
|
||||
[
|
||||
['abc', 'test', 2, 0, [
|
||||
'test1' => 'Test One',
|
||||
'test2' => 'Test Two',
|
||||
]],
|
||||
['xyz', 'test', 2, 0, [
|
||||
'test1' => 'Test One',
|
||||
'test2' => 'Test Two',
|
||||
]],
|
||||
],
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
true,
|
||||
true,
|
||||
['abc', 'xyz'],
|
||||
[
|
||||
['abc', 'test', 2, 0, [
|
||||
'test' => 'Test One',
|
||||
]],
|
||||
['xyz', 'test', 2, 0, [
|
||||
'test2' => 'Test Two',
|
||||
]],
|
||||
],
|
||||
[
|
||||
['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
|
||||
],
|
||||
[
|
||||
['label' => 'Test Two', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test2']],
|
||||
],
|
||||
false,
|
||||
false,
|
||||
],
|
||||
[
|
||||
'test',
|
||||
true,
|
||||
false,
|
||||
['abc', 'xyz'],
|
||||
[
|
||||
['abc', 'test', 2, 0, [
|
||||
'test' => 'Test One',
|
||||
]],
|
||||
['xyz', 'test', 2, 0, [
|
||||
'test2' => 'Test Two',
|
||||
]],
|
||||
],
|
||||
[
|
||||
['label' => 'Test One', 'value' => ['shareType' => Share::SHARE_TYPE_USER, 'shareWith' => 'test']],
|
||||
],
|
||||
[],
|
||||
true,
|
||||
false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataGetUsers
|
||||
*
|
||||
* @param string $searchTerm
|
||||
* @param bool $shareWithGroupOnly
|
||||
* @param bool $shareeEnumeration
|
||||
* @param array $groupResponse
|
||||
* @param array $userResponse
|
||||
* @param array $exactExpected
|
||||
* @param array $expected
|
||||
* @param bool $reachedEnd
|
||||
* @param bool|IUser $singleUser
|
||||
*/
|
||||
public function testSearch(
|
||||
$searchTerm,
|
||||
$shareWithGroupOnly,
|
||||
$shareeEnumeration,
|
||||
array $groupResponse,
|
||||
array $userResponse,
|
||||
array $exactExpected,
|
||||
array $expected,
|
||||
$reachedEnd,
|
||||
$singleUser
|
||||
) {
|
||||
$this->config->expects($this->any())
|
||||
->method('getAppValue')
|
||||
->willReturnCallback(
|
||||
function($appName, $key, $default)
|
||||
use ($shareWithGroupOnly, $shareeEnumeration)
|
||||
{
|
||||
if ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
|
||||
return $shareWithGroupOnly ? 'yes' : 'no';
|
||||
} else if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
|
||||
return $shareeEnumeration ? 'yes' : 'no';
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
);
|
||||
|
||||
$this->instantiatePlugin();
|
||||
|
||||
$this->session->expects($this->any())
|
||||
->method('getUser')
|
||||
->willReturn($this->user);
|
||||
|
||||
if(!$shareWithGroupOnly) {
|
||||
$this->userManager->expects($this->once())
|
||||
->method('searchDisplayName')
|
||||
->with($searchTerm, $this->limit, $this->offset)
|
||||
->willReturn($userResponse);
|
||||
} else {
|
||||
if ($singleUser !== false) {
|
||||
$this->groupManager->expects($this->exactly(2))
|
||||
->method('getUserGroupIds')
|
||||
->withConsecutive(
|
||||
$this->user,
|
||||
$singleUser
|
||||
)
|
||||
->willReturn($groupResponse);
|
||||
} else {
|
||||
$this->groupManager->expects($this->once())
|
||||
->method('getUserGroupIds')
|
||||
->with($this->user)
|
||||
->willReturn($groupResponse);
|
||||
}
|
||||
|
||||
$this->groupManager->expects($this->exactly(sizeof($groupResponse)))
|
||||
->method('displayNamesInGroup')
|
||||
->with($this->anything(), $searchTerm, $this->limit, $this->offset)
|
||||
->willReturnMap($userResponse);
|
||||
}
|
||||
|
||||
if ($singleUser !== false) {
|
||||
$this->userManager->expects($this->once())
|
||||
->method('get')
|
||||
->with($searchTerm)
|
||||
->willReturn($singleUser);
|
||||
}
|
||||
|
||||
|
||||
$moreResults = $this->plugin->search($searchTerm, $this->limit, $this->offset, $this->searchResult);
|
||||
$result = $this->searchResult->asArray();
|
||||
|
||||
$this->assertEquals($exactExpected, $result['exact']['users']);
|
||||
$this->assertEquals($expected, $result['users']);
|
||||
$this->assertSame($reachedEnd, $moreResults);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue