diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-11-01 17:33:50 +0100 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-11-01 17:33:58 +0100 |
commit | 98f30c2dab24f0ab80015ef7849a7d8875651f6f (patch) | |
tree | 9de386977ed99c6627410de53d0cfdfaccf4616c /lib | |
parent | abed75e5cbd200169a236f3b586553e5d9ed0452 (diff) | |
parent | 7246f2ace50e41f68433cd89755413b512fa7909 (diff) | |
download | nextcloud-server-98f30c2dab24f0ab80015ef7849a7d8875651f6f.tar.gz nextcloud-server-98f30c2dab24f0ab80015ef7849a7d8875651f6f.zip |
Merge branch 'addressbook-uid-check-migration' of https://github.com/nextcloud/server into addressbook-uid-check-migration
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'lib')
42 files changed, 4624 insertions, 56 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index e880d5ede49..d7523d52caa 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -231,7 +231,25 @@ return array( 'OCP\\Files\\Storage\\INotifyStorage' => $baseDir . '/lib/public/Files/Storage/INotifyStorage.php', 'OCP\\Files\\Storage\\IStorage' => $baseDir . '/lib/public/Files/Storage/IStorage.php', 'OCP\\Files\\Storage\\IStorageFactory' => $baseDir . '/lib/public/Files/Storage/IStorageFactory.php', + 'OCP\\Files\\Storage\\IWriteStreamStorage' => $baseDir . '/lib/public/Files/Storage/IWriteStreamStorage.php', 'OCP\\Files\\UnseekableException' => $baseDir . '/lib/public/Files/UnseekableException.php', + 'OCP\\Files_FullTextSearch\\Model\\AFilesDocument' => $baseDir . '/lib/public/Files_FullTextSearch/Model/AFilesDocument.php', + 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchAppNotAvailableException' => $baseDir . '/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php', + 'OCP\\FullTextSearch\\IFullTextSearchManager' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchManager.php', + 'OCP\\FullTextSearch\\IFullTextSearchPlatform' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchPlatform.php', + 'OCP\\FullTextSearch\\IFullTextSearchProvider' => $baseDir . '/lib/public/FullTextSearch/IFullTextSearchProvider.php', + 'OCP\\FullTextSearch\\Model\\DocumentAccess' => $baseDir . '/lib/public/FullTextSearch/Model/DocumentAccess.php', + 'OCP\\FullTextSearch\\Model\\IIndex' => $baseDir . '/lib/public/FullTextSearch/Model/IIndex.php', + 'OCP\\FullTextSearch\\Model\\IIndexOptions' => $baseDir . '/lib/public/FullTextSearch/Model/IIndexOptions.php', + 'OCP\\FullTextSearch\\Model\\IRunner' => $baseDir . '/lib/public/FullTextSearch/Model/IRunner.php', + 'OCP\\FullTextSearch\\Model\\ISearchRequest' => $baseDir . '/lib/public/FullTextSearch/Model/ISearchRequest.php', + 'OCP\\FullTextSearch\\Model\\ISearchResult' => $baseDir . '/lib/public/FullTextSearch/Model/ISearchResult.php', + 'OCP\\FullTextSearch\\Model\\IndexDocument' => $baseDir . '/lib/public/FullTextSearch/Model/IndexDocument.php', + 'OCP\\FullTextSearch\\Model\\SearchOption' => $baseDir . '/lib/public/FullTextSearch/Model/SearchOption.php', + 'OCP\\FullTextSearch\\Model\\SearchTemplate' => $baseDir . '/lib/public/FullTextSearch/Model/SearchTemplate.php', + 'OCP\\FullTextSearch\\Service\\IIndexService' => $baseDir . '/lib/public/FullTextSearch/Service/IIndexService.php', + 'OCP\\FullTextSearch\\Service\\IProviderService' => $baseDir . '/lib/public/FullTextSearch/Service/IProviderService.php', + 'OCP\\FullTextSearch\\Service\\ISearchService' => $baseDir . '/lib/public/FullTextSearch/Service/ISearchService.php', 'OCP\\GlobalScale\\IConfig' => $baseDir . '/lib/public/GlobalScale/IConfig.php', 'OCP\\GroupInterface' => $baseDir . '/lib/public/GroupInterface.php', 'OCP\\Group\\Backend\\ABackend' => $baseDir . '/lib/public/Group/Backend/ABackend.php', @@ -458,6 +476,7 @@ return array( 'OC\\Archive\\Archive' => $baseDir . '/lib/private/Archive/Archive.php', 'OC\\Archive\\TAR' => $baseDir . '/lib/private/Archive/TAR.php', 'OC\\Archive\\ZIP' => $baseDir . '/lib/private/Archive/ZIP.php', + 'OC\\Authentication\\Exceptions\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Exceptions\\InvalidProviderException' => $baseDir . '/lib/private/Authentication/Exceptions/InvalidProviderException.php', 'OC\\Authentication\\Exceptions\\InvalidTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/InvalidTokenException.php', 'OC\\Authentication\\Exceptions\\LoginRequiredException' => $baseDir . '/lib/private/Authentication/Exceptions/LoginRequiredException.php', @@ -471,7 +490,6 @@ return array( 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenMapper.php', 'OC\\Authentication\\Token\\DefaultTokenProvider' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenProvider.php', - 'OC\\Authentication\\Token\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Token\\IProvider' => $baseDir . '/lib/private/Authentication/Token/IProvider.php', 'OC\\Authentication\\Token\\IToken' => $baseDir . '/lib/private/Authentication/Token/IToken.php', 'OC\\Authentication\\Token\\Manager' => $baseDir . '/lib/private/Authentication/Token/Manager.php', @@ -652,6 +670,7 @@ return array( 'OC\\Core\\Migrations\\Version14000Date20180710092004' => $baseDir . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => $baseDir . '/core/Migrations/Version14000Date20180712153140.php', 'OC\\Core\\Migrations\\Version15000Date20180926101451' => $baseDir . '/core/Migrations/Version15000Date20180926101451.php', + 'OC\\Core\\Migrations\\Version15000Date20181015062942' => $baseDir . '/core/Migrations/Version15000Date20181015062942.php', 'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => $baseDir . '/lib/private/DB/AdapterOCI8.php', @@ -803,6 +822,7 @@ return array( 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => $baseDir . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => $baseDir . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => $baseDir . '/lib/private/Files/Storage/Wrapper/Wrapper.php', + 'OC\\Files\\Stream\\CountReadStream' => $baseDir . '/lib/private/Files/Stream/CountReadStream.php', 'OC\\Files\\Stream\\Encryption' => $baseDir . '/lib/private/Files/Stream/Encryption.php', 'OC\\Files\\Stream\\Quota' => $baseDir . '/lib/private/Files/Stream/Quota.php', 'OC\\Files\\Type\\Detection' => $baseDir . '/lib/private/Files/Type/Detection.php', @@ -811,6 +831,7 @@ return array( 'OC\\Files\\Utils\\Scanner' => $baseDir . '/lib/private/Files/Utils/Scanner.php', 'OC\\Files\\View' => $baseDir . '/lib/private/Files/View.php', 'OC\\ForbiddenException' => $baseDir . '/lib/private/ForbiddenException.php', + 'OC\\FullTextSearch\\FullTextSearchManager' => $baseDir . '/lib/private/FullTextSearch/FullTextSearchManager.php', 'OC\\GlobalScale\\Config' => $baseDir . '/lib/private/GlobalScale/Config.php', 'OC\\Group\\Backend' => $baseDir . '/lib/private/Group/Backend.php', 'OC\\Group\\Database' => $baseDir . '/lib/private/Group/Database.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c5f6211b69d..cf2fef4282d 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -261,7 +261,25 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Files\\Storage\\INotifyStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/INotifyStorage.php', 'OCP\\Files\\Storage\\IStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IStorage.php', 'OCP\\Files\\Storage\\IStorageFactory' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IStorageFactory.php', + 'OCP\\Files\\Storage\\IWriteStreamStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IWriteStreamStorage.php', 'OCP\\Files\\UnseekableException' => __DIR__ . '/../../..' . '/lib/public/Files/UnseekableException.php', + 'OCP\\Files_FullTextSearch\\Model\\AFilesDocument' => __DIR__ . '/../../..' . '/lib/public/Files_FullTextSearch/Model/AFilesDocument.php', + 'OCP\\FullTextSearch\\Exceptions\\FullTextSearchAppNotAvailableException' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php', + 'OCP\\FullTextSearch\\IFullTextSearchManager' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchManager.php', + 'OCP\\FullTextSearch\\IFullTextSearchPlatform' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchPlatform.php', + 'OCP\\FullTextSearch\\IFullTextSearchProvider' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/IFullTextSearchProvider.php', + 'OCP\\FullTextSearch\\Model\\DocumentAccess' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/DocumentAccess.php', + 'OCP\\FullTextSearch\\Model\\IIndex' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IIndex.php', + 'OCP\\FullTextSearch\\Model\\IIndexOptions' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IIndexOptions.php', + 'OCP\\FullTextSearch\\Model\\IRunner' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IRunner.php', + 'OCP\\FullTextSearch\\Model\\ISearchRequest' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/ISearchRequest.php', + 'OCP\\FullTextSearch\\Model\\ISearchResult' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/ISearchResult.php', + 'OCP\\FullTextSearch\\Model\\IndexDocument' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/IndexDocument.php', + 'OCP\\FullTextSearch\\Model\\SearchOption' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/SearchOption.php', + 'OCP\\FullTextSearch\\Model\\SearchTemplate' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Model/SearchTemplate.php', + 'OCP\\FullTextSearch\\Service\\IIndexService' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Service/IIndexService.php', + 'OCP\\FullTextSearch\\Service\\IProviderService' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Service/IProviderService.php', + 'OCP\\FullTextSearch\\Service\\ISearchService' => __DIR__ . '/../../..' . '/lib/public/FullTextSearch/Service/ISearchService.php', 'OCP\\GlobalScale\\IConfig' => __DIR__ . '/../../..' . '/lib/public/GlobalScale/IConfig.php', 'OCP\\GroupInterface' => __DIR__ . '/../../..' . '/lib/public/GroupInterface.php', 'OCP\\Group\\Backend\\ABackend' => __DIR__ . '/../../..' . '/lib/public/Group/Backend/ABackend.php', @@ -488,6 +506,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Archive\\Archive' => __DIR__ . '/../../..' . '/lib/private/Archive/Archive.php', 'OC\\Archive\\TAR' => __DIR__ . '/../../..' . '/lib/private/Archive/TAR.php', 'OC\\Archive\\ZIP' => __DIR__ . '/../../..' . '/lib/private/Archive/ZIP.php', + 'OC\\Authentication\\Exceptions\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Exceptions\\InvalidProviderException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/InvalidProviderException.php', 'OC\\Authentication\\Exceptions\\InvalidTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/InvalidTokenException.php', 'OC\\Authentication\\Exceptions\\LoginRequiredException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/LoginRequiredException.php', @@ -501,7 +520,6 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenMapper.php', 'OC\\Authentication\\Token\\DefaultTokenProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenProvider.php', - 'OC\\Authentication\\Token\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Token\\IProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IProvider.php', 'OC\\Authentication\\Token\\IToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IToken.php', 'OC\\Authentication\\Token\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/Manager.php', @@ -682,6 +700,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Migrations\\Version14000Date20180710092004' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180712153140.php', 'OC\\Core\\Migrations\\Version15000Date20180926101451' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20180926101451.php', + 'OC\\Core\\Migrations\\Version15000Date20181015062942' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20181015062942.php', 'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterOCI8.php', @@ -833,6 +852,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\Storage\\Wrapper\\PermissionsMask' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/PermissionsMask.php', 'OC\\Files\\Storage\\Wrapper\\Quota' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Quota.php', 'OC\\Files\\Storage\\Wrapper\\Wrapper' => __DIR__ . '/../../..' . '/lib/private/Files/Storage/Wrapper/Wrapper.php', + 'OC\\Files\\Stream\\CountReadStream' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/CountReadStream.php', 'OC\\Files\\Stream\\Encryption' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/Encryption.php', 'OC\\Files\\Stream\\Quota' => __DIR__ . '/../../..' . '/lib/private/Files/Stream/Quota.php', 'OC\\Files\\Type\\Detection' => __DIR__ . '/../../..' . '/lib/private/Files/Type/Detection.php', @@ -841,6 +861,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\Utils\\Scanner' => __DIR__ . '/../../..' . '/lib/private/Files/Utils/Scanner.php', 'OC\\Files\\View' => __DIR__ . '/../../..' . '/lib/private/Files/View.php', 'OC\\ForbiddenException' => __DIR__ . '/../../..' . '/lib/private/ForbiddenException.php', + 'OC\\FullTextSearch\\FullTextSearchManager' => __DIR__ . '/../../..' . '/lib/private/FullTextSearch/FullTextSearchManager.php', 'OC\\GlobalScale\\Config' => __DIR__ . '/../../..' . '/lib/private/GlobalScale/Config.php', 'OC\\Group\\Backend' => __DIR__ . '/../../..' . '/lib/private/Group/Backend.php', 'OC\\Group\\Database' => __DIR__ . '/../../..' . '/lib/private/Group/Database.php', diff --git a/lib/private/Authentication/Exceptions/ExpiredTokenException.php b/lib/private/Authentication/Exceptions/ExpiredTokenException.php index a45ca5b6955..d5b2e2cbca7 100644 --- a/lib/private/Authentication/Exceptions/ExpiredTokenException.php +++ b/lib/private/Authentication/Exceptions/ExpiredTokenException.php @@ -21,9 +21,9 @@ declare(strict_types=1); * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -namespace OC\Authentication\Token; +namespace OC\Authentication\Exceptions; -use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Token\IToken; class ExpiredTokenException extends InvalidTokenException { /** @var IToken */ diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php index a27a875a27f..98609a3f14b 100644 --- a/lib/private/Authentication/Token/DefaultTokenProvider.php +++ b/lib/private/Authentication/Token/DefaultTokenProvider.php @@ -29,6 +29,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; use Exception; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OCP\AppFramework\Db\DoesNotExistException; diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php index 7ee76b7b384..21223cecdf7 100644 --- a/lib/private/Authentication/Token/IProvider.php +++ b/lib/private/Authentication/Token/IProvider.php @@ -26,6 +26,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php index 98a48f41523..3174599221d 100644 --- a/lib/private/Authentication/Token/Manager.php +++ b/lib/private/Authentication/Token/Manager.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 33c0b1d59eb..9f596ac4568 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace OC\Authentication\Token; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OCP\AppFramework\Db\DoesNotExistException; diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index 101d6845ec3..6faa5d5d125 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -84,11 +84,17 @@ class MailPlugin implements ISearchPlugin { foreach ($addressBookContacts as $contact) { if (isset($contact['EMAIL'])) { $emailAddresses = $contact['EMAIL']; - if (!is_array($emailAddresses)) { + if (\is_string($emailAddresses)) { $emailAddresses = [$emailAddresses]; } - foreach ($emailAddresses as $emailAddress) { + foreach ($emailAddresses as $type => $emailAddress) { $displayName = $emailAddress; + $emailAddressType = null; + if (\is_array($emailAddress)) { + $emailAddressData = $emailAddress; + $emailAddress = $emailAddressData['value']; + $emailAddressType = $emailAddressData['type']; + } if (isset($contact['FN'])) { $displayName = $contact['FN'] . ' (' . $emailAddress . ')'; } @@ -121,6 +127,8 @@ class MailPlugin implements ISearchPlugin { if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) { $singleResult = [[ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], 'value' => [ 'shareType' => Share::SHARE_TYPE_USER, 'shareWith' => $cloud->getUser(), @@ -142,6 +150,8 @@ class MailPlugin implements ISearchPlugin { if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) { $userResults['wide'][] = [ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], 'value' => [ 'shareType' => Share::SHARE_TYPE_USER, 'shareWith' => $cloud->getUser(), @@ -160,6 +170,9 @@ class MailPlugin implements ISearchPlugin { } $result['exact'][] = [ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $emailAddressType ?? '', 'value' => [ 'shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => $emailAddress, @@ -168,6 +181,9 @@ class MailPlugin implements ISearchPlugin { } else { $result['wide'][] = [ 'label' => $displayName, + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $emailAddressType ?? '', 'value' => [ 'shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => $emailAddress, @@ -194,6 +210,7 @@ class MailPlugin implements ISearchPlugin { if (!$searchResult->hasExactIdMatch($emailType) && filter_var($search, FILTER_VALIDATE_EMAIL)) { $result['exact'][] = [ 'label' => $search, + 'uuid' => $search, 'value' => [ 'shareType' => Share::SHARE_TYPE_EMAIL, 'shareWith' => $search, diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php index e0f5298f83b..d877346b155 100644 --- a/lib/private/Collaboration/Collaborators/RemotePlugin.php +++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php @@ -30,6 +30,8 @@ use OCP\Collaboration\Collaborators\SearchResultType; use OCP\Contacts\IManager; use OCP\Federation\ICloudIdManager; use OCP\IConfig; +use OCP\IUserManager; +use OCP\IUserSession; use OCP\Share; class RemotePlugin implements ISearchPlugin { @@ -41,12 +43,20 @@ class RemotePlugin implements ISearchPlugin { private $cloudIdManager; /** @var IConfig */ private $config; + /** @var IUserManager */ + private $userManager; + /** @var string */ + private $userId = ''; - public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config) { + 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(); + } $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; } @@ -63,23 +73,47 @@ class RemotePlugin implements ISearchPlugin { } if (isset($contact['CLOUD'])) { $cloudIds = $contact['CLOUD']; - if (!is_array($cloudIds)) { + if (is_string($cloudIds)) { $cloudIds = [$cloudIds]; } $lowerSearch = strtolower($search); foreach ($cloudIds as $cloudId) { + $cloudIdType = ''; + if (\is_array($cloudId)) { + $cloudIdData = $cloudId; + $cloudId = $cloudIdData['value']; + $cloudIdType = $cloudIdData['type']; + } try { - list(, $serverUrl) = $this->splitUserRemote($cloudId); + list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId); } catch (\InvalidArgumentException $e) { continue; } + $localUser = $this->userManager->get($remoteUser); + /** + * Add local share if remote cloud id matches a local user ones + */ + if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId() ) { + $result['wide'][] = [ + 'label' => $contact['FN'], + 'uuid' => $contact['UID'], + 'value' => [ + 'shareType' => Share::SHARE_TYPE_USER, + 'shareWith' => $remoteUser + ] + ]; + } + if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) { if (strtolower($cloudId) === $lowerSearch) { $searchResult->markExactIdMatch($resultType); } $result['exact'][] = [ 'label' => $contact['FN'] . " ($cloudId)", + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $cloudIdType, 'value' => [ 'shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => $cloudId, @@ -89,6 +123,9 @@ class RemotePlugin implements ISearchPlugin { } else { $result['wide'][] = [ 'label' => $contact['FN'] . " ($cloudId)", + 'uuid' => $contact['UID'], + 'name' => $contact['FN'], + 'type' => $cloudIdType, 'value' => [ 'shareType' => Share::SHARE_TYPE_REMOTE, 'shareWith' => $cloudId, @@ -106,14 +143,24 @@ class RemotePlugin implements ISearchPlugin { $result['wide'] = array_slice($result['wide'], $offset, $limit); } + /** + * Add generic share with remote item for valid cloud ids that are not users of the local instance + */ if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) { - $result['exact'][] = [ - 'label' => $search, - 'value' => [ - 'shareType' => Share::SHARE_TYPE_REMOTE, - 'shareWith' => $search, - ], - ]; + try { + list($remoteUser, $serverUrl) = $this->splitUserRemote($search); + $localUser = $this->userManager->get($remoteUser); + if ($localUser === null || $search !== $localUser->getCloudId()) { + $result['exact'][] = [ + 'label' => $search, + 'value' => [ + 'shareType' => Share::SHARE_TYPE_REMOTE, + 'shareWith' => $search, + ], + ]; + } + } catch (\InvalidArgumentException $e) { + } } $searchResult->addResultSet($resultType, $result['wide'], $result['exact']); diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index 3ce919a4cbe..71acd27783c 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -28,6 +28,7 @@ namespace OC\Files\ObjectStore; use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\Cache\CacheEntry; +use OC\Files\Stream\CountReadStream; use OCP\Files\ObjectStore\IObjectStore; class ObjectStoreStorage extends \OC\Files\Storage\Common { @@ -382,25 +383,48 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { } public function writeBack($tmpFile, $path) { + $size = filesize($tmpFile); + $this->writeStream($path, fopen($tmpFile, 'r'), $size); + } + + /** + * external changes are not supported, exclusive access to the object storage is assumed + * + * @param string $path + * @param int $time + * @return false + */ + public function hasUpdated($path, $time) { + return false; + } + + public function needsPartFile() { + return false; + } + + public function file_put_contents($path, $data) { + $stream = fopen('php://temp', 'r+'); + fwrite($stream, $data); + rewind($stream); + return $this->writeStream($path, $stream, strlen($data)) > 0; + } + + public function writeStream(string $path, $stream, int $size = null): int { $stat = $this->stat($path); if (empty($stat)) { // create new file - $stat = array( + $stat = [ 'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE, - ); + ]; } // update stat with new data $mTime = time(); - $stat['size'] = filesize($tmpFile); + $stat['size'] = (int)$size; $stat['mtime'] = $mTime; $stat['storage_mtime'] = $mTime; - // run path based detection first, to use file extension because $tmpFile is only a random string $mimetypeDetector = \OC::$server->getMimeTypeDetector(); $mimetype = $mimetypeDetector->detectPath($path); - if ($mimetype === 'application/octet-stream') { - $mimetype = $mimetypeDetector->detect($tmpFile); - } $stat['mimetype'] = $mimetype; $stat['etag'] = $this->getETag($path); @@ -408,7 +432,20 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { $fileId = $this->getCache()->put($path, $stat); try { //upload to object storage - $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r')); + if ($size === null) { + $countStream = CountReadStream::wrap($stream, function ($writtenSize) use ($fileId, &$size) { + $this->getCache()->update($fileId, [ + 'size' => $writtenSize + ]); + $size = $writtenSize; + }); + $this->objectStore->writeObject($this->getURN($fileId), $countStream); + if (is_resource($countStream)) { + fclose($countStream); + } + } else { + $this->objectStore->writeObject($this->getURN($fileId), $stream); + } } catch (\Exception $ex) { $this->getCache()->remove($path); $this->logger->logException($ex, [ @@ -417,20 +454,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { ]); throw $ex; // make this bubble up } - } - /** - * external changes are not supported, exclusive access to the object storage is assumed - * - * @param string $path - * @param int $time - * @return false - */ - public function hasUpdated($path, $time) { - return false; - } - - public function needsPartFile() { - return false; + return $size; } } diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php index b6c82f3a1df..72fe3a79792 100644 --- a/lib/private/Files/Storage/Common.php +++ b/lib/private/Files/Storage/Common.php @@ -54,6 +54,7 @@ use OCP\Files\InvalidPathException; use OCP\Files\ReservedWordException; use OCP\Files\Storage\ILockingStorage; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IWriteStreamStorage; use OCP\ILogger; use OCP\Lock\ILockingProvider; use OCP\Lock\LockedException; @@ -69,7 +70,7 @@ use OCP\Lock\LockedException; * Some \OC\Files\Storage\Common methods call functions which are first defined * in classes which extend it, e.g. $this->stat() . */ -abstract class Common implements Storage, ILockingStorage { +abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage { use LocalTempFileTrait; @@ -809,4 +810,23 @@ abstract class Common implements Storage, ILockingStorage { public function needsPartFile() { return true; } + + /** + * fallback implementation + * + * @param string $path + * @param resource $stream + * @param int $size + * @return int + */ + public function writeStream(string $path, $stream, int $size = null): int { + $target = $this->fopen($path, 'w'); + if (!$target) { + return 0; + } + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } } diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index 46b53dcf95c..5f7232e64b3 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -462,4 +462,8 @@ class Local extends \OC\Files\Storage\Common { return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); } } + + public function writeStream(string $path, $stream, int $size = null): int { + return (int)file_put_contents($this->getSourcePath($path), $stream); + } } diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 42653b2d4a6..e1c1225e0cc 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -1029,4 +1029,13 @@ class Encryption extends Wrapper { } + public function writeStream(string $path, $stream, int $size = null): int { + // always fall back to fopen + $target = $this->fopen($path, 'w'); + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } + } diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php index 56514af6d80..f21b5716467 100644 --- a/lib/private/Files/Storage/Wrapper/Jail.php +++ b/lib/private/Files/Storage/Wrapper/Jail.php @@ -29,6 +29,7 @@ use OC\Files\Cache\Wrapper\CacheJail; use OC\Files\Cache\Wrapper\JailPropagator; use OC\Files\Filesystem; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IWriteStreamStorage; use OCP\Lock\ILockingProvider; /** @@ -515,4 +516,18 @@ class Jail extends Wrapper { $this->propagator = new JailPropagator($storage, \OC::$server->getDatabaseConnection()); return $this->propagator; } + + public function writeStream(string $path, $stream, int $size = null): int { + $storage = $this->getWrapperStorage(); + if ($storage->instanceOfStorage(IWriteStreamStorage::class)) { + /** @var IWriteStreamStorage $storage */ + return $storage->writeStream($this->getUnjailedPath($path), $stream, $size); + } else { + $target = $this->fopen($path, 'w'); + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } + } } diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php index 060c596ad65..f9c84b89fe5 100644 --- a/lib/private/Files/Storage/Wrapper/Wrapper.php +++ b/lib/private/Files/Storage/Wrapper/Wrapper.php @@ -32,9 +32,10 @@ namespace OC\Files\Storage\Wrapper; use OCP\Files\InvalidPathException; use OCP\Files\Storage\ILockingStorage; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IWriteStreamStorage; use OCP\Lock\ILockingProvider; -class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage { +class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStreamStorage { /** * @var \OC\Files\Storage\Storage $storage */ @@ -621,4 +622,18 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage { public function needsPartFile() { return $this->getWrapperStorage()->needsPartFile(); } + + public function writeStream(string $path, $stream, int $size = null): int { + $storage = $this->getWrapperStorage(); + if ($storage->instanceOfStorage(IWriteStreamStorage::class)) { + /** @var IWriteStreamStorage $storage */ + return $storage->writeStream($path, $stream, $size); + } else { + $target = $this->fopen($path, 'w'); + list($count, $result) = \OC_Helper::streamCopy($stream, $target); + fclose($stream); + fclose($target); + return $count; + } + } } diff --git a/lib/private/Files/Stream/CountReadStream.php b/lib/private/Files/Stream/CountReadStream.php new file mode 100644 index 00000000000..93cadf8f214 --- /dev/null +++ b/lib/private/Files/Stream/CountReadStream.php @@ -0,0 +1,65 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 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/>. + * + */ + +namespace OC\Files\Stream; + +use Icewind\Streams\Wrapper; + +class CountReadStream extends Wrapper { + /** @var int */ + private $count; + + /** @var callback */ + private $callback; + + public static function wrap($source, $callback) { + $context = stream_context_create(array( + 'count' => array( + 'source' => $source, + 'callback' => $callback, + ) + )); + return Wrapper::wrapSource($source, $context, 'count', self::class); + } + + public function dir_opendir($path, $options) { + return false; + } + + public function stream_open($path, $mode, $options, &$opened_path) { + $context = $this->loadContext('count'); + + $this->callback = $context['callback']; + return true; + } + + public function stream_read($count) { + $result = parent::stream_read($count); + $this->count += strlen($result); + return $result; + } + + public function stream_close() { + $result = parent::stream_close(); + call_user_func($this->callback, $this->count); + return $result; + } +} diff --git a/lib/private/FullTextSearch/FullTextSearchManager.php b/lib/private/FullTextSearch/FullTextSearchManager.php new file mode 100644 index 00000000000..9a9b077cf23 --- /dev/null +++ b/lib/private/FullTextSearch/FullTextSearchManager.php @@ -0,0 +1,227 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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/>. + * + */ + + +namespace OC\FullTextSearch; + + +use OCP\FullTextSearch\Exceptions\FullTextSearchAppNotAvailableException; +use OCP\FullTextSearch\IFullTextSearchManager; +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\ISearchResult; +use OCP\FullTextSearch\Service\IIndexService; +use OCP\FullTextSearch\Service\IProviderService; +use OCP\FullTextSearch\Service\ISearchService; + + +/** + * Class FullTextSearchManager + * + * @package OC\FullTextSearch + */ +class FullTextSearchManager implements IFullTextSearchManager { + + + /** @var IProviderService */ + private $providerService; + + /** @var IIndexService */ + private $indexService; + + /** @var ISearchService */ + private $searchService; + + + /** + * @since 15.0.0 + * + * @param IProviderService $providerService + */ + public function registerProviderService(IProviderService $providerService) { + $this->providerService = $providerService; + } + + /** + * @since 15.0.0 + * + * @param IIndexService $indexService + */ + public function registerIndexService(IIndexService $indexService) { + $this->indexService = $indexService; + } + + /** + * @since 15.0.0 + * + * @param ISearchService $searchService + */ + public function registerSearchService(ISearchService $searchService) { + $this->searchService = $searchService; + } + + + /** + * @return IProviderService + * @throws FullTextSearchAppNotAvailableException + */ + private function getProviderService(): IProviderService { + if ($this->providerService === null) { + throw new FullTextSearchAppNotAvailableException('No IProviderService registered'); + } + + return $this->providerService; + } + + + /** + * @return IIndexService + * @throws FullTextSearchAppNotAvailableException + */ + private function getIndexService(): IIndexService { + if ($this->indexService === null) { + throw new FullTextSearchAppNotAvailableException('No IIndexService registered'); + } + + return $this->indexService; + } + + + /** + * @return ISearchService + * @throws FullTextSearchAppNotAvailableException + */ + private function getSearchService(): ISearchService { + if ($this->searchService === null) { + throw new FullTextSearchAppNotAvailableException('No ISearchService registered'); + } + + return $this->searchService; + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + public function addJavascriptAPI() { + $this->getProviderService()->addJavascriptAPI(); + } + + + /** + * @param string $providerId + * + * @return bool + * @throws FullTextSearchAppNotAvailableException + */ + public function isProviderIndexed(string $providerId): bool { + return $this->getProviderService()->isProviderIndexed($providerId); + } + + + /** + * @param string $providerId + * @param string $documentId + * @return IIndex + * @throws FullTextSearchAppNotAvailableException + */ + public function getIndex(string $providerId, string $documentId): IIndex { + return $this->getIndexService()->getIndex($providerId, $documentId); + } + + /** + * @param string $providerId + * @param string $documentId + * @param string $userId + * @param int $status + * + * @see IIndex for available value for $status. + * + * @return IIndex + * @throws FullTextSearchAppNotAvailableException + */ + public function createIndex(string $providerId, string $documentId, string $userId, int $status = 0): IIndex { + return $this->getIndexService()->getIndex($providerId, $documentId); + } + + + /** + * @param string $providerId + * @param string $documentId + * @param int $status + * @param bool $reset + * + * @see IIndex for available value for $status. + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false) { + $this->getIndexService()->updateIndexStatus($providerId, $documentId, $status, $reset); + } + + /** + * @param string $providerId + * @param array $documentIds + * @param int $status + * @param bool $reset + * + * @see IIndex for available value for $status. + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false) { + $this->getIndexService()->updateIndexesStatus($providerId, $documentIds, $status, $reset); + } + + + /** + * @param IIndex[] $indexes + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexes(array $indexes) { + $this->getIndexService()->updateIndexes($indexes); + } + + + /** + * @param array $request + * @param string $userId + * + * @return ISearchResult[] + * @throws FullTextSearchAppNotAvailableException + */ + public function search(array $request, string $userId = ''): array { + $searchRequest = $this->getSearchService()->generateSearchRequest($request); + + return $this->getSearchService()->search($userId, $searchRequest); + } + + +} + diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index 86579e3480b..1f7decf2b79 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -298,19 +298,23 @@ class Generator { if ($height !== $maxHeight && $width !== $maxWidth) { /* - * Scale to the nearest power of two + * Scale to the nearest power of four */ - $pow2height = 2 ** ceil(log($height) / log(2)); - $pow2width = 2 ** ceil(log($width) / log(2)); + $pow4height = 4 ** ceil(log($height) / log(4)); + $pow4width = 4 ** ceil(log($width) / log(4)); - $ratioH = $height / $pow2height; - $ratioW = $width / $pow2width; + // Minimum size is 64 + $pow4height = max($pow4height, 64); + $pow4width = max($pow4width, 64); + + $ratioH = $height / $pow4height; + $ratioW = $width / $pow4width; if ($ratioH < $ratioW) { - $width = $pow2width; + $width = $pow4width; $height /= $ratioW; } else { - $height = $pow2height; + $height = $pow4height; $width /= $ratioH; } } diff --git a/lib/private/Server.php b/lib/private/Server.php index 32d7705919c..ceecd059df2 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -82,6 +82,7 @@ use OC\Files\Node\LazyRoot; use OC\Files\Node\Root; use OC\Files\Storage\StorageFactory; use OC\Files\View; +use OC\FullTextSearch\FullTextSearchManager; use OC\Http\Client\ClientService; use OC\IntegrityCheck\Checker; use OC\IntegrityCheck\Helpers\AppLocator; @@ -138,6 +139,7 @@ use OCP\Federation\ICloudIdManager; use OCP\Authentication\LoginCredentials\IStore; use OCP\Files\NotFoundException; use OCP\Files\Storage\IStorageFactory; +use OCP\FullTextSearch\IFullTextSearchManager; use OCP\GlobalScale\IConfig; use OCP\ICacheFactory; use OCP\IDBConnection; @@ -758,7 +760,7 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService('TrustedDomainHelper', function ($c) { return new TrustedDomainHelper($this->getConfig()); }); - $this->registerService('Throttler', function (Server $c) { + $this->registerService(Throttler::class, function (Server $c) { return new Throttler( $c->getDatabaseConnection(), new TimeFactory(), @@ -766,6 +768,7 @@ class Server extends ServerContainer implements IServerContainer { $c->getConfig() ); }); + $this->registerAlias('Throttler', Throttler::class); $this->registerService('IntegrityCodeChecker', function (Server $c) { // IConfig and IAppManager requires a working database. This code // might however be called when ownCloud is not yet setup. @@ -1183,6 +1186,7 @@ class Server extends ServerContainer implements IServerContainer { }); $this->registerAlias(IDashboardManager::class, Dashboard\DashboardManager::class); + $this->registerAlias(IFullTextSearchManager::class, FullTextSearchManager::class); $this->connectDispatcher(); } diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 9c5d78a5958..3dcca0facbc 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -296,6 +296,7 @@ class DefaultShareProvider implements IShareProvider { ->set('token', $qb->createNamedParameter($share->getToken())) ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) ->set('note', $qb->createNamedParameter($share->getNote())) + ->set('hide_download', $qb->createNamedParameter($share->getHideDownload() ? 1 : 0), IQueryBuilder::PARAM_INT) ->execute(); } @@ -953,6 +954,7 @@ class DefaultShareProvider implements IShareProvider { } $share->setProviderId($this->identifier()); + $share->setHideDownload((int)$data['hide_download'] === 1); return $share; } diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index 71c0453d9e5..e218360f87b 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -30,6 +30,7 @@ use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\IUserManager; use OCP\Share\Exceptions\IllegalIDChangeException; +use OCP\Share\IShare; class Share implements \OCP\Share\IShare { @@ -85,6 +86,9 @@ class Share implements \OCP\Share\IShare { /** @var ICacheEntry|null */ private $nodeCacheEntry; + /** @var bool */ + private $hideDownload = false; + public function __construct(IRootFolder $rootFolder, IUserManager $userManager) { $this->rootFolder = $rootFolder; $this->userManager = $userManager; @@ -514,4 +518,13 @@ class Share implements \OCP\Share\IShare { public function getNodeCacheEntry() { return $this->nodeCacheEntry; } + + public function setHideDownload(bool $hide): IShare { + $this->hideDownload = $hide; + return $this; + } + + public function getHideDownload(): bool { + return $this->hideDownload; + } } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index a9c638dca93..674f38e2401 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -38,6 +38,7 @@ namespace OC\User; use OC; +use OC\Authentication\Exceptions\ExpiredTokenException; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Exceptions\PasswordLoginForbiddenException; @@ -401,7 +402,13 @@ class Session implements IUserSession, Emitter { $this->manager->emit('\OC\User', 'preLogin', array($user, $password)); } - $isTokenPassword = $this->isTokenPassword($password); + try { + $isTokenPassword = $this->isTokenPassword($password); + } catch (ExpiredTokenException $e) { + // Just return on an expired token no need to check further or record a failed login + return false; + } + if (!$isTokenPassword && $this->isTokenAuthEnforced()) { throw new PasswordLoginForbiddenException(); } @@ -474,11 +481,14 @@ class Session implements IUserSession, Emitter { * * @param string $password * @return boolean + * @throws ExpiredTokenException */ public function isTokenPassword($password) { try { $this->tokenProvider->getToken($password); return true; + } catch (ExpiredTokenException $e) { + throw $e; } catch (InvalidTokenException $ex) { return false; } diff --git a/lib/public/Files/Storage/IWriteStreamStorage.php b/lib/public/Files/Storage/IWriteStreamStorage.php new file mode 100644 index 00000000000..39a28dd037b --- /dev/null +++ b/lib/public/Files/Storage/IWriteStreamStorage.php @@ -0,0 +1,40 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 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/>. + * + */ + +namespace OCP\Files\Storage; + +/** + * Interface that adds the ability to write a stream directly to file + * + * @since 15.0.0 + */ +interface IWriteStreamStorage extends IStorage { + /** + * Write the data from a stream to a file + * + * @param string $path + * @param resource $stream + * @param int|null $size the size of the stream if known in advance + * @return int the number of bytes written + * @since 15.0.0 + */ + public function writeStream(string $path, $stream, int $size = null): int; +} diff --git a/lib/public/Files_FullTextSearch/Model/AFilesDocument.php b/lib/public/Files_FullTextSearch/Model/AFilesDocument.php new file mode 100644 index 00000000000..3eed956df84 --- /dev/null +++ b/lib/public/Files_FullTextSearch/Model/AFilesDocument.php @@ -0,0 +1,112 @@ +<?php +declare(strict_types=1); + + +/** + * Files_FullTextSearch - Index the content of your files + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\Files_FullTextSearch\Model; + + +use OCP\FullTextSearch\Model\IndexDocument; + + +/** + * Abstract Class AFilesDocument + * + * This is mostly used by 3rd party apps that want to complete the IndexDocument + * with more information about a file before its index: + * + * \OC::$server->getEventDispatcher()->addListener( + * '\OCA\Files_FullTextSearch::onFileIndexing', + * function(GenericEvent $e) { + * //@var \OCP\Files\Node $file + * $file = $e->getArgument('file'); + * + * // @var \OCP\Files_FullTextSearch\Model\AFilesDocument $document + * $document = $e->getArgument('document'); + * + * } + * ); + * + * @since 15.0.0 + * + * @package OCP\Files_FullTextSearch\Model + */ +abstract class AFilesDocument extends IndexDocument { + + + /** + * Returns the owner of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getOwnerId(): string; + + + /** + * Returns the current viewer of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getViewerId(): string; + + + /** + * Returns the type of the document/file. + * + * @since 15.0.0 + * + * @return string \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER + */ + abstract public function getType(): string; + + + /** + * Returns the mimetype of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getMimetype(): string; + + /** + * Returns the path of the document/file. + * + * @since 15.0.0 + * + * @return string + */ + abstract public function getPath(): string; + + +} + diff --git a/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php b/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php new file mode 100644 index 00000000000..4363376f0f4 --- /dev/null +++ b/lib/public/FullTextSearch/Exceptions/FullTextSearchAppNotAvailableException.php @@ -0,0 +1,42 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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/>. + * + */ + + +namespace OCP\FullTextSearch\Exceptions; + +/** + * @since 15.0.0 + * + * Class FullTextSearchAppNotAvailableException + * + * @package OCP\FullTextSearch\Exceptions + */ +class FullTextSearchAppNotAvailableException extends \Exception { +} + diff --git a/lib/public/FullTextSearch/IFullTextSearchManager.php b/lib/public/FullTextSearch/IFullTextSearchManager.php new file mode 100644 index 00000000000..1027f7ade75 --- /dev/null +++ b/lib/public/FullTextSearch/IFullTextSearchManager.php @@ -0,0 +1,186 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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/>. + * + */ + + +namespace OCP\FullTextSearch; + + +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\ISearchResult; +use OCP\FullTextSearch\Service\IIndexService; +use OCP\FullTextSearch\Service\IProviderService; +use OCP\FullTextSearch\Service\ISearchService; + + +/** + * Interface IFullTextSearchManager + * + * Should be used to manage FullTextSearch from the app that contains your + * Content Provider/Search Platform. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch + */ +interface IFullTextSearchManager { + + + /** + * Register a IProviderService. + * + * @since 15.0.0 + * + * @param IProviderService $providerService + */ + public function registerProviderService(IProviderService $providerService); + + /** + * Register a IIndexService. + * + * @since 15.0.0 + * + * @param IIndexService $indexService + */ + public function registerIndexService(IIndexService $indexService); + + /** + * Register a ISearchService. + * + * @since 15.0.0 + * + * @param ISearchService $searchService + */ + public function registerSearchService(ISearchService $searchService); + + + /** + * Add the Javascript API in the navigation page of an app. + * Needed to replace the default search. + * + * @since 15.0.0 + */ + public function addJavascriptAPI(); + + + /** + * Check if the provider $providerId is already indexed. + * + * @since 15.0.0 + * + * @param string $providerId + * + * @return bool + */ + public function isProviderIndexed(string $providerId): bool; + + + /** + * Retrieve an Index from the database, based on the Id of the Provider + * and the Id of the Document + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * + * @return IIndex + */ + public function getIndex(string $providerId, string $documentId): IIndex; + + + /** + * Create a new Index. + * + * This method must be called when a new document is created. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * @param string $userId + * @param int $status + * + * @return IIndex + */ + public function createIndex(string $providerId, string $documentId, string $userId, int $status = 0): IIndex; + + + /** + * Update the status of an Index. status is a bitflag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * @param int $status + * @param bool $reset + */ + public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false); + + + /** + * Update the status of an array of Index. status is a bit flag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param array $documentIds + * @param int $status + * @param bool $reset + */ + public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false); + + /** + * Update an array of Index. + * + * @since 15.0.0 + * + * @param IIndex[] $indexes + */ + public function updateIndexes(array $indexes); + + /** + * Search using an array as request. If $userId is empty, will use the + * current session. + * + * @see ISearchService::generateSearchRequest + * + * @since 15.0.0 + * + * @param array $request + * @param string $userId + * @return ISearchResult[] + */ + public function search(array $request, string $userId = ''): array; + + +} + diff --git a/lib/public/FullTextSearch/IFullTextSearchPlatform.php b/lib/public/FullTextSearch/IFullTextSearchPlatform.php new file mode 100644 index 00000000000..f3f9a35bae2 --- /dev/null +++ b/lib/public/FullTextSearch/IFullTextSearchPlatform.php @@ -0,0 +1,227 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch; + + +use OCP\FullTextSearch\Model\DocumentAccess; +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\IndexDocument; +use OCP\FullTextSearch\Model\IRunner; +use OCP\FullTextSearch\Model\ISearchResult; + + +/** + * Interface IFullTextSearchPlatform + * + * This interface must be use when creating a Search Platform for FullTextSearch. + * + * A Search Platform is an extension to the FullTextSearch that will act as a + * a gateway between FullTextSearch and a search server (ie. ElasticSearch, + * Solr, ...) + * + * Multiple Search Platform can exist at the same time in Nextcloud, however only + * one Search Platform will be used by FullTextSearch. + * Administrator must select at least one Search Platform to be used by + * FullTextSearch in the admin settings page. + * + * The content provided by FullTextSearch comes in chunk from multiple Content + * Provider. Each chunk is identified by the ID of the Content Provider, and the + * ID of the document. + * + * + * To oversimplify the mechanism: + * + * - When indexing, FullTextSearch will send providerId, documentId, content. + * - When searching within the content of a Content Provider, identified by its + * providerId, FullTextSearch expect documentId as result. + * + * + * The Search Platform ia a PHP class that implement this interface and is defined + * in appinfo/info.xml of the app that contains that class: + * + * <fulltextsearch> + * <platform>OCA\YourApp\YourSearchPlatform</platform> + * </fulltextsearch> + * + * Multiple Search Platform can be defined in a single app. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch + */ +interface IFullTextSearchPlatform { + + + /** + * Must returns a unique Id used to identify the Search Platform. + * Id must contains only alphanumeric chars, with no space. + * + * @since 15.0.0 + * + * @return string + */ + public function getId(): string; + + + /** + * Must returns a descriptive name of the Search Platform. + * This is used mainly in the admin settings page to display the list of + * available Search Platform + * + * @since 15.0.0 + * + * @return string + */ + public function getName(): string; + + + /** + * should returns the current configuration of the Search Platform. + * This is used to display the configuration when using the + * ./occ fulltextsearch:check command line. + * + * @since 15.0.0 + * + * @return array + */ + public function getConfiguration(): array; + + + /** + * Set the wrapper of the currently executed process. + * Because the index process can be long and heavy, and because errors can + * be encountered during the process, the IRunner is a wrapper that allow the + * Search Platform to communicate with the process initiated by + * FullTextSearch. + * + * The IRunner is coming with some methods so the Search Platform can + * returns important information and errors to be displayed to the admin. + * + * @since 15.0.0 + * + * @param IRunner $runner + */ + public function setRunner(IRunner $runner); + + + /** + * Called when FullTextSearch is loading your Search Platform. + * + * @since 15.0.0 + */ + public function loadPlatform(); + + + /** + * Called to check that your Search Platform is correctly configured and that + * This is also the right place to check that the Search Service is available. + * + * @since 15.0.0 + * + * @return bool + */ + public function testPlatform(): bool; + + + /** + * Called before an index is initiated. + * Best place to initiate some stuff on the Search Server (mapping, ...) + * + * @since 15.0.0 + */ + public function initializeIndex(); + + + /** + * Reset the indexes for a specific providerId. + * $providerId can be 'all' if it is a global reset. + * + * @since 15.0.0 + * + * @param string $providerId + */ + public function resetIndex(string $providerId); + + + /** + * Deleting some IIndex, sent in an array + * + * @see IIndex + * + * @since 15.0.0 + * + * @param IIndex[] $indexes + */ + public function deleteIndexes(array $indexes); + + + /** + * Indexing a document. + * + * @see IndexDocument + * + * @since 15.0.0 + * + * @param IndexDocument $document + * + * @return IIndex + */ + public function indexDocument(IndexDocument $document): IIndex; + + + /** + * Searching documents, ISearchResult should be updated with the result of + * the search. + * + * @since 15.0.0 + * + * @param ISearchResult $result + * @param DocumentAccess $access + */ + public function searchRequest(ISearchResult $result, DocumentAccess $access); + + + /** + * Return a document based on its Id and the Provider. + * This is used when an admin execute ./occ fulltextsearch:document:platform + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * + * @return IndexDocument + */ + public function getDocument(string $providerId, string $documentId): IndexDocument; + + +} + diff --git a/lib/public/FullTextSearch/IFullTextSearchProvider.php b/lib/public/FullTextSearch/IFullTextSearchProvider.php new file mode 100644 index 00000000000..890b57d84c9 --- /dev/null +++ b/lib/public/FullTextSearch/IFullTextSearchProvider.php @@ -0,0 +1,304 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch; + + +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\IIndexOptions; +use OCP\FullTextSearch\Model\IndexDocument; +use OCP\FullTextSearch\Model\IRunner; +use OCP\FullTextSearch\Model\ISearchRequest; +use OCP\FullTextSearch\Model\ISearchResult; +use OCP\FullTextSearch\Model\SearchTemplate; + + +/** + * Interface IFullTextSearchProvider + * + * This interface must be use when creating a Content Provider for FullTextSearch. + * + * A Content Provider is an extension to the FullTextSearch that will extract and + * provide content to the FullTextSearch. + * + * There is no limit to the number of Content Provider that can be integrated to + * FullTextSearch. Each Content Provider corresponding to a type of content + * available in Nextcloud (files, bookmarks, notes, deck cards, mails, ...) + * + * Content is split in document identified by an ID and the ID of the Content + * Provider. The content is indexed by a Search Platform that will returns a + * documentId as a result on a search request. + * + * + * To oversimplify the mechanism: + * + * - When indexing, FullTextSearch will ask for documents to every Content Provider. + * - On search, results from the Search Platform, identified by documentId, will + * be improved by each relative Content Provider. + * + * + * The Content Provider is a PHP class that implement this interface and is defined + * in appinfo/info.xml of the app that contains that class: + * + * <fulltextsearch> + * <provider>OCA\YourApp\YourContentProvider</provider> + * </fulltextsearch> + * + * Multiple Content Provider can be defined in a single app. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch + */ +interface IFullTextSearchProvider { + + + /** + * Must returns a unique Id used to identify the Content Provider. + * Id must contains only alphanumeric chars, with no space. + * + * @since 15.0.0 + * + * @return string + */ + public function getId(): string; + + + /** + * Must returns a descriptive name of the Content Provider. + * This is used in multiple places, so better use a clear display name. + * + * @since 15.0.0 + * + * @return string + */ + public function getName(): string; + + + /** + * Should returns the current configuration of the Content Provider. + * This is used to display the configuration when using the + * ./occ fulltextsearch:check command line. + * + * @since 15.0.0 + * + * @return array + */ + public function getConfiguration(): array; + + + /** + * Must returns a SearchTemplate that contains displayable items and + * available options to users when searching. + * + * @see SearchTemplate + * + * @since 15.0.0 + * + * @return SearchTemplate + */ + public function getSearchTemplate(): SearchTemplate; + + + /** + * Called when FullTextSearch is loading your Content Provider. + * + * @since 15.0.0 + */ + public function loadProvider(); + + + /** + * Set the wrapper of the currently executed process. + * Because the index process can be long and heavy, and because errors can + * be encountered during the process, the IRunner is a wrapper that allow the + * Content Provider to communicate with the process initiated by + * FullTextSearch. + * + * The IRunner is coming with some methods so the Content Provider can + * returns important information and errors to be displayed to the admin. + * + * @since 15.0.0 + * + * @param IRunner $runner + */ + public function setRunner(IRunner $runner); + + + /** + * This method is called when the administrator specify options when running + * the ./occ fulltextsearch:index or ./occ fulltextsearch:live + * + * @since 15.0.0 + * + * @param IIndexOptions $options + */ + public function setIndexOptions(IIndexOptions $options); + + + /** + * Returns all indexable document for a user as an array of IndexDocument. + * + * There is no need to fill each IndexDocument with content; at this point, + * only fill the object with the minimum information to not waste memory while + * still being able to identify the document it is referring to. + * + * FullTextSearch will call 2 other methods of this interface for each + * IndexDocument of the array, prior to their indexing: + * + * - first, to compare the date of the last index, + * - then, to fill each IndexDocument with complete data + * + * @see IndexDocument + * + * @since 15.0.0 + * + * @param string $userId + * + * @return IndexDocument[] + */ + public function generateIndexableDocuments(string $userId): array; + + + /** + * Called to verify that the document is not already indexed and that the + * old index is not up-to-date, using the IIndex from + * IndexDocument->getIndex() + * + * Returning true will not queue the current IndexDocument to any further + * operation and will continue on the next element from the list returned by + * generateIndexableDocuments(). + * + * @since 15.0.0 + * + * @param IndexDocument $document + * + * @return bool + */ + public function isDocumentUpToDate(IndexDocument $document): bool; + + + /** + * Must fill IndexDocument with all information relative to the document, + * before its indexing by the Search Platform. + * + * Method is called for each element returned previously by + * generateIndexableDocuments(). + * + * @see IndexDocument + * + * @since 15.0.0 + * + * @param IndexDocument $document + */ + public function fillIndexDocument(IndexDocument $document); + + + /** + * The Search Provider must create and return an IndexDocument + * based on the IIndex and its status. The IndexDocument must contains all + * information as it will be send for indexing. + * + * Method is called during a cron or a ./occ fulltextsearch:live after a + * new document is created, or an old document is set as modified. + * + * @since 15.0.0 + * + * @param IIndex $index + * + * @return IndexDocument + */ + public function updateDocument(IIndex $index): IndexDocument; + + + /** + * Called when an index is initiated by the administrator. + * This is should only be used in case of a specific mapping is needed. + * (ie. _almost_ never) + * + * @since 15.0.0 + * + * @param IFullTextSearchPlatform $platform + */ + public function onInitializingIndex(IFullTextSearchPlatform $platform); + + + /** + * Called when administrator is resetting the index. + * This is should only be used in case of a specific mapping has been + * created. + * + * @since 15.0.0 + * + * @param IFullTextSearchPlatform $platform + */ + public function onResettingIndex(IFullTextSearchPlatform $platform); + + + /** + * Method is called when a search request is initiated by a user, prior to + * be sent to the Search Platform. + * + * Your Content Provider can interact with the ISearchRequest to apply the + * search options and make the search more precise. + * + * @see ISearchRequest + * + * @since 15.0.0 + * + * @param ISearchRequest $searchRequest + */ + public function improveSearchRequest(ISearchRequest $searchRequest); + + + /** + * Method is called after results of a search are returned by the + * Search Platform. + * + * Your Content Provider can detail each entry with local data to improve + * the display of the search result. + * + * @see ISearchResult + * + * @since 15.0.0 + * + * @param ISearchResult $searchResult + */ + public function improveSearchResult(ISearchResult $searchResult); + + + /** + * not used yet. + * + * @since 15.0.0 + */ + public function unloadProvider(); + +} diff --git a/lib/public/FullTextSearch/Model/DocumentAccess.php b/lib/public/FullTextSearch/Model/DocumentAccess.php new file mode 100644 index 00000000000..ef199fb7385 --- /dev/null +++ b/lib/public/FullTextSearch/Model/DocumentAccess.php @@ -0,0 +1,363 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +use JsonSerializable; + + +/** + * Class DocumentAccess + * + * This object is used as a data transfer object when + * + * - indexing a document, + * - generating a search request. + * + * During the index, it is used to define which users, groups, circles, ... + * have access to the IndexDocument + * + * During the search, it is internally use to define to which group, circles, ... + * a user that perform the search belongs to. + * + * @see IndexDocument::setAccess + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +final class DocumentAccess implements JsonSerializable { + + /** @var string */ + private $ownerId; + + /** @var string */ + private $viewerId = ''; + + /** @var array */ + private $users = []; + + /** @var array */ + private $groups = []; + + /** @var array */ + private $circles = []; + + /** @var array */ + private $links = []; + + + /** + * Owner of the document can be set at the init of the object. + * + * @since 15.0.0 + * + * DocumentAccess constructor. + * + * @param string $ownerId + */ + public function __construct(string $ownerId = '') { + $this->setOwnerId($ownerId); + } + + + /** + * Set the Owner of the document. + * + * @since 15.0.0 + * + * @param string $ownerId + * + * @return DocumentAccess + */ + public function setOwnerId(string $ownerId) { + $this->ownerId = $ownerId; + + return $this; + } + + /** + * Get the Owner of the document. + * + * @since 15.0.0 + * + * @return string + */ + public function getOwnerId(): string { + return $this->ownerId; + } + + + /** + * Set the viewer of the document. + * + * @since 15.0.0 + * + * @param string $viewerId + * + * @return DocumentAccess + */ + public function setViewerId(string $viewerId): DocumentAccess { + $this->viewerId = $viewerId; + + return $this; + } + + /** + * Get the viewer of the document. + * + * @since 15.0.0 + * + * @return string + */ + public function getViewerId(): string { + return $this->viewerId; + } + + + /** + * Set the list of users that have read access to the document. + * + * @since 15.0.0 + * + * @param array $users + * + * @return DocumentAccess + */ + public function setUsers(array $users): DocumentAccess { + $this->users = $users; + + return $this; + } + + /** + * Add an entry to the list of users that have read access to the document. + * + * @since 15.0.0 + * + * @param string $user + * + * @return DocumentAccess + */ + public function addUser(string $user): DocumentAccess { + $this->users[] = $user; + + return $this; + } + + /** + * Add multiple entries to the list of users that have read access to the + * document. + * + * @since 15.0.0 + * + * @param array $users + * + * @return DocumentAccess + */ + public function addUsers($users): DocumentAccess { + $this->users = array_merge($this->users, $users); + + return $this; + } + + /** + * Get the complete list of users that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getUsers(): array { + return $this->users; + } + + + /** + * Set the list of groups that have read access to the document. + * + * @since 15.0.0 + * + * @param array $groups + * + * @return DocumentAccess + */ + public function setGroups(array $groups): DocumentAccess { + $this->groups = $groups; + + return $this; + } + + /** + * Add an entry to the list of groups that have read access to the document. + * + * @since 15.0.0 + * + * @param string $group + * + * @return DocumentAccess + */ + public function addGroup(string $group): DocumentAccess { + $this->groups[] = $group; + + return $this; + } + + /** + * Add multiple entries to the list of groups that have read access to the + * document. + * + * @since 15.0.0 + * + * @param array $groups + * + * @return DocumentAccess + */ + public function addGroups(array $groups) { + $this->groups = array_merge($this->groups, $groups); + + return $this; + } + + /** + * Get the complete list of groups that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getGroups(): array { + return $this->groups; + } + + + /** + * Set the list of circles that have read access to the document. + * + * @since 15.0.0 + * + * @param array $circles + * + * @return DocumentAccess + */ + public function setCircles(array $circles): DocumentAccess { + $this->circles = $circles; + + return $this; + } + + /** + * Add an entry to the list of circles that have read access to the document. + * + * @since 15.0.0 + * + * @param string $circle + * + * @return DocumentAccess + */ + public function addCircle(string $circle): DocumentAccess { + $this->circles[] = $circle; + + return $this; + } + + /** + * Add multiple entries to the list of groups that have read access to the + * document. + * + * @since 15.0.0 + * + * @param array $circles + * + * @return DocumentAccess + */ + public function addCircles(array $circles): DocumentAccess { + $this->circles = array_merge($this->circles, $circles); + + return $this; + } + + /** + * Get the complete list of circles that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getCircles(): array { + return $this->circles; + } + + + /** + * Set the list of links that have read access to the document. + * + * @since 15.0.0 + * + * @param array $links + * + * @return DocumentAccess + */ + public function setLinks(array $links): DocumentAccess { + $this->links = $links; + + return $this; + } + + /** + * Get the list of links that have read access to the document. + * + * @since 15.0.0 + * + * @return array + */ + public function getLinks(): array { + return $this->links; + } + + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize(): array { + return [ + 'ownerId' => $this->getOwnerId(), + 'viewerId' => $this->getViewerId(), + 'users' => $this->getUsers(), + 'groups' => $this->getGroups(), + 'circles' => $this->getCircles(), + 'links' => $this->getLinks() + ]; + } +} + diff --git a/lib/public/FullTextSearch/Model/IIndex.php b/lib/public/FullTextSearch/Model/IIndex.php new file mode 100644 index 00000000000..adfdf34aee6 --- /dev/null +++ b/lib/public/FullTextSearch/Model/IIndex.php @@ -0,0 +1,292 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for extcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +/** + * Interface IIndex + * + * Index are generated by FullTextSearch to manage the status of a document + * regarding the date of the last index and the date of the last modification + * of the original document. + * + * The uniqueness of an IndexDocument is made by the Id of the Content Provider + * and the Id of the original document within the Content Provider. + * + * We will call original document the source from which the IndexDocument is + * generated. As an example, an original document can be a file, a mail, ... + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface IIndex { + + + const INDEX_OK = 1; + const INDEX_IGNORE = 2; + + const INDEX_META = 4; + const INDEX_CONTENT = 8; + const INDEX_FULL = 12; + const INDEX_REMOVE = 16; + + const INDEX_DONE = 32; + const INDEX_FAILED = 64; + + const ERROR_FAILED = 1; + const ERROR_FAILED2 = 2; + const ERROR_FAILED3 = 4; + + const ERROR_SEV_1 = 1; + const ERROR_SEV_2 = 2; + const ERROR_SEV_3 = 3; + const ERROR_SEV_4 = 4; + + + /** + * Get the Id of the Content Provider. + * + * @since 15.0.0 + * + * @return string + */ + public function getProviderId(): string; + + + /** + * Get the Id of the original document. + * + * @since 15.0.0 + * + * @return string + */ + public function getDocumentId(): string; + + + /** + * Set the source of the original document. + * + * @since 15.0.0 + * + * @param string $source + * + * @return IIndex + */ + public function setSource(string $source): IIndex; + + /** + * Get the source of the original document. + * + * @since 15.0.0 + * + * @return string + */ + public function getSource(): string; + + + /** + * Set the owner of the original document. + * + * @since 15.0.0 + * + * @param string $ownerId + * + * @return IIndex + */ + public function setOwnerId(string $ownerId): IIndex; + + /** + * Get the owner of the original document. + * + * @since 15.0.0 + * + * @return string + */ + public function getOwnerId(): string; + + + /** + * Set the current index status (bit flag) of the original document. + * If $reset is true, the status is reset to the defined value. + * + * @since 15.0.0 + * + * @param int $status + * @param bool $reset + * + * @return IIndex + */ + public function setStatus(int $status, bool $reset = false): IIndex; + + /** + * Get the current index status of the original document. + * + * @since 15.0.0 + * + * @return int + */ + public function getStatus(): int; + + /** + * Check if the document fit a specific status. + * + * @since 15.0.0 + * + * @param int $status + * + * @return bool + */ + public function isStatus(int $status): bool; + + /** + * Remove a status. + * + * @since 15.0.0 + * + * @param int $status + * + * @return IIndex + */ + public function unsetStatus(int $status): IIndex; + + + /** + * Add an option related to the original document (as string). + * + * @since 15.0.0 + * + * @param string $option + * @param string|int $value + * + * @return IIndex + */ + public function addOption(string $option, string $value): IIndex; + + /** + * Add an option related to the original document (as integer). + * + * @since 15.0.0 + * + * @param string $option + * @param int $value + * + * @return IIndex + */ + public function addOptionInt(string $option, int $value): IIndex; + + /** + * Get the option related to the original document (as string). + * + * @since 15.0.0 + * + * @param string $option + * @param string $default + * + * @return string + */ + public function getOption(string $option, string $default = ''): string; + + /** + * Get the option related to the original document (as integer). + * + * @since 15.0.0 + * + * @param string $option + * @param int $default + * + * @return int + */ + public function getOptionInt(string $option, int $default = 0): int; + + /** + * Get all options related to the original document. + * + * @since 15.0.0 + * + * @return array + */ + public function getOptions(): array; + + + /** + * Add an error log related to the Index. + * + * @since 15.0.0 + * + * @param string $message + * @param string $exception + * @param int $sev + * + * @return IIndex + */ + public function addError(string $message, string $exception = '', int $sev = self::ERROR_SEV_3): IIndex; + + /** + * Returns the number of known errors related to the Index. + * + * @since 15.0.0 + * + * @return int + */ + public function getErrorCount(): int; + + /** + * Reset all error logs related to the Index. + * + * @since 15.0.0 + */ + public function resetErrors(): IIndex; + + + /** + * Set the date of the last index. + * + * @since 15.0.0 + * + * @param int $lastIndex + * + * @return IIndex + */ + public function setLastIndex(int $lastIndex = -1): IIndex; + + /** + * Get the date of the last index. + * + * @since 15.0.0 + * + * @return int + */ + public function getLastIndex(): int; + + +} + diff --git a/lib/public/FullTextSearch/Model/IIndexOptions.php b/lib/public/FullTextSearch/Model/IIndexOptions.php new file mode 100644 index 00000000000..8cc5da13d4d --- /dev/null +++ b/lib/public/FullTextSearch/Model/IIndexOptions.php @@ -0,0 +1,86 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +/** + * Interface IIndexOptions + * + * IndexOptions are created in FullTextSearch when an admin initiate an index + * from the command line: + * + * ./occ fulltextsearch:index "{\"option1\": \"value\", \"option2\": true}" + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface IIndexOptions { + + + /** + * Get the value (as a string) for an option. + * + * @since 15.0.0 + * + * @param string $option + * @param string $default + * + * @return string + */ + public function getOption(string $option, string $default = ''): string; + + /** + * Get the value (as an array) for an option. + * + * @since 15.0.0 + * + * @param string $option + * @param array $default + * + * @return array + */ + public function getOptionArray(string $option, array $default = []): array; + + /** + * Get the value (as an boolean) for an option. + * + * @since 15.0.0 + * + * @param string $option + * @param bool $default + * + * @return bool + */ + public function getOptionBool(string $option, bool $default): bool; + +} + diff --git a/lib/public/FullTextSearch/Model/IRunner.php b/lib/public/FullTextSearch/Model/IRunner.php new file mode 100644 index 00000000000..0dff82bd5a0 --- /dev/null +++ b/lib/public/FullTextSearch/Model/IRunner.php @@ -0,0 +1,142 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +/** + * Interface IRunner + * + * The indexing process can be long and heavy, and because errors can + * be encountered the process is wrapped using this interface. + * It allows the any extension of FullTextSearch to communicate with the process. + * + * The IRunner is coming with some methods so the Search Platform can + * returns important information and errors to be displayed to the admin. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface IRunner { + + + const RESULT_TYPE_SUCCESS = 1; + const RESULT_TYPE_WARNING = 4; + const RESULT_TYPE_FAIL = 9; + + + /** + * Info are displayed in the user interface when an admin execute the + * ./occ fulltextsearch:index command. + * + * quick list of info that can be edited: + * 'documentId', 'info', 'title', 'resultIndex', 'resultStatus', + * 'content', 'documentCurrent', 'documentTotal', 'progressStatus', + * 'errorCurrent', 'errorException', 'errorIndex'. + * + * List of all editable info can be find in the Command\Index.php of the + * FullTextSearch app. + * (look for a comment 'full list of info that can be edited') + * + * @since 15.0.0 + * + * @param string $info + * @param string $value + */ + public function setInfo(string $info, string $value); + + + /** + * This method should be used when editing multiple info to avoid too many + * refresh of the interface. + * + * @since 15.0.0 + * + * @param array $data + */ + public function setInfoArray(array $data); + + + /** + * Method used to update the current Action when an index is running. + * + * This method should be used instead of manually update the 'action' using + * setInfo()/setInfoArray() as it is also used to keep the process alive, + * manage the input, and some statistics of the load of the process. + * + * $action is a string with no space + * $force should be set to true if the action is heavy while being executed + * multiple times + * + * @since 15.0.0 + * + * @param string $action + * @param bool $force + * + * @return string + * @throws \Exception + */ + public function updateAction(string $action = '', bool $force = false): string; + + + /** + * Call this method in a Search Platform or Content Provider if there is an + * issue while generating a document or while indexing the current document. + * This is used to store and display errors in the UI during an index to help + * admin to keep track of errors. + * + * @since 15.0.0 + * + * @param IIndex $index + * @param string $message + * @param string $class + * @param int $sev + */ + public function newIndexError(IIndex $index, string $message, string $class = '', int $sev = 3); + + + /** + * Call this method only in a Search Platform after an index of a document. + * This is used to store and display results (good or bad) in the UI during + * an index to help admin to keep track of fail and successful indexes. + * + * @since 15.0.0 + * + * @param IIndex $index + * @param string $message + * @param string $status + * @param int $type + */ + public function newIndexResult(IIndex $index, string $message, string $status, int $type); + + +} + diff --git a/lib/public/FullTextSearch/Model/ISearchRequest.php b/lib/public/FullTextSearch/Model/ISearchRequest.php new file mode 100644 index 00000000000..073b4805f63 --- /dev/null +++ b/lib/public/FullTextSearch/Model/ISearchRequest.php @@ -0,0 +1,326 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +/** + * Interface ISearchRequest + * + * When a search request is initiated, from a request from the front-end or using + * the IFullTextSearchManager::search() method, FullTextSearch will create a + * SearchRequest object, based on this interface. + * + * The object will be passed to the targeted Content Provider so it can convert + * search options using available method. + * + * The object is then encapsulated in a SearchResult and send to the + * Search Platform. + * + * @since 15.0.0 + * + * + * @package OCP\FullTextSearch\Model + */ +interface ISearchRequest { + + + /** + * Get the maximum number of results to be returns by the Search Platform. + * + * @since 15.0.0 + * + * @return int + */ + public function getSize(): int; + + + /** + * Get the current page. + * Used by pagination. + * + * @since 15.0.0 + * + * @return int + */ + public function getPage(): int; + + + /** + * Get the author of the request. + * + * @since 15.0.0 + * + * @return string + */ + public function getAuthor(): string; + + /** + * Get the searched string. + * + * @since 15.0.0 + * + * @return string + */ + public function getSearch(): string; + + + /** + * Get the value of an option (as string). + * + * @since 15.0.0 + * + * @param string $option + * @param string $default + * + * @return string + */ + public function getOption(string $option, string $default = ''): string; + + /** + * Get the value of an option (as array). + * + * @since 15.0.0 + * + * @param string $option + * @param array $default + * + * @return array + */ + public function getOptionArray(string $option, array $default = []): array; + + + /** + * Limit the search to a part of the document. + * + * @since 15.0.0 + * + * @param string $part + * + * @return ISearchRequest + */ + public function addPart(string $part): ISearchRequest; + + /** + * Limit the search to an array of parts of the document. + * + * @since 15.0.0 + * + * @param array $parts + * + * @return ISearchRequest + */ + public function setParts(array $parts): ISearchRequest; + + /** + * Get the parts the search is limited to. + * + * @since 15.0.0 + * + * @return array + */ + public function getParts(): array; + + + /** + * Limit the search to a specific meta tag. + * + * @since 15.0.0 + * + * @param string $tag + * + * @return ISearchRequest + */ + public function addMetaTag(string $tag): ISearchRequest; + + /** + * Get the meta tags the search is limited to. + * + * @since 15.0.0 + * + * @return array + */ + public function getMetaTags(): array; + + /** + * Limit the search to an array of meta tags. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return ISearchRequest + */ + public function setMetaTags(array $tags): IsearchRequest; + + + /** + * Limit the search to a specific sub tag. + * + * @since 15.0.0 + * + * @param string $source + * @param string $tag + * + * @return ISearchRequest + */ + public function addSubTag(string $source, string $tag): ISearchRequest; + + /** + * Get the sub tags the search is limited to. + * + * @since 15.0.0 + * + * @param bool $formatted + * + * @return array + */ + public function getSubTags(bool $formatted): array; + + /** + * Limit the search to an array of sub tags. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return ISearchRequest + */ + public function setSubTags(array $tags): ISearchRequest; + + + /** + * Limit the search to a specific field of the mapping, using a full string. + * + * @since 15.0.0 + * + * @param string $field + * + * @return ISearchRequest + */ + public function addLimitField(string $field): ISearchRequest; + + /** + * Get the fields the search is limited to. + * + * @since 15.0.0 + * + * @return array + */ + public function getLimitFields(): array; + + + /** + * Limit the search to a specific field of the mapping, using a wildcard on + * the search string. + * + * @since 15.0.0 + * + * @param string $field + * + * @return ISearchRequest + */ + public function addWildcardField(string $field): ISearchRequest; + + /** + * Get the limit to field of the mapping. + * + * @since 15.0.0 + * + * @return array + */ + public function getWildcardFields(): array; + + + /** + * Filter the results, based on a group of field, using regex + * + * @since 15.0.0 + * + * @param array $filters + * + * @return ISearchRequest + */ + public function addRegexFilters(array $filters): ISearchRequest; + + /** + * Get the regex filters the search is limit to. + * + * @since 15.0.0 + * + * @return array + */ + public function getRegexFilters(): array; + + + /** + * Filter the results, based on a group of field, using wildcard + * + * @since 15.0.0 + * + * @param array $filter + * + * @return ISearchRequest + */ + public function addWildcardFilter(array $filter): ISearchRequest; + + /** + * Get the wildcard filters the search is limit to. + * + * @since 15.0.0 + * + * @return array + */ + public function getWildcardFilters(): array; + + + /** + * Add an extra field to the search. + * + * @since 15.0.0 + * + * @param string $field + * + * @return ISearchRequest + */ + public function addField(string $field): ISearchRequest; + + /** + * Get the list of extra field to search into. + * + * @since 15.0.0 + * + * @return array + */ + public function getFields(): array; + + +} + diff --git a/lib/public/FullTextSearch/Model/ISearchResult.php b/lib/public/FullTextSearch/Model/ISearchResult.php new file mode 100644 index 00000000000..a7dcba82f5c --- /dev/null +++ b/lib/public/FullTextSearch/Model/ISearchResult.php @@ -0,0 +1,198 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +use OCP\FullTextSearch\IFullTextSearchProvider; + + +/** + * Interface ISearchResult + * + * When a search request is initiated, FullTextSearch will create a SearchResult + * object, based on this interface, containing the SearchRequest and the targeted + * Content Provider. + * + * The object will be passed to the Search Platform, which will proceed to the + * search and fill the SearchResult object with results. + * + * Then, the object will be passed to the targeted Content Provider that will + * improve the Search Results with detailed informations. + * + * Finally, the SearchResult is returned to the original search request. + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +interface ISearchResult { + + + /** + * Get the original SearchRequest. + * + * @see ISearchRequest + * + * @since 15.0.0 + * + * @return ISearchRequest + */ + public function getRequest(): ISearchRequest; + + /** + * Get the targeted Content Provider. + * + * @since 15.0.0 + * + * @return IFullTextSearchProvider + */ + public function getProvider(): IFullTextSearchProvider; + + + /** + * Add an IndexDocument as one of the result of the search request. + * + * @since 15.0.0 + * + * @param IndexDocument $document + * + * @return ISearchResult + */ + public function addDocument(IndexDocument $document): ISearchResult; + + /** + * Returns all result of the search request, in an array of IndexDocument. + * + * @since 15.0.0 + * + * @return array + */ + public function getDocuments(): array; + + /** + * Set an array of IndexDocument as the result of the search request. + * + * @since 15.0.0 + * + * @param IndexDocument[] $documents + * + * @return ISearchResult + */ + public function setDocuments(array $documents): ISearchResult; + + + /** + * Add an aggregation to the result. + * + * @since 15.0.0 + * + * @param string $category + * @param string $value + * @param int $count + * + * @return ISearchResult + */ + public function addAggregation(string $category, string $value, int $count): ISearchResult; + + /** + * Get all aggregations. + * + * @since 15.0.0 + * + * @param string $category + * + * @return array + */ + public function getAggregations(string $category): array; + + + /** + * Set the raw result of the request. + * + * @since 15.0.0 + * + * @param string $result + * + * @return ISearchResult + */ + public function setRawResult(string $result): ISearchResult; + + + /** + * Set the total number of results for the search request. + * Used by pagination. + * + * @since 15.0.0 + * + * @param int $total + * + * @return ISearchResult + */ + public function setTotal(int $total): ISearchResult; + + + /** + * Set the top score for the search request. + * + * @since 15.0.0 + * + * @param int $score + * + * @return ISearchResult + */ + public function setMaxScore(int $score): ISearchResult; + + + /** + * Set the time spent by the request to perform the search. + * + * @since 15.0.0 + * + * @param int $time + * + * @return ISearchResult + */ + public function setTime(int $time): ISearchResult; + + + /** + * Set to true if the request timed out. + * + * @since 15.0.0 + * + * @param bool $timedOut + * + * @return ISearchResult + */ + public function setTimedOut(bool $timedOut): ISearchResult; + +} + diff --git a/lib/public/FullTextSearch/Model/IndexDocument.php b/lib/public/FullTextSearch/Model/IndexDocument.php new file mode 100644 index 00000000000..a73b702e506 --- /dev/null +++ b/lib/public/FullTextSearch/Model/IndexDocument.php @@ -0,0 +1,898 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +use JsonSerializable; + +/** + * Class IndexDocument + * + * This is one of the main class of the FullTextSearch, used as a data transfer + * object. An IndexDocument is created to manage documents around FullTextSearch, + * during an index and during a search. + * The uniqueness of an IndexDocument is made by the Id of the Content Provider + * and the Id of the original document within the Content Provider. + * + * We will call original document the source from which the IndexDocument is + * generated. As an example, an original document can be a file, a mail, ... + * + * @since 15.0.0 + * + * @package OC\FullTextSearch\Model + */ +class IndexDocument implements JsonSerializable { + + + const NOT_ENCODED = 0; + const ENCODED_BASE64 = 1; + + + /** @var string */ + protected $id; + + /** @var string */ + protected $providerId; + + /** @var DocumentAccess */ + protected $access; + + /** @var IIndex */ + protected $index; + + /** @var int */ + protected $modifiedTime = 0; + + /** @var string */ + protected $source = ''; + + /** @var array */ + protected $tags = []; + + /** @var array */ + protected $metaTags = []; + + /** @var array */ + protected $subTags = []; + + /** @var string */ + protected $title = ''; + + /** @var string */ + protected $content = ''; + + /** @var string */ + protected $hash = ''; + + /** @var array */ + protected $parts = []; + + /** @var string */ + protected $link = ''; + + /** @var array */ + protected $more = []; + + /** @var array */ + protected $excerpts = []; + + /** @var string */ + protected $score = ''; + + /** @var array */ + protected $info = []; + + /** @var int */ + protected $contentEncoded; + + + /** + * IndexDocument constructor. + * + * On creation, we assure the uniqueness of the object using the providerId + * and the Id of the original document. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + */ + public function __construct(string $providerId, string $documentId) { + $this->providerId = $providerId; + $this->id = $documentId; + } + + + /** + * Returns the Id of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getId(): string { + return $this->id; + } + + + /** + * Returns the Id of the provider. + * + * @since 15.0.0 + * + * @return string + */ + final public function getProviderId(): string { + return $this->providerId; + } + + + /** + * Set the Index related to the IndexDocument. + * + * @see IIndex + * + * @since 15.0.0 + * + * @param IIndex $index + * + * @return IndexDocument + */ + final public function setIndex(IIndex $index): IndexDocument { + $this->index = $index; + + return $this; + } + + /** + * Get the Index. + * + * @since 15.0.0 + * + * @return IIndex + */ + final public function getIndex(): IIndex { + return $this->index; + } + + + /** + * Set the modified time of the original document. + * + * @since 15.0.0 + * + * @param int $modifiedTime + * + * @return IndexDocument + */ + final public function setModifiedTime(int $modifiedTime): IndexDocument { + $this->modifiedTime = $modifiedTime; + + return $this; + } + + /** + * Get the modified time of the original document. + * + * @since 15.0.0 + * + * @return int + */ + final public function getModifiedTime(): int { + return $this->modifiedTime; + } + + /** + * Check if the original document of the IndexDocument is older than $time. + * + * @since 15.0.0 + * + * @param int $time + * + * @return bool + */ + final public function isOlderThan(int $time): bool { + return ($this->modifiedTime < $time); + } + + + /** + * Set the read rights of the original document using a DocumentAccess. + * + * @see DocumentAccess + * + * @since 15.0.0 + * + * @param DocumentAccess $access + * + * @return $this + */ + final public function setAccess(DocumentAccess $access) { + $this->access = $access; + + return $this; + } + + /** + * Get the DocumentAccess related to the original document. + * + * @since 15.0.0 + * + * @return DocumentAccess + */ + final public function getAccess(): DocumentAccess { + return $this->access; + } + + + /** + * Add a tag to the list. + * + * @since 15.0.0 + * + * @param string $tag + * + * @return IndexDocument + */ + final public function addTag(string $tag): IndexDocument { + $this->tags[] = $tag; + + return $this; + } + + /** + * Set the list of tags assigned to the original document. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return IndexDocument + */ + final public function setTags(array $tags): IndexDocument { + $this->tags = $tags; + + return $this; + } + + /** + * Get the list of tags assigned to the original document. + * + * @since 15.0.0 + * + * @return array + */ + final public function getTags(): array { + return $this->tags; + } + + + /** + * Add a meta tag to the list. + * + * @since 15.0.0 + * + * @param string $tag + * + * @return IndexDocument + */ + final public function addMetaTag(string $tag): IndexDocument { + $this->metaTags[] = $tag; + + return $this; + } + + /** + * Set the list of meta tags assigned to the original document. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return IndexDocument + */ + final public function setMetaTags(array $tags): IndexDocument { + $this->metaTags = $tags; + + return $this; + } + + /** + * Get the list of meta tags assigned to the original document. + * + * @since 15.0.0 + * + * @return array + */ + final public function getMetaTags(): array { + return $this->metaTags; + } + + + /** + * Add a sub tag to the list. + * + * @since 15.0.0 + * + * @param string $sub + * @param string $tag + * + * @return IndexDocument + */ + final public function addSubTag(string $sub, string $tag): IndexDocument { + $this->subTags[$sub] = $tag; + + return $this; + } + + /** + * Set the list of sub tags assigned to the original document. + * + * @since 15.0.0 + * + * @param array $tags + * + * @return IndexDocument + */ + final public function setSubTags(array $tags): IndexDocument { + $this->subTags = $tags; + + return $this; + } + + /** + * Get the list of sub tags assigned to the original document. + * If $formatted is true, the result will be formatted in a one + * dimensional array. + * + * @since 15.0.0 + * + * @param bool $formatted + * + * @return array + */ + final public function getSubTags(bool $formatted = false): array { + if ($formatted === false) { + return $this->subTags; + } + + $subTags = []; + $ak = array_keys($this->subTags); + foreach ($ak as $source) { + $tags = $this->subTags[$source]; + foreach ($tags as $tag) { + $subTags[] = $source . '_' . $tag; + } + } + + return $subTags; + } + + + /** + * Set the source of the original document. + * + * @since 15.0.0 + * + * @param string $source + * + * @return IndexDocument + */ + final public function setSource(string $source): IndexDocument { + $this->source = $source; + + return $this; + } + + /** + * Get the source of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getSource(): string { + return $this->source; + } + + + /** + * Set the title of the original document. + * + * @since 15.0.0 + * + * @param string $title + * + * @return IndexDocument + */ + final public function setTitle(string $title): IndexDocument { + $this->title = $title; + + return $this; + } + + /** + * Get the title of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getTitle(): string { + return $this->title; + } + + + /** + * Set the content of the document. + * $encoded can be NOT_ENCODED or ENCODED_BASE64 if the content is raw or + * encoded in base64. + * + * @since 15.0.0 + * + * @param string $content + * @param int $encoded + * + * @return IndexDocument + */ + final public function setContent(string $content, int $encoded = 0): IndexDocument { + $this->content = $content; + $this->contentEncoded = $encoded; + + return $this; + } + + /** + * Get the content of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getContent(): string { + return $this->content; + } + + /** + * Returns the type of the encoding on the content. + * + * @since 15.0.0 + * + * @return int + */ + final public function isContentEncoded(): int { + return $this->contentEncoded; + } + + /** + * Return the size of the content. + * + * @since 15.0.0 + * + * @return int + */ + final public function getContentSize(): int { + return strlen($this->getContent()); + } + + + /** + * Generate an hash, based on the content of the original document. + * + * @since 15.0.0 + * + * @return IndexDocument + */ + final public function initHash(): IndexDocument { + if ($this->getContent() === '' || is_null($this->getContent())) { + return $this; + } + + $this->hash = hash("md5", $this->getContent()); + + return $this; + } + + /** + * Set the hash of the original document. + * + * @since 15.0.0 + * + * @param string $hash + * + * @return IndexDocument + */ + final public function setHash(string $hash): IndexDocument { + $this->hash = $hash; + + return $this; + } + + /** + * Get the hash of the original document. + * + * @since 15.0.0 + * + * @return string + */ + final public function getHash(): string { + return $this->hash; + } + + + /** + * Add a part, identified by a string, and its content. + * + * It is strongly advised to use alphanumerical chars with no space in the + * $part string. + * + * @since 15.0.0 + * + * @param string $part + * @param string $content + * + * @return IndexDocument + */ + final public function addPart(string $part, string $content): IndexDocument { + $this->parts[$part] = $content; + + return $this; + } + + /** + * Set all parts and their content. + * + * @since 15.0.0 + * + * @param array $parts + * + * @return IndexDocument + */ + final public function setParts(array $parts): IndexDocument { + $this->parts = $parts; + + return $this; + } + + /** + * Get all parts of the IndexDocument. + * + * @since 15.0.0 + * + * @return array + */ + final public function getParts(): array { + return $this->parts; + } + + + /** + * Add a link, usable by the frontend. + * + * @since 15.0.0 + * + * @param string $link + * + * @return IndexDocument + */ + final public function setLink(string $link): IndexDocument { + $this->link = $link; + + return $this; + } + + /** + * Get the link. + * + * @since 15.0.0 + * + * @return string + */ + final public function getLink(): string { + return $this->link; + } + + + /** + * Set more information that couldn't be set using other method. + * + * @since 15.0.0 + * + * @param array $more + * + * @return IndexDocument + */ + final public function setMore(array $more): IndexDocument { + $this->more = $more; + + return $this; + } + + /** + * Get more information. + * + * @since 15.0.0 + * + * @return array + */ + final public function getMore(): array { + return $this->more; + } + + + /** + * Add some excerpt of the content of the original document, usually based + * on the search request. + * + * @since 15.0.0 + * + * @param string $excerpt + * + * @return IndexDocument + */ + final public function addExcerpt(string $excerpt): IndexDocument { + $excerpt = $this->cleanExcerpt($excerpt); + + $this->excerpts[] = $excerpt; + + return $this; + } + + /** + * Set all excerpts of the content of the original document. + * + * @since 15.0.0 + * + * @param array $excerpts + * + * @return IndexDocument + */ + final public function setExcerpts(array $excerpts): IndexDocument { + $excerpts = array_map([$this, 'cleanExcerpt'], $excerpts); + + $this->excerpts = $excerpts; + + return $this; + } + + /** + * Get all excerpts of the content of the original document. + * + * @since 15.0.0 + * + * @return array + */ + final public function getExcerpts(): array { + return $this->excerpts; + } + + /** + * Clean excerpt. + * + * @since 15.0.0 + * + * @param string $excerpt + * + * @return string + */ + final public function cleanExcerpt(string $excerpt): string { + $excerpt = str_replace("\\n", ' ', $excerpt); + $excerpt = str_replace("\\r", ' ', $excerpt); + $excerpt = str_replace("\\t", ' ', $excerpt); + $excerpt = str_replace("\n", ' ', $excerpt); + $excerpt = str_replace("\r", ' ', $excerpt); + $excerpt = str_replace("\t", ' ', $excerpt); + + return $excerpt; + } + + /** + * Set the score to the result assigned to this document during a search + * request. + * + * @since 15.0.0 + * + * @param string $score + * + * @return IndexDocument + */ + final public function setScore(string $score): IndexDocument { + $this->score = $score; + + return $this; + } + + /** + * Get the score. + * + * @since 15.0.0 + * + * @return string + */ + final public function getScore(): string { + return $this->score; + } + + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as string) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IndexDocument before its + * indexing. + * + * @since 15.0.0 + * + * @param string $info + * @param string $value + * + * @return IndexDocument + */ + final public function setInfo(string $info, string $value): IndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (string) + * + * @since 15.0.0 + * + * @param string $info + * @param string $default + * + * @return string + */ + final public function getInfo(string $info, string $default = ''): string { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as array) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IndexDocument before its + * indexing. + * + * @since 15.0.0 + * + * @param string $info + * @param array $value + * + * @return IndexDocument + */ + final public function setInfoArray(string $info, array $value): IndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (array) + * + * @since 15.0.0 + * + * @param string $info + * @param array $default + * + * @return array + */ + final public function getInfoArray(string $info, array $default = []): array { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Get all info. + * + * @since 15.0.0 + * + * @return array + */ + final public function getInfoAll(): array { + + $info = []; + foreach ($this->info as $k => $v) { + if (substr($k, 0, 1) === '_') { + continue; + } + + $info[$k] = $v; + } + + return $info; + } + + + /** + * @since 15.0.0 + * + * On some version of PHP, it is better to force destruct the object. + * And during the index, the number of generated IndexDocument can be + * _huge_. + */ + public function __destruct() { + unset($this->id); + unset($this->providerId); + unset($this->access); + unset($this->modifiedTime); + unset($this->title); + unset($this->content); + unset($this->hash); + unset($this->link); + unset($this->source); + unset($this->tags); + unset($this->metaTags); + unset($this->subTags); + unset($this->more); + unset($this->excerpts); + unset($this->score); + unset($this->info); + unset($this->contentEncoded); + } + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize() { + return [ + 'id' => $this->getId(), + 'providerId' => $this->getProviderId(), + 'access' => $this->access, + 'modifiedTime' => $this->getModifiedTime(), + 'title' => $this->getTitle(), + 'link' => $this->getLink(), + 'index' => $this->index, + 'source' => $this->getSource(), + 'info' => $this->getInfoAll(), + 'hash' => $this->getHash(), + 'contentSize' => $this->getContentSize(), + 'tags' => $this->getTags(), + 'metatags' => $this->getMetaTags(), + 'subtags' => $this->getSubTags(), + 'more' => $this->getMore(), + 'excerpts' => $this->getExcerpts(), + 'score' => $this->getScore() + ]; + } + +} + diff --git a/lib/public/FullTextSearch/Model/SearchOption.php b/lib/public/FullTextSearch/Model/SearchOption.php new file mode 100644 index 00000000000..ae6ad3241b6 --- /dev/null +++ b/lib/public/FullTextSearch/Model/SearchOption.php @@ -0,0 +1,296 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +use JsonSerializable; + + +/** + * @since 15.0.0 + * + * Class SearchOption + * + * @package OCP\FullTextSearch\Model + */ +final class SearchOption implements JsonSerializable { + + + const CHECKBOX = 'checkbox'; + const INPUT = 'input'; + + const INPUT_SMALL = 'small'; + + + /** @var string */ + private $name = ''; + + /** @var string */ + private $title = ''; + + /** @var string */ + private $type = ''; + + /** @var string */ + private $size = ''; + + /** @var string */ + private $placeholder = ''; + + + /** + * * + * + * The array can be empty in case no search options are available. + * The format of the array must be like this: + * + * [ + * 'panel' => [ + * 'options' => [ + * OPTION1, + * OPTION2, + * OPTION3 + * ] + * ], + * 'navigation' => [ + * 'icon' => 'css-class-of-the-icon', + * 'options' => [ + * OPTION1, + * OPTION2, + * OPTION3 + * ] + * ] + * ] + * + * - PANEL contains entries that will be displayed in the app itself, when + * a search is initiated. + * - NAVIGATION contains entries that will be available when using the + * FullTextSearch navigation page + * - OPTION is an element that define each option available to the user. + * + * The format for the options must be like this: + * + * [ + * 'name' => 'name_of_the_option', + * 'title' => 'Name displayed in the panel', + * 'type' => '', + * 'size' => '' (optional), + * 'placeholder' => '' (optional) + * ] + * + * - NAME is the variable name that is sent to the IFullTextSearchProvider + * when a ISearchRequest is requested. (keys in the array returned by the + * ISearchRequest->getOptions()) + * - TYPE can be 'input' or 'checkbox' + * - SIZE is only used in case TYPE='input', default is 'large' but can be + * 'small' + * - PLACEHOLDER is only used in case TYPE='input', default is empty. + */ + + /** + * SearchOption constructor. + * + * Some value can be setduring the creation of the object. + * + * @since 15.0.0 + * + * @param string $name + * @param string $title + * @param string $type + * @param string $size + * @param string $placeholder + */ + public function __construct(string $name = '', string $title = '', string $type = '', string $size = '', string $placeholder = '') { + $this->name = $name; + $this->title = $title; + $this->type = $type; + $this->size = $size; + $this->placeholder = $placeholder; + } + + + /** + * Set the name/key of the option. + * The string should only contains alphanumerical chars and underscore. + * The key can be retrieve when using ISearchRequest::getOption + * + * @see ISearchRequest::getOption + * + * @since 15.0.0 + * + * @param string $name + * + * @return SearchOption + */ + public function setName(string $name): SearchOption { + $this->name = $name; + + return $this; + } + + /** + * Get the name/key of the option. + * + * @since 15.0.0 + * + * @return string + */ + public function getName(): string { + return $this->name; + } + + + /** + * Set the title/display name of the option. + * + * @since 15.0.0 + * + * @param string $title + * + * @return SearchOption + */ + public function setTitle(string $title): SearchOption { + $this->title = $title; + + return $this; + } + + /** + * Get the title of the option. + * + * @since 15.0.0 + * + * @return string + */ + public function getTitle(): string { + return $this->title; + } + + + /** + * Set the type of the option. + * $type can be SearchOption::CHECKBOX or SearchOption::INPUT + * + * @since 15.0.0 + * + * @param string $type + * + * @return SearchOption + */ + public function setType(string $type): SearchOption { + $this->type = $type; + + return $this; + } + + /** + * Get the type of the option. + * + * @since 15.0.0 + * + * @return string + */ + public function getType(): string { + return $this->type; + } + + + /** + * In case of Type is INPUT, set the size of the input field. + * Value can be SearchOption::INPUT_SMALL or not defined. + * + * @since 15.0.0 + * + * @param string $size + * + * @return SearchOption + */ + public function setSize(string $size): SearchOption { + $this->size = $size; + + return $this; + } + + /** + * Get the size of the INPUT. + * + * @since 15.0.0 + * + * @return string + */ + public function getSize(): string { + return $this->size; + } + + + /** + * In case of Type is , set the placeholder to be displayed in the input + * field. + * + * @since 15.0.0 + * + * @param string $placeholder + * + * @return SearchOption + */ + public function setPlaceholder(string $placeholder): SearchOption { + $this->placeholder = $placeholder; + + return $this; + } + + /** + * Get the placeholder. + * + * @since 15.0.0 + * + * @return string + */ + public function getPlaceholder(): string { + return $this->placeholder; + } + + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize(): array { + return [ + 'name' => $this->getName(), + 'title' => $this->getTitle(), + 'type' => $this->getType(), + 'size' => $this->getSize(), + 'placeholder' => $this->getPlaceholder() + ]; + } +} diff --git a/lib/public/FullTextSearch/Model/SearchTemplate.php b/lib/public/FullTextSearch/Model/SearchTemplate.php new file mode 100644 index 00000000000..7d9159190ea --- /dev/null +++ b/lib/public/FullTextSearch/Model/SearchTemplate.php @@ -0,0 +1,258 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018 + * @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\FullTextSearch\Model; + + +use JsonSerializable; +use OCP\FullTextSearch\IFullTextSearchProvider; + + +/** + * Class SearchTemplate + * + * This is a data transfer object that should be created by Content Provider + * when the getSearchTemplate() method is called. + * + * The object will contain templates to be displayed, and the list of the different + * options to be available to the user when he start a new search. + * + * The display of the Options is generated by the FullTextSearch app and Options + * can be displayed in 2 places: + * + * - the navigation page of the app that generate the indexed content. + * (files, bookmarks, deck, mails, ...) + * - the navigation page of the FullTextSearch app. + * + * Both pages will have different Options, and only the first one can integrate + * a specific template. + * + * @see IFullTextSearchProvider::getSearchTemplate + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Model + */ +final class SearchTemplate implements JsonSerializable { + + + /** @var string */ + private $icon = ''; + + /** @var string */ + private $css = ''; + + /** @var string */ + private $template = ''; + + /** @var SearchOption[] */ + private $panelOptions = []; + + /** @var SearchOption[] */ + private $navigationOptions = []; + + + /** + * SearchTemplate constructor. + * + * the class of the icon and the css file to be loaded can be set during the + * creation of the object. + * + * @since 15.0.0 + * + * @param string $icon + * @param string $css + */ + public function __construct(string $icon = '', string $css = '') { + $this->icon = $icon; + $this->css = $css; + } + + + /** + * Set the class of the icon to be displayed in the left panel of the + * FullTextSearch navigation page, in front of the related Content Provider. + * + * @since 15.0.0 + * + * @param string $class + * + * @return SearchTemplate + */ + public function setIcon(string $class): SearchTemplate { + $this->icon = $class; + + return $this; + } + + /** + * Get the class of the icon. + * + * @since 15.0.0 + * + * @return string + */ + public function getIcon(): string { + return $this->icon; + } + + + /** + * Set the path of a CSS file that will be loaded when needed. + * + * @since 15.0.0 + * + * @param string $css + * + * @return SearchTemplate + */ + public function setCss(string $css): SearchTemplate { + $this->css = $css; + + return $this; + } + + /** + * Get the path of the CSS file. + * + * @since 15.0.0 + * + * @return string + */ + public function getCss(): string { + return $this->css; + } + + + /** + * Set the path of the file of a template that the HTML will be displayed + * below the Options. + * This should only be used if your Content Provider needs to set options in + * a way not generated by FullTextSearch + * + * @since 15.0.0 + * + * @param string $template + * + * @return SearchTemplate + */ + public function setTemplate(string $template): SearchTemplate { + $this->template = $template; + + return $this; + } + + /** + * Get the path of the template file. + * + * @since 15.0.0 + * + * @return string + */ + public function getTemplate(): string { + return $this->template; + } + + + /** + * Add an option in the Panel that is displayed when the user start a search + * within the app that generate the content. + * + * @see SearchOption + * + * @since 15.0.0 + * + * @param SearchOption $option + * + * @return SearchTemplate + */ + public function addPanelOption(SearchOption $option): SearchTemplate { + $this->panelOptions[] = $option; + + return $this; + } + + /** + * Get all options to be displayed in the Panel. + * + * @since 15.0.0 + * + * @return SearchOption[] + */ + public function getPanelOptions(): array { + return $this->panelOptions; + } + + + /** + * Add an option in the left panel of the FullTextSearch navigation page. + * + * @see SearchOption + * + * @since 15.0.0 + * + * @param SearchOption $option + * + * @return SearchTemplate + */ + public function addNavigationOption(SearchOption $option): SearchTemplate { + $this->navigationOptions[] = $option; + + return $this; + } + + /** + * Get all options to be displayed in the FullTextSearch navigation page. + * + * @since 15.0.0 + * + * @return array + */ + public function getNavigationOptions(): array { + return $this->navigationOptions; + } + + + /** + * @since 15.0.0 + * + * @return array + */ + public function jsonSerialize(): array { + return [ + 'icon' => $this->getIcon(), + 'css' => $this->getCss(), + 'template' => $this->getTemplate(), + 'panel' => $this->getPanelOptions(), + 'navigation' => $this->getNavigationOptions() + ]; + } +} + diff --git a/lib/public/FullTextSearch/Service/IIndexService.php b/lib/public/FullTextSearch/Service/IIndexService.php new file mode 100644 index 00000000000..c5d1b9b3bcf --- /dev/null +++ b/lib/public/FullTextSearch/Service/IIndexService.php @@ -0,0 +1,99 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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/>. + * + */ + + +namespace OCP\FullTextSearch\Service; + + +use OCP\FullTextSearch\Model\IIndex; + + +/** + * Interface IIndexService + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Service + */ +interface IIndexService { + + + /** + * Retrieve an Index from the database, based on the Id of the Provider + * and the Id of the Document + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * + * @return IIndex + */ + public function getIndex(string $providerId, string $documentId): IIndex; + + + /** + * Update the status of an Index. status is a bit flag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param string $documentId + * @param int $status + * @param bool $reset + */ + public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false); + + + /** + * Update the status of an array of Index. status is a bit flag, setting $reset to + * true will reset the status to the value defined in the parameter. + * + * @since 15.0.0 + * + * @param string $providerId + * @param array $documentIds + * @param int $status + * @param bool $reset + */ + public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false); + + + /** + * Update an array of Index. + * + * @since 15.0.0 + * + * @param array $indexes + */ + public function updateIndexes(array $indexes); + +} + diff --git a/lib/public/FullTextSearch/Service/IProviderService.php b/lib/public/FullTextSearch/Service/IProviderService.php new file mode 100644 index 00000000000..64153c13965 --- /dev/null +++ b/lib/public/FullTextSearch/Service/IProviderService.php @@ -0,0 +1,65 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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/>. + * + */ + + +namespace OCP\FullTextSearch\Service; + + +/** + * Interface IProviderService + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Service + */ +interface IProviderService { + + + /** + * Check if the provider $providerId is already indexed. + * + * @since 15.0.0 + * + * @param string $providerId + * + * @return bool + */ + public function isProviderIndexed(string $providerId); + + + /** + * Add the Javascript API in the navigation page of an app. + * + * @since 15.0.0 + */ + public function addJavascriptAPI(); + + +} + diff --git a/lib/public/FullTextSearch/Service/ISearchService.php b/lib/public/FullTextSearch/Service/ISearchService.php new file mode 100644 index 00000000000..7da38e44f5c --- /dev/null +++ b/lib/public/FullTextSearch/Service/ISearchService.php @@ -0,0 +1,89 @@ +<?php +declare(strict_types=1); + + +/** + * FullTextSearch - Full text search framework for Nextcloud + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange <maxence@artificial-owl.com> + * @copyright 2018, Maxence Lange <maxence@artificial-owl.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/>. + * + */ + + +namespace OCP\FullTextSearch\Service; + + +use OCP\FullTextSearch\Model\ISearchRequest; +use OCP\FullTextSearch\Model\ISearchResult; + + +/** + * Interface ISearchService + * + * @since 15.0.0 + * + * @package OCP\FullTextSearch\Service + */ +interface ISearchService { + + + /** + * generate a search request, based on an array: + * + * $request = + * [ + * 'providers' => (string/array) 'all' + * 'author' => (string) owner of the document. + * 'search' => (string) search string, + * 'size' => (int) number of items to be return + * 'page' => (int) page + * 'parts' => (array) parts of document to search within, + * 'options' = (array) search options, + * 'tags' => (array) tags, + * 'metatags' => (array) metatags, + * 'subtags' => (array) subtags + * ] + * + * 'providers' can be an array of providerIds + * + * @since 15.0.0 + * + * @param array $request + * + * @return ISearchRequest + */ + public function generateSearchRequest(array $request): ISearchRequest; + + + /** + * Search documents + * + * @since 15.0.0 + * + * @param string $userId + * @param ISearchRequest $searchRequest + * + * @return ISearchResult[] + */ + public function search(string $userId, ISearchRequest $searchRequest): array; + +} + diff --git a/lib/public/IAddressBook.php b/lib/public/IAddressBook.php index 67c34c9e8c9..4739e6f0c5b 100644 --- a/lib/public/IAddressBook.php +++ b/lib/public/IAddressBook.php @@ -55,16 +55,18 @@ namespace OCP { /** * @param string $pattern which should match within the $searchProperties * @param array $searchProperties defines the properties within the query pattern should match - * @param array $options - for future use. One should always have options! + * @param array $options Options to define the output format + * - types boolean (since 15.0.0) If set to true, fields that come with a TYPE property will be an array + * example: ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['type => 'HOME', 'value' => 'g@h.i']] * @return array an array of contacts which are arrays of key-value-pairs + * example result: + * [ + * ['id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => 'a@b.c', 'GEO' => '37.386013;-122.082932'], + * ['id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => ['d@e.f', 'g@h.i']] + * ] * @since 5.0.0 */ public function search($pattern, $searchProperties, $options); - // // dummy results - // return array( - // array('id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => 'a@b.c', 'GEO' => '37.386013;-122.082932'), - // array('id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => array('d@e.f', 'g@h.i')), - // ); /** * @param array $properties this array if key-value-pairs defines a contact diff --git a/lib/public/Share/IShare.php b/lib/public/Share/IShare.php index 43543fdad47..dcd5fdecbea 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -418,4 +418,25 @@ interface IShare { * @since 11.0.0 */ public function getNodeCacheEntry(); + + /** + * Sets a shares hide download state + * This is mainly for public shares. It will signal that the share page should + * hide download buttons etc. + * + * @param bool $ro + * @return IShare + * @since 15.0.0 + */ + public function setHideDownload(bool $hide): IShare; + + /** + * Gets a shares hide download state + * This is mainly for public shares. It will signal that the share page should + * hide download buttons etc. + * + * @return bool + * @since 15.0.0 + */ + public function getHideDownload(): bool; } |