aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Collaboration
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Collaboration')
-rw-r--r--lib/private/Collaboration/AutoComplete/Manager.php64
-rw-r--r--lib/private/Collaboration/Collaborators/GroupPlugin.php69
-rw-r--r--lib/private/Collaboration/Collaborators/LookupPlugin.php72
-rw-r--r--lib/private/Collaboration/Collaborators/MailPlugin.php146
-rw-r--r--lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php41
-rw-r--r--lib/private/Collaboration/Collaborators/RemotePlugin.php62
-rw-r--r--lib/private/Collaboration/Collaborators/Search.php55
-rw-r--r--lib/private/Collaboration/Collaborators/SearchResult.php40
-rw-r--r--lib/private/Collaboration/Collaborators/UserPlugin.php131
-rw-r--r--lib/private/Collaboration/Reference/File/FileReferenceEventListener.php57
-rw-r--r--lib/private/Collaboration/Reference/File/FileReferenceProvider.php161
-rw-r--r--lib/private/Collaboration/Reference/LinkReferenceProvider.php15
-rw-r--r--lib/private/Collaboration/Reference/ReferenceManager.php262
-rw-r--r--lib/private/Collaboration/Reference/RenderReferenceEventListener.php48
-rw-r--r--lib/private/Collaboration/Resources/Collection.php81
-rw-r--r--lib/private/Collaboration/Resources/Listener.php65
-rw-r--r--lib/private/Collaboration/Resources/Manager.php94
-rw-r--r--lib/private/Collaboration/Resources/ProviderManager.php40
-rw-r--r--lib/private/Collaboration/Resources/Resource.php69
19 files changed, 857 insertions, 715 deletions
diff --git a/lib/private/Collaboration/AutoComplete/Manager.php b/lib/private/Collaboration/AutoComplete/Manager.php
index cab15baf535..cc5df78beea 100644
--- a/lib/private/Collaboration/AutoComplete/Manager.php
+++ b/lib/private/Collaboration/AutoComplete/Manager.php
@@ -1,75 +1,67 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\AutoComplete;
use OCP\Collaboration\AutoComplete\IManager;
use OCP\Collaboration\AutoComplete\ISorter;
-use OCP\IServerContainer;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\ContainerInterface;
+use Psr\Log\LoggerInterface;
class Manager implements IManager {
/** @var string[] */
- protected $sorters = [];
+ protected array $sorters = [];
- /** @var ISorter[] */
- protected $sorterInstances = [];
- /** @var IServerContainer */
- private $c;
+ /** @var ISorter[] */
+ protected array $sorterInstances = [];
- public function __construct(IServerContainer $container) {
- $this->c = $container;
+ public function __construct(
+ private ContainerInterface $container,
+ private LoggerInterface $logger,
+ ) {
}
- public function runSorters(array $sorters, array &$sortArray, array $context) {
+ public function runSorters(array $sorters, array &$sortArray, array $context): void {
$sorterInstances = $this->getSorters();
while ($sorter = array_shift($sorters)) {
if (isset($sorterInstances[$sorter])) {
$sorterInstances[$sorter]->sort($sortArray, $context);
} else {
- $this->c->getLogger()->warning('No sorter for ID "{id}", skipping', [
+ $this->logger->warning('No sorter for ID "{id}", skipping', [
'app' => 'core', 'id' => $sorter
]);
}
}
}
- public function registerSorter($className) {
+ public function registerSorter($className): void {
$this->sorters[] = $className;
}
- protected function getSorters() {
+ protected function getSorters(): array {
if (count($this->sorterInstances) === 0) {
foreach ($this->sorters as $sorter) {
- /** @var ISorter $instance */
- $instance = $this->c->resolve($sorter);
+ try {
+ $instance = $this->container->get($sorter);
+ } catch (ContainerExceptionInterface) {
+ $this->logger->notice(
+ 'Skipping not registered sorter. Class name: {class}',
+ ['app' => 'core', 'class' => $sorter],
+ );
+ continue;
+ }
if (!$instance instanceof ISorter) {
- $this->c->getLogger()->notice('Skipping sorter which is not an instance of ISorter. Class name: {class}',
+ $this->logger->notice('Skipping sorter which is not an instance of ISorter. Class name: {class}',
['app' => 'core', 'class' => $sorter]);
continue;
}
$sorterId = trim($instance->getId());
if (trim($sorterId) === '') {
- $this->c->getLogger()->notice('Skipping sorter with empty ID. Class name: {class}',
+ $this->logger->notice('Skipping sorter with empty ID. Class name: {class}',
['app' => 'core', 'class' => $sorter]);
continue;
}
diff --git a/lib/private/Collaboration/Collaborators/GroupPlugin.php b/lib/private/Collaboration/Collaborators/GroupPlugin.php
index 75e52c19e0b..a59d5981825 100644
--- a/lib/private/Collaboration/Collaborators/GroupPlugin.php
+++ b/lib/private/Collaboration/Collaborators/GroupPlugin.php
@@ -1,29 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -37,34 +16,31 @@ use OCP\IUserSession;
use OCP\Share\IShare;
class GroupPlugin implements ISearchPlugin {
- /** @var bool */
- protected $shareeEnumeration;
- /** @var bool */
- protected $shareWithGroupOnly;
- /** @var bool */
- protected $shareeEnumerationInGroupOnly;
- /** @var bool */
- protected $groupSharingDisabled;
-
- /** @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;
+ protected bool $shareeEnumeration;
+
+ protected bool $shareWithGroupOnly;
+
+ protected bool $shareeEnumerationInGroupOnly;
+
+ protected bool $groupSharingDisabled;
+ public function __construct(
+ private IConfig $config,
+ private IGroupManager $groupManager,
+ private IUserSession $userSession,
+ private mixed $shareWithGroupOnlyExcludeGroupsList = [],
+ ) {
$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';
$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
$this->groupSharingDisabled = $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'no';
+
+ if ($this->shareWithGroupOnly) {
+ $this->shareWithGroupOnlyExcludeGroupsList = json_decode($this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''), true) ?? [];
+ }
}
- public function search($search, $limit, $offset, ISearchResult $searchResult) {
+ public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
if ($this->groupSharingDisabled) {
return false;
}
@@ -89,6 +65,9 @@ class GroupPlugin implements ISearchPlugin {
return $group->getGID();
}, $userGroups);
$groupIds = array_intersect($groupIds, $userGroups);
+
+ // ShareWithGroupOnly filtering
+ $groupIds = array_diff($groupIds, $this->shareWithGroupOnlyExcludeGroupsList);
}
$lowerSearch = strtolower($search);
diff --git a/lib/private/Collaboration/Collaborators/LookupPlugin.php b/lib/private/Collaboration/Collaborators/LookupPlugin.php
index 72cbfd4de4b..fb6b9f2e0e8 100644
--- a/lib/private/Collaboration/Collaborators/LookupPlugin.php
+++ b/lib/private/Collaboration/Collaborators/LookupPlugin.php
@@ -1,29 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author J0WI <J0WI@users.noreply.github.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -38,42 +17,33 @@ use OCP\Share\IShare;
use Psr\Log\LoggerInterface;
class LookupPlugin implements ISearchPlugin {
-
- /** @var IConfig */
- private $config;
- /** @var IClientService */
- private $clientService;
/** @var string remote part of the current user's cloud id */
- private $currentUserRemote;
- /** @var ICloudIdManager */
- private $cloudIdManager;
- /** @var LoggerInterface */
- private $logger;
+ private string $currentUserRemote;
- public function __construct(IConfig $config,
- IClientService $clientService,
- IUserSession $userSession,
- ICloudIdManager $cloudIdManager,
- LoggerInterface $logger) {
- $this->config = $config;
- $this->clientService = $clientService;
- $this->cloudIdManager = $cloudIdManager;
+ public function __construct(
+ private IConfig $config,
+ private IClientService $clientService,
+ IUserSession $userSession,
+ private ICloudIdManager $cloudIdManager,
+ private LoggerInterface $logger,
+ ) {
$currentUserCloudId = $userSession->getUser()->getCloudId();
$this->currentUserRemote = $cloudIdManager->resolveCloudId($currentUserCloudId)->getRemote();
- $this->logger = $logger;
}
- public function search($search, $limit, $offset, ISearchResult $searchResult) {
- $isGlobalScaleEnabled = $this->config->getSystemValue('gs.enabled', false);
- $isLookupServerEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
+ public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
+ $isGlobalScaleEnabled = $this->config->getSystemValueBool('gs.enabled', false);
+ $isLookupServerEnabled = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no') === 'yes';
$hasInternetConnection = $this->config->getSystemValueBool('has_internet_connection', true);
- // if case of Global Scale we always search the lookup server
- if (!$isGlobalScaleEnabled && (!$isLookupServerEnabled || !$hasInternetConnection)) {
+ // If case of Global Scale we always search the lookup server
+ // TODO: Reconsider using the lookup server for non-global scale
+ // if (!$isGlobalScaleEnabled && (!$isLookupServerEnabled || !$hasInternetConnection || $disableLookupServer)) {
+ if (!$isGlobalScaleEnabled) {
return false;
}
- $lookupServerUrl = $this->config->getSystemValue('lookup_server', 'https://lookup.nextcloud.com');
+ $lookupServerUrl = $this->config->getSystemValueString('lookup_server', 'https://lookup.nextcloud.com');
if (empty($lookupServerUrl)) {
return false;
}
@@ -96,7 +66,7 @@ class LookupPlugin implements ISearchPlugin {
try {
$remote = $this->cloudIdManager->resolveCloudId($lookup['federationId'])->getRemote();
} catch (\Exception $e) {
- $this->logger->error('Can not parse federated cloud ID "' . $lookup['federationId'] . '"', [
+ $this->logger->error('Can not parse federated cloud ID "' . $lookup['federationId'] . '"', [
'exception' => $e,
]);
continue;
@@ -104,7 +74,7 @@ class LookupPlugin implements ISearchPlugin {
if ($this->currentUserRemote === $remote) {
continue;
}
- $name = isset($lookup['name']['value']) ? $lookup['name']['value'] : '';
+ $name = $lookup['name']['value'] ?? '';
$label = empty($name) ? $lookup['federationId'] : $name . ' (' . $lookup['federationId'] . ')';
$result[] = [
'label' => $label,
diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php
index aae6f305981..55e3945ace2 100644
--- a/lib/private/Collaboration/Collaborators/MailPlugin.php
+++ b/lib/private/Collaboration/Collaborators/MailPlugin.php
@@ -1,28 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Tobia De Koninck <tobia@ledfan.be>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -37,63 +17,58 @@ use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserSession;
-use OCP\Share\IShare;
use OCP\Mail\IMailer;
+use OCP\Share\IShare;
class MailPlugin implements ISearchPlugin {
- /* @var bool */
- protected $shareWithGroupOnly;
- /* @var bool */
- protected $shareeEnumeration;
- /* @var bool */
- protected $shareeEnumerationInGroupOnly;
- /* @var bool */
- protected $shareeEnumerationPhone;
- /* @var bool */
- protected $shareeEnumerationFullMatch;
-
- /** @var IManager */
- private $contactsManager;
- /** @var ICloudIdManager */
- private $cloudIdManager;
- /** @var IConfig */
- private $config;
-
- /** @var IGroupManager */
- private $groupManager;
- /** @var KnownUserService */
- private $knownUserService;
- /** @var IUserSession */
- private $userSession;
- /** @var IMailer */
- private $mailer;
-
- public function __construct(IManager $contactsManager,
- ICloudIdManager $cloudIdManager,
- IConfig $config,
- IGroupManager $groupManager,
- KnownUserService $knownUserService,
- IUserSession $userSession,
- IMailer $mailer) {
- $this->contactsManager = $contactsManager;
- $this->cloudIdManager = $cloudIdManager;
- $this->config = $config;
- $this->groupManager = $groupManager;
- $this->knownUserService = $knownUserService;
- $this->userSession = $userSession;
- $this->mailer = $mailer;
+ protected bool $shareWithGroupOnly;
+
+ protected bool $shareeEnumeration;
+
+ protected bool $shareeEnumerationInGroupOnly;
+ protected bool $shareeEnumerationPhone;
+
+ protected bool $shareeEnumerationFullMatch;
+
+ protected bool $shareeEnumerationFullMatchEmail;
+
+ public function __construct(
+ private IManager $contactsManager,
+ private ICloudIdManager $cloudIdManager,
+ private IConfig $config,
+ private IGroupManager $groupManager,
+ private KnownUserService $knownUserService,
+ private IUserSession $userSession,
+ private IMailer $mailer,
+ private mixed $shareWithGroupOnlyExcludeGroupsList = [],
+ ) {
$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';
$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
$this->shareeEnumerationPhone = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
$this->shareeEnumerationFullMatch = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
+ $this->shareeEnumerationFullMatchEmail = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes') === 'yes';
+
+ if ($this->shareWithGroupOnly) {
+ $this->shareWithGroupOnlyExcludeGroupsList = json_decode($this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''), true) ?? [];
+ }
}
/**
* {@inheritdoc}
*/
- public function search($search, $limit, $offset, ISearchResult $searchResult) {
+ public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
+ if ($this->shareeEnumerationFullMatch && !$this->shareeEnumerationFullMatchEmail) {
+ return false;
+ }
+
+ // Extract the email address from "Foo Bar <foo.bar@example.tld>" and then search with "foo.bar@example.tld" instead
+ $result = preg_match('/<([^@]+@.+)>$/', $search, $matches);
+ if ($result && filter_var($matches[1], FILTER_VALIDATE_EMAIL)) {
+ return $this->search($matches[1], $limit, $offset, $searchResult);
+ }
+
$currentUserId = $this->userSession->getUser()->getUID();
$result = $userResults = ['wide' => [], 'exact' => []];
@@ -107,8 +82,8 @@ class MailPlugin implements ISearchPlugin {
[
'limit' => $limit,
'offset' => $offset,
- 'enumeration' => (bool) $this->shareeEnumeration,
- 'fullmatch' => (bool) $this->shareeEnumerationFullMatch,
+ 'enumeration' => $this->shareeEnumeration,
+ 'fullmatch' => $this->shareeEnumerationFullMatch,
]
);
$lowerSearch = strtolower($search);
@@ -126,6 +101,11 @@ class MailPlugin implements ISearchPlugin {
$emailAddress = $emailAddressData['value'];
$emailAddressType = $emailAddressData['type'];
}
+
+ if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
+ continue;
+ }
+
if (isset($contact['FN'])) {
$displayName = $contact['FN'] . ' (' . $emailAddress . ')';
}
@@ -137,6 +117,10 @@ class MailPlugin implements ISearchPlugin {
* Check if the user may share with the user associated with the e-mail of the just found contact
*/
$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
+
+ // ShareWithGroupOnly filtering
+ $userGroups = array_diff($userGroups, $this->shareWithGroupOnlyExcludeGroupsList);
+
$found = false;
foreach ($userGroups as $userGroup) {
if ($this->groupManager->isInGroup($contact['UID'], $userGroup)) {
@@ -150,7 +134,7 @@ class MailPlugin implements ISearchPlugin {
}
if ($exactEmailMatch && $this->shareeEnumerationFullMatch) {
try {
- $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
+ $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? '');
} catch (\InvalidArgumentException $e) {
continue;
}
@@ -158,8 +142,8 @@ class MailPlugin implements ISearchPlugin {
if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
$singleResult = [[
'label' => $displayName,
- 'uuid' => $contact['UID'],
- 'name' => $contact['FN'],
+ 'uuid' => $contact['UID'] ?? $emailAddress,
+ 'name' => $contact['FN'] ?? $displayName,
'value' => [
'shareType' => IShare::TYPE_USER,
'shareWith' => $cloud->getUser(),
@@ -175,7 +159,7 @@ class MailPlugin implements ISearchPlugin {
if ($this->shareeEnumeration) {
try {
- $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0]);
+ $cloud = $this->cloudIdManager->resolveCloudId($contact['CLOUD'][0] ?? '');
} catch (\InvalidArgumentException $e) {
continue;
}
@@ -198,8 +182,8 @@ class MailPlugin implements ISearchPlugin {
if ($addToWide && !$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
$userResults['wide'][] = [
'label' => $displayName,
- 'uuid' => $contact['UID'],
- 'name' => $contact['FN'],
+ 'uuid' => $contact['UID'] ?? $emailAddress,
+ 'name' => $contact['FN'] ?? $displayName,
'value' => [
'shareType' => IShare::TYPE_USER,
'shareWith' => $cloud->getUser(),
@@ -219,8 +203,8 @@ class MailPlugin implements ISearchPlugin {
}
$result['exact'][] = [
'label' => $displayName,
- 'uuid' => $contact['UID'],
- 'name' => $contact['FN'],
+ 'uuid' => $contact['UID'] ?? $emailAddress,
+ 'name' => $contact['FN'] ?? $displayName,
'type' => $emailAddressType ?? '',
'value' => [
'shareType' => IShare::TYPE_EMAIL,
@@ -230,8 +214,8 @@ class MailPlugin implements ISearchPlugin {
} else {
$result['wide'][] = [
'label' => $displayName,
- 'uuid' => $contact['UID'],
- 'name' => $contact['FN'],
+ 'uuid' => $contact['UID'] ?? $emailAddress,
+ 'name' => $contact['FN'] ?? $displayName,
'type' => $emailAddressType ?? '',
'value' => [
'shareType' => IShare::TYPE_EMAIL,
@@ -245,8 +229,8 @@ class MailPlugin implements ISearchPlugin {
$reachedEnd = true;
if ($this->shareeEnumeration) {
- $reachedEnd = (count($result['wide']) < $offset + $limit) &&
- (count($userResults['wide']) < $offset + $limit);
+ $reachedEnd = (count($result['wide']) < $offset + $limit)
+ && (count($userResults['wide']) < $offset + $limit);
$result['wide'] = array_slice($result['wide'], $offset, $limit);
$userResults['wide'] = array_slice($userResults['wide'], $offset, $limit);
@@ -273,6 +257,6 @@ class MailPlugin implements ISearchPlugin {
public function isCurrentUser(ICloudId $cloud): bool {
$currentUser = $this->userSession->getUser();
- return $currentUser instanceof IUser ? $currentUser->getUID() === $cloud->getUser() : false;
+ return $currentUser instanceof IUser && $currentUser->getUID() === $cloud->getUser();
}
}
diff --git a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php
index 413799e52c6..f4c1793ea0a 100644
--- a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php
+++ b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php
@@ -1,26 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Joas Schilling <coding@schilljs.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -33,14 +15,12 @@ use OCP\Share;
use OCP\Share\IShare;
class RemoteGroupPlugin implements ISearchPlugin {
- protected $shareeEnumeration;
-
- /** @var ICloudIdManager */
- private $cloudIdManager;
- /** @var bool */
- private $enabled = false;
+ private bool $enabled = false;
- public function __construct(ICloudFederationProviderManager $cloudFederationProviderManager, ICloudIdManager $cloudIdManager) {
+ public function __construct(
+ ICloudFederationProviderManager $cloudFederationProviderManager,
+ private ICloudIdManager $cloudIdManager,
+ ) {
try {
$fileSharingProvider = $cloudFederationProviderManager->getCloudFederationProvider('file');
$supportedShareTypes = $fileSharingProvider->getSupportedShareTypes();
@@ -50,10 +30,9 @@ class RemoteGroupPlugin implements ISearchPlugin {
} catch (\Exception $e) {
// do nothing, just don't enable federated group shares
}
- $this->cloudIdManager = $cloudIdManager;
}
- public function search($search, $limit, $offset, ISearchResult $searchResult) {
+ public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
$result = ['wide' => [], 'exact' => []];
$resultType = new SearchResultType('remote_groups');
@@ -83,7 +62,7 @@ class RemoteGroupPlugin implements ISearchPlugin {
* @return array [user, remoteURL]
* @throws \InvalidArgumentException
*/
- public function splitGroupRemote($address) {
+ public function splitGroupRemote($address): array {
try {
$cloudId = $this->cloudIdManager->resolveCloudId($address);
return [$cloudId->getUser(), $cloudId->getRemote()];
diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php
index 7d7a013a38c..037c6f6cbea 100644
--- a/lib/private/Collaboration/Collaborators/RemotePlugin.php
+++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php
@@ -1,28 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- * @author Julius Härtl <jus@bitgrid.net>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -37,32 +17,22 @@ use OCP\IUserSession;
use OCP\Share\IShare;
class RemotePlugin implements ISearchPlugin {
- protected $shareeEnumeration;
+ protected bool $shareeEnumeration;
- /** @var IManager */
- private $contactsManager;
- /** @var ICloudIdManager */
- private $cloudIdManager;
- /** @var IConfig */
- private $config;
- /** @var IUserManager */
- private $userManager;
- /** @var string */
- private $userId = '';
+ private string $userId;
- public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
- $this->contactsManager = $contactsManager;
- $this->cloudIdManager = $cloudIdManager;
- $this->config = $config;
- $this->userManager = $userManager;
- $user = $userSession->getUser();
- if ($user !== null) {
- $this->userId = $user->getUID();
- }
+ public function __construct(
+ private IManager $contactsManager,
+ private ICloudIdManager $cloudIdManager,
+ private IConfig $config,
+ private IUserManager $userManager,
+ IUserSession $userSession,
+ ) {
+ $this->userId = $userSession->getUser()?->getUID() ?? '';
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
}
- public function search($search, $limit, $offset, ISearchResult $searchResult) {
+ public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
$result = ['wide' => [], 'exact' => []];
$resultType = new SearchResultType('remotes');
@@ -185,10 +155,10 @@ class RemotePlugin implements ISearchPlugin {
* @return array [user, remoteURL]
* @throws \InvalidArgumentException
*/
- public function splitUserRemote($address) {
+ public function splitUserRemote(string $address): array {
try {
$cloudId = $this->cloudIdManager->resolveCloudId($address);
- return [$cloudId->getUser(), $cloudId->getRemote()];
+ return [$cloudId->getUser(), $this->cloudIdManager->removeProtocolFromUrl($cloudId->getRemote(), true)];
} catch (\InvalidArgumentException $e) {
throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
}
diff --git a/lib/private/Collaboration/Collaborators/Search.php b/lib/private/Collaboration/Collaborators/Search.php
index b0ee09356af..ea39f885fc6 100644
--- a/lib/private/Collaboration/Collaborators/Search.php
+++ b/lib/private/Collaboration/Collaborators/Search.php
@@ -1,29 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author onehappycat <one.happy.cat@gmx.com>
- * @author Robin Appelman <robin@icewind.nl>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -32,35 +11,31 @@ use OCP\Collaboration\Collaborators\ISearchPlugin;
use OCP\Collaboration\Collaborators\ISearchResult;
use OCP\Collaboration\Collaborators\SearchResultType;
use OCP\IContainer;
-use OCP\Share;
+use OCP\Share\IShare;
class Search implements ISearch {
- /** @var IContainer */
- private $c;
-
- protected $pluginList = [];
+ protected array $pluginList = [];
- public function __construct(IContainer $c) {
- $this->c = $c;
+ public function __construct(
+ private IContainer $container,
+ ) {
}
/**
* @param string $search
- * @param array $shareTypes
* @param bool $lookup
* @param int|null $limit
* @param int|null $offset
- * @return array
* @throws \OCP\AppFramework\QueryException
*/
- public function search($search, array $shareTypes, $lookup, $limit, $offset) {
+ public function search($search, array $shareTypes, $lookup, $limit, $offset): array {
$hasMoreResults = false;
// Trim leading and trailing whitespace characters, e.g. when query is copy-pasted
$search = trim($search);
/** @var ISearchResult $searchResult */
- $searchResult = $this->c->resolve(SearchResult::class);
+ $searchResult = $this->container->resolve(SearchResult::class);
foreach ($shareTypes as $type) {
if (!isset($this->pluginList[$type])) {
@@ -68,14 +43,14 @@ class Search implements ISearch {
}
foreach ($this->pluginList[$type] as $plugin) {
/** @var ISearchPlugin $searchPlugin */
- $searchPlugin = $this->c->resolve($plugin);
+ $searchPlugin = $this->container->resolve($plugin);
$hasMoreResults = $searchPlugin->search($search, $limit, $offset, $searchResult) || $hasMoreResults;
}
}
// Get from lookup server, not a separate share type
if ($lookup) {
- $searchPlugin = $this->c->resolve(LookupPlugin::class);
+ $searchPlugin = $this->container->resolve(LookupPlugin::class);
$hasMoreResults = $searchPlugin->search($search, $limit, $offset, $searchResult) || $hasMoreResults;
}
@@ -97,7 +72,7 @@ class Search implements ISearch {
// if we have an exact local user match with an email-a-like query,
// there is no need to show the remote and email matches.
$userType = new SearchResultType('users');
- if (strpos($search, '@') !== false && $searchResult->hasExactIdMatch($userType)) {
+ if (str_contains($search, '@') && $searchResult->hasExactIdMatch($userType)) {
$searchResult->unsetResult($remoteType);
$searchResult->unsetResult($emailType);
}
@@ -105,8 +80,8 @@ class Search implements ISearch {
return [$searchResult->asArray(), $hasMoreResults];
}
- public function registerPlugin(array $pluginInfo) {
- $shareType = constant(Share::class . '::' . $pluginInfo['shareType']);
+ public function registerPlugin(array $pluginInfo): void {
+ $shareType = constant(IShare::class . '::' . substr($pluginInfo['shareType'], strlen('SHARE_')));
if ($shareType === null) {
throw new \InvalidArgumentException('Provided ShareType is invalid');
}
diff --git a/lib/private/Collaboration/Collaborators/SearchResult.php b/lib/private/Collaboration/Collaborators/SearchResult.php
index 76d78c9c231..c9c2f032f36 100644
--- a/lib/private/Collaboration/Collaborators/SearchResult.php
+++ b/lib/private/Collaboration/Collaborators/SearchResult.php
@@ -1,26 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -28,13 +10,13 @@ use OCP\Collaboration\Collaborators\ISearchResult;
use OCP\Collaboration\Collaborators\SearchResultType;
class SearchResult implements ISearchResult {
- protected $result = [
+ protected array $result = [
'exact' => [],
];
- protected $exactIdMatches = [];
+ protected array $exactIdMatches = [];
- public function addResultSet(SearchResultType $type, array $matches, array $exactMatches = null) {
+ public function addResultSet(SearchResultType $type, array $matches, ?array $exactMatches = null): void {
$type = $type->getLabel();
if (!isset($this->result[$type])) {
$this->result[$type] = [];
@@ -47,15 +29,15 @@ class SearchResult implements ISearchResult {
}
}
- public function markExactIdMatch(SearchResultType $type) {
+ public function markExactIdMatch(SearchResultType $type): void {
$this->exactIdMatches[$type->getLabel()] = 1;
}
- public function hasExactIdMatch(SearchResultType $type) {
+ public function hasExactIdMatch(SearchResultType $type): bool {
return isset($this->exactIdMatches[$type->getLabel()]);
}
- public function hasResult(SearchResultType $type, $collaboratorId) {
+ public function hasResult(SearchResultType $type, $collaboratorId): bool {
$type = $type->getLabel();
if (!isset($this->result[$type])) {
return false;
@@ -73,11 +55,11 @@ class SearchResult implements ISearchResult {
return false;
}
- public function asArray() {
+ public function asArray(): array {
return $this->result;
}
- public function unsetResult(SearchResultType $type) {
+ public function unsetResult(SearchResultType $type): void {
$type = $type->getLabel();
$this->result[$type] = [];
if (isset($this->result['exact'][$type])) {
diff --git a/lib/private/Collaboration/Collaborators/UserPlugin.php b/lib/private/Collaboration/Collaborators/UserPlugin.php
index af4d8b2ccca..671181aea35 100644
--- a/lib/private/Collaboration/Collaborators/UserPlugin.php
+++ b/lib/private/Collaboration/Collaborators/UserPlugin.php
@@ -1,33 +1,8 @@
<?php
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Citharel <nextcloud@tcit.fr>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Collaborators;
@@ -44,70 +19,62 @@ use OCP\Share\IShare;
use OCP\UserStatus\IManager as IUserStatusManager;
class UserPlugin implements ISearchPlugin {
- /* @var bool */
- protected $shareWithGroupOnly;
- /* @var bool */
- protected $shareeEnumeration;
- /* @var bool */
- protected $shareeEnumerationInGroupOnly;
- /* @var bool */
- protected $shareeEnumerationPhone;
- /* @var bool */
- protected $shareeEnumerationFullMatch;
- /* @var bool */
- protected $shareeEnumerationFullMatchUserId;
- /* @var bool */
- protected $shareeEnumerationFullMatchIgnoreSecondDisplayName;
-
- /** @var IConfig */
- private $config;
- /** @var IGroupManager */
- private $groupManager;
- /** @var IUserSession */
- private $userSession;
- /** @var IUserManager */
- private $userManager;
- /** @var KnownUserService */
- private $knownUserService;
- /** @var IUserStatusManager */
- private $userStatusManager;
-
- public function __construct(IConfig $config,
- IUserManager $userManager,
- IGroupManager $groupManager,
- IUserSession $userSession,
- KnownUserService $knownUserService,
- IUserStatusManager $userStatusManager) {
- $this->config = $config;
-
- $this->groupManager = $groupManager;
- $this->userSession = $userSession;
- $this->userManager = $userManager;
- $this->knownUserService = $knownUserService;
- $this->userStatusManager = $userStatusManager;
+ protected bool $shareWithGroupOnly;
+
+ protected bool $shareeEnumeration;
+
+ protected bool $shareeEnumerationInGroupOnly;
+
+ protected bool $shareeEnumerationPhone;
+
+ protected bool $shareeEnumerationFullMatch;
+
+ protected bool $shareeEnumerationFullMatchUserId;
+
+ protected bool $shareeEnumerationFullMatchEmail;
+ protected bool $shareeEnumerationFullMatchIgnoreSecondDisplayName;
+
+ public function __construct(
+ private IConfig $config,
+ private IUserManager $userManager,
+ private IGroupManager $groupManager,
+ private IUserSession $userSession,
+ private KnownUserService $knownUserService,
+ private IUserStatusManager $userStatusManager,
+ private mixed $shareWithGroupOnlyExcludeGroupsList = [],
+ ) {
$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
$this->shareeEnumerationPhone = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
$this->shareeEnumerationFullMatch = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
$this->shareeEnumerationFullMatchUserId = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_userid', 'yes') === 'yes';
- $this->shareeEnumerationFullMatchIgnoreSecondDisplayName = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_display_name', 'no') === 'yes';
+ $this->shareeEnumerationFullMatchEmail = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes') === 'yes';
+ $this->shareeEnumerationFullMatchIgnoreSecondDisplayName = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn', 'no') === 'yes';
+
+ if ($this->shareWithGroupOnly) {
+ $this->shareWithGroupOnlyExcludeGroupsList = json_decode($this->config->getAppValue('core', 'shareapi_only_share_with_group_members_exclude_group_list', ''), true) ?? [];
+ }
}
- public function search($search, $limit, $offset, ISearchResult $searchResult) {
+ public function search($search, $limit, $offset, ISearchResult $searchResult): bool {
$result = ['wide' => [], 'exact' => []];
$users = [];
$hasMoreResults = false;
$currentUserId = $this->userSession->getUser()->getUID();
$currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
+
+ // ShareWithGroupOnly filtering
+ $currentUserGroups = array_diff($currentUserGroups, $this->shareWithGroupOnlyExcludeGroupsList);
+
if ($this->shareWithGroupOnly || $this->shareeEnumerationInGroupOnly) {
// Search in all the groups this user is part of
foreach ($currentUserGroups as $userGroupId) {
$usersInGroup = $this->groupManager->displayNamesInGroup($userGroupId, $search, $limit, $offset);
foreach ($usersInGroup as $userId => $displayName) {
- $userId = (string) $userId;
+ $userId = (string)$userId;
$user = $this->userManager->get($userId);
if (!$user->isEnabled()) {
// Ignore disabled users
@@ -164,7 +131,7 @@ class UserPlugin implements ISearchPlugin {
foreach ($users as $uid => $user) {
$userDisplayName = $user->getDisplayName();
$userEmail = $user->getSystemEMailAddress();
- $uid = (string) $uid;
+ $uid = (string)$uid;
$status = [];
if (array_key_exists($uid, $userStatuses)) {
@@ -181,11 +148,11 @@ class UserPlugin implements ISearchPlugin {
if (
- $this->shareeEnumerationFullMatch &&
- $lowerSearch !== '' && (strtolower($uid) === $lowerSearch ||
- strtolower($userDisplayName) === $lowerSearch ||
- ($this->shareeEnumerationFullMatchIgnoreSecondDisplayName && trim(strtolower(preg_replace('/ \(.*\)$/', '', $userDisplayName))) === $lowerSearch) ||
- strtolower($userEmail ?? '') === $lowerSearch)
+ $this->shareeEnumerationFullMatch
+ && $lowerSearch !== '' && (strtolower($uid) === $lowerSearch
+ || strtolower($userDisplayName) === $lowerSearch
+ || ($this->shareeEnumerationFullMatchIgnoreSecondDisplayName && trim(strtolower(preg_replace('/ \(.*\)$/', '', $userDisplayName))) === $lowerSearch)
+ || ($this->shareeEnumerationFullMatchEmail && strtolower($userEmail ?? '') === $lowerSearch))
) {
if (strtolower($uid) === $lowerSearch) {
$foundUserById = true;
@@ -203,8 +170,8 @@ class UserPlugin implements ISearchPlugin {
];
} else {
$addToWideResults = false;
- if ($this->shareeEnumeration &&
- !($this->shareeEnumerationInGroupOnly || $this->shareeEnumerationPhone)) {
+ if ($this->shareeEnumeration
+ && !($this->shareeEnumerationInGroupOnly || $this->shareeEnumerationPhone)) {
$addToWideResults = true;
}
@@ -279,8 +246,6 @@ class UserPlugin implements ISearchPlugin {
}
}
-
-
$type = new SearchResultType('users');
$searchResult->addResultSet($type, $result['wide'], $result['exact']);
if (count($result['exact'])) {
@@ -290,7 +255,7 @@ class UserPlugin implements ISearchPlugin {
return $hasMoreResults;
}
- public function takeOutCurrentUser(array &$users) {
+ public function takeOutCurrentUser(array &$users): void {
$currentUser = $this->userSession->getUser();
if (!is_null($currentUser)) {
if (isset($users[$currentUser->getUID()])) {
diff --git a/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php b/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php
new file mode 100644
index 00000000000..9c18531c8e7
--- /dev/null
+++ b/lib/private/Collaboration/Reference/File/FileReferenceEventListener.php
@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Collaboration\Reference\File;
+
+use OC\Files\Node\NonExistingFile;
+use OC\Files\Node\NonExistingFolder;
+use OCP\Collaboration\Reference\IReferenceManager;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Files\Events\Node\NodeDeletedEvent;
+use OCP\Files\Events\Node\NodeRenamedEvent;
+use OCP\Share\Events\ShareCreatedEvent;
+use OCP\Share\Events\ShareDeletedEvent;
+
+/** @template-implements IEventListener<Event|NodeDeletedEvent|ShareDeletedEvent|ShareCreatedEvent> */
+class FileReferenceEventListener implements IEventListener {
+ public function __construct(
+ private IReferenceManager $manager,
+ ) {
+ }
+
+ public static function register(IEventDispatcher $eventDispatcher): void {
+ $eventDispatcher->addServiceListener(NodeDeletedEvent::class, FileReferenceEventListener::class);
+ $eventDispatcher->addServiceListener(NodeRenamedEvent::class, FileReferenceEventListener::class);
+ $eventDispatcher->addServiceListener(ShareDeletedEvent::class, FileReferenceEventListener::class);
+ $eventDispatcher->addServiceListener(ShareCreatedEvent::class, FileReferenceEventListener::class);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function handle(Event $event): void {
+ if ($event instanceof NodeDeletedEvent) {
+ if ($event->getNode() instanceof NonExistingFolder || $event->getNode() instanceof NonExistingFile) {
+ return;
+ }
+
+ $this->manager->invalidateCache((string)$event->getNode()->getId());
+ }
+ if ($event instanceof NodeRenamedEvent) {
+ $this->manager->invalidateCache((string)$event->getTarget()->getId());
+ }
+ if ($event instanceof ShareDeletedEvent) {
+ $this->manager->invalidateCache((string)$event->getShare()->getNodeId());
+ }
+ if ($event instanceof ShareCreatedEvent) {
+ $this->manager->invalidateCache((string)$event->getShare()->getNodeId());
+ }
+ }
+}
diff --git a/lib/private/Collaboration/Reference/File/FileReferenceProvider.php b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php
new file mode 100644
index 00000000000..3cb174d9607
--- /dev/null
+++ b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php
@@ -0,0 +1,161 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Collaboration\Reference\File;
+
+use OC\User\NoUserException;
+use OCP\Collaboration\Reference\ADiscoverableReferenceProvider;
+use OCP\Collaboration\Reference\IReference;
+use OCP\Collaboration\Reference\Reference;
+use OCP\Files\IMimeTypeDetector;
+use OCP\Files\InvalidPathException;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+use OCP\IL10N;
+use OCP\IPreview;
+use OCP\IURLGenerator;
+use OCP\IUserSession;
+use OCP\L10N\IFactory;
+
+class FileReferenceProvider extends ADiscoverableReferenceProvider {
+ private ?string $userId;
+ private IL10N $l10n;
+
+ public function __construct(
+ private IURLGenerator $urlGenerator,
+ private IRootFolder $rootFolder,
+ IUserSession $userSession,
+ private IMimeTypeDetector $mimeTypeDetector,
+ private IPreview $previewManager,
+ IFactory $l10n,
+ ) {
+ $this->userId = $userSession->getUser()?->getUID();
+ $this->l10n = $l10n->get('files');
+ }
+
+ public function matchReference(string $referenceText): bool {
+ return $this->getFilesAppLinkId($referenceText) !== null;
+ }
+
+ private function getFilesAppLinkId(string $referenceText): ?int {
+ $start = $this->urlGenerator->getAbsoluteURL('/apps/files/');
+ $startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/files/');
+
+ $fileId = null;
+
+ if (mb_strpos($referenceText, $start) === 0) {
+ $parts = parse_url($referenceText);
+ parse_str($parts['query'] ?? '', $query);
+ $fileId = isset($query['fileid']) ? (int)$query['fileid'] : $fileId;
+ $fileId = isset($query['openfile']) ? (int)$query['openfile'] : $fileId;
+ }
+
+ if (mb_strpos($referenceText, $startIndex) === 0) {
+ $parts = parse_url($referenceText);
+ parse_str($parts['query'] ?? '', $query);
+ $fileId = isset($query['fileid']) ? (int)$query['fileid'] : $fileId;
+ $fileId = isset($query['openfile']) ? (int)$query['openfile'] : $fileId;
+ }
+
+ if (mb_strpos($referenceText, $this->urlGenerator->getAbsoluteURL('/index.php/f/')) === 0) {
+ $fileId = str_replace($this->urlGenerator->getAbsoluteURL('/index.php/f/'), '', $referenceText);
+ }
+
+ if (mb_strpos($referenceText, $this->urlGenerator->getAbsoluteURL('/f/')) === 0) {
+ $fileId = str_replace($this->urlGenerator->getAbsoluteURL('/f/'), '', $referenceText);
+ }
+
+ return $fileId !== null ? (int)$fileId : null;
+ }
+
+ public function resolveReference(string $referenceText): ?IReference {
+ if ($this->matchReference($referenceText)) {
+ $reference = new Reference($referenceText);
+ try {
+ $this->fetchReference($reference);
+ } catch (NotFoundException $e) {
+ $reference->setRichObject('file', null);
+ $reference->setAccessible(false);
+ }
+ return $reference;
+ }
+
+ return null;
+ }
+
+ /**
+ * @throws NotFoundException
+ */
+ private function fetchReference(Reference $reference): void {
+ if ($this->userId === null) {
+ throw new NotFoundException();
+ }
+
+ $fileId = $this->getFilesAppLinkId($reference->getId());
+ if ($fileId === null) {
+ throw new NotFoundException();
+ }
+
+ try {
+ $userFolder = $this->rootFolder->getUserFolder($this->userId);
+ $file = $userFolder->getFirstNodeById($fileId);
+
+ if (!$file) {
+ throw new NotFoundException();
+ }
+
+ $reference->setTitle($file->getName());
+ $reference->setDescription($file->getMimetype());
+ $reference->setUrl($this->urlGenerator->getAbsoluteURL('/index.php/f/' . $fileId));
+ if ($this->previewManager->isMimeSupported($file->getMimeType())) {
+ $reference->setImageUrl($this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreviewByFileId', ['x' => 1600, 'y' => 630, 'fileId' => $fileId]));
+ } else {
+ $fileTypeIconUrl = $this->mimeTypeDetector->mimeTypeIcon($file->getMimeType());
+ $reference->setImageUrl($fileTypeIconUrl);
+ }
+
+ $reference->setRichObject('file', [
+ 'id' => $file->getId(),
+ 'name' => $file->getName(),
+ 'size' => $file->getSize(),
+ 'path' => $userFolder->getRelativePath($file->getPath()),
+ 'link' => $reference->getUrl(),
+ 'mimetype' => $file->getMimetype(),
+ 'mtime' => $file->getMTime(),
+ 'preview-available' => $this->previewManager->isAvailable($file)
+ ]);
+ } catch (InvalidPathException|NotFoundException|NotPermittedException|NoUserException $e) {
+ throw new NotFoundException();
+ }
+ }
+
+ public function getCachePrefix(string $referenceId): string {
+ return (string)$this->getFilesAppLinkId($referenceId);
+ }
+
+ public function getCacheKey(string $referenceId): ?string {
+ return $this->userId ?? '';
+ }
+
+ public function getId(): string {
+ return 'files';
+ }
+
+ public function getTitle(): string {
+ return $this->l10n->t('Files');
+ }
+
+ public function getOrder(): int {
+ return 0;
+ }
+
+ public function getIconUrl(): string {
+ return $this->urlGenerator->imagePath('files', 'folder.svg');
+ }
+}
diff --git a/lib/private/Collaboration/Reference/LinkReferenceProvider.php b/lib/private/Collaboration/Reference/LinkReferenceProvider.php
new file mode 100644
index 00000000000..5af23bf633d
--- /dev/null
+++ b/lib/private/Collaboration/Reference/LinkReferenceProvider.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Collaboration\Reference;
+
+use OCP\Collaboration\Reference\LinkReferenceProvider as OCPLinkReferenceProvider;
+
+/** @deprecated 29.0.0 Use OCP\Collaboration\Reference\LinkReferenceProvider instead */
+class LinkReferenceProvider extends OCPLinkReferenceProvider {
+}
diff --git a/lib/private/Collaboration/Reference/ReferenceManager.php b/lib/private/Collaboration/Reference/ReferenceManager.php
new file mode 100644
index 00000000000..9287b66b2a2
--- /dev/null
+++ b/lib/private/Collaboration/Reference/ReferenceManager.php
@@ -0,0 +1,262 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Collaboration\Reference;
+
+use OC\AppFramework\Bootstrap\Coordinator;
+use OC\Collaboration\Reference\File\FileReferenceProvider;
+use OCP\Collaboration\Reference\IDiscoverableReferenceProvider;
+use OCP\Collaboration\Reference\IPublicReferenceProvider;
+use OCP\Collaboration\Reference\IReference;
+use OCP\Collaboration\Reference\IReferenceManager;
+use OCP\Collaboration\Reference\IReferenceProvider;
+use OCP\Collaboration\Reference\Reference;
+use OCP\ICache;
+use OCP\ICacheFactory;
+use OCP\IConfig;
+use OCP\IURLGenerator;
+use OCP\IUserSession;
+use Psr\Container\ContainerInterface;
+use Psr\Log\LoggerInterface;
+use Throwable;
+
+class ReferenceManager implements IReferenceManager {
+ public const CACHE_TTL = 3600;
+
+ /** @var IReferenceProvider[]|null */
+ private ?array $providers = null;
+ private ICache $cache;
+
+ public function __construct(
+ private LinkReferenceProvider $linkReferenceProvider,
+ ICacheFactory $cacheFactory,
+ private Coordinator $coordinator,
+ private ContainerInterface $container,
+ private LoggerInterface $logger,
+ private IConfig $config,
+ private IUserSession $userSession,
+ ) {
+ $this->cache = $cacheFactory->createDistributed('reference');
+ }
+
+ /**
+ * Extract a list of URLs from a text
+ *
+ * @return string[]
+ */
+ public function extractReferences(string $text): array {
+ preg_match_all(IURLGenerator::URL_REGEX, $text, $matches);
+ $references = $matches[0] ?? [];
+ return array_map(function ($reference) {
+ return trim($reference);
+ }, $references);
+ }
+
+ /**
+ * Try to get a cached reference object from a reference string
+ */
+ public function getReferenceFromCache(string $referenceId, bool $public = false, string $sharingToken = ''): ?IReference {
+ $matchedProvider = $this->getMatchedProvider($referenceId, $public);
+
+ if ($matchedProvider === null) {
+ return null;
+ }
+
+ $cacheKey = $this->getFullCacheKey($matchedProvider, $referenceId, $public, $sharingToken);
+ return $this->getReferenceByCacheKey($cacheKey);
+ }
+
+ /**
+ * Try to get a cached reference object from a full cache key
+ */
+ public function getReferenceByCacheKey(string $cacheKey): ?IReference {
+ $cached = $this->cache->get($cacheKey);
+ if ($cached) {
+ return Reference::fromCache($cached);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get a reference object from a reference string with a matching provider
+ * Use a cached reference if possible
+ */
+ public function resolveReference(string $referenceId, bool $public = false, $sharingToken = ''): ?IReference {
+ $matchedProvider = $this->getMatchedProvider($referenceId, $public);
+
+ if ($matchedProvider === null) {
+ return null;
+ }
+
+ $cacheKey = $this->getFullCacheKey($matchedProvider, $referenceId, $public, $sharingToken);
+ $cached = $this->cache->get($cacheKey);
+ if ($cached) {
+ return Reference::fromCache($cached);
+ }
+
+ $reference = null;
+ if ($public && $matchedProvider instanceof IPublicReferenceProvider) {
+ $reference = $matchedProvider->resolveReferencePublic($referenceId, $sharingToken);
+ } elseif ($matchedProvider instanceof IReferenceProvider) {
+ $reference = $matchedProvider->resolveReference($referenceId);
+ }
+ if ($reference) {
+ $cachePrefix = $matchedProvider->getCachePrefix($referenceId);
+ if ($cachePrefix !== '') {
+ // If a prefix is used we set an additional key to know when we need to delete by prefix during invalidateCache()
+ $this->cache->set('hasPrefix-' . md5($cachePrefix), true, self::CACHE_TTL);
+ }
+ $this->cache->set($cacheKey, Reference::toCache($reference), self::CACHE_TTL);
+ return $reference;
+ }
+
+ return null;
+ }
+
+ /**
+ * Try to match a reference string with all the registered providers
+ * Fallback to the link reference provider (using OpenGraph)
+ *
+ * @return IReferenceProvider|IPublicReferenceProvider|null the first matching provider
+ */
+ private function getMatchedProvider(string $referenceId, bool $public): null|IReferenceProvider|IPublicReferenceProvider {
+ $matchedProvider = null;
+ foreach ($this->getProviders() as $provider) {
+ if ($public && !($provider instanceof IPublicReferenceProvider)) {
+ continue;
+ }
+ $matchedProvider = $provider->matchReference($referenceId) ? $provider : null;
+ if ($matchedProvider !== null) {
+ break;
+ }
+ }
+
+ if ($matchedProvider === null && $this->linkReferenceProvider->matchReference($referenceId)) {
+ $matchedProvider = $this->linkReferenceProvider;
+ }
+
+ return $matchedProvider;
+ }
+
+ /**
+ * Get a hashed full cache key from a key and prefix given by a provider
+ */
+ private function getFullCacheKey(IReferenceProvider $provider, string $referenceId, bool $public, string $sharingToken): string {
+ if ($public && !($provider instanceof IPublicReferenceProvider)) {
+ throw new \RuntimeException('Provider doesn\'t support public lookups');
+ }
+ $cacheKey = $public
+ ? $provider->getCacheKeyPublic($referenceId, $sharingToken)
+ : $provider->getCacheKey($referenceId);
+ return md5($provider->getCachePrefix($referenceId)) . (
+ $cacheKey !== null ? ('-' . md5($cacheKey)) : ''
+ );
+ }
+
+ /**
+ * Remove a specific cache entry from its key+prefix
+ */
+ public function invalidateCache(string $cachePrefix, ?string $cacheKey = null): void {
+ if ($cacheKey === null) {
+ // clear might be a heavy operation, so we only do it if there have actually been keys set
+ if ($this->cache->remove('hasPrefix-' . md5($cachePrefix))) {
+ $this->cache->clear(md5($cachePrefix));
+ }
+
+ return;
+ }
+
+ $this->cache->remove(md5($cachePrefix) . '-' . md5($cacheKey));
+ }
+
+ /**
+ * @return IReferenceProvider[]
+ */
+ public function getProviders(): array {
+ if ($this->providers === null) {
+ $context = $this->coordinator->getRegistrationContext();
+ if ($context === null) {
+ return [];
+ }
+
+ $this->providers = array_filter(array_map(function ($registration): ?IReferenceProvider {
+ try {
+ /** @var IReferenceProvider $provider */
+ $provider = $this->container->get($registration->getService());
+ } catch (Throwable $e) {
+ $this->logger->error('Could not load reference provider ' . $registration->getService() . ': ' . $e->getMessage(), [
+ 'exception' => $e,
+ ]);
+ return null;
+ }
+
+ return $provider;
+ }, $context->getReferenceProviders()));
+
+ $this->providers[] = $this->container->get(FileReferenceProvider::class);
+ }
+
+ return $this->providers;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDiscoverableProviders(): array {
+ // preserve 0 based index to avoid returning an object in data responses
+ return array_values(
+ array_filter($this->getProviders(), static function (IReferenceProvider $provider) {
+ return $provider instanceof IDiscoverableReferenceProvider;
+ })
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function touchProvider(string $userId, string $providerId, ?int $timestamp = null): bool {
+ $providers = $this->getDiscoverableProviders();
+ $matchingProviders = array_filter($providers, static function (IDiscoverableReferenceProvider $provider) use ($providerId) {
+ return $provider->getId() === $providerId;
+ });
+ if (!empty($matchingProviders)) {
+ if ($timestamp === null) {
+ $timestamp = time();
+ }
+
+ $configKey = 'provider-last-use_' . $providerId;
+ $this->config->setUserValue($userId, 'references', $configKey, (string)$timestamp);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getUserProviderTimestamps(): array {
+ $user = $this->userSession->getUser();
+ if ($user === null) {
+ return [];
+ }
+ $userId = $user->getUID();
+ $keys = $this->config->getUserKeys($userId, 'references');
+ $prefix = 'provider-last-use_';
+ $keys = array_filter($keys, static function (string $key) use ($prefix) {
+ return str_starts_with($key, $prefix);
+ });
+ $timestamps = [];
+ foreach ($keys as $key) {
+ $providerId = substr($key, strlen($prefix));
+ $timestamp = (int)$this->config->getUserValue($userId, 'references', $key);
+ $timestamps[$providerId] = $timestamp;
+ }
+ return $timestamps;
+ }
+}
diff --git a/lib/private/Collaboration/Reference/RenderReferenceEventListener.php b/lib/private/Collaboration/Reference/RenderReferenceEventListener.php
new file mode 100644
index 00000000000..9e6192314cb
--- /dev/null
+++ b/lib/private/Collaboration/Reference/RenderReferenceEventListener.php
@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Collaboration\Reference;
+
+use OCP\Collaboration\Reference\IDiscoverableReferenceProvider;
+use OCP\Collaboration\Reference\IReferenceManager;
+use OCP\Collaboration\Reference\RenderReferenceEvent;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IInitialStateService;
+
+/** @template-implements IEventListener<Event|RenderReferenceEvent> */
+class RenderReferenceEventListener implements IEventListener {
+ public function __construct(
+ private IReferenceManager $manager,
+ private IInitialStateService $initialStateService,
+ ) {
+ }
+
+ public static function register(IEventDispatcher $eventDispatcher): void {
+ $eventDispatcher->addServiceListener(RenderReferenceEvent::class, RenderReferenceEventListener::class);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function handle(Event $event): void {
+ if (!($event instanceof RenderReferenceEvent)) {
+ return;
+ }
+
+ $providers = $this->manager->getDiscoverableProviders();
+ $jsonProviders = array_map(static function (IDiscoverableReferenceProvider $provider) {
+ return $provider->jsonSerialize();
+ }, $providers);
+ $this->initialStateService->provideInitialState('core', 'reference-provider-list', $jsonProviders);
+
+ $timestamps = $this->manager->getUserProviderTimestamps();
+ $this->initialStateService->provideInitialState('core', 'reference-provider-timestamps', $timestamps);
+ }
+}
diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php
index ba4005c2139..2481a3e9a09 100644
--- a/lib/private/Collaboration/Resources/Collection.php
+++ b/lib/private/Collaboration/Resources/Collection.php
@@ -3,27 +3,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Resources;
@@ -37,47 +18,21 @@ use OCP\IDBConnection;
use OCP\IUser;
class Collection implements ICollection {
-
- /** @var IManager|Manager */
- protected $manager;
-
- /** @var IDBConnection */
- protected $connection;
-
- /** @var int */
- protected $id;
-
- /** @var string */
- protected $name;
-
- /** @var IUser|null */
- protected $userForAccess;
-
- /** @var bool|null */
- protected $access;
-
/** @var IResource[] */
- protected $resources;
+ protected array $resources = [];
public function __construct(
- IManager $manager,
- IDBConnection $connection,
- int $id,
- string $name,
- ?IUser $userForAccess = null,
- ?bool $access = null
+ /** @var Manager $manager */
+ protected IManager $manager,
+ protected IDBConnection $connection,
+ protected int $id,
+ protected string $name,
+ protected ?IUser $userForAccess = null,
+ protected ?bool $access = null,
) {
- $this->manager = $manager;
- $this->connection = $connection;
- $this->id = $id;
- $this->name = $name;
- $this->userForAccess = $userForAccess;
- $this->access = $access;
- $this->resources = [];
}
/**
- * @return int
* @since 16.0.0
*/
public function getId(): int {
@@ -85,7 +40,6 @@ class Collection implements ICollection {
}
/**
- * @return string
* @since 16.0.0
*/
public function getName(): string {
@@ -93,7 +47,6 @@ class Collection implements ICollection {
}
/**
- * @param string $name
* @since 16.0.0
*/
public function setName(string $name): void {
@@ -101,7 +54,7 @@ class Collection implements ICollection {
$query->update(Manager::TABLE_COLLECTIONS)
->set('name', $query->createNamedParameter($name))
->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
- $query->execute();
+ $query->executeStatement();
$this->name = $name;
}
@@ -121,7 +74,6 @@ class Collection implements ICollection {
/**
* Adds a resource to a collection
*
- * @param IResource $resource
* @throws ResourceException when the resource is already part of the collection
* @since 16.0.0
*/
@@ -154,7 +106,6 @@ class Collection implements ICollection {
/**
* Removes a resource from a collection
*
- * @param IResource $resource
* @since 16.0.0
*/
public function removeResource(IResource $resource): void {
@@ -167,7 +118,7 @@ class Collection implements ICollection {
->where($query->expr()->eq('collection_id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType())))
->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())));
- $query->execute();
+ $query->executeStatement();
if (empty($this->resources)) {
$this->removeCollection();
@@ -179,8 +130,6 @@ class Collection implements ICollection {
/**
* Can a user/guest access the collection
*
- * @param IUser|null $user
- * @return bool
* @since 16.0.0
*/
public function canAccess(?IUser $user): bool {
@@ -215,15 +164,15 @@ class Collection implements ICollection {
}
protected function isSameResource(IResource $resource1, IResource $resource2): bool {
- return $resource1->getType() === $resource2->getType() &&
- $resource1->getId() === $resource2->getId();
+ return $resource1->getType() === $resource2->getType()
+ && $resource1->getId() === $resource2->getId();
}
protected function removeCollection(): void {
$query = $this->connection->getQueryBuilder();
$query->delete(Manager::TABLE_COLLECTIONS)
->where($query->expr()->eq('id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)));
- $query->execute();
+ $query->executeStatement();
$this->manager->invalidateAccessCacheForCollection($this);
$this->id = 0;
diff --git a/lib/private/Collaboration/Resources/Listener.php b/lib/private/Collaboration/Resources/Listener.php
index ba012b4ca44..dfdde24d78e 100644
--- a/lib/private/Collaboration/Resources/Listener.php
+++ b/lib/private/Collaboration/Resources/Listener.php
@@ -3,62 +3,47 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Resources;
use OCP\Collaboration\Resources\IManager;
-use OCP\IGroup;
-use OCP\IUser;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Group\Events\BeforeGroupDeletedEvent;
+use OCP\Group\Events\UserAddedEvent;
+use OCP\Group\Events\UserRemovedEvent;
+use OCP\User\Events\UserDeletedEvent;
class Listener {
- public static function register(EventDispatcherInterface $dispatcher): void {
- $listener = function (GenericEvent $event) {
- /** @var IUser $user */
- $user = $event->getArgument('user');
+ public static function register(IEventDispatcher $eventDispatcher): void {
+ $eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
+ $user = $event->getUser();
/** @var IManager $resourceManager */
- $resourceManager = \OC::$server->query(IManager::class);
+ $resourceManager = \OCP\Server::get(IManager::class);
$resourceManager->invalidateAccessCacheForUser($user);
- };
- $dispatcher->addListener(IGroup::class . '::postAddUser', $listener);
- $dispatcher->addListener(IGroup::class . '::postRemoveUser', $listener);
+ });
+ $eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
+ $user = $event->getUser();
+ /** @var IManager $resourceManager */
+ $resourceManager = \OCP\Server::get(IManager::class);
+
+ $resourceManager->invalidateAccessCacheForUser($user);
+ });
- $dispatcher->addListener(IUser::class . '::postDelete', function (GenericEvent $event) {
- /** @var IUser $user */
- $user = $event->getSubject();
+ $eventDispatcher->addListener(UserDeletedEvent::class, function (UserDeletedEvent $event) {
+ $user = $event->getUser();
/** @var IManager $resourceManager */
- $resourceManager = \OC::$server->query(IManager::class);
+ $resourceManager = \OCP\Server::get(IManager::class);
$resourceManager->invalidateAccessCacheForUser($user);
});
- $dispatcher->addListener(IGroup::class . '::preDelete', function (GenericEvent $event) {
- /** @var IGroup $group */
- $group = $event->getSubject();
+ $eventDispatcher->addListener(BeforeGroupDeletedEvent::class, function (BeforeGroupDeletedEvent $event) {
+ $group = $event->getGroup();
/** @var IManager $resourceManager */
- $resourceManager = \OC::$server->query(IManager::class);
+ $resourceManager = \OCP\Server::get(IManager::class);
foreach ($group->getUsers() as $user) {
$resourceManager->invalidateAccessCacheForUser($user);
diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php
index 8fc3d0dd5ea..8d1e4b13287 100644
--- a/lib/private/Collaboration/Resources/Manager.php
+++ b/lib/private/Collaboration/Resources/Manager.php
@@ -3,27 +3,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
- *
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Julius Härtl <jus@bitgrid.net>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Resources;
@@ -45,26 +26,17 @@ class Manager implements IManager {
public const TABLE_RESOURCES = 'collres_resources';
public const TABLE_ACCESS_CACHE = 'collres_accesscache';
- /** @var IDBConnection */
- protected $connection;
- /** @var IProviderManager */
- protected $providerManager;
- /** @var LoggerInterface */
- protected $logger;
-
/** @var string[] */
- protected $providers = [];
-
+ protected array $providers = [];
- public function __construct(IDBConnection $connection, IProviderManager $providerManager, LoggerInterface $logger) {
- $this->connection = $connection;
- $this->providerManager = $providerManager;
- $this->logger = $logger;
+ public function __construct(
+ protected IDBConnection $connection,
+ protected IProviderManager $providerManager,
+ protected LoggerInterface $logger,
+ ) {
}
/**
- * @param int $id
- * @return ICollection
* @throws CollectionException when the collection could not be found
* @since 16.0.0
*/
@@ -81,13 +53,10 @@ class Manager implements IManager {
throw new CollectionException('Collection not found');
}
- return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name']);
+ return new Collection($this, $this->connection, (int)$row['id'], (string)$row['name']);
}
/**
- * @param int $id
- * @param IUser|null $user
- * @return ICollection
* @throws CollectionException when the collection could not be found
* @since 16.0.0
*/
@@ -113,19 +82,15 @@ class Manager implements IManager {
throw new CollectionException('Collection not found');
}
- $access = $row['access'] === null ? null : (bool) $row['access'];
+ $access = $row['access'] === null ? null : (bool)$row['access'];
if ($user instanceof IUser) {
- return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name'], $user, $access);
+ return new Collection($this, $this->connection, (int)$row['id'], (string)$row['name'], $user, $access);
}
- return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name'], $user, $access);
+ return new Collection($this, $this->connection, (int)$row['id'], (string)$row['name'], $user, $access);
}
/**
- * @param IUser $user
- * @param string $filter
- * @param int $limit
- * @param int $start
* @return ICollection[]
* @since 16.0.0
*/
@@ -148,7 +113,7 @@ class Manager implements IManager {
->setFirstResult($start);
if ($filter !== '') {
- $query->where($query->expr()->iLike('c.name', $query->createNamedParameter('%' . $this->connection->escapeLikeParameter($filter) . '%')));
+ $query->andWhere($query->expr()->iLike('c.name', $query->createNamedParameter('%' . $this->connection->escapeLikeParameter($filter) . '%')));
}
$result = $query->execute();
@@ -157,7 +122,7 @@ class Manager implements IManager {
$foundResults = 0;
while ($row = $result->fetch()) {
$foundResults++;
- $access = $row['access'] === null ? null : (bool) $row['access'];
+ $access = $row['access'] === null ? null : (bool)$row['access'];
$collection = new Collection($this, $this->connection, (int)$row['id'], (string)$row['name'], $user, $access);
if ($collection->canAccess($user)) {
$collections[] = $collection;
@@ -173,8 +138,6 @@ class Manager implements IManager {
}
/**
- * @param string $name
- * @return ICollection
* @since 16.0.0
*/
public function newCollection(string $name): ICollection {
@@ -189,9 +152,6 @@ class Manager implements IManager {
}
/**
- * @param string $type
- * @param string $id
- * @return IResource
* @since 16.0.0
*/
public function createResource(string $type, string $id): IResource {
@@ -199,10 +159,6 @@ class Manager implements IManager {
}
/**
- * @param string $type
- * @param string $id
- * @param IUser|null $user
- * @return IResource
* @throws ResourceException
* @since 16.0.0
*/
@@ -230,7 +186,7 @@ class Manager implements IManager {
throw new ResourceException('Resource not found');
}
- $access = $row['access'] === null ? null : (bool) $row['access'];
+ $access = $row['access'] === null ? null : (bool)$row['access'];
if ($user instanceof IUser) {
return new Resource($this, $this->connection, $type, $id, $user, $access);
}
@@ -239,8 +195,6 @@ class Manager implements IManager {
}
/**
- * @param ICollection $collection
- * @param IUser|null $user
* @return IResource[]
* @since 16.0.0
*/
@@ -263,7 +217,7 @@ class Manager implements IManager {
$resources = [];
$result = $query->execute();
while ($row = $result->fetch()) {
- $access = $row['access'] === null ? null : (bool) $row['access'];
+ $access = $row['access'] === null ? null : (bool)$row['access'];
$resources[] = new Resource($this, $this->connection, $row['resource_type'], $row['resource_id'], $user, $access);
}
$result->closeCursor();
@@ -274,8 +228,6 @@ class Manager implements IManager {
/**
* Get the rich object data of a resource
*
- * @param IResource $resource
- * @return array
* @since 16.0.0
*/
public function getResourceRichObject(IResource $resource): array {
@@ -294,9 +246,6 @@ class Manager implements IManager {
/**
* Can a user/guest access the collection
*
- * @param IResource $resource
- * @param IUser|null $user
- * @return bool
* @since 16.0.0
*/
public function canAccessResource(IResource $resource, ?IUser $user): bool {
@@ -325,9 +274,6 @@ class Manager implements IManager {
/**
* Can a user/guest access the collection
*
- * @param ICollection $collection
- * @param IUser|null $user
- * @return bool
* @since 16.0.0
*/
public function canAccessCollection(ICollection $collection, ?IUser $user): bool {
@@ -365,7 +311,7 @@ class Manager implements IManager {
$hasAccess = null;
$result = $query->execute();
if ($row = $result->fetch()) {
- $hasAccess = (bool) $row['access'];
+ $hasAccess = (bool)$row['access'];
}
$result->closeCursor();
@@ -385,7 +331,7 @@ class Manager implements IManager {
$hasAccess = null;
$result = $query->execute();
if ($row = $result->fetch()) {
- $hasAccess = (bool) $row['access'];
+ $hasAccess = (bool)$row['access'];
}
$result->closeCursor();
@@ -505,9 +451,6 @@ class Manager implements IManager {
$query->execute();
}
- /**
- * @param string $provider
- */
public function registerResourceProvider(string $provider): void {
$this->logger->debug('\OC\Collaboration\Resources\Manager::registerResourceProvider is deprecated', ['provider' => $provider]);
$this->providerManager->registerResourceProvider($provider);
@@ -516,7 +459,6 @@ class Manager implements IManager {
/**
* Get the resource type of the provider
*
- * @return string
* @since 16.0.0
*/
public function getType(): string {
diff --git a/lib/private/Collaboration/Resources/ProviderManager.php b/lib/private/Collaboration/Resources/ProviderManager.php
index 4b099f33b4f..0ce4ae7155a 100644
--- a/lib/private/Collaboration/Resources/ProviderManager.php
+++ b/lib/private/Collaboration/Resources/ProviderManager.php
@@ -3,26 +3,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2019 Daniel Kesselberg <mail@danielkesselberg.de>
- *
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Resources;
@@ -33,22 +15,16 @@ use OCP\IServerContainer;
use Psr\Log\LoggerInterface;
class ProviderManager implements IProviderManager {
-
/** @var string[] */
- protected $providers = [];
+ protected array $providers = [];
/** @var IProvider[] */
- protected $providerInstances = [];
-
- /** @var IServerContainer */
- protected $serverContainer;
-
- /** @var LoggerInterface */
- protected $logger;
+ protected array $providerInstances = [];
- public function __construct(IServerContainer $serverContainer, LoggerInterface $logger) {
- $this->serverContainer = $serverContainer;
- $this->logger = $logger;
+ public function __construct(
+ protected IServerContainer $serverContainer,
+ protected LoggerInterface $logger,
+ ) {
}
public function getResourceProviders(): array {
diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php
index f138204403c..19da3da7e7d 100644
--- a/lib/private/Collaboration/Resources/Resource.php
+++ b/lib/private/Collaboration/Resources/Resource.php
@@ -3,26 +3,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Julius Härtl <jus@bitgrid.net>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Collaboration\Resources;
@@ -33,46 +15,19 @@ use OCP\IDBConnection;
use OCP\IUser;
class Resource implements IResource {
-
- /** @var IManager */
- protected $manager;
-
- /** @var IDBConnection */
- protected $connection;
-
- /** @var string */
- protected $type;
-
- /** @var string */
- protected $id;
-
- /** @var IUser|null */
- protected $userForAccess;
-
- /** @var bool|null */
- protected $access;
-
- /** @var array|null */
- protected $data;
+ protected ?array $data = null;
public function __construct(
- IManager $manager,
- IDBConnection $connection,
- string $type,
- string $id,
- ?IUser $userForAccess = null,
- ?bool $access = null
+ protected IManager $manager,
+ protected IDBConnection $connection,
+ protected string $type,
+ protected string $id,
+ protected ?IUser $userForAccess = null,
+ protected ?bool $access = null,
) {
- $this->manager = $manager;
- $this->connection = $connection;
- $this->type = $type;
- $this->id = $id;
- $this->userForAccess = $userForAccess;
- $this->access = $access;
}
/**
- * @return string
* @since 16.0.0
*/
public function getType(): string {
@@ -80,7 +35,6 @@ class Resource implements IResource {
}
/**
- * @return string
* @since 16.0.0
*/
public function getId(): string {
@@ -88,7 +42,6 @@ class Resource implements IResource {
}
/**
- * @return array
* @since 16.0.0
*/
public function getRichObject(): array {
@@ -102,8 +55,6 @@ class Resource implements IResource {
/**
* Can a user/guest access the resource
*
- * @param IUser|null $user
- * @return bool
* @since 16.0.0
*/
public function canAccess(?IUser $user): bool {
@@ -153,7 +104,7 @@ class Resource implements IResource {
$result = $query->execute();
while ($row = $result->fetch()) {
- $collections[] = $this->manager->getCollection((int) $row['collection_id']);
+ $collections[] = $this->manager->getCollection((int)$row['collection_id']);
}
$result->closeCursor();