You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FileSystemTags.php 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Julius Härtl <jus@bitgrid.net>
  9. * @author Richard Steinmetz <richard@steinmetz.cloud>
  10. *
  11. * @license GNU AGPL version 3 or any later version
  12. *
  13. * This program is free software: you can redistribute it and/or modify
  14. * it under the terms of the GNU Affero General Public License as
  15. * published by the Free Software Foundation, either version 3 of the
  16. * License, or (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU Affero General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Affero General Public License
  24. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  25. *
  26. */
  27. namespace OCA\WorkflowEngine\Check;
  28. use OCA\Files_Sharing\SharedStorage;
  29. use OCA\WorkflowEngine\Entity\File;
  30. use OCP\Files\Cache\ICache;
  31. use OCP\Files\IHomeStorage;
  32. use OCP\IL10N;
  33. use OCP\SystemTag\ISystemTagManager;
  34. use OCP\SystemTag\ISystemTagObjectMapper;
  35. use OCP\SystemTag\TagNotFoundException;
  36. use OCP\WorkflowEngine\ICheck;
  37. use OCP\WorkflowEngine\IFileCheck;
  38. class FileSystemTags implements ICheck, IFileCheck {
  39. use TFileCheck;
  40. /** @var array */
  41. protected $fileIds;
  42. /** @var array */
  43. protected $fileSystemTags;
  44. /** @var IL10N */
  45. protected $l;
  46. /** @var ISystemTagManager */
  47. protected $systemTagManager;
  48. /** @var ISystemTagObjectMapper */
  49. protected $systemTagObjectMapper;
  50. /**
  51. * @param IL10N $l
  52. * @param ISystemTagManager $systemTagManager
  53. * @param ISystemTagObjectMapper $systemTagObjectMapper
  54. */
  55. public function __construct(IL10N $l, ISystemTagManager $systemTagManager, ISystemTagObjectMapper $systemTagObjectMapper) {
  56. $this->l = $l;
  57. $this->systemTagManager = $systemTagManager;
  58. $this->systemTagObjectMapper = $systemTagObjectMapper;
  59. }
  60. /**
  61. * @param string $operator
  62. * @param string $value
  63. * @return bool
  64. */
  65. public function executeCheck($operator, $value) {
  66. $systemTags = $this->getSystemTags();
  67. return ($operator === 'is') === in_array($value, $systemTags);
  68. }
  69. /**
  70. * @param string $operator
  71. * @param string $value
  72. * @throws \UnexpectedValueException
  73. */
  74. public function validateCheck($operator, $value) {
  75. if (!in_array($operator, ['is', '!is'])) {
  76. throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1);
  77. }
  78. try {
  79. $this->systemTagManager->getTagsByIds($value);
  80. } catch (TagNotFoundException $e) {
  81. throw new \UnexpectedValueException($this->l->t('The given tag id is invalid'), 2);
  82. } catch (\InvalidArgumentException $e) {
  83. throw new \UnexpectedValueException($this->l->t('The given tag id is invalid'), 3);
  84. }
  85. }
  86. /**
  87. * Get the ids of the assigned system tags
  88. * @return string[]
  89. */
  90. protected function getSystemTags() {
  91. $cache = $this->storage->getCache();
  92. $fileIds = $this->getFileIds($cache, $this->path, !$this->storage->instanceOfStorage(IHomeStorage::class) || $this->storage->instanceOfStorage(SharedStorage::class));
  93. $systemTags = [];
  94. foreach ($fileIds as $i => $fileId) {
  95. if (isset($this->fileSystemTags[$fileId])) {
  96. $systemTags[] = $this->fileSystemTags[$fileId];
  97. unset($fileIds[$i]);
  98. }
  99. }
  100. if (!empty($fileIds)) {
  101. $mappedSystemTags = $this->systemTagObjectMapper->getTagIdsForObjects($fileIds, 'files');
  102. foreach ($mappedSystemTags as $fileId => $fileSystemTags) {
  103. $this->fileSystemTags[$fileId] = $fileSystemTags;
  104. $systemTags[] = $fileSystemTags;
  105. }
  106. }
  107. $systemTags = call_user_func_array('array_merge', $systemTags);
  108. $systemTags = array_unique($systemTags);
  109. return $systemTags;
  110. }
  111. /**
  112. * Get the file ids of the given path and its parents
  113. * @param ICache $cache
  114. * @param string $path
  115. * @param bool $isExternalStorage
  116. * @return int[]
  117. */
  118. protected function getFileIds(ICache $cache, $path, $isExternalStorage) {
  119. // TODO: Fix caching inside group folders
  120. // Do not cache file ids inside group folders because multiple file ids might be mapped to
  121. // the same combination of cache id + path.
  122. $shouldCacheFileIds = !$this->storage
  123. ->instanceOfStorage(\OCA\GroupFolders\Mount\GroupFolderStorage::class);
  124. $cacheId = $cache->getNumericStorageId();
  125. if ($shouldCacheFileIds && isset($this->fileIds[$cacheId][$path])) {
  126. return $this->fileIds[$cacheId][$path];
  127. }
  128. $parentIds = [];
  129. if ($path !== $this->dirname($path)) {
  130. $parentIds = $this->getFileIds($cache, $this->dirname($path), $isExternalStorage);
  131. } elseif (!$isExternalStorage) {
  132. return [];
  133. }
  134. $fileId = $cache->getId($path);
  135. if ($fileId !== -1) {
  136. $parentIds[] = $cache->getId($path);
  137. }
  138. if ($shouldCacheFileIds) {
  139. $this->fileIds[$cacheId][$path] = $parentIds;
  140. }
  141. return $parentIds;
  142. }
  143. protected function dirname($path) {
  144. $dir = dirname($path);
  145. return $dir === '.' ? '' : $dir;
  146. }
  147. public function supportedEntities(): array {
  148. return [ File::class ];
  149. }
  150. public function isAvailableForScope(int $scope): bool {
  151. return true;
  152. }
  153. }