TasksSearchProvider.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\DAV\Search;
  8. use OCA\DAV\CalDAV\CalDavBackend;
  9. use OCP\IUser;
  10. use OCP\Search\ISearchQuery;
  11. use OCP\Search\SearchResult;
  12. use OCP\Search\SearchResultEntry;
  13. use Sabre\VObject\Component;
  14. /**
  15. * Class TasksSearchProvider
  16. *
  17. * @package OCA\DAV\Search
  18. */
  19. class TasksSearchProvider extends ACalendarSearchProvider {
  20. /**
  21. * @var string[]
  22. */
  23. private static $searchProperties = [
  24. 'SUMMARY',
  25. 'DESCRIPTION',
  26. 'CATEGORIES',
  27. ];
  28. /**
  29. * @var string[]
  30. */
  31. private static $searchParameters = [];
  32. /**
  33. * @var string
  34. */
  35. private static $componentType = 'VTODO';
  36. /**
  37. * @inheritDoc
  38. */
  39. public function getId(): string {
  40. return 'tasks';
  41. }
  42. /**
  43. * @inheritDoc
  44. */
  45. public function getName(): string {
  46. return $this->l10n->t('Tasks');
  47. }
  48. /**
  49. * @inheritDoc
  50. */
  51. public function getOrder(string $route, array $routeParameters): ?int {
  52. if ($this->appManager->isEnabledForUser('tasks')) {
  53. return $route === 'tasks.Page.index' ? -1 : 35;
  54. }
  55. return null;
  56. }
  57. /**
  58. * @inheritDoc
  59. */
  60. public function search(
  61. IUser $user,
  62. ISearchQuery $query,
  63. ): SearchResult {
  64. if (!$this->appManager->isEnabledForUser('tasks', $user)) {
  65. return SearchResult::complete($this->getName(), []);
  66. }
  67. $principalUri = 'principals/users/' . $user->getUID();
  68. $calendarsById = $this->getSortedCalendars($principalUri);
  69. $subscriptionsById = $this->getSortedSubscriptions($principalUri);
  70. $searchResults = $this->backend->searchPrincipalUri(
  71. $principalUri,
  72. $query->getFilter('term')?->get() ?? '',
  73. [self::$componentType],
  74. self::$searchProperties,
  75. self::$searchParameters,
  76. [
  77. 'limit' => $query->getLimit(),
  78. 'offset' => $query->getCursor(),
  79. 'since' => $query->getFilter('since'),
  80. 'until' => $query->getFilter('until'),
  81. ]
  82. );
  83. $formattedResults = \array_map(function (array $taskRow) use ($calendarsById, $subscriptionsById):SearchResultEntry {
  84. $component = $this->getPrimaryComponent($taskRow['calendardata'], self::$componentType);
  85. $title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled task'));
  86. $subline = $this->generateSubline($component);
  87. if ($taskRow['calendartype'] === CalDavBackend::CALENDAR_TYPE_CALENDAR) {
  88. $calendar = $calendarsById[$taskRow['calendarid']];
  89. } else {
  90. $calendar = $subscriptionsById[$taskRow['calendarid']];
  91. }
  92. $resourceUrl = $this->getDeepLinkToTasksApp($calendar['uri'], $taskRow['uri']);
  93. return new SearchResultEntry('', $title, $subline, $resourceUrl, 'icon-checkmark', false);
  94. }, $searchResults);
  95. return SearchResult::paginated(
  96. $this->getName(),
  97. $formattedResults,
  98. $query->getCursor() + count($formattedResults)
  99. );
  100. }
  101. protected function getDeepLinkToTasksApp(
  102. string $calendarUri,
  103. string $taskUri,
  104. ): string {
  105. return $this->urlGenerator->getAbsoluteURL(
  106. $this->urlGenerator->linkToRoute('tasks.page.index')
  107. . '#/calendars/'
  108. . $calendarUri
  109. . '/tasks/'
  110. . $taskUri
  111. );
  112. }
  113. protected function generateSubline(Component $taskComponent): string {
  114. if ($taskComponent->COMPLETED) {
  115. $completedDateTime = new \DateTime($taskComponent->COMPLETED->getDateTime()->format(\DateTimeInterface::ATOM));
  116. $formattedDate = $this->l10n->l('date', $completedDateTime, ['width' => 'medium']);
  117. return $this->l10n->t('Completed on %s', [$formattedDate]);
  118. }
  119. if ($taskComponent->DUE) {
  120. $dueDateTime = new \DateTime($taskComponent->DUE->getDateTime()->format(\DateTimeInterface::ATOM));
  121. $formattedDate = $this->l10n->l('date', $dueDateTime, ['width' => 'medium']);
  122. if ($taskComponent->DUE->hasTime()) {
  123. $formattedTime = $this->l10n->l('time', $dueDateTime, ['width' => 'short']);
  124. return $this->l10n->t('Due on %s by %s', [$formattedDate, $formattedTime]);
  125. }
  126. return $this->l10n->t('Due on %s', [$formattedDate]);
  127. }
  128. return '';
  129. }
  130. }