Browse Source

Merge pull request #55400 from nextcloud/carl/remove-legacy-search-provider

refactor: Remove legacy search provider
pull/52012/merge
Côme Chilliet 3 weeks ago
committed by GitHub
parent
commit
e739898cc7
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      apps/comments/composer/composer/autoload_classmap.php
  2. 2
      apps/comments/composer/composer/autoload_static.php
  3. 101
      apps/comments/lib/Search/CommentsSearchProvider.php
  4. 99
      apps/comments/lib/Search/LegacyProvider.php
  5. 109
      apps/comments/lib/Search/Result.php
  6. 50
      build/psalm-baseline.xml
  7. 3
      lib/composer/composer/autoload_classmap.php
  8. 3
      lib/composer/composer/autoload_static.php
  9. 55
      lib/public/Search/PagedProvider.php
  10. 78
      lib/public/Search/Provider.php
  11. 64
      lib/public/Search/Result.php

2
apps/comments/composer/composer/autoload_classmap.php

@ -23,6 +23,4 @@ return array(
'OCA\\Comments\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\Search\\CommentsSearchProvider' => $baseDir . '/../lib/Search/CommentsSearchProvider.php',
'OCA\\Comments\\Search\\LegacyProvider' => $baseDir . '/../lib/Search/LegacyProvider.php',
'OCA\\Comments\\Search\\Result' => $baseDir . '/../lib/Search/Result.php',
);

2
apps/comments/composer/composer/autoload_static.php

@ -38,8 +38,6 @@ class ComposerStaticInitComments
'OCA\\Comments\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\Search\\CommentsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/CommentsSearchProvider.php',
'OCA\\Comments\\Search\\LegacyProvider' => __DIR__ . '/..' . '/../lib/Search/LegacyProvider.php',
'OCA\\Comments\\Search\\Result' => __DIR__ . '/..' . '/../lib/Search/Result.php',
);
public static function getInitializer(ClassLoader $loader)

101
apps/comments/lib/Search/CommentsSearchProvider.php

@ -8,6 +8,13 @@ declare(strict_types=1);
*/
namespace OCA\Comments\Search;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsManager;
use OCP\Files\Folder;
use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
@ -16,14 +23,14 @@ use OCP\Search\IProvider;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use function array_map;
class CommentsSearchProvider implements IProvider {
public function __construct(
private IUserManager $userManager,
private IL10N $l10n,
private IURLGenerator $urlGenerator,
private LegacyProvider $legacyProvider,
private ICommentsManager $commentsManager,
private IRootFolder $rootFolder,
) {
}
@ -44,30 +51,76 @@ class CommentsSearchProvider implements IProvider {
}
public function search(IUser $user, ISearchQuery $query): SearchResult {
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
if ($userFolder === null) {
return SearchResult::complete($this->l10n->t('Comments'), []);
}
$result = [];
$numComments = 50;
$offset = 0;
while (count($result) < $numComments) {
$comments = $this->commentsManager->search($query->getTerm(), 'files', '', 'comment', $offset, $numComments);
foreach ($comments as $comment) {
if ($comment->getActorType() !== 'users') {
continue;
}
$displayName = $this->commentsManager->resolveDisplayName('user', $comment->getActorId());
try {
$file = $this->getFileForComment($userFolder, $comment);
$isUser = $this->userManager->userExists($comment->getActorId());
$avatarUrl = $isUser
? $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $comment->getActorId(), 'size' => 42])
: $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => $comment->getActorId(), 'size' => 42]);
$link = $this->urlGenerator->linkToRoute(
'files.View.showFile',
['fileid' => $file->getId()]
);
$result[] = new SearchResultEntry(
$avatarUrl,
$displayName,
$file->getPath(),
$link,
'',
true
);
} catch (NotFoundException|InvalidPathException $e) {
continue;
}
}
if (count($comments) < $numComments) {
// Didn't find more comments when we tried to get, so there are no more comments.
break;
}
$offset += $numComments;
$numComments = 50 - count($result);
}
return SearchResult::complete(
$this->l10n->t('Comments'),
array_map(function (Result $result) {
$path = $result->path;
$isUser = $this->userManager->userExists($result->authorId);
$avatarUrl = $isUser
? $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $result->authorId, 'size' => 42])
: $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => $result->authorId, 'size' => 42]);
$link = $this->urlGenerator->linkToRoute(
'files.View.showFile',
['fileid' => $result->fileId]
);
$searchResultEntry = new SearchResultEntry(
$avatarUrl,
$result->name,
$path,
$link,
'',
true
);
$searchResultEntry->addAttribute('fileId', (string)$result->fileId);
$searchResultEntry->addAttribute('path', $path);
return $searchResultEntry;
}, $this->legacyProvider->search($query->getTerm()))
$result,
);
}
/**
* @throws NotFoundException
*/
protected function getFileForComment(Folder $userFolder, IComment $comment): Node {
$nodes = $userFolder->getById((int)$comment->getObjectId());
if (empty($nodes)) {
throw new NotFoundException('File not found');
}
return array_shift($nodes);
}
}

99
apps/comments/lib/Search/LegacyProvider.php

@ -1,99 +0,0 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Comments\Search;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsManager;
use OCP\Files\Folder;
use OCP\Files\InvalidPathException;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\IUser;
use OCP\IUserSession;
use OCP\Search\Provider;
use OCP\Server;
use function count;
class LegacyProvider extends Provider {
/**
* Search for $query
*
* @param string $query
* @return array An array of OCP\Search\Result's
* @since 7.0.0
*/
public function search($query): array {
$cm = Server::get(ICommentsManager::class);
$us = Server::get(IUserSession::class);
$user = $us->getUser();
if (!$user instanceof IUser) {
return [];
}
$uf = \OC::$server->getUserFolder($user->getUID());
if ($uf === null) {
return [];
}
$result = [];
$numComments = 50;
$offset = 0;
while (count($result) < $numComments) {
/** @var IComment[] $comments */
$comments = $cm->search($query, 'files', '', 'comment', $offset, $numComments);
foreach ($comments as $comment) {
if ($comment->getActorType() !== 'users') {
continue;
}
$displayName = $cm->resolveDisplayName('user', $comment->getActorId());
try {
$file = $this->getFileForComment($uf, $comment);
$result[] = new Result($query,
$comment,
$displayName,
$file->getPath(),
$file->getId(),
);
} catch (NotFoundException|InvalidPathException $e) {
continue;
}
}
if (count($comments) < $numComments) {
// Didn't find more comments when we tried to get, so there are no more comments.
return $result;
}
$offset += $numComments;
$numComments = 50 - count($result);
}
return $result;
}
/**
* @param Folder $userFolder
* @param IComment $comment
* @return Node
* @throws NotFoundException
*/
protected function getFileForComment(Folder $userFolder, IComment $comment): Node {
$nodes = $userFolder->getById((int)$comment->getObjectId());
if (empty($nodes)) {
throw new NotFoundException('File not found');
}
return array_shift($nodes);
}
}

109
apps/comments/lib/Search/Result.php

@ -1,109 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Comments\Search;
use OCP\Comments\IComment;
use OCP\Files\NotFoundException;
use OCP\Search\Result as BaseResult;
/**
* @deprecated 20.0.0
*/
class Result extends BaseResult {
/**
* @deprecated 20.0.0
*/
public $type = 'comment';
/**
* @deprecated 20.0.0
*/
public $comment;
/**
* @deprecated 20.0.0
*/
public $authorId;
/**
* @deprecated 20.0.0
*/
public $path;
/**
* @deprecated 20.0.0
*/
public $fileName;
/**
* @throws NotFoundException
* @deprecated 20.0.0
*/
public function __construct(
string $search,
IComment $comment,
/**
* @deprecated 20.0.0
*/
public string $authorName,
string $path,
/**
* @deprecated 20.0.0
*/
public int $fileId,
) {
parent::__construct(
$comment->getId(),
$comment->getMessage()
/* @todo , [link to file] */
);
$this->comment = $this->getRelevantMessagePart($comment->getMessage(), $search);
$this->authorId = $comment->getActorId();
$this->fileName = basename($path);
$this->path = $this->getVisiblePath($path);
}
/**
* @throws NotFoundException
*/
protected function getVisiblePath(string $path): string {
$segments = explode('/', trim($path, '/'), 3);
if (!isset($segments[2])) {
throw new NotFoundException('Path not inside visible section');
}
return $segments[2];
}
/**
* @throws NotFoundException
*/
protected function getRelevantMessagePart(string $message, string $search): string {
$start = mb_stripos($message, $search);
if ($start === false) {
throw new NotFoundException('Comment section not found');
}
$end = $start + mb_strlen($search);
if ($start <= 25) {
$start = 0;
$prefix = '';
} else {
$start -= 25;
$prefix = '…';
}
if ((mb_strlen($message) - $end) <= 25) {
$end = mb_strlen($message);
$suffix = '';
} else {
$end += 25;
$suffix = '…';
}
return $prefix . mb_substr($message, $start, $end - $start) . $suffix;
}
}

50
build/psalm-baseline.xml

@ -63,56 +63,6 @@
<code><![CDATA[CommentsEvent::EVENT_PRE_UPDATE]]></code>
</DeprecatedConstant>
</file>
<file src="apps/comments/lib/Search/CommentsSearchProvider.php">
<DeprecatedClass>
<code><![CDATA[Result]]></code>
</DeprecatedClass>
<DeprecatedProperty>
<code><![CDATA[$result->authorId]]></code>
<code><![CDATA[$result->authorId]]></code>
<code><![CDATA[$result->authorId]]></code>
<code><![CDATA[$result->name]]></code>
<code><![CDATA[$result->path]]></code>
</DeprecatedProperty>
</file>
<file src="apps/comments/lib/Search/LegacyProvider.php">
<DeprecatedClass>
<code><![CDATA[Provider]]></code>
<code><![CDATA[new Result($query,
$comment,
$displayName,
$file->getPath(),
$file->getId(),
)]]></code>
</DeprecatedClass>
<DeprecatedMethod>
<code><![CDATA[Provider]]></code>
<code><![CDATA[getUserFolder]]></code>
</DeprecatedMethod>
</file>
<file src="apps/comments/lib/Search/Result.php">
<DeprecatedClass>
<code><![CDATA[BaseResult]]></code>
<code><![CDATA[parent::__construct(
$comment->getId(),
$comment->getMessage()
/* @todo , [link to file] */
)]]></code>
</DeprecatedClass>
<DeprecatedMethod>
<code><![CDATA[parent::__construct(
$comment->getId(),
$comment->getMessage()
/* @todo , [link to file] */
)]]></code>
</DeprecatedMethod>
<DeprecatedProperty>
<code><![CDATA[$this->authorId]]></code>
<code><![CDATA[$this->comment]]></code>
<code><![CDATA[$this->fileName]]></code>
<code><![CDATA[$this->path]]></code>
</DeprecatedProperty>
</file>
<file src="apps/dav/appinfo/v1/caldav.php">
<DeprecatedMethod>
<code><![CDATA[exec]]></code>

3
lib/composer/composer/autoload_classmap.php

@ -753,9 +753,6 @@ return array(
'OCP\\Search\\IInAppSearch' => $baseDir . '/lib/public/Search/IInAppSearch.php',
'OCP\\Search\\IProvider' => $baseDir . '/lib/public/Search/IProvider.php',
'OCP\\Search\\ISearchQuery' => $baseDir . '/lib/public/Search/ISearchQuery.php',
'OCP\\Search\\PagedProvider' => $baseDir . '/lib/public/Search/PagedProvider.php',
'OCP\\Search\\Provider' => $baseDir . '/lib/public/Search/Provider.php',
'OCP\\Search\\Result' => $baseDir . '/lib/public/Search/Result.php',
'OCP\\Search\\SearchResult' => $baseDir . '/lib/public/Search/SearchResult.php',
'OCP\\Search\\SearchResultEntry' => $baseDir . '/lib/public/Search/SearchResultEntry.php',
'OCP\\Security\\Bruteforce\\IThrottler' => $baseDir . '/lib/public/Security/Bruteforce/IThrottler.php',

3
lib/composer/composer/autoload_static.php

@ -794,9 +794,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Search\\IInAppSearch' => __DIR__ . '/../../..' . '/lib/public/Search/IInAppSearch.php',
'OCP\\Search\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Search/IProvider.php',
'OCP\\Search\\ISearchQuery' => __DIR__ . '/../../..' . '/lib/public/Search/ISearchQuery.php',
'OCP\\Search\\PagedProvider' => __DIR__ . '/../../..' . '/lib/public/Search/PagedProvider.php',
'OCP\\Search\\Provider' => __DIR__ . '/../../..' . '/lib/public/Search/Provider.php',
'OCP\\Search\\Result' => __DIR__ . '/../../..' . '/lib/public/Search/Result.php',
'OCP\\Search\\SearchResult' => __DIR__ . '/../../..' . '/lib/public/Search/SearchResult.php',
'OCP\\Search\\SearchResultEntry' => __DIR__ . '/../../..' . '/lib/public/Search/SearchResultEntry.php',
'OCP\\Security\\Bruteforce\\IThrottler' => __DIR__ . '/../../..' . '/lib/public/Security/Bruteforce/IThrottler.php',

55
lib/public/Search/PagedProvider.php

@ -1,55 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCP\Search;
/**
* Provides a template for search functionality throughout ownCloud;
* @since 8.0.0
* @deprecated 20.0.0
*/
abstract class PagedProvider extends Provider {
/**
* show all results
* @since 8.0.0
* @deprecated 20.0.0
*/
public const SIZE_ALL = 0;
/**
* Constructor
* @param array $options
* @since 8.0.0
* @deprecated 20.0.0
*/
public function __construct($options) {
parent::__construct($options);
}
/**
* Search for $query
* @param string $query
* @return array An array of OCP\Search\Result's
* @since 8.0.0
* @deprecated 20.0.0
*/
public function search($query) {
// old apps might assume they get all results, so we use SIZE_ALL
return $this->searchPaged($query, 1, self::SIZE_ALL);
}
/**
* Search for $query
* @param string $query
* @param int $page pages start at page 1
* @param int $size 0 = SIZE_ALL
* @return array An array of OCP\Search\Result's
* @since 8.0.0
* @deprecated 20.0.0
*/
abstract public function searchPaged($query, $page, $size);
}

78
lib/public/Search/Provider.php

@ -1,78 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCP\Search;
/**
* Provides a template for search functionality throughout Nextcloud;
* @since 7.0.0
* @deprecated 20.0.0
*/
abstract class Provider {
/**
* @since 8.0.0
* @deprecated 20.0.0
*/
public const OPTION_APPS = 'apps';
/**
* List of options
* @var array
* @since 7.0.0
* @deprecated 20.0.0
*/
protected $options;
/**
* Constructor
* @param array $options as key => value
* @since 7.0.0 - default value for $options was added in 8.0.0
* @deprecated 20.0.0
*/
public function __construct($options = []) {
$this->options = $options;
}
/**
* get a value from the options array or null
* @param string $key
* @return mixed
* @since 8.0.0
* @deprecated 20.0.0
*/
public function getOption($key) {
if (is_array($this->options) && isset($this->options[$key])) {
return $this->options[$key];
} else {
return null;
}
}
/**
* checks if the given apps and the apps this provider has results for intersect
* returns true if the given array is empty (all apps)
* or if this provider does not have a list of apps it provides results for (legacy search providers)
* or if the two above arrays have elements in common (intersect)
* @param string[] $apps
* @return bool
* @since 8.0.0
* @deprecated 20.0.0
*/
public function providesResultsFor(array $apps = []) {
$forApps = $this->getOption(self::OPTION_APPS);
return empty($apps) || empty($forApps) || array_intersect($forApps, $apps);
}
/**
* Search for $query
* @param string $query
* @return array An array of OCP\Search\Result's
* @since 7.0.0
* @deprecated 20.0.0
*/
abstract public function search($query);
}

64
lib/public/Search/Result.php

@ -1,64 +0,0 @@
<?php
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCP\Search;
/**
* The generic result of a search
* @since 7.0.0
* @deprecated 20.0.0
*/
class Result {
/**
* A unique identifier for the result, usually given as the item ID in its
* corresponding application.
* @var string
* @since 7.0.0
* @deprecated 20.0.0
*/
public $id;
/**
* The name of the item returned; this will be displayed in the search
* results.
* @var string
* @since 7.0.0
* @deprecated 20.0.0
*/
public $name;
/**
* URL to the application item.
* @var string
* @since 7.0.0
* @deprecated 20.0.0
*/
public $link;
/**
* The type of search result returned; for consistency, name this the same
* as the class name (e.g. \OC\Search\File -> 'file') in lowercase.
* @var string
* @since 7.0.0
* @deprecated 20.0.0
*/
public $type = 'generic';
/**
* Create a new search result
* @param string $id unique identifier from application: '[app_name]/[item_identifier_in_app]'
* @param string $name displayed text of result
* @param string $link URL to the result within its app
* @since 7.0.0
* @deprecated 20.0.0
*/
public function __construct($id = null, $name = null, $link = null) {
$this->id = $id;
$this->name = $name;
$this->link = $link;
}
}
Loading…
Cancel
Save