@@ -38,113 +38,113 @@ |
||
| 38 | 38 | |
| 39 | 39 | class UnifiedSearchController extends Controller { |
| 40 | 40 | |
| 41 | - /** @var SearchComposer */ |
|
| 42 | - private $composer; |
|
| 43 | - |
|
| 44 | - /** @var IUserSession */ |
|
| 45 | - private $userSession; |
|
| 46 | - |
|
| 47 | - /** @var IRouter */ |
|
| 48 | - private $router; |
|
| 49 | - |
|
| 50 | - public function __construct(IRequest $request, |
|
| 51 | - IUserSession $userSession, |
|
| 52 | - SearchComposer $composer, |
|
| 53 | - IRouter $router) { |
|
| 54 | - parent::__construct('core', $request); |
|
| 55 | - |
|
| 56 | - $this->composer = $composer; |
|
| 57 | - $this->userSession = $userSession; |
|
| 58 | - $this->router = $router; |
|
| 59 | - } |
|
| 60 | - |
|
| 61 | - /** |
|
| 62 | - * @NoAdminRequired |
|
| 63 | - * @NoCSRFRequired |
|
| 64 | - * |
|
| 65 | - * @param string $from the url the user is currently at |
|
| 66 | - * |
|
| 67 | - * @return JSONResponse |
|
| 68 | - */ |
|
| 69 | - public function getProviders(string $from = ''): JSONResponse { |
|
| 70 | - [$route, $parameters] = $this->getRouteInformation($from); |
|
| 71 | - |
|
| 72 | - return new JSONResponse( |
|
| 73 | - $this->composer->getProviders($route, $parameters) |
|
| 74 | - ); |
|
| 75 | - } |
|
| 76 | - |
|
| 77 | - /** |
|
| 78 | - * @NoAdminRequired |
|
| 79 | - * @NoCSRFRequired |
|
| 80 | - * |
|
| 81 | - * @param string $providerId |
|
| 82 | - * @param string $term |
|
| 83 | - * @param int|null $sortOrder |
|
| 84 | - * @param int|null $limit |
|
| 85 | - * @param int|string|null $cursor |
|
| 86 | - * @param string $from |
|
| 87 | - * |
|
| 88 | - * @return JSONResponse |
|
| 89 | - */ |
|
| 90 | - public function search(string $providerId, |
|
| 91 | - string $term = '', |
|
| 92 | - ?int $sortOrder = null, |
|
| 93 | - ?int $limit = null, |
|
| 94 | - $cursor = null, |
|
| 95 | - string $from = ''): JSONResponse { |
|
| 96 | - if (empty(trim($term))) { |
|
| 97 | - return new JSONResponse(null, Http::STATUS_BAD_REQUEST); |
|
| 98 | - } |
|
| 99 | - [$route, $routeParameters] = $this->getRouteInformation($from); |
|
| 100 | - |
|
| 101 | - return new JSONResponse( |
|
| 102 | - $this->composer->search( |
|
| 103 | - $this->userSession->getUser(), |
|
| 104 | - $providerId, |
|
| 105 | - new SearchQuery( |
|
| 106 | - $term, |
|
| 107 | - $sortOrder ?? ISearchQuery::SORT_DATE_DESC, |
|
| 108 | - $limit ?? SearchQuery::LIMIT_DEFAULT, |
|
| 109 | - $cursor, |
|
| 110 | - $route, |
|
| 111 | - $routeParameters |
|
| 112 | - ) |
|
| 113 | - ) |
|
| 114 | - ); |
|
| 115 | - } |
|
| 116 | - |
|
| 117 | - protected function getRouteInformation(string $url): array { |
|
| 118 | - $routeStr = ''; |
|
| 119 | - $parameters = []; |
|
| 120 | - |
|
| 121 | - if ($url !== '') { |
|
| 122 | - $urlParts = parse_url($url); |
|
| 123 | - |
|
| 124 | - try { |
|
| 125 | - $parameters = $this->router->findMatchingRoute($urlParts['path']); |
|
| 126 | - |
|
| 127 | - // contacts.PageController.index => contacts.Page.index |
|
| 128 | - $route = $parameters['caller']; |
|
| 129 | - if (substr($route[1], -10) === 'Controller') { |
|
| 130 | - $route[1] = substr($route[1], 0, -10); |
|
| 131 | - } |
|
| 132 | - $routeStr = implode('.', $route); |
|
| 133 | - |
|
| 134 | - // cleanup |
|
| 135 | - unset($parameters['_route'], $parameters['action'], $parameters['caller']); |
|
| 136 | - } catch (ResourceNotFoundException $exception) { |
|
| 137 | - } |
|
| 138 | - |
|
| 139 | - if (isset($urlParts['query'])) { |
|
| 140 | - parse_str($urlParts['query'], $queryParameters); |
|
| 141 | - $parameters = array_merge($parameters, $queryParameters); |
|
| 142 | - } |
|
| 143 | - } |
|
| 144 | - |
|
| 145 | - return [ |
|
| 146 | - $routeStr, |
|
| 147 | - $parameters, |
|
| 148 | - ]; |
|
| 149 | - } |
|
| 41 | + /** @var SearchComposer */ |
|
| 42 | + private $composer; |
|
| 43 | + |
|
| 44 | + /** @var IUserSession */ |
|
| 45 | + private $userSession; |
|
| 46 | + |
|
| 47 | + /** @var IRouter */ |
|
| 48 | + private $router; |
|
| 49 | + |
|
| 50 | + public function __construct(IRequest $request, |
|
| 51 | + IUserSession $userSession, |
|
| 52 | + SearchComposer $composer, |
|
| 53 | + IRouter $router) { |
|
| 54 | + parent::__construct('core', $request); |
|
| 55 | + |
|
| 56 | + $this->composer = $composer; |
|
| 57 | + $this->userSession = $userSession; |
|
| 58 | + $this->router = $router; |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + /** |
|
| 62 | + * @NoAdminRequired |
|
| 63 | + * @NoCSRFRequired |
|
| 64 | + * |
|
| 65 | + * @param string $from the url the user is currently at |
|
| 66 | + * |
|
| 67 | + * @return JSONResponse |
|
| 68 | + */ |
|
| 69 | + public function getProviders(string $from = ''): JSONResponse { |
|
| 70 | + [$route, $parameters] = $this->getRouteInformation($from); |
|
| 71 | + |
|
| 72 | + return new JSONResponse( |
|
| 73 | + $this->composer->getProviders($route, $parameters) |
|
| 74 | + ); |
|
| 75 | + } |
|
| 76 | + |
|
| 77 | + /** |
|
| 78 | + * @NoAdminRequired |
|
| 79 | + * @NoCSRFRequired |
|
| 80 | + * |
|
| 81 | + * @param string $providerId |
|
| 82 | + * @param string $term |
|
| 83 | + * @param int|null $sortOrder |
|
| 84 | + * @param int|null $limit |
|
| 85 | + * @param int|string|null $cursor |
|
| 86 | + * @param string $from |
|
| 87 | + * |
|
| 88 | + * @return JSONResponse |
|
| 89 | + */ |
|
| 90 | + public function search(string $providerId, |
|
| 91 | + string $term = '', |
|
| 92 | + ?int $sortOrder = null, |
|
| 93 | + ?int $limit = null, |
|
| 94 | + $cursor = null, |
|
| 95 | + string $from = ''): JSONResponse { |
|
| 96 | + if (empty(trim($term))) { |
|
| 97 | + return new JSONResponse(null, Http::STATUS_BAD_REQUEST); |
|
| 98 | + } |
|
| 99 | + [$route, $routeParameters] = $this->getRouteInformation($from); |
|
| 100 | + |
|
| 101 | + return new JSONResponse( |
|
| 102 | + $this->composer->search( |
|
| 103 | + $this->userSession->getUser(), |
|
| 104 | + $providerId, |
|
| 105 | + new SearchQuery( |
|
| 106 | + $term, |
|
| 107 | + $sortOrder ?? ISearchQuery::SORT_DATE_DESC, |
|
| 108 | + $limit ?? SearchQuery::LIMIT_DEFAULT, |
|
| 109 | + $cursor, |
|
| 110 | + $route, |
|
| 111 | + $routeParameters |
|
| 112 | + ) |
|
| 113 | + ) |
|
| 114 | + ); |
|
| 115 | + } |
|
| 116 | + |
|
| 117 | + protected function getRouteInformation(string $url): array { |
|
| 118 | + $routeStr = ''; |
|
| 119 | + $parameters = []; |
|
| 120 | + |
|
| 121 | + if ($url !== '') { |
|
| 122 | + $urlParts = parse_url($url); |
|
| 123 | + |
|
| 124 | + try { |
|
| 125 | + $parameters = $this->router->findMatchingRoute($urlParts['path']); |
|
| 126 | + |
|
| 127 | + // contacts.PageController.index => contacts.Page.index |
|
| 128 | + $route = $parameters['caller']; |
|
| 129 | + if (substr($route[1], -10) === 'Controller') { |
|
| 130 | + $route[1] = substr($route[1], 0, -10); |
|
| 131 | + } |
|
| 132 | + $routeStr = implode('.', $route); |
|
| 133 | + |
|
| 134 | + // cleanup |
|
| 135 | + unset($parameters['_route'], $parameters['action'], $parameters['caller']); |
|
| 136 | + } catch (ResourceNotFoundException $exception) { |
|
| 137 | + } |
|
| 138 | + |
|
| 139 | + if (isset($urlParts['query'])) { |
|
| 140 | + parse_str($urlParts['query'], $queryParameters); |
|
| 141 | + $parameters = array_merge($parameters, $queryParameters); |
|
| 142 | + } |
|
| 143 | + } |
|
| 144 | + |
|
| 145 | + return [ |
|
| 146 | + $routeStr, |
|
| 147 | + $parameters, |
|
| 148 | + ]; |
|
| 149 | + } |
|
| 150 | 150 | } |
@@ -38,89 +38,89 @@ |
||
| 38 | 38 | |
| 39 | 39 | class FilesSearchProvider implements IProvider { |
| 40 | 40 | |
| 41 | - /** @var File */ |
|
| 42 | - private $fileSearch; |
|
| 43 | - |
|
| 44 | - /** @var IL10N */ |
|
| 45 | - private $l10n; |
|
| 46 | - |
|
| 47 | - /** @var IURLGenerator */ |
|
| 48 | - private $urlGenerator; |
|
| 49 | - |
|
| 50 | - /** @var IMimeTypeDetector */ |
|
| 51 | - private $mimeTypeDetector; |
|
| 52 | - |
|
| 53 | - public function __construct(File $fileSearch, |
|
| 54 | - IL10N $l10n, |
|
| 55 | - IURLGenerator $urlGenerator, |
|
| 56 | - IMimeTypeDetector $mimeTypeDetector) { |
|
| 57 | - $this->l10n = $l10n; |
|
| 58 | - $this->fileSearch = $fileSearch; |
|
| 59 | - $this->urlGenerator = $urlGenerator; |
|
| 60 | - $this->mimeTypeDetector = $mimeTypeDetector; |
|
| 61 | - } |
|
| 62 | - |
|
| 63 | - /** |
|
| 64 | - * @inheritDoc |
|
| 65 | - */ |
|
| 66 | - public function getId(): string { |
|
| 67 | - return 'files'; |
|
| 68 | - } |
|
| 69 | - |
|
| 70 | - /** |
|
| 71 | - * @inheritDoc |
|
| 72 | - */ |
|
| 73 | - public function getName(): string { |
|
| 74 | - return $this->l10n->t('Files'); |
|
| 75 | - } |
|
| 76 | - |
|
| 77 | - /** |
|
| 78 | - * @inheritDoc |
|
| 79 | - */ |
|
| 80 | - public function getOrder(string $route, array $routeParameters): int { |
|
| 81 | - if ($route === 'files.View.index') { |
|
| 82 | - // Before comments |
|
| 83 | - return -5; |
|
| 84 | - } |
|
| 85 | - return 5; |
|
| 86 | - } |
|
| 87 | - |
|
| 88 | - /** |
|
| 89 | - * @inheritDoc |
|
| 90 | - */ |
|
| 91 | - public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 92 | - return SearchResult::complete( |
|
| 93 | - $this->l10n->t('Files'), |
|
| 94 | - array_map(function (FileResult $result) { |
|
| 95 | - // Generate thumbnail url |
|
| 96 | - $thumbnailUrl = $result->has_preview |
|
| 97 | - ? $this->urlGenerator->linkToRoute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->id]) |
|
| 98 | - : ''; |
|
| 99 | - |
|
| 100 | - return new SearchResultEntry( |
|
| 101 | - $thumbnailUrl, |
|
| 102 | - $result->name, |
|
| 103 | - $this->formatSubline($result), |
|
| 104 | - $result->link, |
|
| 105 | - $result->type === 'folder' ? 'icon-folder' : $this->mimeTypeDetector->mimeTypeIcon($result->mime_type) |
|
| 106 | - ); |
|
| 107 | - }, $this->fileSearch->search($query->getTerm())) |
|
| 108 | - ); |
|
| 109 | - } |
|
| 110 | - |
|
| 111 | - /** |
|
| 112 | - * Format subline for files |
|
| 113 | - * |
|
| 114 | - * @param FileResult $result |
|
| 115 | - * @return string |
|
| 116 | - */ |
|
| 117 | - private function formatSubline($result): string { |
|
| 118 | - // Do not show the location if the file is in root |
|
| 119 | - if ($result->path === '/' . $result->name) { |
|
| 120 | - return ''; |
|
| 121 | - } |
|
| 122 | - |
|
| 123 | - $path = ltrim(dirname($result->path), '/'); |
|
| 124 | - return $this->l10n->t('in %s', [$path]); |
|
| 125 | - } |
|
| 41 | + /** @var File */ |
|
| 42 | + private $fileSearch; |
|
| 43 | + |
|
| 44 | + /** @var IL10N */ |
|
| 45 | + private $l10n; |
|
| 46 | + |
|
| 47 | + /** @var IURLGenerator */ |
|
| 48 | + private $urlGenerator; |
|
| 49 | + |
|
| 50 | + /** @var IMimeTypeDetector */ |
|
| 51 | + private $mimeTypeDetector; |
|
| 52 | + |
|
| 53 | + public function __construct(File $fileSearch, |
|
| 54 | + IL10N $l10n, |
|
| 55 | + IURLGenerator $urlGenerator, |
|
| 56 | + IMimeTypeDetector $mimeTypeDetector) { |
|
| 57 | + $this->l10n = $l10n; |
|
| 58 | + $this->fileSearch = $fileSearch; |
|
| 59 | + $this->urlGenerator = $urlGenerator; |
|
| 60 | + $this->mimeTypeDetector = $mimeTypeDetector; |
|
| 61 | + } |
|
| 62 | + |
|
| 63 | + /** |
|
| 64 | + * @inheritDoc |
|
| 65 | + */ |
|
| 66 | + public function getId(): string { |
|
| 67 | + return 'files'; |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | + /** |
|
| 71 | + * @inheritDoc |
|
| 72 | + */ |
|
| 73 | + public function getName(): string { |
|
| 74 | + return $this->l10n->t('Files'); |
|
| 75 | + } |
|
| 76 | + |
|
| 77 | + /** |
|
| 78 | + * @inheritDoc |
|
| 79 | + */ |
|
| 80 | + public function getOrder(string $route, array $routeParameters): int { |
|
| 81 | + if ($route === 'files.View.index') { |
|
| 82 | + // Before comments |
|
| 83 | + return -5; |
|
| 84 | + } |
|
| 85 | + return 5; |
|
| 86 | + } |
|
| 87 | + |
|
| 88 | + /** |
|
| 89 | + * @inheritDoc |
|
| 90 | + */ |
|
| 91 | + public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 92 | + return SearchResult::complete( |
|
| 93 | + $this->l10n->t('Files'), |
|
| 94 | + array_map(function (FileResult $result) { |
|
| 95 | + // Generate thumbnail url |
|
| 96 | + $thumbnailUrl = $result->has_preview |
|
| 97 | + ? $this->urlGenerator->linkToRoute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->id]) |
|
| 98 | + : ''; |
|
| 99 | + |
|
| 100 | + return new SearchResultEntry( |
|
| 101 | + $thumbnailUrl, |
|
| 102 | + $result->name, |
|
| 103 | + $this->formatSubline($result), |
|
| 104 | + $result->link, |
|
| 105 | + $result->type === 'folder' ? 'icon-folder' : $this->mimeTypeDetector->mimeTypeIcon($result->mime_type) |
|
| 106 | + ); |
|
| 107 | + }, $this->fileSearch->search($query->getTerm())) |
|
| 108 | + ); |
|
| 109 | + } |
|
| 110 | + |
|
| 111 | + /** |
|
| 112 | + * Format subline for files |
|
| 113 | + * |
|
| 114 | + * @param FileResult $result |
|
| 115 | + * @return string |
|
| 116 | + */ |
|
| 117 | + private function formatSubline($result): string { |
|
| 118 | + // Do not show the location if the file is in root |
|
| 119 | + if ($result->path === '/' . $result->name) { |
|
| 120 | + return ''; |
|
| 121 | + } |
|
| 122 | + |
|
| 123 | + $path = ltrim(dirname($result->path), '/'); |
|
| 124 | + return $this->l10n->t('in %s', [$path]); |
|
| 125 | + } |
|
| 126 | 126 | } |
@@ -40,203 +40,203 @@ |
||
| 40 | 40 | */ |
| 41 | 41 | class EventsSearchProvider extends ACalendarSearchProvider { |
| 42 | 42 | |
| 43 | - /** |
|
| 44 | - * @var string[] |
|
| 45 | - */ |
|
| 46 | - private static $searchProperties = [ |
|
| 47 | - 'SUMMARY', |
|
| 48 | - 'LOCATION', |
|
| 49 | - 'DESCRIPTION', |
|
| 50 | - 'ATTENDEE', |
|
| 51 | - 'ORGANIZER', |
|
| 52 | - 'CATEGORIES', |
|
| 53 | - ]; |
|
| 54 | - |
|
| 55 | - /** |
|
| 56 | - * @var string[] |
|
| 57 | - */ |
|
| 58 | - private static $searchParameters = [ |
|
| 59 | - 'ATTENDEE' => ['CN'], |
|
| 60 | - 'ORGANIZER' => ['CN'], |
|
| 61 | - ]; |
|
| 62 | - |
|
| 63 | - /** |
|
| 64 | - * @var string |
|
| 65 | - */ |
|
| 66 | - private static $componentType = 'VEVENT'; |
|
| 67 | - |
|
| 68 | - /** |
|
| 69 | - * @inheritDoc |
|
| 70 | - */ |
|
| 71 | - public function getId(): string { |
|
| 72 | - return 'calendar-dav'; |
|
| 73 | - } |
|
| 74 | - |
|
| 75 | - /** |
|
| 76 | - * @inheritDoc |
|
| 77 | - */ |
|
| 78 | - public function getName(): string { |
|
| 79 | - return $this->l10n->t('Events'); |
|
| 80 | - } |
|
| 81 | - |
|
| 82 | - /** |
|
| 83 | - * @inheritDoc |
|
| 84 | - */ |
|
| 85 | - public function getOrder(string $route, array $routeParameters): int { |
|
| 86 | - if ($route === 'calendar.View.index') { |
|
| 87 | - return -1; |
|
| 88 | - } |
|
| 89 | - return 10; |
|
| 90 | - } |
|
| 91 | - |
|
| 92 | - /** |
|
| 93 | - * @inheritDoc |
|
| 94 | - */ |
|
| 95 | - public function search(IUser $user, |
|
| 96 | - ISearchQuery $query): SearchResult { |
|
| 97 | - if (!$this->appManager->isEnabledForUser('calendar', $user)) { |
|
| 98 | - return SearchResult::complete($this->getName(), []); |
|
| 99 | - } |
|
| 100 | - |
|
| 101 | - $principalUri = 'principals/users/' . $user->getUID(); |
|
| 102 | - $calendarsById = $this->getSortedCalendars($principalUri); |
|
| 103 | - $subscriptionsById = $this->getSortedSubscriptions($principalUri); |
|
| 104 | - |
|
| 105 | - $searchResults = $this->backend->searchPrincipalUri( |
|
| 106 | - $principalUri, |
|
| 107 | - $query->getTerm(), |
|
| 108 | - [self::$componentType], |
|
| 109 | - self::$searchProperties, |
|
| 110 | - self::$searchParameters, |
|
| 111 | - [ |
|
| 112 | - 'limit' => $query->getLimit(), |
|
| 113 | - 'offset' => $query->getCursor(), |
|
| 114 | - ] |
|
| 115 | - ); |
|
| 116 | - $formattedResults = \array_map(function (array $eventRow) use ($calendarsById, $subscriptionsById):SearchResultEntry { |
|
| 117 | - $component = $this->getPrimaryComponent($eventRow['calendardata'], self::$componentType); |
|
| 118 | - $title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled event')); |
|
| 119 | - $subline = $this->generateSubline($component); |
|
| 120 | - |
|
| 121 | - if ($eventRow['calendartype'] === CalDavBackend::CALENDAR_TYPE_CALENDAR) { |
|
| 122 | - $calendar = $calendarsById[$eventRow['calendarid']]; |
|
| 123 | - } else { |
|
| 124 | - $calendar = $subscriptionsById[$eventRow['calendarid']]; |
|
| 125 | - } |
|
| 126 | - $resourceUrl = $this->getDeepLinkToCalendarApp($calendar['principaluri'], $calendar['uri'], $eventRow['uri']); |
|
| 127 | - |
|
| 128 | - return new SearchResultEntry('', $title, $subline, $resourceUrl, 'icon-calendar-dark', false); |
|
| 129 | - }, $searchResults); |
|
| 130 | - |
|
| 131 | - return SearchResult::paginated( |
|
| 132 | - $this->getName(), |
|
| 133 | - $formattedResults, |
|
| 134 | - $query->getCursor() + count($formattedResults) |
|
| 135 | - ); |
|
| 136 | - } |
|
| 137 | - |
|
| 138 | - /** |
|
| 139 | - * @param string $principalUri |
|
| 140 | - * @param string $calendarUri |
|
| 141 | - * @param string $calendarObjectUri |
|
| 142 | - * @return string |
|
| 143 | - */ |
|
| 144 | - protected function getDeepLinkToCalendarApp(string $principalUri, |
|
| 145 | - string $calendarUri, |
|
| 146 | - string $calendarObjectUri): string { |
|
| 147 | - $davUrl = $this->getDavUrlForCalendarObject($principalUri, $calendarUri, $calendarObjectUri); |
|
| 148 | - // This route will automatically figure out what recurrence-id to open |
|
| 149 | - return $this->urlGenerator->getAbsoluteURL( |
|
| 150 | - $this->urlGenerator->linkToRoute('calendar.view.index') |
|
| 151 | - . 'edit/' |
|
| 152 | - . base64_encode($davUrl) |
|
| 153 | - ); |
|
| 154 | - } |
|
| 155 | - |
|
| 156 | - /** |
|
| 157 | - * @param string $principalUri |
|
| 158 | - * @param string $calendarUri |
|
| 159 | - * @param string $calendarObjectUri |
|
| 160 | - * @return string |
|
| 161 | - */ |
|
| 162 | - protected function getDavUrlForCalendarObject(string $principalUri, |
|
| 163 | - string $calendarUri, |
|
| 164 | - string $calendarObjectUri): string { |
|
| 165 | - [,, $principalId] = explode('/', $principalUri, 3); |
|
| 166 | - |
|
| 167 | - return $this->urlGenerator->linkTo('', 'remote.php') . '/dav/calendars/' |
|
| 168 | - . $principalId . '/' |
|
| 169 | - . $calendarUri . '/' |
|
| 170 | - . $calendarObjectUri; |
|
| 171 | - } |
|
| 172 | - |
|
| 173 | - /** |
|
| 174 | - * @param Component $eventComponent |
|
| 175 | - * @return string |
|
| 176 | - */ |
|
| 177 | - protected function generateSubline(Component $eventComponent): string { |
|
| 178 | - $dtStart = $eventComponent->DTSTART; |
|
| 179 | - $dtEnd = $this->getDTEndForEvent($eventComponent); |
|
| 180 | - $isAllDayEvent = $dtStart instanceof Property\ICalendar\Date; |
|
| 181 | - $startDateTime = new \DateTime($dtStart->getDateTime()->format(\DateTime::ATOM)); |
|
| 182 | - $endDateTime = new \DateTime($dtEnd->getDateTime()->format(\DateTime::ATOM)); |
|
| 183 | - |
|
| 184 | - if ($isAllDayEvent) { |
|
| 185 | - $endDateTime->modify('-1 day'); |
|
| 186 | - if ($this->isDayEqual($startDateTime, $endDateTime)) { |
|
| 187 | - return $this->l10n->l('date', $startDateTime, ['width' => 'medium']); |
|
| 188 | - } |
|
| 189 | - |
|
| 190 | - $formattedStart = $this->l10n->l('date', $startDateTime, ['width' => 'medium']); |
|
| 191 | - $formattedEnd = $this->l10n->l('date', $endDateTime, ['width' => 'medium']); |
|
| 192 | - return "$formattedStart - $formattedEnd"; |
|
| 193 | - } |
|
| 194 | - |
|
| 195 | - $formattedStartDate = $this->l10n->l('date', $startDateTime, ['width' => 'medium']); |
|
| 196 | - $formattedEndDate = $this->l10n->l('date', $endDateTime, ['width' => 'medium']); |
|
| 197 | - $formattedStartTime = $this->l10n->l('time', $startDateTime, ['width' => 'short']); |
|
| 198 | - $formattedEndTime = $this->l10n->l('time', $endDateTime, ['width' => 'short']); |
|
| 199 | - |
|
| 200 | - if ($this->isDayEqual($startDateTime, $endDateTime)) { |
|
| 201 | - return "$formattedStartDate $formattedStartTime - $formattedEndTime"; |
|
| 202 | - } |
|
| 203 | - |
|
| 204 | - return "$formattedStartDate $formattedStartTime - $formattedEndDate $formattedEndTime"; |
|
| 205 | - } |
|
| 206 | - |
|
| 207 | - /** |
|
| 208 | - * @param Component $eventComponent |
|
| 209 | - * @return Property |
|
| 210 | - */ |
|
| 211 | - protected function getDTEndForEvent(Component $eventComponent):Property { |
|
| 212 | - if (isset($eventComponent->DTEND)) { |
|
| 213 | - $end = $eventComponent->DTEND; |
|
| 214 | - } elseif (isset($eventComponent->DURATION)) { |
|
| 215 | - $isFloating = $eventComponent->DTSTART->isFloating(); |
|
| 216 | - $end = clone $eventComponent->DTSTART; |
|
| 217 | - $endDateTime = $end->getDateTime(); |
|
| 218 | - $endDateTime = $endDateTime->add(DateTimeParser::parse($eventComponent->DURATION->getValue())); |
|
| 219 | - $end->setDateTime($endDateTime, $isFloating); |
|
| 220 | - } elseif (!$eventComponent->DTSTART->hasTime()) { |
|
| 221 | - $isFloating = $eventComponent->DTSTART->isFloating(); |
|
| 222 | - $end = clone $eventComponent->DTSTART; |
|
| 223 | - $endDateTime = $end->getDateTime(); |
|
| 224 | - $endDateTime = $endDateTime->modify('+1 day'); |
|
| 225 | - $end->setDateTime($endDateTime, $isFloating); |
|
| 226 | - } else { |
|
| 227 | - $end = clone $eventComponent->DTSTART; |
|
| 228 | - } |
|
| 229 | - |
|
| 230 | - return $end; |
|
| 231 | - } |
|
| 232 | - |
|
| 233 | - /** |
|
| 234 | - * @param \DateTime $dtStart |
|
| 235 | - * @param \DateTime $dtEnd |
|
| 236 | - * @return bool |
|
| 237 | - */ |
|
| 238 | - protected function isDayEqual(\DateTime $dtStart, |
|
| 239 | - \DateTime $dtEnd) { |
|
| 240 | - return $dtStart->format('Y-m-d') === $dtEnd->format('Y-m-d'); |
|
| 241 | - } |
|
| 43 | + /** |
|
| 44 | + * @var string[] |
|
| 45 | + */ |
|
| 46 | + private static $searchProperties = [ |
|
| 47 | + 'SUMMARY', |
|
| 48 | + 'LOCATION', |
|
| 49 | + 'DESCRIPTION', |
|
| 50 | + 'ATTENDEE', |
|
| 51 | + 'ORGANIZER', |
|
| 52 | + 'CATEGORIES', |
|
| 53 | + ]; |
|
| 54 | + |
|
| 55 | + /** |
|
| 56 | + * @var string[] |
|
| 57 | + */ |
|
| 58 | + private static $searchParameters = [ |
|
| 59 | + 'ATTENDEE' => ['CN'], |
|
| 60 | + 'ORGANIZER' => ['CN'], |
|
| 61 | + ]; |
|
| 62 | + |
|
| 63 | + /** |
|
| 64 | + * @var string |
|
| 65 | + */ |
|
| 66 | + private static $componentType = 'VEVENT'; |
|
| 67 | + |
|
| 68 | + /** |
|
| 69 | + * @inheritDoc |
|
| 70 | + */ |
|
| 71 | + public function getId(): string { |
|
| 72 | + return 'calendar-dav'; |
|
| 73 | + } |
|
| 74 | + |
|
| 75 | + /** |
|
| 76 | + * @inheritDoc |
|
| 77 | + */ |
|
| 78 | + public function getName(): string { |
|
| 79 | + return $this->l10n->t('Events'); |
|
| 80 | + } |
|
| 81 | + |
|
| 82 | + /** |
|
| 83 | + * @inheritDoc |
|
| 84 | + */ |
|
| 85 | + public function getOrder(string $route, array $routeParameters): int { |
|
| 86 | + if ($route === 'calendar.View.index') { |
|
| 87 | + return -1; |
|
| 88 | + } |
|
| 89 | + return 10; |
|
| 90 | + } |
|
| 91 | + |
|
| 92 | + /** |
|
| 93 | + * @inheritDoc |
|
| 94 | + */ |
|
| 95 | + public function search(IUser $user, |
|
| 96 | + ISearchQuery $query): SearchResult { |
|
| 97 | + if (!$this->appManager->isEnabledForUser('calendar', $user)) { |
|
| 98 | + return SearchResult::complete($this->getName(), []); |
|
| 99 | + } |
|
| 100 | + |
|
| 101 | + $principalUri = 'principals/users/' . $user->getUID(); |
|
| 102 | + $calendarsById = $this->getSortedCalendars($principalUri); |
|
| 103 | + $subscriptionsById = $this->getSortedSubscriptions($principalUri); |
|
| 104 | + |
|
| 105 | + $searchResults = $this->backend->searchPrincipalUri( |
|
| 106 | + $principalUri, |
|
| 107 | + $query->getTerm(), |
|
| 108 | + [self::$componentType], |
|
| 109 | + self::$searchProperties, |
|
| 110 | + self::$searchParameters, |
|
| 111 | + [ |
|
| 112 | + 'limit' => $query->getLimit(), |
|
| 113 | + 'offset' => $query->getCursor(), |
|
| 114 | + ] |
|
| 115 | + ); |
|
| 116 | + $formattedResults = \array_map(function (array $eventRow) use ($calendarsById, $subscriptionsById):SearchResultEntry { |
|
| 117 | + $component = $this->getPrimaryComponent($eventRow['calendardata'], self::$componentType); |
|
| 118 | + $title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled event')); |
|
| 119 | + $subline = $this->generateSubline($component); |
|
| 120 | + |
|
| 121 | + if ($eventRow['calendartype'] === CalDavBackend::CALENDAR_TYPE_CALENDAR) { |
|
| 122 | + $calendar = $calendarsById[$eventRow['calendarid']]; |
|
| 123 | + } else { |
|
| 124 | + $calendar = $subscriptionsById[$eventRow['calendarid']]; |
|
| 125 | + } |
|
| 126 | + $resourceUrl = $this->getDeepLinkToCalendarApp($calendar['principaluri'], $calendar['uri'], $eventRow['uri']); |
|
| 127 | + |
|
| 128 | + return new SearchResultEntry('', $title, $subline, $resourceUrl, 'icon-calendar-dark', false); |
|
| 129 | + }, $searchResults); |
|
| 130 | + |
|
| 131 | + return SearchResult::paginated( |
|
| 132 | + $this->getName(), |
|
| 133 | + $formattedResults, |
|
| 134 | + $query->getCursor() + count($formattedResults) |
|
| 135 | + ); |
|
| 136 | + } |
|
| 137 | + |
|
| 138 | + /** |
|
| 139 | + * @param string $principalUri |
|
| 140 | + * @param string $calendarUri |
|
| 141 | + * @param string $calendarObjectUri |
|
| 142 | + * @return string |
|
| 143 | + */ |
|
| 144 | + protected function getDeepLinkToCalendarApp(string $principalUri, |
|
| 145 | + string $calendarUri, |
|
| 146 | + string $calendarObjectUri): string { |
|
| 147 | + $davUrl = $this->getDavUrlForCalendarObject($principalUri, $calendarUri, $calendarObjectUri); |
|
| 148 | + // This route will automatically figure out what recurrence-id to open |
|
| 149 | + return $this->urlGenerator->getAbsoluteURL( |
|
| 150 | + $this->urlGenerator->linkToRoute('calendar.view.index') |
|
| 151 | + . 'edit/' |
|
| 152 | + . base64_encode($davUrl) |
|
| 153 | + ); |
|
| 154 | + } |
|
| 155 | + |
|
| 156 | + /** |
|
| 157 | + * @param string $principalUri |
|
| 158 | + * @param string $calendarUri |
|
| 159 | + * @param string $calendarObjectUri |
|
| 160 | + * @return string |
|
| 161 | + */ |
|
| 162 | + protected function getDavUrlForCalendarObject(string $principalUri, |
|
| 163 | + string $calendarUri, |
|
| 164 | + string $calendarObjectUri): string { |
|
| 165 | + [,, $principalId] = explode('/', $principalUri, 3); |
|
| 166 | + |
|
| 167 | + return $this->urlGenerator->linkTo('', 'remote.php') . '/dav/calendars/' |
|
| 168 | + . $principalId . '/' |
|
| 169 | + . $calendarUri . '/' |
|
| 170 | + . $calendarObjectUri; |
|
| 171 | + } |
|
| 172 | + |
|
| 173 | + /** |
|
| 174 | + * @param Component $eventComponent |
|
| 175 | + * @return string |
|
| 176 | + */ |
|
| 177 | + protected function generateSubline(Component $eventComponent): string { |
|
| 178 | + $dtStart = $eventComponent->DTSTART; |
|
| 179 | + $dtEnd = $this->getDTEndForEvent($eventComponent); |
|
| 180 | + $isAllDayEvent = $dtStart instanceof Property\ICalendar\Date; |
|
| 181 | + $startDateTime = new \DateTime($dtStart->getDateTime()->format(\DateTime::ATOM)); |
|
| 182 | + $endDateTime = new \DateTime($dtEnd->getDateTime()->format(\DateTime::ATOM)); |
|
| 183 | + |
|
| 184 | + if ($isAllDayEvent) { |
|
| 185 | + $endDateTime->modify('-1 day'); |
|
| 186 | + if ($this->isDayEqual($startDateTime, $endDateTime)) { |
|
| 187 | + return $this->l10n->l('date', $startDateTime, ['width' => 'medium']); |
|
| 188 | + } |
|
| 189 | + |
|
| 190 | + $formattedStart = $this->l10n->l('date', $startDateTime, ['width' => 'medium']); |
|
| 191 | + $formattedEnd = $this->l10n->l('date', $endDateTime, ['width' => 'medium']); |
|
| 192 | + return "$formattedStart - $formattedEnd"; |
|
| 193 | + } |
|
| 194 | + |
|
| 195 | + $formattedStartDate = $this->l10n->l('date', $startDateTime, ['width' => 'medium']); |
|
| 196 | + $formattedEndDate = $this->l10n->l('date', $endDateTime, ['width' => 'medium']); |
|
| 197 | + $formattedStartTime = $this->l10n->l('time', $startDateTime, ['width' => 'short']); |
|
| 198 | + $formattedEndTime = $this->l10n->l('time', $endDateTime, ['width' => 'short']); |
|
| 199 | + |
|
| 200 | + if ($this->isDayEqual($startDateTime, $endDateTime)) { |
|
| 201 | + return "$formattedStartDate $formattedStartTime - $formattedEndTime"; |
|
| 202 | + } |
|
| 203 | + |
|
| 204 | + return "$formattedStartDate $formattedStartTime - $formattedEndDate $formattedEndTime"; |
|
| 205 | + } |
|
| 206 | + |
|
| 207 | + /** |
|
| 208 | + * @param Component $eventComponent |
|
| 209 | + * @return Property |
|
| 210 | + */ |
|
| 211 | + protected function getDTEndForEvent(Component $eventComponent):Property { |
|
| 212 | + if (isset($eventComponent->DTEND)) { |
|
| 213 | + $end = $eventComponent->DTEND; |
|
| 214 | + } elseif (isset($eventComponent->DURATION)) { |
|
| 215 | + $isFloating = $eventComponent->DTSTART->isFloating(); |
|
| 216 | + $end = clone $eventComponent->DTSTART; |
|
| 217 | + $endDateTime = $end->getDateTime(); |
|
| 218 | + $endDateTime = $endDateTime->add(DateTimeParser::parse($eventComponent->DURATION->getValue())); |
|
| 219 | + $end->setDateTime($endDateTime, $isFloating); |
|
| 220 | + } elseif (!$eventComponent->DTSTART->hasTime()) { |
|
| 221 | + $isFloating = $eventComponent->DTSTART->isFloating(); |
|
| 222 | + $end = clone $eventComponent->DTSTART; |
|
| 223 | + $endDateTime = $end->getDateTime(); |
|
| 224 | + $endDateTime = $endDateTime->modify('+1 day'); |
|
| 225 | + $end->setDateTime($endDateTime, $isFloating); |
|
| 226 | + } else { |
|
| 227 | + $end = clone $eventComponent->DTSTART; |
|
| 228 | + } |
|
| 229 | + |
|
| 230 | + return $end; |
|
| 231 | + } |
|
| 232 | + |
|
| 233 | + /** |
|
| 234 | + * @param \DateTime $dtStart |
|
| 235 | + * @param \DateTime $dtEnd |
|
| 236 | + * @return bool |
|
| 237 | + */ |
|
| 238 | + protected function isDayEqual(\DateTime $dtStart, |
|
| 239 | + \DateTime $dtEnd) { |
|
| 240 | + return $dtStart->format('Y-m-d') === $dtEnd->format('Y-m-d'); |
|
| 241 | + } |
|
| 242 | 242 | } |
@@ -38,134 +38,134 @@ |
||
| 38 | 38 | */ |
| 39 | 39 | class TasksSearchProvider extends ACalendarSearchProvider { |
| 40 | 40 | |
| 41 | - /** |
|
| 42 | - * @var string[] |
|
| 43 | - */ |
|
| 44 | - private static $searchProperties = [ |
|
| 45 | - 'SUMMARY', |
|
| 46 | - 'DESCRIPTION', |
|
| 47 | - 'CATEGORIES', |
|
| 48 | - ]; |
|
| 49 | - |
|
| 50 | - /** |
|
| 51 | - * @var string[] |
|
| 52 | - */ |
|
| 53 | - private static $searchParameters = []; |
|
| 54 | - |
|
| 55 | - /** |
|
| 56 | - * @var string |
|
| 57 | - */ |
|
| 58 | - private static $componentType = 'VTODO'; |
|
| 59 | - |
|
| 60 | - /** |
|
| 61 | - * @inheritDoc |
|
| 62 | - */ |
|
| 63 | - public function getId(): string { |
|
| 64 | - return 'tasks-dav'; |
|
| 65 | - } |
|
| 66 | - |
|
| 67 | - /** |
|
| 68 | - * @inheritDoc |
|
| 69 | - */ |
|
| 70 | - public function getName(): string { |
|
| 71 | - return $this->l10n->t('Tasks'); |
|
| 72 | - } |
|
| 73 | - |
|
| 74 | - /** |
|
| 75 | - * @inheritDoc |
|
| 76 | - */ |
|
| 77 | - public function getOrder(string $route, array $routeParameters): int { |
|
| 78 | - if ($route === 'tasks.Page.index') { |
|
| 79 | - return -1; |
|
| 80 | - } |
|
| 81 | - return 10; |
|
| 82 | - } |
|
| 83 | - |
|
| 84 | - /** |
|
| 85 | - * @inheritDoc |
|
| 86 | - */ |
|
| 87 | - public function search(IUser $user, |
|
| 88 | - ISearchQuery $query): SearchResult { |
|
| 89 | - if (!$this->appManager->isEnabledForUser('tasks', $user)) { |
|
| 90 | - return SearchResult::complete($this->getName(), []); |
|
| 91 | - } |
|
| 92 | - |
|
| 93 | - $principalUri = 'principals/users/' . $user->getUID(); |
|
| 94 | - $calendarsById = $this->getSortedCalendars($principalUri); |
|
| 95 | - $subscriptionsById = $this->getSortedSubscriptions($principalUri); |
|
| 96 | - |
|
| 97 | - $searchResults = $this->backend->searchPrincipalUri( |
|
| 98 | - $principalUri, |
|
| 99 | - $query->getTerm(), |
|
| 100 | - [self::$componentType], |
|
| 101 | - self::$searchProperties, |
|
| 102 | - self::$searchParameters, |
|
| 103 | - [ |
|
| 104 | - 'limit' => $query->getLimit(), |
|
| 105 | - 'offset' => $query->getCursor(), |
|
| 106 | - ] |
|
| 107 | - ); |
|
| 108 | - $formattedResults = \array_map(function (array $taskRow) use ($calendarsById, $subscriptionsById):SearchResultEntry { |
|
| 109 | - $component = $this->getPrimaryComponent($taskRow['calendardata'], self::$componentType); |
|
| 110 | - $title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled task')); |
|
| 111 | - $subline = $this->generateSubline($component); |
|
| 112 | - |
|
| 113 | - if ($taskRow['calendartype'] === CalDavBackend::CALENDAR_TYPE_CALENDAR) { |
|
| 114 | - $calendar = $calendarsById[$taskRow['calendarid']]; |
|
| 115 | - } else { |
|
| 116 | - $calendar = $subscriptionsById[$taskRow['calendarid']]; |
|
| 117 | - } |
|
| 118 | - $resourceUrl = $this->getDeepLinkToTasksApp($calendar['uri'], $taskRow['uri']); |
|
| 119 | - |
|
| 120 | - return new SearchResultEntry('', $title, $subline, $resourceUrl, 'icon-checkmark', false); |
|
| 121 | - }, $searchResults); |
|
| 122 | - |
|
| 123 | - return SearchResult::paginated( |
|
| 124 | - $this->getName(), |
|
| 125 | - $formattedResults, |
|
| 126 | - $query->getCursor() + count($formattedResults) |
|
| 127 | - ); |
|
| 128 | - } |
|
| 129 | - |
|
| 130 | - /** |
|
| 131 | - * @param string $calendarUri |
|
| 132 | - * @param string $taskUri |
|
| 133 | - * @return string |
|
| 134 | - */ |
|
| 135 | - protected function getDeepLinkToTasksApp(string $calendarUri, |
|
| 136 | - string $taskUri): string { |
|
| 137 | - return $this->urlGenerator->getAbsoluteURL( |
|
| 138 | - $this->urlGenerator->linkToRoute('tasks.page.index') |
|
| 139 | - . '#/calendars/' |
|
| 140 | - . $calendarUri |
|
| 141 | - . '/tasks/' |
|
| 142 | - . $taskUri |
|
| 143 | - ); |
|
| 144 | - } |
|
| 145 | - |
|
| 146 | - /** |
|
| 147 | - * @param Component $taskComponent |
|
| 148 | - * @return string |
|
| 149 | - */ |
|
| 150 | - protected function generateSubline(Component $taskComponent): string { |
|
| 151 | - if ($taskComponent->COMPLETED) { |
|
| 152 | - $completedDateTime = new \DateTime($taskComponent->COMPLETED->getDateTime()->format(\DateTime::ATOM)); |
|
| 153 | - $formattedDate = $this->l10n->l('date', $completedDateTime, ['width' => 'medium']); |
|
| 154 | - return $this->l10n->t('Completed on %s', [$formattedDate]); |
|
| 155 | - } |
|
| 156 | - |
|
| 157 | - if ($taskComponent->DUE) { |
|
| 158 | - $dueDateTime = new \DateTime($taskComponent->DUE->getDateTime()->format(\DateTime::ATOM)); |
|
| 159 | - $formattedDate = $this->l10n->l('date', $dueDateTime, ['width' => 'medium']); |
|
| 160 | - |
|
| 161 | - if ($taskComponent->DUE->hasTime()) { |
|
| 162 | - $formattedTime = $this->l10n->l('time', $dueDateTime, ['width' => 'short']); |
|
| 163 | - return $this->l10n->t('Due on %s by %s', [$formattedDate, $formattedTime]); |
|
| 164 | - } |
|
| 165 | - |
|
| 166 | - return $this->l10n->t('Due on %s', [$formattedDate]); |
|
| 167 | - } |
|
| 168 | - |
|
| 169 | - return ''; |
|
| 170 | - } |
|
| 41 | + /** |
|
| 42 | + * @var string[] |
|
| 43 | + */ |
|
| 44 | + private static $searchProperties = [ |
|
| 45 | + 'SUMMARY', |
|
| 46 | + 'DESCRIPTION', |
|
| 47 | + 'CATEGORIES', |
|
| 48 | + ]; |
|
| 49 | + |
|
| 50 | + /** |
|
| 51 | + * @var string[] |
|
| 52 | + */ |
|
| 53 | + private static $searchParameters = []; |
|
| 54 | + |
|
| 55 | + /** |
|
| 56 | + * @var string |
|
| 57 | + */ |
|
| 58 | + private static $componentType = 'VTODO'; |
|
| 59 | + |
|
| 60 | + /** |
|
| 61 | + * @inheritDoc |
|
| 62 | + */ |
|
| 63 | + public function getId(): string { |
|
| 64 | + return 'tasks-dav'; |
|
| 65 | + } |
|
| 66 | + |
|
| 67 | + /** |
|
| 68 | + * @inheritDoc |
|
| 69 | + */ |
|
| 70 | + public function getName(): string { |
|
| 71 | + return $this->l10n->t('Tasks'); |
|
| 72 | + } |
|
| 73 | + |
|
| 74 | + /** |
|
| 75 | + * @inheritDoc |
|
| 76 | + */ |
|
| 77 | + public function getOrder(string $route, array $routeParameters): int { |
|
| 78 | + if ($route === 'tasks.Page.index') { |
|
| 79 | + return -1; |
|
| 80 | + } |
|
| 81 | + return 10; |
|
| 82 | + } |
|
| 83 | + |
|
| 84 | + /** |
|
| 85 | + * @inheritDoc |
|
| 86 | + */ |
|
| 87 | + public function search(IUser $user, |
|
| 88 | + ISearchQuery $query): SearchResult { |
|
| 89 | + if (!$this->appManager->isEnabledForUser('tasks', $user)) { |
|
| 90 | + return SearchResult::complete($this->getName(), []); |
|
| 91 | + } |
|
| 92 | + |
|
| 93 | + $principalUri = 'principals/users/' . $user->getUID(); |
|
| 94 | + $calendarsById = $this->getSortedCalendars($principalUri); |
|
| 95 | + $subscriptionsById = $this->getSortedSubscriptions($principalUri); |
|
| 96 | + |
|
| 97 | + $searchResults = $this->backend->searchPrincipalUri( |
|
| 98 | + $principalUri, |
|
| 99 | + $query->getTerm(), |
|
| 100 | + [self::$componentType], |
|
| 101 | + self::$searchProperties, |
|
| 102 | + self::$searchParameters, |
|
| 103 | + [ |
|
| 104 | + 'limit' => $query->getLimit(), |
|
| 105 | + 'offset' => $query->getCursor(), |
|
| 106 | + ] |
|
| 107 | + ); |
|
| 108 | + $formattedResults = \array_map(function (array $taskRow) use ($calendarsById, $subscriptionsById):SearchResultEntry { |
|
| 109 | + $component = $this->getPrimaryComponent($taskRow['calendardata'], self::$componentType); |
|
| 110 | + $title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled task')); |
|
| 111 | + $subline = $this->generateSubline($component); |
|
| 112 | + |
|
| 113 | + if ($taskRow['calendartype'] === CalDavBackend::CALENDAR_TYPE_CALENDAR) { |
|
| 114 | + $calendar = $calendarsById[$taskRow['calendarid']]; |
|
| 115 | + } else { |
|
| 116 | + $calendar = $subscriptionsById[$taskRow['calendarid']]; |
|
| 117 | + } |
|
| 118 | + $resourceUrl = $this->getDeepLinkToTasksApp($calendar['uri'], $taskRow['uri']); |
|
| 119 | + |
|
| 120 | + return new SearchResultEntry('', $title, $subline, $resourceUrl, 'icon-checkmark', false); |
|
| 121 | + }, $searchResults); |
|
| 122 | + |
|
| 123 | + return SearchResult::paginated( |
|
| 124 | + $this->getName(), |
|
| 125 | + $formattedResults, |
|
| 126 | + $query->getCursor() + count($formattedResults) |
|
| 127 | + ); |
|
| 128 | + } |
|
| 129 | + |
|
| 130 | + /** |
|
| 131 | + * @param string $calendarUri |
|
| 132 | + * @param string $taskUri |
|
| 133 | + * @return string |
|
| 134 | + */ |
|
| 135 | + protected function getDeepLinkToTasksApp(string $calendarUri, |
|
| 136 | + string $taskUri): string { |
|
| 137 | + return $this->urlGenerator->getAbsoluteURL( |
|
| 138 | + $this->urlGenerator->linkToRoute('tasks.page.index') |
|
| 139 | + . '#/calendars/' |
|
| 140 | + . $calendarUri |
|
| 141 | + . '/tasks/' |
|
| 142 | + . $taskUri |
|
| 143 | + ); |
|
| 144 | + } |
|
| 145 | + |
|
| 146 | + /** |
|
| 147 | + * @param Component $taskComponent |
|
| 148 | + * @return string |
|
| 149 | + */ |
|
| 150 | + protected function generateSubline(Component $taskComponent): string { |
|
| 151 | + if ($taskComponent->COMPLETED) { |
|
| 152 | + $completedDateTime = new \DateTime($taskComponent->COMPLETED->getDateTime()->format(\DateTime::ATOM)); |
|
| 153 | + $formattedDate = $this->l10n->l('date', $completedDateTime, ['width' => 'medium']); |
|
| 154 | + return $this->l10n->t('Completed on %s', [$formattedDate]); |
|
| 155 | + } |
|
| 156 | + |
|
| 157 | + if ($taskComponent->DUE) { |
|
| 158 | + $dueDateTime = new \DateTime($taskComponent->DUE->getDateTime()->format(\DateTime::ATOM)); |
|
| 159 | + $formattedDate = $this->l10n->l('date', $dueDateTime, ['width' => 'medium']); |
|
| 160 | + |
|
| 161 | + if ($taskComponent->DUE->hasTime()) { |
|
| 162 | + $formattedTime = $this->l10n->l('time', $dueDateTime, ['width' => 'short']); |
|
| 163 | + return $this->l10n->t('Due on %s by %s', [$formattedDate, $formattedTime]); |
|
| 164 | + } |
|
| 165 | + |
|
| 166 | + return $this->l10n->t('Due on %s', [$formattedDate]); |
|
| 167 | + } |
|
| 168 | + |
|
| 169 | + return ''; |
|
| 170 | + } |
|
| 171 | 171 | } |
@@ -38,163 +38,163 @@ |
||
| 38 | 38 | |
| 39 | 39 | class ContactsSearchProvider implements IProvider { |
| 40 | 40 | |
| 41 | - /** @var IAppManager */ |
|
| 42 | - private $appManager; |
|
| 43 | - |
|
| 44 | - /** @var IL10N */ |
|
| 45 | - private $l10n; |
|
| 46 | - |
|
| 47 | - /** @var IURLGenerator */ |
|
| 48 | - private $urlGenerator; |
|
| 49 | - |
|
| 50 | - /** @var CardDavBackend */ |
|
| 51 | - private $backend; |
|
| 52 | - |
|
| 53 | - /** |
|
| 54 | - * @var string[] |
|
| 55 | - */ |
|
| 56 | - private static $searchProperties = [ |
|
| 57 | - 'N', |
|
| 58 | - 'FN', |
|
| 59 | - 'NICKNAME', |
|
| 60 | - 'EMAIL', |
|
| 61 | - 'ADR', |
|
| 62 | - ]; |
|
| 63 | - |
|
| 64 | - /** |
|
| 65 | - * ContactsSearchProvider constructor. |
|
| 66 | - * |
|
| 67 | - * @param IAppManager $appManager |
|
| 68 | - * @param IL10N $l10n |
|
| 69 | - * @param IURLGenerator $urlGenerator |
|
| 70 | - * @param CardDavBackend $backend |
|
| 71 | - */ |
|
| 72 | - public function __construct(IAppManager $appManager, |
|
| 73 | - IL10N $l10n, |
|
| 74 | - IURLGenerator $urlGenerator, |
|
| 75 | - CardDavBackend $backend) { |
|
| 76 | - $this->appManager = $appManager; |
|
| 77 | - $this->l10n = $l10n; |
|
| 78 | - $this->urlGenerator = $urlGenerator; |
|
| 79 | - $this->backend = $backend; |
|
| 80 | - } |
|
| 81 | - |
|
| 82 | - /** |
|
| 83 | - * @inheritDoc |
|
| 84 | - */ |
|
| 85 | - public function getId(): string { |
|
| 86 | - return 'contacts-dav'; |
|
| 87 | - } |
|
| 88 | - |
|
| 89 | - /** |
|
| 90 | - * @inheritDoc |
|
| 91 | - */ |
|
| 92 | - public function getName(): string { |
|
| 93 | - return $this->l10n->t('Contacts'); |
|
| 94 | - } |
|
| 95 | - |
|
| 96 | - /** |
|
| 97 | - * @inheritDoc |
|
| 98 | - */ |
|
| 99 | - public function getOrder(string $route, array $routeParameters): int { |
|
| 100 | - if ($route === 'contacts.Page.index') { |
|
| 101 | - return -1; |
|
| 102 | - } |
|
| 103 | - return 20; |
|
| 104 | - } |
|
| 105 | - |
|
| 106 | - /** |
|
| 107 | - * @inheritDoc |
|
| 108 | - */ |
|
| 109 | - public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 110 | - if (!$this->appManager->isEnabledForUser('contacts', $user)) { |
|
| 111 | - return SearchResult::complete($this->getName(), []); |
|
| 112 | - } |
|
| 113 | - |
|
| 114 | - $principalUri = 'principals/users/' . $user->getUID(); |
|
| 115 | - $addressBooks = $this->backend->getAddressBooksForUser($principalUri); |
|
| 116 | - $addressBooksById = []; |
|
| 117 | - foreach ($addressBooks as $addressBook) { |
|
| 118 | - $addressBooksById[(int) $addressBook['id']] = $addressBook; |
|
| 119 | - } |
|
| 120 | - |
|
| 121 | - $searchResults = $this->backend->searchPrincipalUri( |
|
| 122 | - $principalUri, |
|
| 123 | - $query->getTerm(), |
|
| 124 | - self::$searchProperties, |
|
| 125 | - [ |
|
| 126 | - 'limit' => $query->getLimit(), |
|
| 127 | - 'offset' => $query->getCursor(), |
|
| 128 | - ] |
|
| 129 | - ); |
|
| 130 | - $formattedResults = \array_map(function (array $contactRow) use ($addressBooksById):SearchResultEntry { |
|
| 131 | - $addressBook = $addressBooksById[$contactRow['addressbookid']]; |
|
| 132 | - |
|
| 133 | - /** @var VCard $vCard */ |
|
| 134 | - $vCard = Reader::read($contactRow['carddata']); |
|
| 135 | - $thumbnailUrl = ''; |
|
| 136 | - if ($vCard->PHOTO) { |
|
| 137 | - $thumbnailUrl = $this->getDavUrlForContact($addressBook['principaluri'], $addressBook['uri'], $contactRow['uri']) . '?photo'; |
|
| 138 | - } |
|
| 139 | - |
|
| 140 | - $title = (string)$vCard->FN; |
|
| 141 | - $subline = $this->generateSubline($vCard); |
|
| 142 | - $resourceUrl = $this->getDeepLinkToContactsApp($addressBook['uri'], (string) $vCard->UID); |
|
| 143 | - |
|
| 144 | - return new SearchResultEntry($thumbnailUrl, $title, $subline, $resourceUrl, 'icon-contacts-dark', true); |
|
| 145 | - }, $searchResults); |
|
| 146 | - |
|
| 147 | - return SearchResult::paginated( |
|
| 148 | - $this->getName(), |
|
| 149 | - $formattedResults, |
|
| 150 | - $query->getCursor() + count($formattedResults) |
|
| 151 | - ); |
|
| 152 | - } |
|
| 153 | - |
|
| 154 | - /** |
|
| 155 | - * @param string $principalUri |
|
| 156 | - * @param string $addressBookUri |
|
| 157 | - * @param string $contactsUri |
|
| 158 | - * @return string |
|
| 159 | - */ |
|
| 160 | - protected function getDavUrlForContact(string $principalUri, |
|
| 161 | - string $addressBookUri, |
|
| 162 | - string $contactsUri): string { |
|
| 163 | - [, $principalType, $principalId] = explode('/', $principalUri, 3); |
|
| 164 | - |
|
| 165 | - return $this->urlGenerator->getAbsoluteURL( |
|
| 166 | - $this->urlGenerator->linkTo('', 'remote.php') . '/dav/addressbooks/' |
|
| 167 | - . $principalType . '/' |
|
| 168 | - . $principalId . '/' |
|
| 169 | - . $addressBookUri . '/' |
|
| 170 | - . $contactsUri |
|
| 171 | - ); |
|
| 172 | - } |
|
| 173 | - |
|
| 174 | - /** |
|
| 175 | - * @param string $addressBookUri |
|
| 176 | - * @param string $contactUid |
|
| 177 | - * @return string |
|
| 178 | - */ |
|
| 179 | - protected function getDeepLinkToContactsApp(string $addressBookUri, |
|
| 180 | - string $contactUid): string { |
|
| 181 | - return $this->urlGenerator->getAbsoluteURL( |
|
| 182 | - $this->urlGenerator->linkToRoute('contacts.contacts.direct', [ |
|
| 183 | - 'contact' => $contactUid . '~' . $addressBookUri |
|
| 184 | - ]) |
|
| 185 | - ); |
|
| 186 | - } |
|
| 187 | - |
|
| 188 | - /** |
|
| 189 | - * @param VCard $vCard |
|
| 190 | - * @return string |
|
| 191 | - */ |
|
| 192 | - protected function generateSubline(VCard $vCard): string { |
|
| 193 | - $emailAddresses = $vCard->select('EMAIL'); |
|
| 194 | - if (!is_array($emailAddresses) || empty($emailAddresses)) { |
|
| 195 | - return ''; |
|
| 196 | - } |
|
| 197 | - |
|
| 198 | - return (string)$emailAddresses[0]; |
|
| 199 | - } |
|
| 41 | + /** @var IAppManager */ |
|
| 42 | + private $appManager; |
|
| 43 | + |
|
| 44 | + /** @var IL10N */ |
|
| 45 | + private $l10n; |
|
| 46 | + |
|
| 47 | + /** @var IURLGenerator */ |
|
| 48 | + private $urlGenerator; |
|
| 49 | + |
|
| 50 | + /** @var CardDavBackend */ |
|
| 51 | + private $backend; |
|
| 52 | + |
|
| 53 | + /** |
|
| 54 | + * @var string[] |
|
| 55 | + */ |
|
| 56 | + private static $searchProperties = [ |
|
| 57 | + 'N', |
|
| 58 | + 'FN', |
|
| 59 | + 'NICKNAME', |
|
| 60 | + 'EMAIL', |
|
| 61 | + 'ADR', |
|
| 62 | + ]; |
|
| 63 | + |
|
| 64 | + /** |
|
| 65 | + * ContactsSearchProvider constructor. |
|
| 66 | + * |
|
| 67 | + * @param IAppManager $appManager |
|
| 68 | + * @param IL10N $l10n |
|
| 69 | + * @param IURLGenerator $urlGenerator |
|
| 70 | + * @param CardDavBackend $backend |
|
| 71 | + */ |
|
| 72 | + public function __construct(IAppManager $appManager, |
|
| 73 | + IL10N $l10n, |
|
| 74 | + IURLGenerator $urlGenerator, |
|
| 75 | + CardDavBackend $backend) { |
|
| 76 | + $this->appManager = $appManager; |
|
| 77 | + $this->l10n = $l10n; |
|
| 78 | + $this->urlGenerator = $urlGenerator; |
|
| 79 | + $this->backend = $backend; |
|
| 80 | + } |
|
| 81 | + |
|
| 82 | + /** |
|
| 83 | + * @inheritDoc |
|
| 84 | + */ |
|
| 85 | + public function getId(): string { |
|
| 86 | + return 'contacts-dav'; |
|
| 87 | + } |
|
| 88 | + |
|
| 89 | + /** |
|
| 90 | + * @inheritDoc |
|
| 91 | + */ |
|
| 92 | + public function getName(): string { |
|
| 93 | + return $this->l10n->t('Contacts'); |
|
| 94 | + } |
|
| 95 | + |
|
| 96 | + /** |
|
| 97 | + * @inheritDoc |
|
| 98 | + */ |
|
| 99 | + public function getOrder(string $route, array $routeParameters): int { |
|
| 100 | + if ($route === 'contacts.Page.index') { |
|
| 101 | + return -1; |
|
| 102 | + } |
|
| 103 | + return 20; |
|
| 104 | + } |
|
| 105 | + |
|
| 106 | + /** |
|
| 107 | + * @inheritDoc |
|
| 108 | + */ |
|
| 109 | + public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 110 | + if (!$this->appManager->isEnabledForUser('contacts', $user)) { |
|
| 111 | + return SearchResult::complete($this->getName(), []); |
|
| 112 | + } |
|
| 113 | + |
|
| 114 | + $principalUri = 'principals/users/' . $user->getUID(); |
|
| 115 | + $addressBooks = $this->backend->getAddressBooksForUser($principalUri); |
|
| 116 | + $addressBooksById = []; |
|
| 117 | + foreach ($addressBooks as $addressBook) { |
|
| 118 | + $addressBooksById[(int) $addressBook['id']] = $addressBook; |
|
| 119 | + } |
|
| 120 | + |
|
| 121 | + $searchResults = $this->backend->searchPrincipalUri( |
|
| 122 | + $principalUri, |
|
| 123 | + $query->getTerm(), |
|
| 124 | + self::$searchProperties, |
|
| 125 | + [ |
|
| 126 | + 'limit' => $query->getLimit(), |
|
| 127 | + 'offset' => $query->getCursor(), |
|
| 128 | + ] |
|
| 129 | + ); |
|
| 130 | + $formattedResults = \array_map(function (array $contactRow) use ($addressBooksById):SearchResultEntry { |
|
| 131 | + $addressBook = $addressBooksById[$contactRow['addressbookid']]; |
|
| 132 | + |
|
| 133 | + /** @var VCard $vCard */ |
|
| 134 | + $vCard = Reader::read($contactRow['carddata']); |
|
| 135 | + $thumbnailUrl = ''; |
|
| 136 | + if ($vCard->PHOTO) { |
|
| 137 | + $thumbnailUrl = $this->getDavUrlForContact($addressBook['principaluri'], $addressBook['uri'], $contactRow['uri']) . '?photo'; |
|
| 138 | + } |
|
| 139 | + |
|
| 140 | + $title = (string)$vCard->FN; |
|
| 141 | + $subline = $this->generateSubline($vCard); |
|
| 142 | + $resourceUrl = $this->getDeepLinkToContactsApp($addressBook['uri'], (string) $vCard->UID); |
|
| 143 | + |
|
| 144 | + return new SearchResultEntry($thumbnailUrl, $title, $subline, $resourceUrl, 'icon-contacts-dark', true); |
|
| 145 | + }, $searchResults); |
|
| 146 | + |
|
| 147 | + return SearchResult::paginated( |
|
| 148 | + $this->getName(), |
|
| 149 | + $formattedResults, |
|
| 150 | + $query->getCursor() + count($formattedResults) |
|
| 151 | + ); |
|
| 152 | + } |
|
| 153 | + |
|
| 154 | + /** |
|
| 155 | + * @param string $principalUri |
|
| 156 | + * @param string $addressBookUri |
|
| 157 | + * @param string $contactsUri |
|
| 158 | + * @return string |
|
| 159 | + */ |
|
| 160 | + protected function getDavUrlForContact(string $principalUri, |
|
| 161 | + string $addressBookUri, |
|
| 162 | + string $contactsUri): string { |
|
| 163 | + [, $principalType, $principalId] = explode('/', $principalUri, 3); |
|
| 164 | + |
|
| 165 | + return $this->urlGenerator->getAbsoluteURL( |
|
| 166 | + $this->urlGenerator->linkTo('', 'remote.php') . '/dav/addressbooks/' |
|
| 167 | + . $principalType . '/' |
|
| 168 | + . $principalId . '/' |
|
| 169 | + . $addressBookUri . '/' |
|
| 170 | + . $contactsUri |
|
| 171 | + ); |
|
| 172 | + } |
|
| 173 | + |
|
| 174 | + /** |
|
| 175 | + * @param string $addressBookUri |
|
| 176 | + * @param string $contactUid |
|
| 177 | + * @return string |
|
| 178 | + */ |
|
| 179 | + protected function getDeepLinkToContactsApp(string $addressBookUri, |
|
| 180 | + string $contactUid): string { |
|
| 181 | + return $this->urlGenerator->getAbsoluteURL( |
|
| 182 | + $this->urlGenerator->linkToRoute('contacts.contacts.direct', [ |
|
| 183 | + 'contact' => $contactUid . '~' . $addressBookUri |
|
| 184 | + ]) |
|
| 185 | + ); |
|
| 186 | + } |
|
| 187 | + |
|
| 188 | + /** |
|
| 189 | + * @param VCard $vCard |
|
| 190 | + * @return string |
|
| 191 | + */ |
|
| 192 | + protected function generateSubline(VCard $vCard): string { |
|
| 193 | + $emailAddresses = $vCard->select('EMAIL'); |
|
| 194 | + if (!is_array($emailAddresses) || empty($emailAddresses)) { |
|
| 195 | + return ''; |
|
| 196 | + } |
|
| 197 | + |
|
| 198 | + return (string)$emailAddresses[0]; |
|
| 199 | + } |
|
| 200 | 200 | } |
@@ -38,78 +38,78 @@ |
||
| 38 | 38 | |
| 39 | 39 | class CommentsSearchProvider implements IProvider { |
| 40 | 40 | |
| 41 | - /** @var IUserManager */ |
|
| 42 | - private $userManager; |
|
| 41 | + /** @var IUserManager */ |
|
| 42 | + private $userManager; |
|
| 43 | 43 | |
| 44 | - /** @var IL10N */ |
|
| 45 | - private $l10n; |
|
| 44 | + /** @var IL10N */ |
|
| 45 | + private $l10n; |
|
| 46 | 46 | |
| 47 | - /** @var IURLGenerator */ |
|
| 48 | - private $urlGenerator; |
|
| 47 | + /** @var IURLGenerator */ |
|
| 48 | + private $urlGenerator; |
|
| 49 | 49 | |
| 50 | - /** @var LegacyProvider */ |
|
| 51 | - private $legacyProvider; |
|
| 50 | + /** @var LegacyProvider */ |
|
| 51 | + private $legacyProvider; |
|
| 52 | 52 | |
| 53 | - public function __construct(IUserManager $userManager, |
|
| 54 | - IL10N $l10n, |
|
| 55 | - IURLGenerator $urlGenerator, |
|
| 56 | - LegacyProvider $legacyProvider) { |
|
| 57 | - $this->userManager = $userManager; |
|
| 58 | - $this->l10n = $l10n; |
|
| 59 | - $this->urlGenerator = $urlGenerator; |
|
| 60 | - $this->legacyProvider = $legacyProvider; |
|
| 61 | - } |
|
| 53 | + public function __construct(IUserManager $userManager, |
|
| 54 | + IL10N $l10n, |
|
| 55 | + IURLGenerator $urlGenerator, |
|
| 56 | + LegacyProvider $legacyProvider) { |
|
| 57 | + $this->userManager = $userManager; |
|
| 58 | + $this->l10n = $l10n; |
|
| 59 | + $this->urlGenerator = $urlGenerator; |
|
| 60 | + $this->legacyProvider = $legacyProvider; |
|
| 61 | + } |
|
| 62 | 62 | |
| 63 | - /** |
|
| 64 | - * @inheritDoc |
|
| 65 | - */ |
|
| 66 | - public function getId(): string { |
|
| 67 | - return 'comments'; |
|
| 68 | - } |
|
| 63 | + /** |
|
| 64 | + * @inheritDoc |
|
| 65 | + */ |
|
| 66 | + public function getId(): string { |
|
| 67 | + return 'comments'; |
|
| 68 | + } |
|
| 69 | 69 | |
| 70 | - /** |
|
| 71 | - * @inheritDoc |
|
| 72 | - */ |
|
| 73 | - public function getName(): string { |
|
| 74 | - return $this->l10n->t('Comments'); |
|
| 75 | - } |
|
| 70 | + /** |
|
| 71 | + * @inheritDoc |
|
| 72 | + */ |
|
| 73 | + public function getName(): string { |
|
| 74 | + return $this->l10n->t('Comments'); |
|
| 75 | + } |
|
| 76 | 76 | |
| 77 | - /** |
|
| 78 | - * @inheritDoc |
|
| 79 | - */ |
|
| 80 | - public function getOrder(string $route, array $routeParameters): int { |
|
| 81 | - if ($route === 'files.View.index') { |
|
| 82 | - // Files first |
|
| 83 | - return 0; |
|
| 84 | - } |
|
| 85 | - return 10; |
|
| 86 | - } |
|
| 77 | + /** |
|
| 78 | + * @inheritDoc |
|
| 79 | + */ |
|
| 80 | + public function getOrder(string $route, array $routeParameters): int { |
|
| 81 | + if ($route === 'files.View.index') { |
|
| 82 | + // Files first |
|
| 83 | + return 0; |
|
| 84 | + } |
|
| 85 | + return 10; |
|
| 86 | + } |
|
| 87 | 87 | |
| 88 | - /** |
|
| 89 | - * @inheritDoc |
|
| 90 | - */ |
|
| 91 | - public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 92 | - return SearchResult::complete( |
|
| 93 | - $this->l10n->t('Comments'), |
|
| 94 | - array_map(function (Result $result) { |
|
| 95 | - $path = $result->path; |
|
| 96 | - $pathInfo = pathinfo($path); |
|
| 97 | - $isUser = $this->userManager->userExists($result->authorId); |
|
| 98 | - $avatarUrl = $isUser |
|
| 99 | - ? $this->urlGenerator->linkToRoute('core.avatar.getAvatar', ['userId' => $result->authorId, 'size' => 42]) |
|
| 100 | - : $this->urlGenerator->linkToRoute('core.GuestAvatar.getAvatar', ['guestName' => $result->authorId, 'size' => 42]); |
|
| 101 | - return new SearchResultEntry( |
|
| 102 | - $avatarUrl, |
|
| 103 | - $result->name, |
|
| 104 | - $path, |
|
| 105 | - $this->urlGenerator->linkToRoute('files.view.index',[ |
|
| 106 | - 'dir' => $pathInfo['dirname'], |
|
| 107 | - 'scrollto' => $pathInfo['basename'], |
|
| 108 | - ]), |
|
| 109 | - '', |
|
| 110 | - true |
|
| 111 | - ); |
|
| 112 | - }, $this->legacyProvider->search($query->getTerm())) |
|
| 113 | - ); |
|
| 114 | - } |
|
| 88 | + /** |
|
| 89 | + * @inheritDoc |
|
| 90 | + */ |
|
| 91 | + public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 92 | + return SearchResult::complete( |
|
| 93 | + $this->l10n->t('Comments'), |
|
| 94 | + array_map(function (Result $result) { |
|
| 95 | + $path = $result->path; |
|
| 96 | + $pathInfo = pathinfo($path); |
|
| 97 | + $isUser = $this->userManager->userExists($result->authorId); |
|
| 98 | + $avatarUrl = $isUser |
|
| 99 | + ? $this->urlGenerator->linkToRoute('core.avatar.getAvatar', ['userId' => $result->authorId, 'size' => 42]) |
|
| 100 | + : $this->urlGenerator->linkToRoute('core.GuestAvatar.getAvatar', ['guestName' => $result->authorId, 'size' => 42]); |
|
| 101 | + return new SearchResultEntry( |
|
| 102 | + $avatarUrl, |
|
| 103 | + $result->name, |
|
| 104 | + $path, |
|
| 105 | + $this->urlGenerator->linkToRoute('files.view.index',[ |
|
| 106 | + 'dir' => $pathInfo['dirname'], |
|
| 107 | + 'scrollto' => $pathInfo['basename'], |
|
| 108 | + ]), |
|
| 109 | + '', |
|
| 110 | + true |
|
| 111 | + ); |
|
| 112 | + }, $this->legacyProvider->search($query->getTerm())) |
|
| 113 | + ); |
|
| 114 | + } |
|
| 115 | 115 | } |
@@ -36,116 +36,116 @@ |
||
| 36 | 36 | |
| 37 | 37 | class SectionSearch implements IProvider { |
| 38 | 38 | |
| 39 | - /** @var IManager */ |
|
| 40 | - protected $settingsManager; |
|
| 41 | - |
|
| 42 | - /** @var IGroupManager */ |
|
| 43 | - protected $groupManager; |
|
| 44 | - |
|
| 45 | - /** @var IURLGenerator */ |
|
| 46 | - protected $urlGenerator; |
|
| 47 | - |
|
| 48 | - /** @var IL10N */ |
|
| 49 | - protected $l; |
|
| 50 | - |
|
| 51 | - public function __construct(IManager $settingsManager, |
|
| 52 | - IGroupManager $groupManager, |
|
| 53 | - IURLGenerator $urlGenerator, |
|
| 54 | - IL10N $l) { |
|
| 55 | - $this->settingsManager = $settingsManager; |
|
| 56 | - $this->groupManager = $groupManager; |
|
| 57 | - $this->urlGenerator = $urlGenerator; |
|
| 58 | - $this->l = $l; |
|
| 59 | - } |
|
| 60 | - |
|
| 61 | - /** |
|
| 62 | - * @inheritDoc |
|
| 63 | - */ |
|
| 64 | - public function getId(): string { |
|
| 65 | - return 'settings_sections'; |
|
| 66 | - } |
|
| 67 | - |
|
| 68 | - /** |
|
| 69 | - * @inheritDoc |
|
| 70 | - */ |
|
| 71 | - public function getName(): string { |
|
| 72 | - return $this->l->t('Settings'); |
|
| 73 | - } |
|
| 74 | - |
|
| 75 | - /** |
|
| 76 | - * @inheritDoc |
|
| 77 | - */ |
|
| 78 | - public function getOrder(string $route, array $routeParameters): int { |
|
| 79 | - if ($route === 'settings.PersonalSettings.index' || $route === 'settings.AdminSettings.index') { |
|
| 80 | - return -1; |
|
| 81 | - } |
|
| 82 | - return 20; |
|
| 83 | - } |
|
| 84 | - |
|
| 85 | - /** |
|
| 86 | - * @inheritDoc |
|
| 87 | - */ |
|
| 88 | - public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 89 | - $isAdmin = $this->groupManager->isAdmin($user->getUID()); |
|
| 90 | - |
|
| 91 | - $result = $this->searchSections( |
|
| 92 | - $query, |
|
| 93 | - $this->settingsManager->getPersonalSections(), |
|
| 94 | - $isAdmin ? $this->l->t('Personal') : '', |
|
| 95 | - 'settings.PersonalSettings.index' |
|
| 96 | - ); |
|
| 97 | - |
|
| 98 | - if ($this->groupManager->isAdmin($user->getUID())) { |
|
| 99 | - $result = array_merge($result, $this->searchSections( |
|
| 100 | - $query, |
|
| 101 | - $this->settingsManager->getAdminSections(), |
|
| 102 | - $this->l->t('Administration'), |
|
| 103 | - 'settings.AdminSettings.index' |
|
| 104 | - )); |
|
| 105 | - } |
|
| 106 | - |
|
| 107 | - return SearchResult::complete( |
|
| 108 | - $this->l->t('Settings'), |
|
| 109 | - $result |
|
| 110 | - ); |
|
| 111 | - } |
|
| 112 | - |
|
| 113 | - /** |
|
| 114 | - * @param ISearchQuery $query |
|
| 115 | - * @param ISection[][] $sections |
|
| 116 | - * @param string $subline |
|
| 117 | - * @param string $routeName |
|
| 118 | - * @return array |
|
| 119 | - */ |
|
| 120 | - public function searchSections(ISearchQuery $query, array $sections, string $subline, string $routeName): array { |
|
| 121 | - $result = []; |
|
| 122 | - foreach ($sections as $priority => $sectionsByPriority) { |
|
| 123 | - foreach ($sectionsByPriority as $section) { |
|
| 124 | - if ( |
|
| 125 | - stripos($section->getName(), $query->getTerm()) === false && |
|
| 126 | - stripos($section->getID(), $query->getTerm()) === false |
|
| 127 | - ) { |
|
| 128 | - continue; |
|
| 129 | - } |
|
| 130 | - |
|
| 131 | - /** |
|
| 132 | - * We can't use the icon URL at the moment as they don't invert correctly for dark theme |
|
| 133 | - * $iconUrl = ''; |
|
| 134 | - * if ($section instanceof IIconSection) { |
|
| 135 | - * $iconUrl = $section->getIcon(); |
|
| 136 | - * } |
|
| 137 | - */ |
|
| 138 | - |
|
| 139 | - $result[] = new SearchResultEntry( |
|
| 140 | - '', |
|
| 141 | - $section->getName(), |
|
| 142 | - $subline, |
|
| 143 | - $this->urlGenerator->linkToRouteAbsolute($routeName, ['section' => $section->getID()]), |
|
| 144 | - 'icon-settings' |
|
| 145 | - ); |
|
| 146 | - } |
|
| 147 | - } |
|
| 148 | - |
|
| 149 | - return $result; |
|
| 150 | - } |
|
| 39 | + /** @var IManager */ |
|
| 40 | + protected $settingsManager; |
|
| 41 | + |
|
| 42 | + /** @var IGroupManager */ |
|
| 43 | + protected $groupManager; |
|
| 44 | + |
|
| 45 | + /** @var IURLGenerator */ |
|
| 46 | + protected $urlGenerator; |
|
| 47 | + |
|
| 48 | + /** @var IL10N */ |
|
| 49 | + protected $l; |
|
| 50 | + |
|
| 51 | + public function __construct(IManager $settingsManager, |
|
| 52 | + IGroupManager $groupManager, |
|
| 53 | + IURLGenerator $urlGenerator, |
|
| 54 | + IL10N $l) { |
|
| 55 | + $this->settingsManager = $settingsManager; |
|
| 56 | + $this->groupManager = $groupManager; |
|
| 57 | + $this->urlGenerator = $urlGenerator; |
|
| 58 | + $this->l = $l; |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + /** |
|
| 62 | + * @inheritDoc |
|
| 63 | + */ |
|
| 64 | + public function getId(): string { |
|
| 65 | + return 'settings_sections'; |
|
| 66 | + } |
|
| 67 | + |
|
| 68 | + /** |
|
| 69 | + * @inheritDoc |
|
| 70 | + */ |
|
| 71 | + public function getName(): string { |
|
| 72 | + return $this->l->t('Settings'); |
|
| 73 | + } |
|
| 74 | + |
|
| 75 | + /** |
|
| 76 | + * @inheritDoc |
|
| 77 | + */ |
|
| 78 | + public function getOrder(string $route, array $routeParameters): int { |
|
| 79 | + if ($route === 'settings.PersonalSettings.index' || $route === 'settings.AdminSettings.index') { |
|
| 80 | + return -1; |
|
| 81 | + } |
|
| 82 | + return 20; |
|
| 83 | + } |
|
| 84 | + |
|
| 85 | + /** |
|
| 86 | + * @inheritDoc |
|
| 87 | + */ |
|
| 88 | + public function search(IUser $user, ISearchQuery $query): SearchResult { |
|
| 89 | + $isAdmin = $this->groupManager->isAdmin($user->getUID()); |
|
| 90 | + |
|
| 91 | + $result = $this->searchSections( |
|
| 92 | + $query, |
|
| 93 | + $this->settingsManager->getPersonalSections(), |
|
| 94 | + $isAdmin ? $this->l->t('Personal') : '', |
|
| 95 | + 'settings.PersonalSettings.index' |
|
| 96 | + ); |
|
| 97 | + |
|
| 98 | + if ($this->groupManager->isAdmin($user->getUID())) { |
|
| 99 | + $result = array_merge($result, $this->searchSections( |
|
| 100 | + $query, |
|
| 101 | + $this->settingsManager->getAdminSections(), |
|
| 102 | + $this->l->t('Administration'), |
|
| 103 | + 'settings.AdminSettings.index' |
|
| 104 | + )); |
|
| 105 | + } |
|
| 106 | + |
|
| 107 | + return SearchResult::complete( |
|
| 108 | + $this->l->t('Settings'), |
|
| 109 | + $result |
|
| 110 | + ); |
|
| 111 | + } |
|
| 112 | + |
|
| 113 | + /** |
|
| 114 | + * @param ISearchQuery $query |
|
| 115 | + * @param ISection[][] $sections |
|
| 116 | + * @param string $subline |
|
| 117 | + * @param string $routeName |
|
| 118 | + * @return array |
|
| 119 | + */ |
|
| 120 | + public function searchSections(ISearchQuery $query, array $sections, string $subline, string $routeName): array { |
|
| 121 | + $result = []; |
|
| 122 | + foreach ($sections as $priority => $sectionsByPriority) { |
|
| 123 | + foreach ($sectionsByPriority as $section) { |
|
| 124 | + if ( |
|
| 125 | + stripos($section->getName(), $query->getTerm()) === false && |
|
| 126 | + stripos($section->getID(), $query->getTerm()) === false |
|
| 127 | + ) { |
|
| 128 | + continue; |
|
| 129 | + } |
|
| 130 | + |
|
| 131 | + /** |
|
| 132 | + * We can't use the icon URL at the moment as they don't invert correctly for dark theme |
|
| 133 | + * $iconUrl = ''; |
|
| 134 | + * if ($section instanceof IIconSection) { |
|
| 135 | + * $iconUrl = $section->getIcon(); |
|
| 136 | + * } |
|
| 137 | + */ |
|
| 138 | + |
|
| 139 | + $result[] = new SearchResultEntry( |
|
| 140 | + '', |
|
| 141 | + $section->getName(), |
|
| 142 | + $subline, |
|
| 143 | + $this->urlGenerator->linkToRouteAbsolute($routeName, ['section' => $section->getID()]), |
|
| 144 | + 'icon-settings' |
|
| 145 | + ); |
|
| 146 | + } |
|
| 147 | + } |
|
| 148 | + |
|
| 149 | + return $result; |
|
| 150 | + } |
|
| 151 | 151 | } |
@@ -28,87 +28,87 @@ |
||
| 28 | 28 | use OCP\Search\ISearchQuery; |
| 29 | 29 | |
| 30 | 30 | class SearchQuery implements ISearchQuery { |
| 31 | - public const LIMIT_DEFAULT = 5; |
|
| 32 | - |
|
| 33 | - /** @var string */ |
|
| 34 | - private $term; |
|
| 35 | - |
|
| 36 | - /** @var int */ |
|
| 37 | - private $sortOrder; |
|
| 38 | - |
|
| 39 | - /** @var int */ |
|
| 40 | - private $limit; |
|
| 41 | - |
|
| 42 | - /** @var int|string|null */ |
|
| 43 | - private $cursor; |
|
| 44 | - |
|
| 45 | - /** @var string */ |
|
| 46 | - private $route; |
|
| 47 | - |
|
| 48 | - /** @var array */ |
|
| 49 | - private $routeParameters; |
|
| 50 | - |
|
| 51 | - /** |
|
| 52 | - * @param string $term |
|
| 53 | - * @param int $sortOrder |
|
| 54 | - * @param int $limit |
|
| 55 | - * @param int|string|null $cursor |
|
| 56 | - * @param string $route |
|
| 57 | - * @param array $routeParameters |
|
| 58 | - */ |
|
| 59 | - public function __construct(string $term, |
|
| 60 | - int $sortOrder = ISearchQuery::SORT_DATE_DESC, |
|
| 61 | - int $limit = self::LIMIT_DEFAULT, |
|
| 62 | - $cursor = null, |
|
| 63 | - string $route = '', |
|
| 64 | - array $routeParameters = []) { |
|
| 65 | - $this->term = $term; |
|
| 66 | - $this->sortOrder = $sortOrder; |
|
| 67 | - $this->limit = $limit; |
|
| 68 | - $this->cursor = $cursor; |
|
| 69 | - $this->route = $route; |
|
| 70 | - $this->routeParameters = $routeParameters; |
|
| 71 | - } |
|
| 72 | - |
|
| 73 | - /** |
|
| 74 | - * @inheritDoc |
|
| 75 | - */ |
|
| 76 | - public function getTerm(): string { |
|
| 77 | - return $this->term; |
|
| 78 | - } |
|
| 79 | - |
|
| 80 | - /** |
|
| 81 | - * @inheritDoc |
|
| 82 | - */ |
|
| 83 | - public function getSortOrder(): int { |
|
| 84 | - return $this->sortOrder; |
|
| 85 | - } |
|
| 86 | - |
|
| 87 | - /** |
|
| 88 | - * @inheritDoc |
|
| 89 | - */ |
|
| 90 | - public function getLimit(): int { |
|
| 91 | - return $this->limit; |
|
| 92 | - } |
|
| 93 | - |
|
| 94 | - /** |
|
| 95 | - * @inheritDoc |
|
| 96 | - */ |
|
| 97 | - public function getCursor() { |
|
| 98 | - return $this->cursor; |
|
| 99 | - } |
|
| 100 | - |
|
| 101 | - /** |
|
| 102 | - * @inheritDoc |
|
| 103 | - */ |
|
| 104 | - public function getRoute(): string { |
|
| 105 | - return $this->route; |
|
| 106 | - } |
|
| 107 | - |
|
| 108 | - /** |
|
| 109 | - * @inheritDoc |
|
| 110 | - */ |
|
| 111 | - public function getRouteParameters(): array { |
|
| 112 | - return $this->routeParameters; |
|
| 113 | - } |
|
| 31 | + public const LIMIT_DEFAULT = 5; |
|
| 32 | + |
|
| 33 | + /** @var string */ |
|
| 34 | + private $term; |
|
| 35 | + |
|
| 36 | + /** @var int */ |
|
| 37 | + private $sortOrder; |
|
| 38 | + |
|
| 39 | + /** @var int */ |
|
| 40 | + private $limit; |
|
| 41 | + |
|
| 42 | + /** @var int|string|null */ |
|
| 43 | + private $cursor; |
|
| 44 | + |
|
| 45 | + /** @var string */ |
|
| 46 | + private $route; |
|
| 47 | + |
|
| 48 | + /** @var array */ |
|
| 49 | + private $routeParameters; |
|
| 50 | + |
|
| 51 | + /** |
|
| 52 | + * @param string $term |
|
| 53 | + * @param int $sortOrder |
|
| 54 | + * @param int $limit |
|
| 55 | + * @param int|string|null $cursor |
|
| 56 | + * @param string $route |
|
| 57 | + * @param array $routeParameters |
|
| 58 | + */ |
|
| 59 | + public function __construct(string $term, |
|
| 60 | + int $sortOrder = ISearchQuery::SORT_DATE_DESC, |
|
| 61 | + int $limit = self::LIMIT_DEFAULT, |
|
| 62 | + $cursor = null, |
|
| 63 | + string $route = '', |
|
| 64 | + array $routeParameters = []) { |
|
| 65 | + $this->term = $term; |
|
| 66 | + $this->sortOrder = $sortOrder; |
|
| 67 | + $this->limit = $limit; |
|
| 68 | + $this->cursor = $cursor; |
|
| 69 | + $this->route = $route; |
|
| 70 | + $this->routeParameters = $routeParameters; |
|
| 71 | + } |
|
| 72 | + |
|
| 73 | + /** |
|
| 74 | + * @inheritDoc |
|
| 75 | + */ |
|
| 76 | + public function getTerm(): string { |
|
| 77 | + return $this->term; |
|
| 78 | + } |
|
| 79 | + |
|
| 80 | + /** |
|
| 81 | + * @inheritDoc |
|
| 82 | + */ |
|
| 83 | + public function getSortOrder(): int { |
|
| 84 | + return $this->sortOrder; |
|
| 85 | + } |
|
| 86 | + |
|
| 87 | + /** |
|
| 88 | + * @inheritDoc |
|
| 89 | + */ |
|
| 90 | + public function getLimit(): int { |
|
| 91 | + return $this->limit; |
|
| 92 | + } |
|
| 93 | + |
|
| 94 | + /** |
|
| 95 | + * @inheritDoc |
|
| 96 | + */ |
|
| 97 | + public function getCursor() { |
|
| 98 | + return $this->cursor; |
|
| 99 | + } |
|
| 100 | + |
|
| 101 | + /** |
|
| 102 | + * @inheritDoc |
|
| 103 | + */ |
|
| 104 | + public function getRoute(): string { |
|
| 105 | + return $this->route; |
|
| 106 | + } |
|
| 107 | + |
|
| 108 | + /** |
|
| 109 | + * @inheritDoc |
|
| 110 | + */ |
|
| 111 | + public function getRouteParameters(): array { |
|
| 112 | + return $this->routeParameters; |
|
| 113 | + } |
|
| 114 | 114 | } |
@@ -57,105 +57,105 @@ |
||
| 57 | 57 | */ |
| 58 | 58 | class SearchComposer { |
| 59 | 59 | |
| 60 | - /** @var IProvider[] */ |
|
| 61 | - private $providers = []; |
|
| 62 | - |
|
| 63 | - /** @var Coordinator */ |
|
| 64 | - private $bootstrapCoordinator; |
|
| 65 | - |
|
| 66 | - /** @var IServerContainer */ |
|
| 67 | - private $container; |
|
| 68 | - |
|
| 69 | - /** @var ILogger */ |
|
| 70 | - private $logger; |
|
| 71 | - |
|
| 72 | - public function __construct(Coordinator $bootstrapCoordinator, |
|
| 73 | - IServerContainer $container, |
|
| 74 | - ILogger $logger) { |
|
| 75 | - $this->container = $container; |
|
| 76 | - $this->logger = $logger; |
|
| 77 | - $this->bootstrapCoordinator = $bootstrapCoordinator; |
|
| 78 | - } |
|
| 79 | - |
|
| 80 | - /** |
|
| 81 | - * Load all providers dynamically that were registered through `registerProvider` |
|
| 82 | - * |
|
| 83 | - * If a provider can't be loaded we log it but the operation continues nevertheless |
|
| 84 | - */ |
|
| 85 | - private function loadLazyProviders(): void { |
|
| 86 | - $context = $this->bootstrapCoordinator->getRegistrationContext(); |
|
| 87 | - if ($context === null) { |
|
| 88 | - // Too early, nothing registered yet |
|
| 89 | - return; |
|
| 90 | - } |
|
| 91 | - |
|
| 92 | - $registrations = $context->getSearchProviders(); |
|
| 93 | - foreach ($registrations as $registration) { |
|
| 94 | - try { |
|
| 95 | - /** @var IProvider $provider */ |
|
| 96 | - $provider = $this->container->query($registration['class']); |
|
| 97 | - $this->providers[$provider->getId()] = $provider; |
|
| 98 | - } catch (QueryException $e) { |
|
| 99 | - // Log an continue. We can be fault tolerant here. |
|
| 100 | - $this->logger->logException($e, [ |
|
| 101 | - 'message' => 'Could not load search provider dynamically: ' . $e->getMessage(), |
|
| 102 | - 'level' => ILogger::ERROR, |
|
| 103 | - ]); |
|
| 104 | - } |
|
| 105 | - } |
|
| 106 | - } |
|
| 107 | - |
|
| 108 | - /** |
|
| 109 | - * Get a list of all provider IDs & Names for the consecutive calls to `search` |
|
| 110 | - * Sort the list by the order property |
|
| 111 | - * |
|
| 112 | - * @param string $route the route the user is currently at |
|
| 113 | - * @param array $routeParameters the parameters of the route the user is currently at |
|
| 114 | - * |
|
| 115 | - * @return array |
|
| 116 | - */ |
|
| 117 | - public function getProviders(string $route, array $routeParameters): array { |
|
| 118 | - $this->loadLazyProviders(); |
|
| 119 | - |
|
| 120 | - $providers = array_values( |
|
| 121 | - array_map(function (IProvider $provider) use ($route, $routeParameters) { |
|
| 122 | - return [ |
|
| 123 | - 'id' => $provider->getId(), |
|
| 124 | - 'name' => $provider->getName(), |
|
| 125 | - 'order' => $provider->getOrder($route, $routeParameters), |
|
| 126 | - ]; |
|
| 127 | - }, $this->providers) |
|
| 128 | - ); |
|
| 129 | - |
|
| 130 | - usort($providers, function ($provider1, $provider2) { |
|
| 131 | - return $provider1['order'] <=> $provider2['order']; |
|
| 132 | - }); |
|
| 133 | - |
|
| 134 | - /** |
|
| 135 | - * Return an array with the IDs, but strip the associative keys |
|
| 136 | - */ |
|
| 137 | - return $providers; |
|
| 138 | - } |
|
| 139 | - |
|
| 140 | - /** |
|
| 141 | - * Query an individual search provider for results |
|
| 142 | - * |
|
| 143 | - * @param IUser $user |
|
| 144 | - * @param string $providerId one of the IDs received by `getProviders` |
|
| 145 | - * @param ISearchQuery $query |
|
| 146 | - * |
|
| 147 | - * @return SearchResult |
|
| 148 | - * @throws InvalidArgumentException when the $providerId does not correspond to a registered provider |
|
| 149 | - */ |
|
| 150 | - public function search(IUser $user, |
|
| 151 | - string $providerId, |
|
| 152 | - ISearchQuery $query): SearchResult { |
|
| 153 | - $this->loadLazyProviders(); |
|
| 154 | - |
|
| 155 | - $provider = $this->providers[$providerId] ?? null; |
|
| 156 | - if ($provider === null) { |
|
| 157 | - throw new InvalidArgumentException("Provider $providerId is unknown"); |
|
| 158 | - } |
|
| 159 | - return $provider->search($user, $query); |
|
| 160 | - } |
|
| 60 | + /** @var IProvider[] */ |
|
| 61 | + private $providers = []; |
|
| 62 | + |
|
| 63 | + /** @var Coordinator */ |
|
| 64 | + private $bootstrapCoordinator; |
|
| 65 | + |
|
| 66 | + /** @var IServerContainer */ |
|
| 67 | + private $container; |
|
| 68 | + |
|
| 69 | + /** @var ILogger */ |
|
| 70 | + private $logger; |
|
| 71 | + |
|
| 72 | + public function __construct(Coordinator $bootstrapCoordinator, |
|
| 73 | + IServerContainer $container, |
|
| 74 | + ILogger $logger) { |
|
| 75 | + $this->container = $container; |
|
| 76 | + $this->logger = $logger; |
|
| 77 | + $this->bootstrapCoordinator = $bootstrapCoordinator; |
|
| 78 | + } |
|
| 79 | + |
|
| 80 | + /** |
|
| 81 | + * Load all providers dynamically that were registered through `registerProvider` |
|
| 82 | + * |
|
| 83 | + * If a provider can't be loaded we log it but the operation continues nevertheless |
|
| 84 | + */ |
|
| 85 | + private function loadLazyProviders(): void { |
|
| 86 | + $context = $this->bootstrapCoordinator->getRegistrationContext(); |
|
| 87 | + if ($context === null) { |
|
| 88 | + // Too early, nothing registered yet |
|
| 89 | + return; |
|
| 90 | + } |
|
| 91 | + |
|
| 92 | + $registrations = $context->getSearchProviders(); |
|
| 93 | + foreach ($registrations as $registration) { |
|
| 94 | + try { |
|
| 95 | + /** @var IProvider $provider */ |
|
| 96 | + $provider = $this->container->query($registration['class']); |
|
| 97 | + $this->providers[$provider->getId()] = $provider; |
|
| 98 | + } catch (QueryException $e) { |
|
| 99 | + // Log an continue. We can be fault tolerant here. |
|
| 100 | + $this->logger->logException($e, [ |
|
| 101 | + 'message' => 'Could not load search provider dynamically: ' . $e->getMessage(), |
|
| 102 | + 'level' => ILogger::ERROR, |
|
| 103 | + ]); |
|
| 104 | + } |
|
| 105 | + } |
|
| 106 | + } |
|
| 107 | + |
|
| 108 | + /** |
|
| 109 | + * Get a list of all provider IDs & Names for the consecutive calls to `search` |
|
| 110 | + * Sort the list by the order property |
|
| 111 | + * |
|
| 112 | + * @param string $route the route the user is currently at |
|
| 113 | + * @param array $routeParameters the parameters of the route the user is currently at |
|
| 114 | + * |
|
| 115 | + * @return array |
|
| 116 | + */ |
|
| 117 | + public function getProviders(string $route, array $routeParameters): array { |
|
| 118 | + $this->loadLazyProviders(); |
|
| 119 | + |
|
| 120 | + $providers = array_values( |
|
| 121 | + array_map(function (IProvider $provider) use ($route, $routeParameters) { |
|
| 122 | + return [ |
|
| 123 | + 'id' => $provider->getId(), |
|
| 124 | + 'name' => $provider->getName(), |
|
| 125 | + 'order' => $provider->getOrder($route, $routeParameters), |
|
| 126 | + ]; |
|
| 127 | + }, $this->providers) |
|
| 128 | + ); |
|
| 129 | + |
|
| 130 | + usort($providers, function ($provider1, $provider2) { |
|
| 131 | + return $provider1['order'] <=> $provider2['order']; |
|
| 132 | + }); |
|
| 133 | + |
|
| 134 | + /** |
|
| 135 | + * Return an array with the IDs, but strip the associative keys |
|
| 136 | + */ |
|
| 137 | + return $providers; |
|
| 138 | + } |
|
| 139 | + |
|
| 140 | + /** |
|
| 141 | + * Query an individual search provider for results |
|
| 142 | + * |
|
| 143 | + * @param IUser $user |
|
| 144 | + * @param string $providerId one of the IDs received by `getProviders` |
|
| 145 | + * @param ISearchQuery $query |
|
| 146 | + * |
|
| 147 | + * @return SearchResult |
|
| 148 | + * @throws InvalidArgumentException when the $providerId does not correspond to a registered provider |
|
| 149 | + */ |
|
| 150 | + public function search(IUser $user, |
|
| 151 | + string $providerId, |
|
| 152 | + ISearchQuery $query): SearchResult { |
|
| 153 | + $this->loadLazyProviders(); |
|
| 154 | + |
|
| 155 | + $provider = $this->providers[$providerId] ?? null; |
|
| 156 | + if ($provider === null) { |
|
| 157 | + throw new InvalidArgumentException("Provider $providerId is unknown"); |
|
| 158 | + } |
|
| 159 | + return $provider->search($user, $query); |
|
| 160 | + } |
|
| 161 | 161 | } |
@@ -98,7 +98,7 @@ discard block |
||
| 98 | 98 | } catch (QueryException $e) { |
| 99 | 99 | // Log an continue. We can be fault tolerant here. |
| 100 | 100 | $this->logger->logException($e, [ |
| 101 | - 'message' => 'Could not load search provider dynamically: ' . $e->getMessage(), |
|
| 101 | + 'message' => 'Could not load search provider dynamically: '.$e->getMessage(), |
|
| 102 | 102 | 'level' => ILogger::ERROR, |
| 103 | 103 | ]); |
| 104 | 104 | } |
@@ -118,7 +118,7 @@ discard block |
||
| 118 | 118 | $this->loadLazyProviders(); |
| 119 | 119 | |
| 120 | 120 | $providers = array_values( |
| 121 | - array_map(function (IProvider $provider) use ($route, $routeParameters) { |
|
| 121 | + array_map(function(IProvider $provider) use ($route, $routeParameters) { |
|
| 122 | 122 | return [ |
| 123 | 123 | 'id' => $provider->getId(), |
| 124 | 124 | 'name' => $provider->getName(), |
@@ -127,7 +127,7 @@ discard block |
||
| 127 | 127 | }, $this->providers) |
| 128 | 128 | ); |
| 129 | 129 | |
| 130 | - usort($providers, function ($provider1, $provider2) { |
|
| 130 | + usort($providers, function($provider1, $provider2) { |
|
| 131 | 131 | return $provider1['order'] <=> $provider2['order']; |
| 132 | 132 | }); |
| 133 | 133 | |